Delete base unittests and build files Change-Id: I734ea94edff2974d8ebe5c990bbd18233e9ce356 Reviewed-on: https://gn-review.googlesource.com/1403 Reviewed-by: Brett Wilson <brettw@chromium.org>
diff --git a/base/BUILD.gn b/base/BUILD.gn deleted file mode 100644 index 28542b2..0000000 --- a/base/BUILD.gn +++ /dev/null
@@ -1,3164 +0,0 @@ -# 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. - -# HOW TO WRITE CONDITIONALS IN THIS FILE -# ====================================== -# -# In many other places, one would write a conditional that expresses all the -# cases when a source file is used or unused, and then either add or subtract -# it from the sources list in that case -# -# Since base includes so many low-level things that vary widely and -# unpredictably for the various build types, we prefer a slightly different -# style. Instead, there are big per-platform blocks of inclusions and -# exclusions. If a given file has an inclusion or exclusion rule that applies -# for multiple conditions, prefer to duplicate it in both lists. This makes it -# a bit easier to see which files apply in which cases rather than having a -# huge sequence of random-looking conditionals. - -import("//build/buildflag_header.gni") -import("//build/config/allocator.gni") -import("//build/config/arm.gni") -import("//build/config/c++/c++.gni") -import("//build/config/chromecast_build.gni") -import("//build/config/compiler/compiler.gni") -import("//build/config/dcheck_always_on.gni") -import("//build/config/jumbo.gni") -import("//build/config/nacl/config.gni") -import("//build/config/sysroot.gni") -import("//build/config/ui.gni") -import("//build/nocompile.gni") -import("//testing/libfuzzer/fuzzer_test.gni") -import("//testing/test.gni") - -declare_args() { - # Override this value to give a specific build date. - # See //base/build_time.cc and //build/write_build_date_header.py for more - # details and the expected format. - override_build_date = "N/A" - - # Indicates if the Location object contains the source code information - # (file, function, line). False means only the program counter (and currently - # file name) is saved. - enable_location_source = true - - # Unsafe developer build. Has developer-friendly features that may weaken or - # disable security measures like sandboxing or ASLR. - # IMPORTANT: Unsafe developer builds should never be distributed to end users. - is_unsafe_developer_build = !is_official_build - - # Set to true to disable COM init check hooks. - com_init_check_hook_disabled = false - - # Set to true to enable mutex priority inheritance. See the comments in - # LockImpl::PriorityInheritanceAvailable() in lock_impl_posix.cc for the - # platform requirements to safely enable priority inheritance. - enable_mutex_priority_inheritance = false -} - -# Determines whether libevent should be dep. -dep_libevent = !is_fuchsia && !is_win && !(is_nacl && !is_nacl_nonsfi) - -# Determines whether message_pump_libevent should be used. -use_libevent = dep_libevent && !is_ios - -if (is_android) { - import("//build/config/android/rules.gni") -} - -if (is_fuchsia) { - import("//third_party/fuchsia-sdk/fidl_library.gni") -} - -config("base_flags") { - if (is_clang) { - cflags = [ - # Don't die on dtoa code that uses a char as an array index. - # This is required solely for base/third_party/dmg_fp/dtoa_wrapper.cc. - "-Wno-char-subscripts", - - # Ideally all product code (but no test code) in chrome would have these - # flags. But this isn't trivial so start with //base as a minimum - # requirement. - # https://groups.google.com/a/chromium.org/d/topic/chromium-dev/B9Q5KTD7iCo/discussion - "-Wglobal-constructors", - "-Wexit-time-destructors", - ] - } -} - -config("base_implementation") { - defines = [ "BASE_IMPLEMENTATION" ] - configs = [ "//build/config/compiler:wexit_time_destructors" ] -} - -if (is_win) { - # This is in a separate config so the flags can be applied to dependents. - # ldflags in GN aren't automatically inherited. - config("base_win_linker_flags") { - ldflags = [ - "/DELAYLOAD:cfgmgr32.dll", - "/DELAYLOAD:powrprof.dll", - "/DELAYLOAD:setupapi.dll", - ] - } -} - -if (is_nacl_nonsfi) { - # Must be in a config because of how GN orders flags (otherwise -Wall will - # appear after this, and turn it back on). - config("nacl_nonsfi_warnings") { - # file_util_posix.cc contains a function which is not - # being used by nacl_helper_nonsfi. - cflags = [ "-Wno-unused-function" ] - } -} - -if (is_android) { - config("android_system_libs") { - libs = [ "log" ] # Used by logging.cc. - } -} - -# Base and everything it depends on should be a static library rather than -# a source set. Base is more of a "library" in the classic sense in that many -# small parts of it are used in many different contexts. This combined with a -# few static initializers floating around means that dead code stripping -# still leaves a lot of code behind that isn't always used. For example, this -# saves more than 40K for a smaller target like chrome_elf. -# -# Use static libraries for the helper stuff as well like //base/debug since -# those things refer back to base code, which will force base compilation units -# to be linked in where they wouldn't have otherwise. This does not include -# test code (test support and anything in the test directory) which should use -# source_set as is recommended for GN targets). -jumbo_component("base") { - if (is_nacl_nonsfi) { - # TODO(phosek) bug 570839: If field_trial.cc is in a static library, - # nacl_helper_nonsfi doesn't link properly on Linux in debug builds. The - # reasons for this seem to involve obscure toolchain bugs. This should be - # fixed and this target should always be a static_library in the - # non-component case. - static_component_type = "source_set" - } - if (is_nacl || is_ios) { - # Link errors related to malloc functions if libbase for nacl is - # compiled with jumbo: https://crbug.com/775959. - # Same for ios: https://crbug.com/776313. - never_build_jumbo = true - } - - sources = [ - "allocator/allocator_check.cc", - "allocator/allocator_check.h", - "allocator/allocator_extension.cc", - "allocator/allocator_extension.h", - "allocator/allocator_interception_mac.h", - "allocator/allocator_interception_mac.mm", - "allocator/allocator_shim.h", - "allocator/malloc_zone_functions_mac.cc", - "allocator/malloc_zone_functions_mac.h", - "android/android_hardware_buffer_abi.h", - "android/android_hardware_buffer_compat.cc", - "android/android_hardware_buffer_compat.h", - "android/animation_frame_time_histogram.cc", - "android/apk_assets.cc", - "android/apk_assets.h", - "android/application_status_listener.cc", - "android/application_status_listener.h", - "android/base_jni_onload.cc", - "android/base_jni_onload.h", - "android/build_info.cc", - "android/build_info.h", - "android/callback_android.cc", - "android/callback_android.h", - "android/child_process_service.cc", - "android/command_line_android.cc", - "android/content_uri_utils.cc", - "android/content_uri_utils.h", - "android/cpu_features.cc", - "android/early_trace_event_binding.cc", - "android/event_log.cc", - "android/event_log.h", - "android/field_trial_list.cc", - "android/important_file_writer_android.cc", - "android/java_exception_reporter.cc", - "android/java_exception_reporter.h", - "android/java_handler_thread.cc", - "android/java_handler_thread.h", - "android/java_runtime.cc", - "android/java_runtime.h", - "android/jni_android.cc", - "android/jni_android.h", - "android/jni_array.cc", - "android/jni_array.h", - "android/jni_generator/jni_generator_helper.h", - "android/jni_int_wrapper.h", - "android/jni_registrar.cc", - "android/jni_registrar.h", - "android/jni_string.cc", - "android/jni_string.h", - "android/jni_utils.cc", - "android/jni_utils.h", - "android/jni_weak_ref.cc", - "android/jni_weak_ref.h", - "android/library_loader/anchor_functions.cc", - "android/library_loader/anchor_functions.h", - "android/library_loader/library_load_from_apk_status_codes.h", - "android/library_loader/library_loader_hooks.cc", - "android/library_loader/library_loader_hooks.h", - "android/library_loader/library_prefetcher.cc", - "android/library_loader/library_prefetcher.h", - "android/locale_utils.cc", - "android/locale_utils.h", - "android/memory_pressure_listener_android.cc", - "android/memory_pressure_listener_android.h", - "android/path_service_android.cc", - "android/path_utils.cc", - "android/path_utils.h", - "android/record_histogram.cc", - "android/record_user_action.cc", - "android/scoped_hardware_buffer_handle.cc", - "android/scoped_hardware_buffer_handle.h", - "android/scoped_java_ref.cc", - "android/scoped_java_ref.h", - "android/statistics_recorder_android.cc", - "android/sys_utils.cc", - "android/sys_utils.h", - "android/throw_uncaught_exception.cc", - "android/throw_uncaught_exception.h", - "android/time_utils.cc", - "android/timezone_utils.cc", - "android/timezone_utils.h", - "android/trace_event_binding.cc", - "android/unguessable_token_android.cc", - "android/unguessable_token_android.h", - "at_exit.cc", - "at_exit.h", - "atomic_ref_count.h", - "atomic_sequence_num.h", - "atomicops.h", - "atomicops_internals_atomicword_compat.h", - "atomicops_internals_portable.h", - "atomicops_internals_x86_msvc.h", - "auto_reset.h", - "barrier_closure.cc", - "barrier_closure.h", - "base64.cc", - "base64.h", - "base64url.cc", - "base64url.h", - "base_export.h", - "base_switches.h", - "big_endian.cc", - "big_endian.h", - "bind.h", - "bind_helpers.h", - "bind_internal.h", - "bit_cast.h", - "bits.h", - "build_time.cc", - "build_time.h", - "callback.h", - "callback_forward.h", - "callback_helpers.cc", - "callback_helpers.h", - "callback_internal.cc", - "callback_internal.h", - "callback_list.h", - "cancelable_callback.h", - "command_line.cc", - "command_line.h", - "compiler_specific.h", - "component_export.h", - "containers/adapters.h", - "containers/circular_deque.h", - "containers/flat_map.h", - "containers/flat_set.h", - "containers/flat_tree.h", - "containers/hash_tables.h", - "containers/id_map.h", - "containers/linked_list.h", - "containers/mru_cache.h", - "containers/small_map.h", - "containers/span.h", - "containers/stack.h", - "containers/stack_container.h", - "containers/unique_ptr_adapters.h", - "containers/vector_buffer.h", - "cpu.cc", - "cpu.h", - "critical_closure.h", - "critical_closure_internal_ios.mm", - - # This file depends on files from the "debug/allocator" target, - # but this target does not depend on "debug/allocator". - "debug/activity_analyzer.cc", - "debug/activity_analyzer.h", - "debug/activity_tracker.cc", - "debug/activity_tracker.h", - "debug/alias.cc", - "debug/alias.h", - "debug/asan_invalid_access.cc", - "debug/asan_invalid_access.h", - "debug/close_handle_hook_win.cc", - "debug/close_handle_hook_win.h", - "debug/crash_logging.cc", - "debug/crash_logging.h", - "debug/debugger.cc", - "debug/debugger.h", - "debug/debugger_win.cc", - "debug/dump_without_crashing.cc", - "debug/dump_without_crashing.h", - "debug/gdi_debug_util_win.cc", - "debug/gdi_debug_util_win.h", - "debug/leak_annotations.h", - "debug/leak_tracker.h", - "debug/proc_maps_linux.cc", - "debug/proc_maps_linux.h", - "debug/profiler.cc", - "debug/profiler.h", - "debug/stack_trace.cc", - "debug/stack_trace.h", - "debug/stack_trace_android.cc", - "debug/stack_trace_win.cc", - "debug/task_annotator.cc", - "debug/task_annotator.h", - "debug/thread_heap_usage_tracker.cc", - "debug/thread_heap_usage_tracker.h", - "deferred_sequenced_task_runner.cc", - "deferred_sequenced_task_runner.h", - "environment.cc", - "environment.h", - "export_template.h", - "feature_list.cc", - "feature_list.h", - "file_descriptor_store.cc", - "file_descriptor_store.h", - "file_version_info.h", - "file_version_info_mac.h", - "file_version_info_mac.mm", - "file_version_info_win.cc", - "file_version_info_win.h", - "files/dir_reader_fallback.h", - "files/dir_reader_linux.h", - "files/file.cc", - "files/file.h", - "files/file_enumerator.cc", - "files/file_enumerator.h", - "files/file_enumerator_win.cc", - "files/file_path.cc", - "files/file_path.h", - "files/file_path_constants.cc", - "files/file_path_watcher.cc", - "files/file_path_watcher.h", - "files/file_path_watcher_fsevents.cc", - "files/file_path_watcher_fsevents.h", - "files/file_path_watcher_kqueue.cc", - "files/file_path_watcher_kqueue.h", - "files/file_path_watcher_linux.cc", - "files/file_path_watcher_mac.cc", - "files/file_path_watcher_win.cc", - "files/file_proxy.cc", - "files/file_proxy.h", - "files/file_tracing.cc", - "files/file_tracing.h", - "files/file_util.cc", - "files/file_util.h", - "files/file_util_android.cc", - "files/file_util_linux.cc", - "files/file_util_mac.mm", - "files/file_util_win.cc", - "files/file_win.cc", - "files/important_file_writer.cc", - "files/important_file_writer.h", - "files/memory_mapped_file.cc", - "files/memory_mapped_file.h", - "files/memory_mapped_file_win.cc", - "files/platform_file.h", - "files/scoped_file.cc", - "files/scoped_file.h", - "files/scoped_temp_dir.cc", - "files/scoped_temp_dir.h", - "format_macros.h", - "gtest_prod_util.h", - "guid.cc", - "guid.h", - "hash.cc", - "hash.h", - "ios/block_types.h", - "ios/crb_protocol_observers.h", - "ios/crb_protocol_observers.mm", - "ios/device_util.h", - "ios/device_util.mm", - "ios/ios_util.h", - "ios/ios_util.mm", - "ios/ns_error_util.h", - "ios/ns_error_util.mm", - "ios/scoped_critical_action.h", - "ios/scoped_critical_action.mm", - "ios/weak_nsobject.h", - "ios/weak_nsobject.mm", - "json/json_file_value_serializer.cc", - "json/json_file_value_serializer.h", - "json/json_parser.cc", - "json/json_parser.h", - "json/json_reader.cc", - "json/json_reader.h", - "json/json_string_value_serializer.cc", - "json/json_string_value_serializer.h", - "json/json_value_converter.cc", - "json/json_value_converter.h", - "json/json_writer.cc", - "json/json_writer.h", - "json/string_escape.cc", - "json/string_escape.h", - "lazy_instance.h", - "lazy_instance_helpers.cc", - "lazy_instance_helpers.h", - "linux_util.cc", - "linux_util.h", - "location.cc", - "location.h", - "logging.cc", - "logging.h", - "logging_win.cc", - "logging_win.h", - "mac/authorization_util.h", - "mac/authorization_util.mm", - "mac/availability.h", - "mac/bind_objc_block.h", - "mac/bundle_locations.h", - "mac/bundle_locations.mm", - "mac/call_with_eh_frame.cc", - "mac/call_with_eh_frame.h", - "mac/call_with_eh_frame_asm.S", - "mac/close_nocancel.cc", - "mac/dispatch_source_mach.cc", - "mac/dispatch_source_mach.h", - "mac/foundation_util.h", - "mac/foundation_util.mm", - "mac/launch_services_util.h", - "mac/launch_services_util.mm", - "mac/launchd.cc", - "mac/launchd.h", - "mac/mac_logging.h", - "mac/mac_logging.mm", - "mac/mac_util.h", - "mac/mac_util.mm", - "mac/mach_logging.cc", - "mac/mach_logging.h", - "mac/mach_port_broker.h", - "mac/mach_port_broker.mm", - "mac/mach_port_util.cc", - "mac/mach_port_util.h", - "mac/objc_release_properties.h", - "mac/objc_release_properties.mm", - "mac/os_crash_dumps.cc", - "mac/os_crash_dumps.h", - "mac/scoped_aedesc.h", - "mac/scoped_authorizationref.h", - "mac/scoped_block.h", - "mac/scoped_cffiledescriptorref.h", - "mac/scoped_cftyperef.h", - "mac/scoped_dispatch_object.h", - "mac/scoped_ionotificationportref.h", - "mac/scoped_ioobject.h", - "mac/scoped_ioplugininterface.h", - "mac/scoped_launch_data.h", - "mac/scoped_mach_port.cc", - "mac/scoped_mach_port.h", - "mac/scoped_mach_vm.cc", - "mac/scoped_mach_vm.h", - "mac/scoped_nsautorelease_pool.h", - "mac/scoped_nsautorelease_pool.mm", - "mac/scoped_nsobject.h", - "mac/scoped_nsobject.mm", - "mac/scoped_objc_class_swizzler.h", - "mac/scoped_objc_class_swizzler.mm", - "mac/scoped_sending_event.h", - "mac/scoped_sending_event.mm", - "mac/sdk_forward_declarations.h", - "mac/sdk_forward_declarations.mm", - "macros.h", - "md5.cc", - "md5.h", - "memory/aligned_memory.cc", - "memory/aligned_memory.h", - "memory/discardable_memory.cc", - "memory/discardable_memory.h", - "memory/discardable_memory_allocator.cc", - "memory/discardable_memory_allocator.h", - "memory/discardable_shared_memory.cc", - "memory/discardable_shared_memory.h", - "memory/free_deleter.h", - "memory/linked_ptr.h", - "memory/memory_coordinator_client.cc", - "memory/memory_coordinator_client.h", - "memory/memory_coordinator_client_registry.cc", - "memory/memory_coordinator_client_registry.h", - "memory/memory_coordinator_proxy.cc", - "memory/memory_coordinator_proxy.h", - "memory/memory_pressure_listener.cc", - "memory/memory_pressure_listener.h", - "memory/memory_pressure_monitor.cc", - "memory/memory_pressure_monitor.h", - "memory/memory_pressure_monitor_chromeos.cc", - "memory/memory_pressure_monitor_chromeos.h", - "memory/memory_pressure_monitor_mac.cc", - "memory/memory_pressure_monitor_mac.h", - "memory/memory_pressure_monitor_win.cc", - "memory/memory_pressure_monitor_win.h", - "memory/platform_shared_memory_region.cc", - "memory/platform_shared_memory_region.h", - "memory/protected_memory.cc", - "memory/protected_memory.h", - "memory/protected_memory_cfi.h", - "memory/protected_memory_win.cc", - "memory/ptr_util.h", - "memory/raw_scoped_refptr_mismatch_checker.h", - "memory/read_only_shared_memory_region.cc", - "memory/read_only_shared_memory_region.h", - "memory/ref_counted.cc", - "memory/ref_counted.h", - "memory/ref_counted_delete_on_sequence.h", - "memory/ref_counted_memory.cc", - "memory/ref_counted_memory.h", - "memory/scoped_policy.h", - "memory/scoped_refptr.h", - "memory/shared_memory.h", - "memory/shared_memory_handle.cc", - "memory/shared_memory_handle.h", - "memory/shared_memory_helper.cc", - "memory/shared_memory_helper.h", - "memory/shared_memory_mapping.cc", - "memory/shared_memory_mapping.h", - "memory/shared_memory_tracker.cc", - "memory/shared_memory_tracker.h", - "memory/singleton.h", - "memory/unsafe_shared_memory_region.cc", - "memory/unsafe_shared_memory_region.h", - "memory/weak_ptr.cc", - "memory/weak_ptr.h", - "memory/writable_shared_memory_region.cc", - "memory/writable_shared_memory_region.h", - "message_loop/incoming_task_queue.cc", - "message_loop/incoming_task_queue.h", - "message_loop/message_loop.cc", - "message_loop/message_loop.h", - "message_loop/message_loop_current.cc", - "message_loop/message_loop_current.h", - "message_loop/message_loop_task_runner.cc", - "message_loop/message_loop_task_runner.h", - "message_loop/message_pump.cc", - "message_loop/message_pump.h", - "message_loop/message_pump_android.cc", - "message_loop/message_pump_android.h", - "message_loop/message_pump_default.cc", - "message_loop/message_pump_default.h", - "message_loop/message_pump_for_io.h", - "message_loop/message_pump_for_ui.h", - "message_loop/message_pump_glib.cc", - "message_loop/message_pump_glib.h", - "message_loop/message_pump_io_ios.cc", - "message_loop/message_pump_io_ios.h", - "message_loop/message_pump_mac.h", - "message_loop/message_pump_mac.mm", - "message_loop/message_pump_win.cc", - "message_loop/message_pump_win.h", - "message_loop/timer_slack.h", - "metrics/bucket_ranges.cc", - "metrics/bucket_ranges.h", - "metrics/dummy_histogram.cc", - "metrics/dummy_histogram.h", - "metrics/field_trial.cc", - "metrics/field_trial.h", - "metrics/field_trial_param_associator.cc", - "metrics/field_trial_param_associator.h", - "metrics/field_trial_params.cc", - "metrics/field_trial_params.h", - "metrics/histogram.cc", - "metrics/histogram.h", - "metrics/histogram_base.cc", - "metrics/histogram_base.h", - "metrics/histogram_delta_serialization.cc", - "metrics/histogram_delta_serialization.h", - "metrics/histogram_flattener.h", - "metrics/histogram_functions.cc", - "metrics/histogram_functions.h", - "metrics/histogram_macros.h", - "metrics/histogram_macros_internal.h", - "metrics/histogram_macros_local.h", - "metrics/histogram_samples.cc", - "metrics/histogram_samples.h", - "metrics/histogram_snapshot_manager.cc", - "metrics/histogram_snapshot_manager.h", - "metrics/metrics_hashes.cc", - "metrics/metrics_hashes.h", - "metrics/persistent_histogram_allocator.cc", - "metrics/persistent_histogram_allocator.h", - "metrics/persistent_memory_allocator.cc", - "metrics/persistent_memory_allocator.h", - "metrics/persistent_sample_map.cc", - "metrics/persistent_sample_map.h", - "metrics/record_histogram_checker.h", - "metrics/sample_map.cc", - "metrics/sample_map.h", - "metrics/sample_vector.cc", - "metrics/sample_vector.h", - "metrics/single_sample_metrics.cc", - "metrics/single_sample_metrics.h", - "metrics/sparse_histogram.cc", - "metrics/sparse_histogram.h", - "metrics/statistics_recorder.cc", - "metrics/statistics_recorder.h", - "metrics/user_metrics.cc", - "metrics/user_metrics.h", - "metrics/user_metrics_action.h", - "native_library.cc", - "native_library.h", - "native_library_ios.mm", - "native_library_mac.mm", - "native_library_win.cc", - "nix/mime_util_xdg.cc", - "nix/mime_util_xdg.h", - "nix/xdg_util.cc", - "nix/xdg_util.h", - "no_destructor.h", - "observer_list.h", - "observer_list_threadsafe.cc", - "observer_list_threadsafe.h", - "optional.h", - "os_compat_android.cc", - "os_compat_android.h", - "os_compat_nacl.cc", - "os_compat_nacl.h", - "path_service.cc", - "path_service.h", - "pending_task.cc", - "pending_task.h", - "pickle.cc", - "pickle.h", - "post_task_and_reply_with_result_internal.h", - "power_monitor/power_monitor.cc", - "power_monitor/power_monitor.h", - "power_monitor/power_monitor_device_source.cc", - "power_monitor/power_monitor_device_source.h", - "power_monitor/power_monitor_source.cc", - "power_monitor/power_monitor_source.h", - "power_monitor/power_observer.h", - "process/internal_linux.cc", - "process/internal_linux.h", - "process/kill.cc", - "process/kill.h", - "process/kill_mac.cc", - "process/kill_win.cc", - "process/launch.cc", - "process/launch.h", - "process/launch_ios.cc", - "process/launch_mac.cc", - "process/launch_win.cc", - "process/memory.cc", - "process/memory.h", - "process/memory_linux.cc", - "process/memory_mac.mm", - "process/memory_win.cc", - "process/port_provider_mac.cc", - "process/port_provider_mac.h", - "process/process.h", - "process/process_handle.cc", - "process/process_handle.h", - - #"process/process_handle_freebsd.cc", # Unused in Chromium build. - "process/process_handle_linux.cc", - "process/process_handle_mac.cc", - - #"process/process_handle_openbsd.cc", # Unused in Chromium build. - "process/process_handle_win.cc", - "process/process_info.h", - "process/process_info_linux.cc", - "process/process_info_mac.cc", - "process/process_info_win.cc", - "process/process_iterator.cc", - "process/process_iterator.h", - - #"process/process_iterator_freebsd.cc", # Unused in Chromium build. - "process/process_iterator_linux.cc", - "process/process_iterator_mac.cc", - - #"process/process_iterator_openbsd.cc", # Unused in Chromium build. - "process/process_iterator_win.cc", - "process/process_linux.cc", - "process/process_mac.cc", - "process/process_metrics.cc", - "process/process_metrics.h", - - #"process/process_metrics_freebsd.cc", # Unused in Chromium build. - "process/process_metrics_ios.cc", - "process/process_metrics_linux.cc", - "process/process_metrics_mac.cc", - - #"process/process_metrics_openbsd.cc", # Unused in Chromium build. - "process/process_metrics_win.cc", - "process/process_win.cc", - "profiler/native_stack_sampler.cc", - "profiler/native_stack_sampler.h", - "profiler/native_stack_sampler_mac.cc", - "profiler/native_stack_sampler_win.cc", - "profiler/stack_sampling_profiler.cc", - "profiler/stack_sampling_profiler.h", - "rand_util.cc", - "rand_util.h", - "rand_util_nacl.cc", - "rand_util_win.cc", - "run_loop.cc", - "run_loop.h", - "sampling_heap_profiler/sampling_heap_profiler.cc", - "sampling_heap_profiler/sampling_heap_profiler.h", - "scoped_clear_errno.h", - "scoped_generic.h", - "scoped_native_library.cc", - "scoped_native_library.h", - "scoped_observer.h", - "sequence_checker.h", - "sequence_checker_impl.cc", - "sequence_checker_impl.h", - "sequence_token.cc", - "sequence_token.h", - "sequenced_task_runner.cc", - "sequenced_task_runner.h", - "sequenced_task_runner_helpers.h", - "sha1.cc", - "sha1.h", - "single_thread_task_runner.h", - "stl_util.h", - "strings/char_traits.h", - "strings/latin1_string_conversions.cc", - "strings/latin1_string_conversions.h", - "strings/nullable_string16.cc", - "strings/nullable_string16.h", - "strings/pattern.cc", - "strings/pattern.h", - "strings/safe_sprintf.cc", - "strings/safe_sprintf.h", - "strings/strcat.cc", - "strings/strcat.h", - "strings/string16.cc", - "strings/string16.h", - "strings/string_number_conversions.cc", - "strings/string_number_conversions.h", - "strings/string_piece.cc", - "strings/string_piece.h", - "strings/string_piece_forward.h", - "strings/string_split.cc", - "strings/string_split.h", - "strings/string_tokenizer.h", - "strings/string_util.cc", - "strings/string_util.h", - "strings/string_util_constants.cc", - "strings/string_util_win.h", - "strings/stringize_macros.h", - "strings/stringprintf.cc", - "strings/stringprintf.h", - "strings/sys_string_conversions.h", - "strings/sys_string_conversions_mac.mm", - "strings/sys_string_conversions_win.cc", - "strings/utf_offset_string_conversions.cc", - "strings/utf_offset_string_conversions.h", - "strings/utf_string_conversion_utils.cc", - "strings/utf_string_conversion_utils.h", - "strings/utf_string_conversions.cc", - "strings/utf_string_conversions.h", - "supports_user_data.cc", - "supports_user_data.h", - "sync_socket.h", - "sync_socket_win.cc", - "synchronization/atomic_flag.cc", - "synchronization/atomic_flag.h", - "synchronization/cancellation_flag.h", - "synchronization/condition_variable.h", - "synchronization/condition_variable_win.cc", - "synchronization/lock.cc", - "synchronization/lock.h", - "synchronization/lock_impl.h", - "synchronization/lock_impl_win.cc", - "synchronization/spin_wait.h", - "synchronization/waitable_event.h", - "synchronization/waitable_event_mac.cc", - "synchronization/waitable_event_watcher.h", - "synchronization/waitable_event_watcher_mac.cc", - "synchronization/waitable_event_watcher_win.cc", - "synchronization/waitable_event_win.cc", - "sys_byteorder.h", - "sys_info.cc", - "sys_info.h", - "sys_info_android.cc", - "sys_info_chromeos.cc", - "sys_info_internal.h", - "syslog_logging.cc", - "syslog_logging.h", - - #"sys_info_freebsd.cc", # Unused in Chromium build. - "sys_info_ios.mm", - "sys_info_linux.cc", - "sys_info_mac.mm", - - #"sys_info_openbsd.cc", # Unused in Chromium build. - "sys_info_win.cc", - "system_monitor/system_monitor.cc", - "system_monitor/system_monitor.h", - "task/cancelable_task_tracker.cc", - "task/cancelable_task_tracker.h", - "task_runner.cc", - "task_runner.h", - "task_runner_util.h", - "task_scheduler/can_schedule_sequence_observer.h", - "task_scheduler/delayed_task_manager.cc", - "task_scheduler/delayed_task_manager.h", - "task_scheduler/environment_config.cc", - "task_scheduler/environment_config.h", - "task_scheduler/initialization_util.cc", - "task_scheduler/initialization_util.h", - "task_scheduler/lazy_task_runner.cc", - "task_scheduler/lazy_task_runner.h", - "task_scheduler/platform_native_worker_pool_win.cc", - "task_scheduler/platform_native_worker_pool_win.h", - "task_scheduler/post_task.cc", - "task_scheduler/post_task.h", - "task_scheduler/priority_queue.cc", - "task_scheduler/priority_queue.h", - "task_scheduler/scheduler_lock.h", - "task_scheduler/scheduler_lock_impl.cc", - "task_scheduler/scheduler_lock_impl.h", - "task_scheduler/scheduler_single_thread_task_runner_manager.cc", - "task_scheduler/scheduler_single_thread_task_runner_manager.h", - "task_scheduler/scheduler_worker.cc", - "task_scheduler/scheduler_worker.h", - "task_scheduler/scheduler_worker_observer.h", - "task_scheduler/scheduler_worker_params.h", - "task_scheduler/scheduler_worker_pool.cc", - "task_scheduler/scheduler_worker_pool.h", - "task_scheduler/scheduler_worker_pool_impl.cc", - "task_scheduler/scheduler_worker_pool_impl.h", - "task_scheduler/scheduler_worker_pool_params.cc", - "task_scheduler/scheduler_worker_pool_params.h", - "task_scheduler/scheduler_worker_stack.cc", - "task_scheduler/scheduler_worker_stack.h", - "task_scheduler/scoped_set_task_priority_for_current_thread.cc", - "task_scheduler/scoped_set_task_priority_for_current_thread.h", - "task_scheduler/sequence.cc", - "task_scheduler/sequence.h", - "task_scheduler/sequence_sort_key.cc", - "task_scheduler/sequence_sort_key.h", - "task_scheduler/service_thread.cc", - "task_scheduler/service_thread.h", - "task_scheduler/single_thread_task_runner_thread_mode.h", - "task_scheduler/task.cc", - "task_scheduler/task.h", - "task_scheduler/task_scheduler.cc", - "task_scheduler/task_scheduler.h", - "task_scheduler/task_scheduler_impl.cc", - "task_scheduler/task_scheduler_impl.h", - "task_scheduler/task_tracker.cc", - "task_scheduler/task_tracker.h", - "task_scheduler/task_traits.cc", - "task_scheduler/task_traits.h", - "task_scheduler/task_traits_details.h", - "task_scheduler/tracked_ref.h", - "template_util.h", - "test/malloc_wrapper.h", - "third_party/dmg_fp/dmg_fp.h", - "third_party/dmg_fp/dtoa_wrapper.cc", - "third_party/dmg_fp/g_fmt.cc", - "third_party/icu/icu_utf.cc", - "third_party/icu/icu_utf.h", - "third_party/nspr/prtime.cc", - "third_party/nspr/prtime.h", - "third_party/superfasthash/superfasthash.c", - "thread_annotations.h", - "threading/platform_thread.h", - "threading/platform_thread_android.cc", - "threading/platform_thread_linux.cc", - "threading/platform_thread_mac.mm", - "threading/platform_thread_win.cc", - "threading/post_task_and_reply_impl.cc", - "threading/post_task_and_reply_impl.h", - "threading/scoped_blocking_call.cc", - "threading/scoped_blocking_call.h", - "threading/sequence_local_storage_map.cc", - "threading/sequence_local_storage_map.h", - "threading/sequence_local_storage_slot.cc", - "threading/sequence_local_storage_slot.h", - "threading/sequenced_task_runner_handle.cc", - "threading/sequenced_task_runner_handle.h", - "threading/simple_thread.cc", - "threading/simple_thread.h", - "threading/thread.cc", - "threading/thread.h", - "threading/thread_checker.h", - "threading/thread_checker_impl.cc", - "threading/thread_checker_impl.h", - "threading/thread_collision_warner.cc", - "threading/thread_collision_warner.h", - "threading/thread_id_name_manager.cc", - "threading/thread_id_name_manager.h", - "threading/thread_local.h", - "threading/thread_local_storage.cc", - "threading/thread_local_storage.h", - "threading/thread_local_storage_win.cc", - "threading/thread_restrictions.cc", - "threading/thread_restrictions.h", - "threading/thread_task_runner_handle.cc", - "threading/thread_task_runner_handle.h", - "threading/watchdog.cc", - "threading/watchdog.h", - "time/clock.cc", - "time/clock.h", - "time/default_clock.cc", - "time/default_clock.h", - "time/default_tick_clock.cc", - "time/default_tick_clock.h", - "time/tick_clock.cc", - "time/tick_clock.h", - "time/time.cc", - "time/time.h", - "time/time_override.cc", - "time/time_override.h", - "time/time_to_iso8601.cc", - "time/time_to_iso8601.h", - "timer/elapsed_timer.cc", - "timer/elapsed_timer.h", - "timer/hi_res_timer_manager.h", - "timer/hi_res_timer_manager_win.cc", - "timer/mock_timer.cc", - "timer/mock_timer.h", - "timer/timer.cc", - "timer/timer.h", - "trace_event/auto_open_close_event.cc", - "trace_event/auto_open_close_event.h", - "trace_event/blame_context.cc", - "trace_event/blame_context.h", - "trace_event/category_registry.cc", - "trace_event/category_registry.h", - "trace_event/common/trace_event_common.h", - "trace_event/event_name_filter.cc", - "trace_event/event_name_filter.h", - "trace_event/heap_profiler.h", - "trace_event/heap_profiler_allocation_context.cc", - "trace_event/heap_profiler_allocation_context.h", - "trace_event/heap_profiler_allocation_context_tracker.cc", - "trace_event/heap_profiler_allocation_context_tracker.h", - "trace_event/heap_profiler_event_filter.cc", - "trace_event/heap_profiler_event_filter.h", - "trace_event/heap_profiler_heap_dump_writer.cc", - "trace_event/heap_profiler_heap_dump_writer.h", - "trace_event/heap_profiler_serialization_state.cc", - "trace_event/heap_profiler_serialization_state.h", - "trace_event/heap_profiler_stack_frame_deduplicator.cc", - "trace_event/heap_profiler_stack_frame_deduplicator.h", - "trace_event/heap_profiler_type_name_deduplicator.cc", - "trace_event/heap_profiler_type_name_deduplicator.h", - "trace_event/java_heap_dump_provider_android.cc", - "trace_event/java_heap_dump_provider_android.h", - "trace_event/malloc_dump_provider.cc", - "trace_event/malloc_dump_provider.h", - "trace_event/memory_allocator_dump.cc", - "trace_event/memory_allocator_dump.h", - "trace_event/memory_allocator_dump_guid.cc", - "trace_event/memory_allocator_dump_guid.h", - "trace_event/memory_dump_manager.cc", - "trace_event/memory_dump_manager.h", - "trace_event/memory_dump_manager_test_utils.h", - "trace_event/memory_dump_provider.h", - "trace_event/memory_dump_provider_info.cc", - "trace_event/memory_dump_provider_info.h", - "trace_event/memory_dump_request_args.cc", - "trace_event/memory_dump_request_args.h", - "trace_event/memory_dump_scheduler.cc", - "trace_event/memory_dump_scheduler.h", - "trace_event/memory_infra_background_whitelist.cc", - "trace_event/memory_infra_background_whitelist.h", - "trace_event/memory_peak_detector.cc", - "trace_event/memory_peak_detector.h", - "trace_event/memory_usage_estimator.cc", - "trace_event/memory_usage_estimator.h", - "trace_event/process_memory_dump.cc", - "trace_event/process_memory_dump.h", - "trace_event/trace_buffer.cc", - "trace_event/trace_buffer.h", - "trace_event/trace_category.h", - "trace_event/trace_config.cc", - "trace_event/trace_config.h", - "trace_event/trace_config_category_filter.cc", - "trace_event/trace_config_category_filter.h", - "trace_event/trace_event.h", - "trace_event/trace_event_android.cc", - "trace_event/trace_event_argument.cc", - "trace_event/trace_event_argument.h", - "trace_event/trace_event_etw_export_win.cc", - "trace_event/trace_event_etw_export_win.h", - "trace_event/trace_event_filter.cc", - "trace_event/trace_event_filter.h", - "trace_event/trace_event_impl.cc", - "trace_event/trace_event_impl.h", - "trace_event/trace_event_memory_overhead.cc", - "trace_event/trace_event_memory_overhead.h", - "trace_event/trace_event_system_stats_monitor.cc", - "trace_event/trace_event_system_stats_monitor.h", - "trace_event/trace_log.cc", - "trace_event/trace_log.h", - "trace_event/trace_log_constants.cc", - "trace_event/tracing_agent.cc", - "trace_event/tracing_agent.h", - "tuple.h", - "unguessable_token.cc", - "unguessable_token.h", - "value_conversions.cc", - "value_conversions.h", - "value_iterators.cc", - "value_iterators.h", - "values.cc", - "values.h", - "version.cc", - "version.h", - "vlog.cc", - "vlog.h", - "win/async_operation.h", - "win/com_init_check_hook.cc", - "win/com_init_check_hook.h", - "win/com_init_util.cc", - "win/com_init_util.h", - "win/core_winrt_util.cc", - "win/core_winrt_util.h", - "win/current_module.h", - "win/enum_variant.cc", - "win/enum_variant.h", - "win/event_trace_consumer.h", - "win/event_trace_controller.cc", - "win/event_trace_controller.h", - "win/event_trace_provider.cc", - "win/event_trace_provider.h", - "win/i18n.cc", - "win/i18n.h", - "win/iat_patch_function.cc", - "win/iat_patch_function.h", - "win/iunknown_impl.cc", - "win/iunknown_impl.h", - "win/message_window.cc", - "win/message_window.h", - "win/object_watcher.cc", - "win/object_watcher.h", - "win/patch_util.cc", - "win/patch_util.h", - "win/process_startup_helper.cc", - "win/process_startup_helper.h", - "win/registry.cc", - "win/registry.h", - "win/resource_util.cc", - "win/resource_util.h", - "win/scoped_bstr.cc", - "win/scoped_bstr.h", - "win/scoped_co_mem.h", - "win/scoped_com_initializer.cc", - "win/scoped_com_initializer.h", - "win/scoped_gdi_object.h", - "win/scoped_handle.cc", - "win/scoped_handle.h", - "win/scoped_handle_verifier.cc", - "win/scoped_handle_verifier.h", - "win/scoped_hdc.h", - "win/scoped_hglobal.h", - "win/scoped_hstring.cc", - "win/scoped_hstring.h", - "win/scoped_process_information.cc", - "win/scoped_process_information.h", - "win/scoped_propvariant.h", - "win/scoped_select_object.h", - "win/scoped_variant.cc", - "win/scoped_variant.h", - "win/scoped_windows_thread_environment.h", - "win/scoped_winrt_initializer.cc", - "win/scoped_winrt_initializer.h", - "win/shortcut.cc", - "win/shortcut.h", - "win/startup_information.cc", - "win/startup_information.h", - "win/typed_event_handler.h", - "win/wait_chain.cc", - "win/wait_chain.h", - "win/win_util.cc", - "win/win_util.h", - "win/windows_version.cc", - "win/windows_version.h", - "win/winrt_storage_util.cc", - "win/winrt_storage_util.h", - "win/wrapped_window_proc.cc", - "win/wrapped_window_proc.h", - ] - - # winternl.h and NTSecAPI.h have different definitions of UNICODE_STRING. - # There's only one client of NTSecAPI.h in base but several of winternl.h, - # so exclude the NTSecAPI.h one. - if (is_win) { - jumbo_excluded_sources = [ "rand_util_win.cc" ] - } - - if (is_posix) { - sources += [ - "base_paths_posix.h", - "debug/debugger_posix.cc", - "debug/stack_trace_posix.cc", - "file_descriptor_posix.h", - "files/dir_reader_posix.h", - "files/file_descriptor_watcher_posix.cc", - "files/file_descriptor_watcher_posix.h", - "files/file_enumerator_posix.cc", - "files/file_posix.cc", - "files/file_util_posix.cc", - "files/memory_mapped_file_posix.cc", - "memory/protected_memory_posix.cc", - "message_loop/watchable_io_message_pump_posix.cc", - "message_loop/watchable_io_message_pump_posix.h", - "native_library_posix.cc", - "posix/eintr_wrapper.h", - "posix/file_descriptor_shuffle.cc", - "posix/file_descriptor_shuffle.h", - "posix/global_descriptors.cc", - "posix/global_descriptors.h", - "posix/safe_strerror.cc", - "posix/safe_strerror.h", - "posix/unix_domain_socket.cc", - "posix/unix_domain_socket.h", - "process/kill_posix.cc", - "process/launch_posix.cc", - "process/process_handle_posix.cc", - "process/process_metrics_posix.cc", - "process/process_posix.cc", - "profiler/native_stack_sampler_posix.cc", - "rand_util_posix.cc", - "strings/string_util_posix.h", - "strings/sys_string_conversions_posix.cc", - "sync_socket_posix.cc", - "synchronization/condition_variable_posix.cc", - "synchronization/lock_impl_posix.cc", - "synchronization/waitable_event_posix.cc", - "synchronization/waitable_event_watcher_posix.cc", - "sys_info_posix.cc", - "task_scheduler/task_tracker_posix.cc", - "task_scheduler/task_tracker_posix.h", - "threading/platform_thread_internal_posix.cc", - "threading/platform_thread_internal_posix.h", - "threading/platform_thread_posix.cc", - "threading/thread_local_storage_posix.cc", - "timer/hi_res_timer_manager_posix.cc", - ] - } - - if (!is_nacl) { - sources += [ - "base_paths.cc", - "base_paths.h", - "base_paths_android.cc", - "base_paths_android.h", - "base_paths_mac.h", - "base_paths_mac.mm", - "base_paths_posix.h", - "base_paths_win.cc", - "base_paths_win.h", - "metrics/persistent_histogram_storage.cc", - "metrics/persistent_histogram_storage.h", - ] - - if (is_linux) { - sources += [ - "base_paths_posix.cc", - "debug/elf_reader_linux.cc", - "debug/elf_reader_linux.h", - ] - } - } - - all_dependent_configs = [] - defines = [] - data = [] - data_deps = [] - - configs += [ - ":base_flags", - ":base_implementation", - "//build/config:precompiled_headers", - "//build/config/compiler:noshadowing", - ] - - deps = [ - "//base/allocator", - "//base/allocator:buildflags", - "//base/third_party/dynamic_annotations", - "//third_party/modp_b64", - ] - - public_deps = [ - ":anchor_functions_buildflags", - ":base_static", - ":build_date", - ":cfi_buildflags", - ":debugging_buildflags", - ":partition_alloc_buildflags", - ":protected_memory_buildflags", - ":synchronization_buildflags", - "//base/numerics:base_numerics", - ] - - # Needed for <atomic> if using newer C++ library than sysroot, except if - # building inside the cros_sdk environment - use host_toolchain as a - # more robust check for this. - if (!use_sysroot && (is_android || (is_linux && !is_chromecast)) && - host_toolchain != "//build/toolchain/cros:host") { - libs = [ "atomic" ] - } - - if (use_allocator_shim) { - sources += [ - "allocator/allocator_shim.cc", - "allocator/allocator_shim.h", - "allocator/allocator_shim_internals.h", - "allocator/allocator_shim_override_cpp_symbols.h", - "allocator/allocator_shim_override_libc_symbols.h", - ] - if (is_win) { - sources += [ - "allocator/allocator_shim_default_dispatch_to_winheap.cc", - "allocator/allocator_shim_override_ucrt_symbols_win.h", - "allocator/winheap_stubs_win.cc", - "allocator/winheap_stubs_win.h", - ] - } else if (is_linux && use_allocator == "tcmalloc") { - sources += [ - "allocator/allocator_shim_default_dispatch_to_tcmalloc.cc", - "allocator/allocator_shim_override_glibc_weak_symbols.h", - ] - deps += [ "//base/allocator:tcmalloc" ] - } else if (is_linux && use_allocator == "none") { - sources += [ "allocator/allocator_shim_default_dispatch_to_glibc.cc" ] - } else if (is_android && use_allocator == "none") { - sources += [ - "allocator/allocator_shim_default_dispatch_to_linker_wrapped_symbols.cc", - "allocator/allocator_shim_override_linker_wrapped_symbols.h", - ] - all_dependent_configs += [ "//base/allocator:wrap_malloc_symbols" ] - } else if (is_mac) { - sources += [ - "allocator/allocator_shim_default_dispatch_to_mac_zoned_malloc.cc", - "allocator/allocator_shim_default_dispatch_to_mac_zoned_malloc.h", - "allocator/allocator_shim_override_mac_symbols.h", - ] - } - } - - # Allow more direct string conversions on platforms with native utf8 - # strings - if (is_mac || is_ios || is_chromeos || is_chromecast || is_fuchsia) { - defines += [ "SYSTEM_NATIVE_UTF8" ] - } - - # Android. - if (is_android) { - sources -= [ "debug/stack_trace_posix.cc" ] - sources += [ - "memory/platform_shared_memory_region_android.cc", - "memory/shared_memory_android.cc", - "memory/shared_memory_handle_android.cc", - "time/time_android.cc", - ] - - # Android uses some Linux sources, put those back. - set_sources_assignment_filter([]) - sources += [ - "debug/elf_reader_linux.cc", - "debug/elf_reader_linux.h", - "debug/proc_maps_linux.cc", - "debug/proc_maps_linux.h", - "files/file_path_watcher_linux.cc", - "power_monitor/power_monitor_device_source_android.cc", - "process/internal_linux.cc", - "process/internal_linux.h", - "process/memory_linux.cc", - "process/process_handle_linux.cc", - "process/process_info_linux.cc", - "process/process_iterator_linux.cc", - "process/process_metrics_linux.cc", - "sys_info_linux.cc", - ] - set_sources_assignment_filter(sources_assignment_filter) - - deps += [ - ":base_jni_headers", - "//third_party/android_tools:cpu_features", - "//third_party/ashmem", - ] - - # TODO(thomasanderson): Remove this once use_custom_libcxx is always set to - # true on Android. - if (!use_custom_libcxx) { - deps += [ "//buildtools/third_party/libc++abi:cxa_demangle_stub" ] - } - - # Needs to be a public config so that dependent targets link against it as - # well when doing a component build. - public_configs = [ ":android_system_libs" ] - - if (can_unwind_with_cfi_table) { - sources += [ - "trace_event/cfi_backtrace_android.cc", - "trace_event/cfi_backtrace_android.h", - ] - } - - # This is actually a linker script, but it can be added to the link in the - # same way as a library. - libs = [ "android/library_loader/anchor_functions.lds" ] - } - - # Chromeos. - if (is_chromeos) { - sources += [ "power_monitor/power_monitor_device_source_chromeos.cc" ] - } - - # Fuchsia. - if (is_fuchsia) { - sources += [ - "base_paths_fuchsia.cc", - "base_paths_fuchsia.h", - "debug/debugger_posix.cc", - "debug/stack_trace_fuchsia.cc", - "file_descriptor_posix.h", - "files/dir_reader_posix.h", - "files/file_descriptor_watcher_posix.cc", - "files/file_descriptor_watcher_posix.h", - "files/file_enumerator_posix.cc", - "files/file_path_watcher_fuchsia.cc", - "files/file_posix.cc", - "files/file_util_posix.cc", - "files/memory_mapped_file_posix.cc", - "fuchsia/async_dispatcher.cc", - "fuchsia/async_dispatcher.h", - "fuchsia/component_context.cc", - "fuchsia/component_context.h", - "fuchsia/default_job.cc", - "fuchsia/default_job.h", - "fuchsia/fidl_interface_request.cc", - "fuchsia/fidl_interface_request.h", - "fuchsia/fuchsia_logging.cc", - "fuchsia/fuchsia_logging.h", - "fuchsia/scoped_zx_handle.cc", - "fuchsia/scoped_zx_handle.h", - "fuchsia/services_directory.cc", - "fuchsia/services_directory.h", - "memory/platform_shared_memory_region_fuchsia.cc", - "memory/protected_memory_posix.cc", - "memory/shared_memory_fuchsia.cc", - "memory/shared_memory_handle_fuchsia.cc", - "message_loop/message_pump_fuchsia.cc", - "message_loop/message_pump_fuchsia.h", - "message_loop/watchable_io_message_pump_posix.cc", - "message_loop/watchable_io_message_pump_posix.h", - "native_library_fuchsia.cc", - "posix/eintr_wrapper.h", - "posix/file_descriptor_shuffle.cc", - "posix/file_descriptor_shuffle.h", - "posix/global_descriptors.cc", - "posix/global_descriptors.h", - "posix/safe_strerror.cc", - "posix/safe_strerror.h", - "process/kill_fuchsia.cc", - "process/launch_fuchsia.cc", - "process/memory_fuchsia.cc", - "process/process_fuchsia.cc", - "process/process_handle_fuchsia.cc", - "process/process_iterator_fuchsia.cc", - "process/process_metrics_fuchsia.cc", - "process/process_metrics_posix.cc", - "profiler/native_stack_sampler_posix.cc", - "rand_util_fuchsia.cc", - "strings/string_util_posix.h", - "strings/sys_string_conversions_posix.cc", - "sync_socket_posix.cc", - "synchronization/condition_variable_posix.cc", - "synchronization/lock_impl_posix.cc", - "synchronization/waitable_event_posix.cc", - "synchronization/waitable_event_watcher_posix.cc", - "sys_info_fuchsia.cc", - "sys_info_posix.cc", - "task_scheduler/task_tracker_posix.cc", - "task_scheduler/task_tracker_posix.h", - "threading/platform_thread_fuchsia.cc", - "threading/platform_thread_posix.cc", - "threading/thread_local_storage_posix.cc", - "time/time_conversion_posix.cc", - "time/time_exploded_posix.cc", - "time/time_fuchsia.cc", - "timer/hi_res_timer_manager_posix.cc", - ] - - # These only need to be public deps because of includes of their headers - # by public //base headers, which requires they be on the include path. - # TODO(https://crbug.com/841171): Move these back to |deps|. - public_deps += [ - "//third_party/fuchsia-sdk:async", - "//third_party/fuchsia-sdk:launchpad", - ] - - deps += [ - "//third_party/fuchsia-sdk:async_default", - "//third_party/fuchsia-sdk:fdio", - "//third_party/fuchsia-sdk:fidl", - "//third_party/fuchsia-sdk:svc", - "//third_party/fuchsia-sdk:zx", - ] - } - - # NaCl. - if (is_nacl) { - # We reset sources_assignment_filter in order to explicitly include - # the linux file (which would otherwise be filtered out). - set_sources_assignment_filter([]) - sources += [ - "files/file_path_watcher_stub.cc", - "memory/shared_memory_nacl.cc", - "process/process_metrics_nacl.cc", - "sync_socket_nacl.cc", - "threading/platform_thread_linux.cc", - ] - set_sources_assignment_filter(sources_assignment_filter) - - sources -= [ - "cpu.cc", - "debug/crash_logging.cc", - "debug/crash_logging.h", - "debug/stack_trace.cc", - "debug/stack_trace_posix.cc", - "files/file_enumerator_posix.cc", - "files/file_proxy.cc", - "files/important_file_writer.cc", - "files/important_file_writer.h", - "files/scoped_temp_dir.cc", - "memory/discardable_memory.cc", - "memory/discardable_memory.h", - "memory/discardable_memory_allocator.cc", - "memory/discardable_memory_allocator.h", - "memory/discardable_shared_memory.cc", - "memory/discardable_shared_memory.h", - "memory/shared_memory_helper.cc", - "memory/shared_memory_helper.h", - "native_library.cc", - "native_library_posix.cc", - "path_service.cc", - "process/kill.cc", - "process/kill.h", - "process/memory.cc", - "process/memory.h", - "process/process_iterator.cc", - "process/process_iterator.h", - "process/process_metrics.cc", - "process/process_metrics_posix.cc", - "process/process_posix.cc", - "scoped_native_library.cc", - "sync_socket_posix.cc", - "sys_info.cc", - "sys_info_posix.cc", - "task_scheduler/initialization_util.cc", - "task_scheduler/initialization_util.h", - "trace_event/trace_event_system_stats_monitor.cc", - ] - - if (is_nacl_nonsfi) { - sources -= [ "rand_util_nacl.cc" ] - configs += [ ":nacl_nonsfi_warnings" ] - } else { - sources -= [ - "files/file_descriptor_watcher_posix.cc", - "files/file_descriptor_watcher_posix.h", - "files/file_util.cc", - "files/file_util.h", - "files/file_util_posix.cc", - "json/json_file_value_serializer.cc", - "json/json_file_value_serializer.h", - "posix/unix_domain_socket.cc", - "process/kill_posix.cc", - "process/launch.cc", - "process/launch.h", - "process/launch_posix.cc", - "rand_util_posix.cc", - "task_scheduler/task_tracker_posix.cc", - "task_scheduler/task_tracker_posix.h", - ] - } - } else { - # Remove NaCl stuff. - sources -= [ - "os_compat_nacl.cc", - "os_compat_nacl.h", - "rand_util_nacl.cc", - ] - - if (use_partition_alloc) { - # Add stuff that doesn't work in NaCl. - sources += [ - # PartitionAlloc uses SpinLock, which doesn't work in NaCl (see below). - "allocator/partition_allocator/address_space_randomization.cc", - "allocator/partition_allocator/address_space_randomization.h", - "allocator/partition_allocator/oom.h", - "allocator/partition_allocator/page_allocator.cc", - "allocator/partition_allocator/page_allocator.h", - "allocator/partition_allocator/page_allocator_internal.h", - "allocator/partition_allocator/partition_alloc.cc", - "allocator/partition_allocator/partition_alloc.h", - "allocator/partition_allocator/partition_alloc_constants.h", - "allocator/partition_allocator/partition_bucket.cc", - "allocator/partition_allocator/partition_bucket.h", - "allocator/partition_allocator/partition_cookie.h", - "allocator/partition_allocator/partition_direct_map_extent.h", - "allocator/partition_allocator/partition_freelist_entry.h", - "allocator/partition_allocator/partition_oom.cc", - "allocator/partition_allocator/partition_oom.h", - "allocator/partition_allocator/partition_page.cc", - "allocator/partition_allocator/partition_page.h", - "allocator/partition_allocator/partition_root_base.cc", - "allocator/partition_allocator/partition_root_base.h", - "allocator/partition_allocator/spin_lock.cc", - "allocator/partition_allocator/spin_lock.h", - ] - if (is_win) { - sources += - [ "allocator/partition_allocator/page_allocator_internals_win.h" ] - } else if (is_posix || is_fuchsia) { - sources += - [ "allocator/partition_allocator/page_allocator_internals_posix.h" ] - } - } - } - - # Windows. - if (is_win) { - sources += [ - "memory/platform_shared_memory_region_win.cc", - "memory/shared_memory_handle_win.cc", - "memory/shared_memory_win.cc", - "power_monitor/power_monitor_device_source_win.cc", - "profiler/win32_stack_frame_unwinder.cc", - "profiler/win32_stack_frame_unwinder.h", - "time/time_win.cc", - ] - - sources -= [ - "file_descriptor_store.cc", - "file_descriptor_store.h", - "memory/shared_memory_helper.cc", - "memory/shared_memory_helper.h", - "strings/string16.cc", - ] - - deps += [ - "//base/trace_event/etw_manifest:chrome_events_win", - "//base/win:base_win_buildflags", - ] - - data_deps += [ "//build/win:runtime_libs" ] - - if (com_init_check_hook_disabled) { - defines += [ "COM_INIT_CHECK_HOOK_DISABLED" ] - } - - # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. - configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] - - libs = [ - "cfgmgr32.lib", - "powrprof.lib", - "propsys.lib", - "setupapi.lib", - "userenv.lib", - "winmm.lib", - ] - all_dependent_configs += [ - ":base_win_linker_flags", - "//tools/win/DebugVisualizers:chrome", - ] - } - - # Desktop Mac. - if (is_mac) { - sources -= [ "profiler/native_stack_sampler_posix.cc" ] - sources += [ - "mac/scoped_typeref.h", - "memory/platform_shared_memory_region_mac.cc", - "memory/shared_memory_handle_mac.cc", - "memory/shared_memory_mac.cc", - "power_monitor/power_monitor_device_source_mac.mm", - "time/time_conversion_posix.cc", - "time/time_exploded_posix.cc", - "time/time_mac.cc", - ] - - libs = [ - "ApplicationServices.framework", - "AppKit.framework", - "bsm", - "CoreFoundation.framework", - "IOKit.framework", - "Security.framework", - ] - } - - # Mac or iOS. - if (is_mac || is_ios) { - sources -= [ - "native_library_posix.cc", - "strings/sys_string_conversions_posix.cc", - "synchronization/waitable_event_posix.cc", - "synchronization/waitable_event_watcher_posix.cc", - "threading/platform_thread_internal_posix.cc", - ] - } else { - # Non-Mac/ios. - sources -= [ - "files/file_path_watcher_fsevents.cc", - "files/file_path_watcher_fsevents.h", - "files/file_path_watcher_kqueue.cc", - "files/file_path_watcher_kqueue.h", - ] - } - - # Linux. - if (is_linux) { - # TODO(brettw) this will need to be parameterized at some point. - linux_configs = [] - if (use_glib) { - linux_configs += [ "//build/config/linux:glib" ] - } - - defines += [ "USE_SYMBOLIZE" ] - - configs += linux_configs - all_dependent_configs += linux_configs - - # These dependencies are not required on Android, and in the case - # of xdg_mime must be excluded due to licensing restrictions. - deps += [ - "//base/third_party/symbolize", - "//base/third_party/xdg_mime", - "//base/third_party/xdg_user_dirs", - ] - } else { - # Non-Linux. - sources -= [ - "nix/mime_util_xdg.cc", - "nix/mime_util_xdg.h", - "nix/xdg_util.cc", - "nix/xdg_util.h", - ] - - if (!is_android) { - sources -= [ - "linux_util.cc", - "linux_util.h", - ] - } - } - - # iOS - if (is_ios) { - set_sources_assignment_filter([]) - - sources -= [ - "files/file_path_watcher.cc", - "files/file_path_watcher.h", - "files/file_path_watcher_fsevents.cc", - "files/file_path_watcher_fsevents.h", - "files/file_path_watcher_kqueue.cc", - "files/file_path_watcher_kqueue.h", - "memory/discardable_shared_memory.cc", - "memory/discardable_shared_memory.h", - "process/kill.cc", - "process/kill.h", - "process/kill_posix.cc", - "process/launch.cc", - "process/launch.h", - "process/launch_posix.cc", - "process/memory.cc", - "process/memory.h", - "process/process_iterator.cc", - "process/process_iterator.h", - "process/process_metrics_posix.cc", - "process/process_posix.cc", - "sync_socket.h", - "sync_socket_posix.cc", - "synchronization/waitable_event_watcher.h", - ] - sources += [ - "base_paths_mac.h", - "base_paths_mac.mm", - "file_version_info_mac.h", - "file_version_info_mac.mm", - "files/file_util_mac.mm", - "mac/bundle_locations.h", - "mac/bundle_locations.mm", - "mac/call_with_eh_frame.cc", - "mac/call_with_eh_frame.h", - "mac/foundation_util.h", - "mac/foundation_util.mm", - "mac/mac_logging.h", - "mac/mac_logging.mm", - "mac/mach_logging.cc", - "mac/mach_logging.h", - "mac/objc_release_properties.h", - "mac/objc_release_properties.mm", - "mac/scoped_block.h", - "mac/scoped_mach_port.cc", - "mac/scoped_mach_port.h", - "mac/scoped_mach_vm.cc", - "mac/scoped_mach_vm.h", - "mac/scoped_nsautorelease_pool.h", - "mac/scoped_nsautorelease_pool.mm", - "mac/scoped_nsobject.h", - "mac/scoped_nsobject.mm", - "mac/scoped_objc_class_swizzler.h", - "mac/scoped_objc_class_swizzler.mm", - "mac/scoped_typeref.h", - "message_loop/message_pump_mac.h", - "message_loop/message_pump_mac.mm", - "power_monitor/power_monitor_device_source_ios.mm", - "process/memory_stubs.cc", - "strings/sys_string_conversions_mac.mm", - "synchronization/waitable_event_mac.cc", - "threading/platform_thread_mac.mm", - "time/time_conversion_posix.cc", - "time/time_mac.cc", - ] - - set_sources_assignment_filter(sources_assignment_filter) - } - - if (dep_libevent) { - deps += [ "//base/third_party/libevent" ] - } - - if (use_libevent) { - sources += [ - "message_loop/message_pump_libevent.cc", - "message_loop/message_pump_libevent.h", - ] - } - - # Android and MacOS have their own custom shared memory handle - # implementations. e.g. due to supporting both POSIX and native handles. - if (is_posix && !is_android && !is_mac) { - sources += [ - "memory/platform_shared_memory_region_posix.cc", - "memory/shared_memory_handle_posix.cc", - ] - } - - if (is_posix && !is_mac && !is_nacl) { - sources += [ "memory/shared_memory_posix.cc" ] - } - - if (is_posix && !is_mac && !is_ios) { - sources += [ - "time/time_conversion_posix.cc", - "time/time_exploded_posix.cc", - "time/time_now_posix.cc", - ] - } - - if ((is_posix && !is_mac && !is_ios && !is_android && !is_chromeos) || - is_fuchsia) { - sources += [ "power_monitor/power_monitor_device_source_stub.cc" ] - } - - if (!use_glib) { - sources -= [ - "message_loop/message_pump_glib.cc", - "message_loop/message_pump_glib.h", - ] - } - - if (using_sanitizer) { - data += [ "//tools/valgrind/asan/" ] - if (is_win) { - data += - [ "//third_party/llvm-build/Release+Asserts/bin/llvm-symbolizer.exe" ] - } else { - data += [ "//third_party/llvm-build/Release+Asserts/bin/llvm-symbolizer" ] - } - } - - configs += [ "//build/config/compiler:wexit_time_destructors" ] - if (!is_debug) { - configs -= [ "//build/config/compiler:default_optimization" ] - configs += [ "//build/config/compiler:optimize_max" ] - } -} - -# Build flags for Control Flow Integrity -# https://www.chromium.org/developers/testing/control-flow-integrity -buildflag_header("cfi_buildflags") { - header = "cfi_buildflags.h" - - # buildflag entries added to this header must also must be manually added to - # tools/gn/bootstrap/bootstrap.py - flags = [ - # TODO(pcc): remove CFI_CAST_CHECK, see https://crbug.com/626794. - "CFI_CAST_CHECK=$is_cfi && $use_cfi_cast", - "CFI_ICALL_CHECK=$is_cfi && $use_cfi_icall", - "CFI_ENFORCEMENT_TRAP=$is_cfi && !$use_cfi_diag", - "CFI_ENFORCEMENT_DIAGNOSTIC=$is_cfi && $use_cfi_diag && !$use_cfi_recover", - ] -} - -buildflag_header("debugging_buildflags") { - header = "debugging_buildflags.h" - header_dir = "base/debug" - - # buildflag entries added to this header must also must be manually added to - # tools/gn/bootstrap/bootstrap.py - flags = [ - "ENABLE_LOCATION_SOURCE=$enable_location_source", - "ENABLE_PROFILING=$enable_profiling", - "CAN_UNWIND_WITH_FRAME_POINTERS=$can_unwind_with_frame_pointers", - "UNSAFE_DEVELOPER_BUILD=$is_unsafe_developer_build", - "CAN_UNWIND_WITH_CFI_TABLE=$can_unwind_with_cfi_table", - ] -} - -# Build flags for ProtectedMemory, temporary workaround for crbug.com/792777 -# TODO(vtsyrklevich): Remove once support for gold on Android/CrOs is dropped -buildflag_header("protected_memory_buildflags") { - header = "protected_memory_buildflags.h" - header_dir = "base/memory" - - # buildflag entries added to this header must also must be manually added to - # tools/gn/bootstrap/bootstrap.py - flags = [ "USE_LLD=$use_lld" ] -} - -buildflag_header("synchronization_buildflags") { - header = "synchronization_buildflags.h" - header_dir = "base/synchronization" - - flags = - [ "ENABLE_MUTEX_PRIORITY_INHERITANCE=$enable_mutex_priority_inheritance" ] -} - -buildflag_header("anchor_functions_buildflags") { - header = "anchor_functions_buildflags.h" - header_dir = "base/android/library_loader" - _supports_code_ordering = current_cpu == "arm" - - # buildflag entries added to this header must also must be manually added to - # tools/gn/bootstrap/bootstrap.py - flags = [ - "USE_LLD=$use_lld", - "SUPPORTS_CODE_ORDERING=$_supports_code_ordering", - ] -} - -buildflag_header("partition_alloc_buildflags") { - header = "partition_alloc_buildflags.h" - header_dir = "base" - - flags = [ "USE_PARTITION_ALLOC=$use_partition_alloc" ] -} - -# This is the subset of files from base that should not be used with a dynamic -# library. Note that this library cannot depend on base because base depends on -# base_static. -static_library("base_static") { - sources = [ - "base_switches.cc", - "base_switches.h", - ] - - if (is_win) { - public_deps = [ - "//base/win:pe_image", - ] - - # Disable sanitizer coverage in win/pe_image.cc. It is called by the sandbox - # before sanitizer coverage can initialize. http://crbug.com/484711 - configs -= [ "//build/config/sanitizers:default_sanitizer_flags" ] - configs += - [ "//build/config/sanitizers:default_sanitizer_flags_but_coverage" ] - } - - if (!is_debug) { - configs -= [ "//build/config/compiler:default_optimization" ] - configs += [ "//build/config/compiler:optimize_max" ] - } -} - -component("i18n") { - output_name = "base_i18n" - sources = [ - "i18n/base_i18n_export.h", - "i18n/base_i18n_switches.cc", - "i18n/base_i18n_switches.h", - "i18n/bidi_line_iterator.cc", - "i18n/bidi_line_iterator.h", - "i18n/break_iterator.cc", - "i18n/break_iterator.h", - "i18n/case_conversion.cc", - "i18n/case_conversion.h", - "i18n/char_iterator.cc", - "i18n/char_iterator.h", - "i18n/character_encoding.cc", - "i18n/character_encoding.h", - "i18n/encoding_detection.cc", - "i18n/encoding_detection.h", - "i18n/file_util_icu.cc", - "i18n/file_util_icu.h", - "i18n/i18n_constants.cc", - "i18n/i18n_constants.h", - "i18n/icu_string_conversions.cc", - "i18n/icu_string_conversions.h", - "i18n/icu_util.cc", - "i18n/icu_util.h", - "i18n/message_formatter.cc", - "i18n/message_formatter.h", - "i18n/number_formatting.cc", - "i18n/number_formatting.h", - "i18n/rtl.cc", - "i18n/rtl.h", - "i18n/streaming_utf8_validator.cc", - "i18n/streaming_utf8_validator.h", - "i18n/string_compare.cc", - "i18n/string_compare.h", - "i18n/string_search.cc", - "i18n/string_search.h", - "i18n/time_formatting.cc", - "i18n/time_formatting.h", - "i18n/timezone.cc", - "i18n/timezone.h", - "i18n/unicodestring.h", - "i18n/utf8_validator_tables.cc", - "i18n/utf8_validator_tables.h", - ] - defines = [ "BASE_I18N_IMPLEMENTATION" ] - configs += [ "//build/config/compiler:wexit_time_destructors" ] - public_deps = [ - "//third_party/ced", - "//third_party/icu", - ] - deps = [ - ":base", - "//base/third_party/dynamic_annotations", - ] - - if (!is_debug) { - configs -= [ "//build/config/compiler:default_optimization" ] - configs += [ "//build/config/compiler:optimize_max" ] - } - - # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. - configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] - - if (is_mac) { - libs = [ "CoreFoundation.framework" ] - } -} - -test("base_perftests") { - sources = [ - "message_loop/message_loop_perftest.cc", - "message_loop/message_pump_perftest.cc", - - # "test/run_all_unittests.cc", - "json/json_perftest.cc", - "synchronization/waitable_event_perftest.cc", - "threading/thread_perftest.cc", - ] - deps = [ - ":base", - "//base/test:test_support", - "//base/test:test_support_perf", - "//testing/gtest", - "//testing/perf", - ] - - if (is_android) { - deps += [ "//testing/android/native_test:native_test_native_code" ] - } -} - -test("base_i18n_perftests") { - sources = [ - "i18n/streaming_utf8_validator_perftest.cc", - ] - deps = [ - ":base", - ":i18n", - "//base/test:test_support", - "//base/test:test_support_perf", - "//testing/gtest", - ] -} - -if (!is_ios) { - executable("build_utf8_validator_tables") { - sources = [ - "i18n/build_utf8_validator_tables.cc", - ] - deps = [ - ":base", - "//build/config:exe_and_shlib_deps", - "//build/win:default_exe_manifest", - "//third_party/icu:icuuc", - ] - } - - executable("check_example") { - sources = [ - "check_example.cc", - ] - deps = [ - ":base", - "//build/config:exe_and_shlib_deps", - "//build/win:default_exe_manifest", - ] - } -} - -if (is_win) { - # Target to manually rebuild pe_image_test.dll which is checked into - # base/test/data/pe_image. - shared_library("pe_image_test") { - sources = [ - "win/pe_image_test.cc", - ] - ldflags = [ - "/DELAYLOAD:cfgmgr32.dll", - "/DELAYLOAD:shell32.dll", - "/SUBSYSTEM:WINDOWS", - ] - libs = [ - "cfgmgr32.lib", - "shell32.lib", - ] - deps = [ - "//build/config:exe_and_shlib_deps", - ] - } - - loadable_module("scoped_handle_test_dll") { - sources = [ - "win/scoped_handle_test_dll.cc", - ] - deps = [ - ":base", - "//base/win:base_win_buildflags", - ] - } -} - -if (is_win || is_mac) { - if (current_cpu == "x64") { - # Must be a shared library so that it can be unloaded during testing. - shared_library("base_profiler_test_support_library") { - sources = [ - "profiler/test_support_library.cc", - ] - deps = [ - "//build/config:exe_and_shlib_deps", - ] - } - } -} - -bundle_data("base_unittests_bundle_data") { - testonly = true - sources = [ - "test/data/file_util/binary_file.bin", - "test/data/file_util/binary_file_diff.bin", - "test/data/file_util/binary_file_same.bin", - "test/data/file_util/blank_line.txt", - "test/data/file_util/blank_line_crlf.txt", - "test/data/file_util/crlf.txt", - "test/data/file_util/different.txt", - "test/data/file_util/different_first.txt", - "test/data/file_util/different_last.txt", - "test/data/file_util/empty1.txt", - "test/data/file_util/empty2.txt", - "test/data/file_util/first1.txt", - "test/data/file_util/first2.txt", - "test/data/file_util/original.txt", - "test/data/file_util/same.txt", - "test/data/file_util/same_length.txt", - "test/data/file_util/shortened.txt", - "test/data/json/bom_feff.json", - "test/data/serializer_nested_test.json", - "test/data/serializer_test.json", - "test/data/serializer_test_nowhitespace.json", - ] - outputs = [ - "{{bundle_resources_dir}}/" + - "{{source_root_relative_dir}}/{{source_file_part}}", - ] -} - -if (is_ios || is_mac) { - source_set("base_unittests_arc") { - testonly = true - set_sources_assignment_filter([]) - sources = [ - "mac/bind_objc_block_unittest_arc.mm", - "mac/scoped_nsobject_unittest_arc.mm", - ] - set_sources_assignment_filter(sources_assignment_filter) - configs += [ "//build/config/compiler:enable_arc" ] - deps = [ - ":base", - "//testing/gtest", - ] - } -} - -if (is_fuchsia) { - fidl_library("test_fidl") { - namespace = "base.fuchsia" - namespace_path = "base/fuchsia" - - sources = [ - "fuchsia/test.fidl", - ] - } -} - -test("base_unittests") { - sources = [ - "allocator/allocator_interception_mac_unittest.mm", - "allocator/malloc_zone_functions_mac_unittest.cc", - "allocator/tcmalloc_unittest.cc", - "android/application_status_listener_unittest.cc", - "android/content_uri_utils_unittest.cc", - "android/jni_android_unittest.cc", - "android/jni_array_unittest.cc", - "android/jni_string_unittest.cc", - "android/library_loader/library_prefetcher_unittest.cc", - "android/path_utils_unittest.cc", - "android/scoped_java_ref_unittest.cc", - "android/sys_utils_unittest.cc", - "android/unguessable_token_android_unittest.cc", - "at_exit_unittest.cc", - "atomicops_unittest.cc", - "barrier_closure_unittest.cc", - "base64_unittest.cc", - "base64url_unittest.cc", - "big_endian_unittest.cc", - "bind_unittest.cc", - "bit_cast_unittest.cc", - "bits_unittest.cc", - "build_time_unittest.cc", - "callback_helpers_unittest.cc", - "callback_list_unittest.cc", - "callback_unittest.cc", - "cancelable_callback_unittest.cc", - "command_line_unittest.cc", - "component_export_unittest.cc", - "containers/adapters_unittest.cc", - "containers/circular_deque_unittest.cc", - "containers/flat_map_unittest.cc", - "containers/flat_set_unittest.cc", - "containers/flat_tree_unittest.cc", - "containers/hash_tables_unittest.cc", - "containers/id_map_unittest.cc", - "containers/linked_list_unittest.cc", - "containers/mru_cache_unittest.cc", - "containers/small_map_unittest.cc", - "containers/span_unittest.cc", - "containers/stack_container_unittest.cc", - "containers/unique_ptr_adapters_unittest.cc", - "containers/vector_buffer_unittest.cc", - "cpu_unittest.cc", - "debug/activity_analyzer_unittest.cc", - "debug/activity_tracker_unittest.cc", - "debug/alias_unittest.cc", - "debug/crash_logging_unittest.cc", - "debug/debugger_unittest.cc", - "debug/elf_reader_linux_unittest.cc", - "debug/leak_tracker_unittest.cc", - "debug/proc_maps_linux_unittest.cc", - "debug/stack_trace_unittest.cc", - "debug/task_annotator_unittest.cc", - "debug/thread_heap_usage_tracker_unittest.cc", - "deferred_sequenced_task_runner_unittest.cc", - "environment_unittest.cc", - "feature_list_unittest.cc", - "file_version_info_win_unittest.cc", - "files/file_enumerator_unittest.cc", - "files/file_path_unittest.cc", - "files/file_path_watcher_unittest.cc", - "files/file_proxy_unittest.cc", - "files/file_unittest.cc", - "files/file_util_unittest.cc", - "files/important_file_writer_unittest.cc", - "files/memory_mapped_file_unittest.cc", - "files/scoped_temp_dir_unittest.cc", - "gmock_unittest.cc", - "guid_unittest.cc", - "hash_unittest.cc", - "i18n/bidi_line_iterator_unittest.cc", - "i18n/break_iterator_unittest.cc", - "i18n/case_conversion_unittest.cc", - "i18n/char_iterator_unittest.cc", - "i18n/character_encoding_unittest.cc", - "i18n/file_util_icu_unittest.cc", - "i18n/icu_string_conversions_unittest.cc", - "i18n/message_formatter_unittest.cc", - "i18n/number_formatting_unittest.cc", - "i18n/rtl_unittest.cc", - "i18n/streaming_utf8_validator_unittest.cc", - "i18n/string_search_unittest.cc", - "i18n/time_formatting_unittest.cc", - "i18n/timezone_unittest.cc", - "ios/crb_protocol_observers_unittest.mm", - "ios/device_util_unittest.mm", - "ios/weak_nsobject_unittest.mm", - "json/json_parser_unittest.cc", - "json/json_reader_unittest.cc", - "json/json_value_converter_unittest.cc", - "json/json_value_serializer_unittest.cc", - "json/json_writer_unittest.cc", - "json/string_escape_unittest.cc", - "lazy_instance_unittest.cc", - "logging_unittest.cc", - "mac/bind_objc_block_unittest.mm", - "mac/call_with_eh_frame_unittest.mm", - "mac/dispatch_source_mach_unittest.cc", - "mac/foundation_util_unittest.mm", - "mac/mac_util_unittest.mm", - "mac/mach_port_broker_unittest.cc", - "mac/objc_release_properties_unittest.mm", - "mac/scoped_nsobject_unittest.mm", - "mac/scoped_objc_class_swizzler_unittest.mm", - "mac/scoped_sending_event_unittest.mm", - "md5_unittest.cc", - "memory/aligned_memory_unittest.cc", - "memory/discardable_shared_memory_unittest.cc", - "memory/linked_ptr_unittest.cc", - "memory/memory_coordinator_client_registry_unittest.cc", - "memory/memory_pressure_listener_unittest.cc", - "memory/memory_pressure_monitor_chromeos_unittest.cc", - "memory/memory_pressure_monitor_mac_unittest.cc", - "memory/memory_pressure_monitor_unittest.cc", - "memory/memory_pressure_monitor_win_unittest.cc", - "memory/platform_shared_memory_region_unittest.cc", - "memory/protected_memory_unittest.cc", - "memory/ptr_util_unittest.cc", - "memory/ref_counted_memory_unittest.cc", - "memory/ref_counted_unittest.cc", - "memory/shared_memory_mac_unittest.cc", - "memory/shared_memory_region_unittest.cc", - "memory/shared_memory_unittest.cc", - "memory/shared_memory_win_unittest.cc", - "memory/singleton_unittest.cc", - "memory/weak_ptr_unittest.cc", - "message_loop/message_loop_task_runner_unittest.cc", - "message_loop/message_loop_unittest.cc", - "message_loop/message_pump_glib_unittest.cc", - "message_loop/message_pump_io_ios_unittest.cc", - "message_loop/message_pump_mac_unittest.mm", - "metrics/bucket_ranges_unittest.cc", - "metrics/field_trial_params_unittest.cc", - "metrics/field_trial_unittest.cc", - "metrics/histogram_base_unittest.cc", - "metrics/histogram_delta_serialization_unittest.cc", - "metrics/histogram_functions_unittest.cc", - "metrics/histogram_macros_unittest.cc", - "metrics/histogram_samples_unittest.cc", - "metrics/histogram_snapshot_manager_unittest.cc", - "metrics/histogram_unittest.cc", - "metrics/metrics_hashes_unittest.cc", - "metrics/persistent_histogram_allocator_unittest.cc", - "metrics/persistent_histogram_storage_unittest.cc", - "metrics/persistent_memory_allocator_unittest.cc", - "metrics/persistent_sample_map_unittest.cc", - "metrics/sample_map_unittest.cc", - "metrics/sample_vector_unittest.cc", - "metrics/single_sample_metrics_unittest.cc", - "metrics/sparse_histogram_unittest.cc", - "metrics/statistics_recorder_unittest.cc", - "native_library_unittest.cc", - "no_destructor_unittest.cc", - "observer_list_unittest.cc", - "optional_unittest.cc", - "os_compat_android_unittest.cc", - "path_service_unittest.cc", - "pickle_unittest.cc", - "power_monitor/power_monitor_unittest.cc", - "process/launch_unittest_win.cc", - "process/memory_unittest.cc", - "process/memory_unittest_mac.h", - "process/memory_unittest_mac.mm", - "process/process_info_unittest.cc", - "process/process_metrics_unittest.cc", - "process/process_unittest.cc", - "process/process_util_unittest.cc", - "profiler/stack_sampling_profiler_unittest.cc", - "rand_util_unittest.cc", - "run_loop_unittest.cc", - "safe_numerics_unittest.cc", - "scoped_clear_errno_unittest.cc", - "scoped_generic_unittest.cc", - "scoped_native_library_unittest.cc", - "security_unittest.cc", - "sequence_checker_unittest.cc", - "sequence_token_unittest.cc", - "sequenced_task_runner_unittest.cc", - "sha1_unittest.cc", - "stl_util_unittest.cc", - "strings/char_traits_unittest.cc", - "strings/nullable_string16_unittest.cc", - "strings/pattern_unittest.cc", - "strings/safe_sprintf_unittest.cc", - "strings/strcat_unittest.cc", - "strings/string16_unittest.cc", - "strings/string_number_conversions_unittest.cc", - "strings/string_piece_unittest.cc", - "strings/string_split_unittest.cc", - "strings/string_tokenizer_unittest.cc", - "strings/string_util_unittest.cc", - "strings/stringize_macros_unittest.cc", - "strings/stringprintf_unittest.cc", - "strings/sys_string_conversions_mac_unittest.mm", - "strings/sys_string_conversions_unittest.cc", - "strings/utf_offset_string_conversions_unittest.cc", - "strings/utf_string_conversions_unittest.cc", - "supports_user_data_unittest.cc", - "sync_socket_unittest.cc", - "synchronization/atomic_flag_unittest.cc", - "synchronization/condition_variable_unittest.cc", - "synchronization/lock_unittest.cc", - "synchronization/waitable_event_unittest.cc", - "synchronization/waitable_event_watcher_unittest.cc", - "sys_byteorder_unittest.cc", - "sys_info_unittest.cc", - "system_monitor/system_monitor_unittest.cc", - "task/cancelable_task_tracker_unittest.cc", - "task_runner_util_unittest.cc", - "task_scheduler/delayed_task_manager_unittest.cc", - "task_scheduler/lazy_task_runner_unittest.cc", - "task_scheduler/priority_queue_unittest.cc", - "task_scheduler/scheduler_lock_unittest.cc", - "task_scheduler/scheduler_single_thread_task_runner_manager_unittest.cc", - "task_scheduler/scheduler_worker_pool_impl_unittest.cc", - "task_scheduler/scheduler_worker_pool_unittest.cc", - "task_scheduler/scheduler_worker_stack_unittest.cc", - "task_scheduler/scheduler_worker_unittest.cc", - "task_scheduler/scoped_set_task_priority_for_current_thread_unittest.cc", - "task_scheduler/sequence_sort_key_unittest.cc", - "task_scheduler/sequence_unittest.cc", - "task_scheduler/service_thread_unittest.cc", - "task_scheduler/task_scheduler_impl_unittest.cc", - "task_scheduler/task_tracker_unittest.cc", - "task_scheduler/task_traits_unittest.cc", - "task_scheduler/task_unittest.cc", - "task_scheduler/test_task_factory.cc", - "task_scheduler/test_task_factory.h", - "task_scheduler/test_utils.cc", - "task_scheduler/test_utils.h", - "task_scheduler/tracked_ref_unittest.cc", - "template_util_unittest.cc", - "test/histogram_tester_unittest.cc", - "test/mock_callback_unittest.cc", - "test/scoped_feature_list_unittest.cc", - "test/scoped_mock_time_message_loop_task_runner_unittest.cc", - "test/scoped_task_environment_unittest.cc", - "test/test_mock_time_task_runner_unittest.cc", - "test/test_pending_task_unittest.cc", - "test/test_reg_util_win_unittest.cc", - "test/trace_event_analyzer_unittest.cc", - "test/user_action_tester_unittest.cc", - "thread_annotations_unittest.cc", - "threading/platform_thread_unittest.cc", - "threading/post_task_and_reply_impl_unittest.cc", - "threading/scoped_blocking_call_unittest.cc", - "threading/sequence_local_storage_map_unittest.cc", - "threading/sequence_local_storage_slot_unittest.cc", - "threading/sequenced_task_runner_handle_unittest.cc", - "threading/simple_thread_unittest.cc", - "threading/thread_checker_unittest.cc", - "threading/thread_collision_warner_unittest.cc", - "threading/thread_id_name_manager_unittest.cc", - "threading/thread_local_storage_unittest.cc", - "threading/thread_local_unittest.cc", - "threading/thread_restrictions_unittest.cc", - "threading/thread_task_runner_handle_unittest.cc", - "threading/thread_unittest.cc", - "threading/watchdog_unittest.cc", - "time/pr_time_unittest.cc", - "time/time_unittest.cc", - "time/time_win_unittest.cc", - "timer/hi_res_timer_manager_unittest.cc", - "timer/mock_timer_unittest.cc", - "timer/timer_unittest.cc", - "tools_sanity_unittest.cc", - "trace_event/blame_context_unittest.cc", - "trace_event/event_name_filter_unittest.cc", - "trace_event/heap_profiler_allocation_context_tracker_unittest.cc", - "trace_event/heap_profiler_heap_dump_writer_unittest.cc", - "trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc", - "trace_event/heap_profiler_type_name_deduplicator_unittest.cc", - "trace_event/java_heap_dump_provider_android_unittest.cc", - "trace_event/memory_allocator_dump_unittest.cc", - "trace_event/memory_dump_manager_unittest.cc", - "trace_event/memory_dump_scheduler_unittest.cc", - "trace_event/memory_peak_detector_unittest.cc", - "trace_event/memory_usage_estimator_unittest.cc", - "trace_event/process_memory_dump_unittest.cc", - "trace_event/trace_category_unittest.cc", - "trace_event/trace_config_unittest.cc", - "trace_event/trace_event_argument_unittest.cc", - "trace_event/trace_event_filter_test_utils.cc", - "trace_event/trace_event_filter_test_utils.h", - "trace_event/trace_event_system_stats_monitor_unittest.cc", - "trace_event/trace_event_unittest.cc", - "tuple_unittest.cc", - "unguessable_token_unittest.cc", - "value_iterators_unittest.cc", - "values_unittest.cc", - "version_unittest.cc", - "vlog_unittest.cc", - "win/async_operation_unittest.cc", - "win/com_init_check_hook_unittest.cc", - "win/com_init_util_unittest.cc", - "win/core_winrt_util_unittest.cc", - "win/dllmain.cc", - "win/enum_variant_unittest.cc", - "win/event_trace_consumer_unittest.cc", - "win/event_trace_controller_unittest.cc", - "win/event_trace_provider_unittest.cc", - "win/i18n_unittest.cc", - "win/iunknown_impl_unittest.cc", - "win/message_window_unittest.cc", - "win/object_watcher_unittest.cc", - "win/pe_image_unittest.cc", - "win/registry_unittest.cc", - "win/scoped_bstr_unittest.cc", - "win/scoped_handle_unittest.cc", - "win/scoped_hstring_unittest.cc", - "win/scoped_process_information_unittest.cc", - "win/scoped_variant_unittest.cc", - "win/scoped_winrt_initializer_unittest.cc", - "win/shortcut_unittest.cc", - "win/startup_information_unittest.cc", - "win/typed_event_handler_unittest.cc", - "win/wait_chain_unittest.cc", - "win/win_includes_unittest.cc", - "win/win_util_unittest.cc", - "win/windows_version_unittest.cc", - "win/winrt_storage_util_unittest.cc", - "win/wrapped_window_proc_unittest.cc", - ] - - defines = [] - - deps = [ - ":base", - ":i18n", - "//base/allocator:buildflags", - "//base/test:native_library_test_utils", - "//base/test:run_all_base_unittests", - "//base/test:test_support", - "//base/third_party/dynamic_annotations", - "//testing/gmock", - "//testing/gtest", - "//third_party/icu", - ] - - data_deps = [ - "//base/test:test_child_process", - "//base/test:test_shared_library", - ] - - if (is_ios || is_mac) { - deps += [ ":base_unittests_arc" ] - } - - public_deps = [ - ":base_unittests_bundle_data", - ] - - data = [ - "test/data/", - ] - - if (is_posix) { - sources += [ - "files/dir_reader_posix_unittest.cc", - "files/file_descriptor_watcher_posix_unittest.cc", - "message_loop/message_loop_io_posix_unittest.cc", - "posix/file_descriptor_shuffle_unittest.cc", - "posix/unix_domain_socket_unittest.cc", - "task_scheduler/task_tracker_posix_unittest.cc", - ] - } - - # Allow more direct string conversions on platforms with native utf8 - # strings - if (is_mac || is_ios || is_chromeos || is_chromecast || is_fuchsia) { - defines += [ "SYSTEM_NATIVE_UTF8" ] - } - - if (is_android) { - # Add unwind tables in base_unittests_apk test apk. The unwind tables are - # generated from debug info in the binary. Removing "default_symbols" and - # adding symbols config removes the "strip_debug" config that strips the - # debug info, on base unittests apk. - if (can_unwind_with_cfi_table) { - configs -= [ "//build/config/compiler:default_symbols" ] - if (symbol_level == 2) { - configs += [ "//build/config/compiler:symbols" ] - } else { - configs += [ "//build/config/compiler:minimal_symbols" ] - } - add_unwind_tables_in_apk = true - sources += [ "trace_event/cfi_backtrace_android_unittest.cc" ] - } - sources -= [ - "process/process_unittest.cc", - "process/process_util_unittest.cc", - ] - deps += [ - ":base_java", - ":base_java_unittest_support", - "//base/test:test_support_java", - ] - } - - if (is_ios) { - sources -= [ - "files/file_path_watcher_unittest.cc", - "memory/discardable_shared_memory_unittest.cc", - "memory/shared_memory_unittest.cc", - "process/memory_unittest.cc", - "process/process_unittest.cc", - "process/process_util_unittest.cc", - "sync_socket_unittest.cc", - "synchronization/waitable_event_watcher_unittest.cc", - ] - - # Pull in specific Mac files for iOS (which have been filtered out by file - # name rules). - set_sources_assignment_filter([]) - sources += [ - "mac/bind_objc_block_unittest.mm", - "mac/foundation_util_unittest.mm", - "mac/objc_release_properties_unittest.mm", - "mac/scoped_nsobject_unittest.mm", - "strings/sys_string_conversions_mac_unittest.mm", - ] - set_sources_assignment_filter(sources_assignment_filter) - - # TODO(GYP): dep on copy_test_data_ios action. - } - - if (use_partition_alloc) { - sources += [ - "allocator/partition_allocator/address_space_randomization_unittest.cc", - "allocator/partition_allocator/page_allocator_unittest.cc", - "allocator/partition_allocator/partition_alloc_unittest.cc", - "allocator/partition_allocator/spin_lock_unittest.cc", - ] - } - - if (is_mac) { - libs = [ - "CoreFoundation.framework", - "Foundation.framework", - ] - if (current_cpu == "x64") { - data_deps += [ ":base_profiler_test_support_library" ] - } - } - - if (is_linux) { - if (is_desktop_linux) { - sources += [ "nix/xdg_util_unittest.cc" ] - } - - deps += [ "//base/test:malloc_wrapper" ] - defines += [ - # This library is used by ElfReaderTest to test reading elf files. - "MALLOC_WRAPPER_LIB=\"${shlib_prefix}malloc_wrapper${shlib_extension}\"", - ] - - if (!is_component_build) { - # Set rpath to find libmalloc_wrapper.so even in a non-component build. - configs += [ "//build/config/gcc:rpath_for_built_shared_libraries" ] - } - } - - if (!use_glib) { - sources -= [ "message_loop/message_pump_glib_unittest.cc" ] - } - - if (use_libevent) { - sources += [ "message_loop/message_pump_libevent_unittest.cc" ] - deps += [ "//base/third_party/libevent" ] - } - - if (is_fuchsia) { - sources += [ - "files/dir_reader_posix_unittest.cc", - "files/file_descriptor_watcher_posix_unittest.cc", - "fuchsia/services_directory_unittest.cc", - "message_loop/message_loop_io_posix_unittest.cc", - "posix/file_descriptor_shuffle_unittest.cc", - "task_scheduler/task_tracker_posix_unittest.cc", - ] - - sources += [ "fuchsia/async_dispatcher_unittest.cc" ] - deps += [ - ":test_fidl", - "//third_party/fuchsia-sdk:async", - "//third_party/fuchsia-sdk:async_default", - "//third_party/fuchsia-sdk:fdio", - ] - } - - if (!is_fuchsia && !is_ios) { - sources += [ "files/file_locking_unittest.cc" ] - } - - if (is_android) { - deps += [ "//testing/android/native_test:native_test_native_code" ] - set_sources_assignment_filter([]) - sources += [ - "debug/elf_reader_linux_unittest.cc", - "debug/proc_maps_linux_unittest.cc", - "trace_event/trace_event_android_unittest.cc", - ] - set_sources_assignment_filter(sources_assignment_filter) - } - - if (is_win) { - deps += [ "//base:scoped_handle_test_dll" ] - if (current_cpu == "x64") { - sources += [ "profiler/win32_stack_frame_unwinder_unittest.cc" ] - data_deps += [ ":base_profiler_test_support_library" ] - } - } - - if (use_allocator_shim) { - sources += [ - "allocator/allocator_shim_unittest.cc", - "sampling_heap_profiler/sampling_heap_profiler_unittest.cc", - ] - } - - # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. - configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] - - # Symbols for crashes when running tests on swarming. - if (symbol_level > 0) { - if (is_win) { - data += [ "$root_out_dir/base_unittests.exe.pdb" ] - } else if (is_mac) { - # TODO(crbug.com/330301): make this conditional on mac_strip_release. - # data += [ "$root_out_dir/base_unittests.dSYM/" ] - } - } -} - -action("build_date") { - script = "//build/write_build_date_header.py" - - # Force recalculation if there's been a change. - inputs = [ - "//build/util/LASTCHANGE", - ] - outputs = [ - "$target_gen_dir/generated_build_date.h", - ] - - args = - [ rebase_path("$target_gen_dir/generated_build_date.h", root_build_dir) ] - - if (is_official_build) { - args += [ "official" ] - } else { - args += [ "default" ] - } - - if (override_build_date != "N/A") { - args += [ override_build_date ] - } -} - -if (enable_nocompile_tests) { - nocompile_test("base_nocompile_tests") { - sources = [ - "bind_unittest.nc", - "callback_list_unittest.nc", - "callback_unittest.nc", - "containers/span_unittest.nc", - "memory/ref_counted_unittest.nc", - "memory/weak_ptr_unittest.nc", - "metrics/field_trial_params_unittest.nc", - "metrics/histogram_unittest.nc", - "optional_unittest.nc", - "strings/string16_unittest.nc", - "task_scheduler/task_traits_unittest.nc", - "thread_annotations_unittest.nc", - ] - - deps = [ - ":base", - "//base/test:run_all_unittests", - "//testing/gtest", - ] - } -} - -if (is_android) { - generate_jni("base_jni_headers") { - sources = [ - "android/java/src/org/chromium/base/AnimationFrameTimeHistogram.java", - "android/java/src/org/chromium/base/ApkAssets.java", - "android/java/src/org/chromium/base/ApplicationStatus.java", - "android/java/src/org/chromium/base/BuildInfo.java", - "android/java/src/org/chromium/base/Callback.java", - "android/java/src/org/chromium/base/CommandLine.java", - "android/java/src/org/chromium/base/ContentUriUtils.java", - "android/java/src/org/chromium/base/CpuFeatures.java", - "android/java/src/org/chromium/base/EarlyTraceEvent.java", - "android/java/src/org/chromium/base/EventLog.java", - "android/java/src/org/chromium/base/FieldTrialList.java", - "android/java/src/org/chromium/base/ImportantFileWriterAndroid.java", - "android/java/src/org/chromium/base/JNIUtils.java", - "android/java/src/org/chromium/base/JavaExceptionReporter.java", - "android/java/src/org/chromium/base/JavaHandlerThread.java", - "android/java/src/org/chromium/base/LocaleUtils.java", - "android/java/src/org/chromium/base/MemoryPressureListener.java", - "android/java/src/org/chromium/base/PathService.java", - "android/java/src/org/chromium/base/PathUtils.java", - "android/java/src/org/chromium/base/PowerMonitor.java", - "android/java/src/org/chromium/base/SysUtils.java", - "android/java/src/org/chromium/base/SystemMessageHandler.java", - "android/java/src/org/chromium/base/ThreadUtils.java", - "android/java/src/org/chromium/base/ThrowUncaughtException.java", - "android/java/src/org/chromium/base/TimeUtils.java", - "android/java/src/org/chromium/base/TimezoneUtils.java", - "android/java/src/org/chromium/base/TraceEvent.java", - "android/java/src/org/chromium/base/UnguessableToken.java", - "android/java/src/org/chromium/base/library_loader/LibraryLoader.java", - "android/java/src/org/chromium/base/metrics/RecordHistogram.java", - "android/java/src/org/chromium/base/metrics/RecordUserAction.java", - "android/java/src/org/chromium/base/metrics/StatisticsRecorderAndroid.java", - "android/java/src/org/chromium/base/process_launcher/ChildProcessService.java", - ] - - public_deps = [ - ":android_runtime_jni_headers", - ] - - jni_package = "base" - } - - generate_jar_jni("android_runtime_jni_headers") { - jni_package = "base" - classes = [ "java/lang/Runtime.class" ] - } - - android_library("base_java") { - srcjar_deps = [ - ":base_android_java_enums_srcjar", - ":base_build_config_gen", - ":base_java_aidl", - ":base_native_libraries_gen", - ] - - deps = [ - "//third_party/android_tools:android_support_annotations_java", - "//third_party/android_tools:android_support_multidex_java", - "//third_party/android_tools:android_support_v4_java", - "//third_party/jsr-305:jsr_305_javalib", - ] - - java_files = [ - "android/java/src/org/chromium/base/ActivityState.java", - "android/java/src/org/chromium/base/AnimationFrameTimeHistogram.java", - "android/java/src/org/chromium/base/ApiCompatibilityUtils.java", - "android/java/src/org/chromium/base/ApkAssets.java", - "android/java/src/org/chromium/base/ApplicationStatus.java", - "android/java/src/org/chromium/base/BaseSwitches.java", - "android/java/src/org/chromium/base/BuildInfo.java", - "android/java/src/org/chromium/base/Callback.java", - "android/java/src/org/chromium/base/CollectionUtil.java", - "android/java/src/org/chromium/base/CommandLine.java", - "android/java/src/org/chromium/base/CommandLineInitUtil.java", - "android/java/src/org/chromium/base/ContentUriUtils.java", - "android/java/src/org/chromium/base/ContextUtils.java", - "android/java/src/org/chromium/base/CpuFeatures.java", - "android/java/src/org/chromium/base/DiscardableReferencePool.java", - "android/java/src/org/chromium/base/EarlyTraceEvent.java", - "android/java/src/org/chromium/base/EventLog.java", - "android/java/src/org/chromium/base/FieldTrialList.java", - "android/java/src/org/chromium/base/FileUtils.java", - "android/java/src/org/chromium/base/ImportantFileWriterAndroid.java", - "android/java/src/org/chromium/base/JNIUtils.java", - "android/java/src/org/chromium/base/JavaExceptionReporter.java", - "android/java/src/org/chromium/base/JavaHandlerThread.java", - "android/java/src/org/chromium/base/LocaleUtils.java", - "android/java/src/org/chromium/base/Log.java", - "android/java/src/org/chromium/base/MemoryPressureListener.java", - "android/java/src/org/chromium/base/NonThreadSafe.java", - "android/java/src/org/chromium/base/ObserverList.java", - "android/java/src/org/chromium/base/PackageUtils.java", - "android/java/src/org/chromium/base/PathService.java", - "android/java/src/org/chromium/base/PathUtils.java", - "android/java/src/org/chromium/base/PowerMonitor.java", - "android/java/src/org/chromium/base/Promise.java", - "android/java/src/org/chromium/base/ResourceExtractor.java", - "android/java/src/org/chromium/base/SecureRandomInitializer.java", - "android/java/src/org/chromium/base/StreamUtil.java", - "android/java/src/org/chromium/base/StrictModeContext.java", - "android/java/src/org/chromium/base/Supplier.java", - "android/java/src/org/chromium/base/SysUtils.java", - "android/java/src/org/chromium/base/SystemMessageHandler.java", - "android/java/src/org/chromium/base/ThreadUtils.java", - "android/java/src/org/chromium/base/ThrowUncaughtException.java", - "android/java/src/org/chromium/base/TimeUtils.java", - "android/java/src/org/chromium/base/TimezoneUtils.java", - "android/java/src/org/chromium/base/TraceEvent.java", - "android/java/src/org/chromium/base/UnguessableToken.java", - "android/java/src/org/chromium/base/VisibleForTesting.java", - "android/java/src/org/chromium/base/annotations/AccessedByNative.java", - "android/java/src/org/chromium/base/annotations/CalledByNative.java", - "android/java/src/org/chromium/base/annotations/CalledByNativeUnchecked.java", - "android/java/src/org/chromium/base/annotations/JNIAdditionalImport.java", - "android/java/src/org/chromium/base/annotations/JNINamespace.java", - "android/java/src/org/chromium/base/annotations/MainDex.java", - "android/java/src/org/chromium/base/annotations/NativeCall.java", - "android/java/src/org/chromium/base/annotations/NativeClassQualifiedName.java", - "android/java/src/org/chromium/base/annotations/RemovableInRelease.java", - "android/java/src/org/chromium/base/annotations/UsedByReflection.java", - "android/java/src/org/chromium/base/library_loader/LegacyLinker.java", - "android/java/src/org/chromium/base/library_loader/LibraryLoader.java", - "android/java/src/org/chromium/base/library_loader/Linker.java", - "android/java/src/org/chromium/base/library_loader/LoaderErrors.java", - "android/java/src/org/chromium/base/library_loader/NativeLibraryPreloader.java", - "android/java/src/org/chromium/base/library_loader/ProcessInitException.java", - "android/java/src/org/chromium/base/metrics/CachedMetrics.java", - "android/java/src/org/chromium/base/metrics/RecordHistogram.java", - "android/java/src/org/chromium/base/metrics/RecordUserAction.java", - "android/java/src/org/chromium/base/metrics/StatisticsRecorderAndroid.java", - "android/java/src/org/chromium/base/multidex/ChromiumMultiDexInstaller.java", - "android/java/src/org/chromium/base/process_launcher/ChildConnectionAllocator.java", - "android/java/src/org/chromium/base/process_launcher/ChildProcessConnection.java", - "android/java/src/org/chromium/base/process_launcher/ChildProcessConstants.java", - "android/java/src/org/chromium/base/process_launcher/ChildProcessLauncher.java", - "android/java/src/org/chromium/base/process_launcher/ChildProcessService.java", - "android/java/src/org/chromium/base/process_launcher/ChildProcessServiceDelegate.java", - "android/java/src/org/chromium/base/process_launcher/FileDescriptorInfo.java", - "android/java/src/org/chromium/base/memory/MemoryPressureMonitor.java", - "android/java/src/org/chromium/base/memory/MemoryPressureCallback.java", - "android/java/src/org/chromium/base/memory/MemoryPressureUma.java", - ] - - # New versions of BuildConfig.java and NativeLibraries.java - # (with the actual correct values) will be created when creating an apk. - jar_excluded_patterns = [ - "*/BuildConfig.class", - "*/NativeLibraries.class", - "*/NativeLibraries##*.class", - ] - } - - android_aidl("base_java_aidl") { - import_include = [ "android/java/src" ] - sources = [ - "android/java/src/org/chromium/base/process_launcher/ICallbackInt.aidl", - "android/java/src/org/chromium/base/process_launcher/IChildProcessService.aidl", - ] - } - - android_library("base_javatests") { - testonly = true - deps = [ - ":base_java", - ":base_java_test_support", - "//third_party/android_support_test_runner:runner_java", - "//third_party/junit:junit", - ] - java_files = [ - "android/javatests/src/org/chromium/base/AdvancedMockContextTest.java", - "android/javatests/src/org/chromium/base/ApiCompatibilityUtilsTest.java", - "android/javatests/src/org/chromium/base/CommandLineInitUtilTest.java", - "android/javatests/src/org/chromium/base/CommandLineTest.java", - "android/javatests/src/org/chromium/base/EarlyTraceEventTest.java", - - # TODO(nona): move to Junit once that is built for Android N. - "android/javatests/src/org/chromium/base/LocaleUtilsTest.java", - "android/javatests/src/org/chromium/base/ObserverListTest.java", - "android/javatests/src/org/chromium/base/StrictModeContextTest.java", - "android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java", - ] - } - - android_library("base_java_test_support") { - testonly = true - deps = [ - ":base_java", - "//testing/android/reporter:reporter_java", - "//third_party/android_support_test_runner:exposed_instrumentation_api_publish_java", - "//third_party/android_support_test_runner:rules_java", - "//third_party/android_support_test_runner:runner_java", - "//third_party/android_tools:android_support_annotations_java", - "//third_party/android_tools:android_support_chromium_java", - "//third_party/android_tools:android_support_compat_java", - "//third_party/hamcrest:hamcrest_core_java", - "//third_party/junit", - "//third_party/ub-uiautomator:ub_uiautomator_java", - ] - - deps += android_extra_test_deps - - java_files = [ - "test/android/javatests/src/org/chromium/base/test/BaseJUnit4ClassRunner.java", - "test/android/javatests/src/org/chromium/base/test/BaseChromiumAndroidJUnitRunner.java", - "test/android/javatests/src/org/chromium/base/test/BaseChromiumRunnerCommon.java", - "test/android/javatests/src/org/chromium/base/test/BaseTestResult.java", - "test/android/javatests/src/org/chromium/base/test/ScreenshotOnFailureStatement.java", - "test/android/javatests/src/org/chromium/base/test/SetUpTestRule.java", - "test/android/javatests/src/org/chromium/base/test/SetUpStatement.java", - "test/android/javatests/src/org/chromium/base/test/TestListInstrumentationRunListener.java", - "test/android/javatests/src/org/chromium/base/test/TestTraceEvent.java", - "test/android/javatests/src/org/chromium/base/test/params/ParameterizedRunner.java", - "test/android/javatests/src/org/chromium/base/test/params/BlockJUnit4RunnerDelegate.java", - "test/android/javatests/src/org/chromium/base/test/params/BaseJUnit4RunnerDelegate.java", - "test/android/javatests/src/org/chromium/base/test/params/MethodParamAnnotationRule.java", - "test/android/javatests/src/org/chromium/base/test/params/MethodParamRule.java", - "test/android/javatests/src/org/chromium/base/test/params/ParameterAnnotations.java", - "test/android/javatests/src/org/chromium/base/test/params/ParameterizedFrameworkMethod.java", - "test/android/javatests/src/org/chromium/base/test/params/ParameterizedRunnerDelegate.java", - "test/android/javatests/src/org/chromium/base/test/params/ParameterizedRunnerDelegateCommon.java", - "test/android/javatests/src/org/chromium/base/test/params/ParameterizedRunnerDelegateFactory.java", - "test/android/javatests/src/org/chromium/base/test/params/ParameterProvider.java", - "test/android/javatests/src/org/chromium/base/test/params/ParameterSet.java", - "test/android/javatests/src/org/chromium/base/test/util/AdvancedMockContext.java", - "test/android/javatests/src/org/chromium/base/test/util/AnnotationRule.java", - "test/android/javatests/src/org/chromium/base/test/util/CallbackHelper.java", - "test/android/javatests/src/org/chromium/base/test/util/CommandLineFlags.java", - "test/android/javatests/src/org/chromium/base/test/util/DisableIf.java", - "test/android/javatests/src/org/chromium/base/test/util/DisableIfSkipCheck.java", - "test/android/javatests/src/org/chromium/base/test/util/AnnotationProcessingUtils.java", - "test/android/javatests/src/org/chromium/base/test/util/DisabledTest.java", - "test/android/javatests/src/org/chromium/base/test/util/EnormousTest.java", - "test/android/javatests/src/org/chromium/base/test/util/Feature.java", - "test/android/javatests/src/org/chromium/base/test/util/FlakyTest.java", - "test/android/javatests/src/org/chromium/base/test/util/InMemorySharedPreferences.java", - "test/android/javatests/src/org/chromium/base/test/util/InstrumentationUtils.java", - "test/android/javatests/src/org/chromium/base/test/util/IntegrationTest.java", - "test/android/javatests/src/org/chromium/base/test/util/Manual.java", - "test/android/javatests/src/org/chromium/base/test/util/ManualSkipCheck.java", - "test/android/javatests/src/org/chromium/base/test/util/Matchers.java", - "test/android/javatests/src/org/chromium/base/test/util/MetricsUtils.java", - "test/android/javatests/src/org/chromium/base/test/util/MinAndroidSdkLevel.java", - "test/android/javatests/src/org/chromium/base/test/util/MinAndroidSdkLevelSkipCheck.java", - "test/android/javatests/src/org/chromium/base/test/util/Restriction.java", - "test/android/javatests/src/org/chromium/base/test/util/RestrictionSkipCheck.java", - "test/android/javatests/src/org/chromium/base/test/util/RetryOnFailure.java", - "test/android/javatests/src/org/chromium/base/test/util/ScalableTimeout.java", - "test/android/javatests/src/org/chromium/base/test/util/SkipCheck.java", - "test/android/javatests/src/org/chromium/base/test/util/TestFileUtil.java", - "test/android/javatests/src/org/chromium/base/test/util/TestThread.java", - "test/android/javatests/src/org/chromium/base/test/util/TimeoutScale.java", - "test/android/javatests/src/org/chromium/base/test/util/UserActionTester.java", - "test/android/javatests/src/org/chromium/base/test/util/UrlUtils.java", - "test/android/javatests/src/org/chromium/base/test/util/parameter/CommandLineParameter.java", - "test/android/javatests/src/org/chromium/base/test/util/parameter/SkipCommandLineParameterization.java", - ] - } - - android_library("base_java_process_launcher_test_support") { - testonly = true - deps = [ - ":base_java", - ":base_java_test_support", - ] - java_files = [ "test/android/javatests/src/org/chromium/base/test/TestChildProcessConnection.java" ] - } - - android_library("base_junit_test_support") { - # Plaform checks are broken for Robolectric. - bypass_platform_checks = true - testonly = true - java_files = [ - "android/junit/src/org/chromium/base/metrics/test/ShadowRecordHistogram.java", - "test/android/junit/src/org/chromium/base/test/BaseRobolectricTestRunner.java", - ] - deps = [ - ":base_java", - "//testing/android/junit:junit_test_support", - "//third_party/robolectric:robolectric_all_java", - ] - } - - junit_binary("base_junit_tests") { - java_files = [ - "android/junit/src/org/chromium/base/ApplicationStatusTest.java", - "android/junit/src/org/chromium/base/DiscardableReferencePoolTest.java", - "android/junit/src/org/chromium/base/LogTest.java", - "android/junit/src/org/chromium/base/NonThreadSafeTest.java", - "android/junit/src/org/chromium/base/PromiseTest.java", - "android/junit/src/org/chromium/base/memory/MemoryPressureMonitorTest.java", - "android/junit/src/org/chromium/base/process_launcher/ChildConnectionAllocatorTest.java", - "android/junit/src/org/chromium/base/process_launcher/ChildProcessConnectionTest.java", - "test/android/junit/src/org/chromium/base/test/SetUpStatementTest.java", - "test/android/junit/src/org/chromium/base/test/TestListInstrumentationRunListenerTest.java", - "test/android/junit/src/org/chromium/base/test/util/AnnotationProcessingUtilsTest.java", - "test/android/junit/src/org/chromium/base/test/util/DisableIfTest.java", - "test/android/junit/src/org/chromium/base/test/util/ManualSkipCheckTest.java", - "test/android/junit/src/org/chromium/base/test/util/MinAndroidSdkLevelSkipCheckTest.java", - "test/android/junit/src/org/chromium/base/test/util/RestrictionSkipCheckTest.java", - "test/android/junit/src/org/chromium/base/test/util/SkipCheckTest.java", - "test/android/junit/src/org/chromium/base/test/params/ExampleParameterizedTest.java", - "test/android/junit/src/org/chromium/base/test/params/ParameterizedRunnerTest.java", - "test/android/junit/src/org/chromium/base/test/params/ParameterizedRunnerDelegateCommonTest.java", - "test/android/junit/src/org/chromium/base/test/params/ParameterizedRunnerDelegateFactoryTest.java", - "test/android/junit/src/org/chromium/base/test/params/ParameterizedTestNameTest.java", - ] - deps = [ - ":base_java", - ":base_java_process_launcher_test_support", - ":base_java_test_support", - ":base_junit_test_support", - "//third_party/hamcrest:hamcrest_java", - ] - } - - java_cpp_enum("base_android_java_enums_srcjar") { - sources = [ - "android/application_status_listener.h", - "android/library_loader/library_load_from_apk_status_codes.h", - "android/library_loader/library_loader_hooks.h", - "memory/memory_pressure_listener.h", - "metrics/histogram_base.h", - "trace_event/trace_config.h", - ] - } - - generate_build_config_srcjar("base_build_config_gen") { - use_final_fields = false - } - - java_cpp_template("base_native_libraries_gen") { - sources = [ - "android/java/templates/NativeLibraries.template", - ] - package_path = "org/chromium/base/library_loader" - } - - android_library("base_java_unittest_support") { - testonly = true - deps = [ - ":base_java", - ] - java_files = [ - "test/android/java/src/org/chromium/base/ContentUriTestUtils.java", - "test/android/java/src/org/chromium/base/JavaHandlerThreadHelpers.java", - ] - } -} - -# Keep the list of fuzzer_tests in alphabetical order. -fuzzer_test("base64_decode_fuzzer") { - sources = [ - "base64_decode_fuzzer.cc", - ] - deps = [ - "//base", - ] -} - -fuzzer_test("base64_encode_fuzzer") { - sources = [ - "base64_encode_fuzzer.cc", - ] - deps = [ - "//base", - ] -} - -fuzzer_test("base_json_correctness_fuzzer") { - sources = [ - "json/json_correctness_fuzzer.cc", - ] - deps = [ - ":base", - ] - dict = "//testing/libfuzzer/fuzzers/dicts/json.dict" -} - -fuzzer_test("base_json_reader_fuzzer") { - sources = [ - "json/json_reader_fuzzer.cc", - ] - deps = [ - "//base", - ] - dict = "//testing/libfuzzer/fuzzers/dicts/json.dict" -} - -fuzzer_test("base_json_string_escape_fuzzer") { - sources = [ - "json/string_escape_fuzzer.cc", - ] - deps = [ - "//base", - ] -} - -fuzzer_test("string_number_conversions_fuzzer") { - sources = [ - "strings/string_number_conversions_fuzzer.cc", - ] - deps = [ - "//base", - ] -} - -fuzzer_test("string_tokenizer_fuzzer") { - sources = [ - "strings/string_tokenizer_fuzzer.cc", - ] - deps = [ - "//base", - ] -} - -fuzzer_test("utf_string_conversions_fuzzer") { - sources = [ - "strings/utf_string_conversions_fuzzer.cc", - ] - deps = [ - "//base", - ] -} - -# TODO(dyaroshev): remove regression fuzzer, after we run it for a few days -# and are confident that the transition was ok. -fuzzer_test("utf_string_conversions_regression_fuzzer") { - sources = [ - "strings/old_utf_string_conversions.cc", - "strings/old_utf_string_conversions.h", - "strings/utf_string_conversions_regression_fuzzer.cc", - ] - deps = [ - ":base", - ] - - libfuzzer_options = [ "max_len=32" ] -}
diff --git a/base/allocator/BUILD.gn b/base/allocator/BUILD.gn deleted file mode 100644 index 636a342..0000000 --- a/base/allocator/BUILD.gn +++ /dev/null
@@ -1,284 +0,0 @@ -# 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. - -import("//build/buildflag_header.gni") -import("//build/config/allocator.gni") -import("//build/config/compiler/compiler.gni") - -declare_args() { - # Provide a way to force disable debugallocation in Debug builds, - # e.g. for profiling (it's more rare to profile Debug builds, - # but people sometimes need to do that). - enable_debugallocation = is_debug -} - -# This "allocator" meta-target will forward to the default allocator according -# to the build settings. -group("allocator") { - public_deps = [] - deps = [] - - if (use_allocator == "tcmalloc") { - deps += [ ":tcmalloc" ] - } -} - -config("tcmalloc_flags") { - defines = [] - if (enable_debugallocation) { - defines += [ - # Use debugallocation for Debug builds to catch problems early - # and cleanly, http://crbug.com/30715 . - "TCMALLOC_FOR_DEBUGALLOCATION", - ] - } - if (use_allocator_shim) { - defines += [ "TCMALLOC_DONT_REPLACE_SYSTEM_ALLOC" ] - } - if (is_clang) { - cflags = [ - # tcmalloc initializes some fields in the wrong order. - "-Wno-reorder", - - # tcmalloc contains some unused local template specializations. - "-Wno-unused-function", - - # tcmalloc uses COMPILE_ASSERT without static_assert but with typedefs. - "-Wno-unused-local-typedefs", - - # for magic2_ in debugallocation.cc (only built in Debug builds) typedefs. - "-Wno-unused-private-field", - ] - } else { - cflags = [] - } - - if (is_linux || is_android) { - # We enable all warnings by default, but upstream disables a few. - # Keep "-Wno-*" flags in sync with upstream by comparing against: - # http://code.google.com/p/google-perftools/source/browse/trunk/Makefile.am - cflags += [ - "-Wno-sign-compare", - "-Wno-unused-result", - ] - } -} - -if (use_allocator == "tcmalloc") { - # tcmalloc currently won't compile on Android. - source_set("tcmalloc") { - tcmalloc_dir = "//third_party/tcmalloc/chromium" - - # Don't check tcmalloc's includes. These files include various files like - # base/foo.h and they actually refer to tcmalloc's forked copy of base - # rather than the regular one, which confuses the header checker. - check_includes = false - - sources = [ - # Generated for our configuration from tcmalloc's build - # and checked in. - "$tcmalloc_dir/src/config.h", - "$tcmalloc_dir/src/config_android.h", - "$tcmalloc_dir/src/config_linux.h", - "$tcmalloc_dir/src/config_win.h", - - # tcmalloc native and forked files. - "$tcmalloc_dir/src/base/abort.cc", - "$tcmalloc_dir/src/base/abort.h", - "$tcmalloc_dir/src/base/arm_instruction_set_select.h", - "$tcmalloc_dir/src/base/atomicops-internals-arm-generic.h", - "$tcmalloc_dir/src/base/atomicops-internals-arm-v6plus.h", - "$tcmalloc_dir/src/base/atomicops-internals-linuxppc.h", - "$tcmalloc_dir/src/base/atomicops-internals-macosx.h", - "$tcmalloc_dir/src/base/atomicops-internals-windows.h", - "$tcmalloc_dir/src/base/atomicops-internals-x86.cc", - "$tcmalloc_dir/src/base/atomicops-internals-x86.h", - "$tcmalloc_dir/src/base/atomicops.h", - "$tcmalloc_dir/src/base/commandlineflags.h", - "$tcmalloc_dir/src/base/cycleclock.h", - - # We don't list dynamic_annotations.c since its copy is already - # present in the dynamic_annotations target. - "$tcmalloc_dir/src/base/elf_mem_image.cc", - "$tcmalloc_dir/src/base/elf_mem_image.h", - "$tcmalloc_dir/src/base/linuxthreads.cc", - "$tcmalloc_dir/src/base/linuxthreads.h", - "$tcmalloc_dir/src/base/logging.cc", - "$tcmalloc_dir/src/base/logging.h", - "$tcmalloc_dir/src/base/low_level_alloc.cc", - "$tcmalloc_dir/src/base/low_level_alloc.h", - "$tcmalloc_dir/src/base/spinlock.cc", - "$tcmalloc_dir/src/base/spinlock.h", - "$tcmalloc_dir/src/base/spinlock_internal.cc", - "$tcmalloc_dir/src/base/spinlock_internal.h", - "$tcmalloc_dir/src/base/synchronization_profiling.h", - "$tcmalloc_dir/src/base/sysinfo.cc", - "$tcmalloc_dir/src/base/sysinfo.h", - "$tcmalloc_dir/src/base/vdso_support.cc", - "$tcmalloc_dir/src/base/vdso_support.h", - "$tcmalloc_dir/src/central_freelist.cc", - "$tcmalloc_dir/src/central_freelist.h", - "$tcmalloc_dir/src/common.cc", - "$tcmalloc_dir/src/common.h", - - # #included by debugallocation_shim.cc - #"$tcmalloc_dir/src/debugallocation.cc", - "$tcmalloc_dir/src/free_list.cc", - "$tcmalloc_dir/src/free_list.h", - "$tcmalloc_dir/src/gperftools/heap-profiler.h", - "$tcmalloc_dir/src/gperftools/malloc_extension.h", - "$tcmalloc_dir/src/gperftools/malloc_hook.h", - "$tcmalloc_dir/src/gperftools/stacktrace.h", - "$tcmalloc_dir/src/heap-profile-table.cc", - "$tcmalloc_dir/src/heap-profile-table.h", - "$tcmalloc_dir/src/heap-profiler.cc", - "$tcmalloc_dir/src/internal_logging.cc", - "$tcmalloc_dir/src/internal_logging.h", - "$tcmalloc_dir/src/linked_list.h", - "$tcmalloc_dir/src/malloc_extension.cc", - "$tcmalloc_dir/src/malloc_hook-inl.h", - "$tcmalloc_dir/src/malloc_hook.cc", - "$tcmalloc_dir/src/maybe_threads.cc", - "$tcmalloc_dir/src/maybe_threads.h", - "$tcmalloc_dir/src/memory_region_map.cc", - "$tcmalloc_dir/src/memory_region_map.h", - "$tcmalloc_dir/src/page_heap.cc", - "$tcmalloc_dir/src/page_heap.h", - "$tcmalloc_dir/src/raw_printer.cc", - "$tcmalloc_dir/src/raw_printer.h", - "$tcmalloc_dir/src/sampler.cc", - "$tcmalloc_dir/src/sampler.h", - "$tcmalloc_dir/src/span.cc", - "$tcmalloc_dir/src/span.h", - "$tcmalloc_dir/src/stack_trace_table.cc", - "$tcmalloc_dir/src/stack_trace_table.h", - "$tcmalloc_dir/src/stacktrace.cc", - "$tcmalloc_dir/src/static_vars.cc", - "$tcmalloc_dir/src/static_vars.h", - "$tcmalloc_dir/src/symbolize.cc", - "$tcmalloc_dir/src/symbolize.h", - "$tcmalloc_dir/src/system-alloc.cc", - "$tcmalloc_dir/src/system-alloc.h", - - # #included by debugallocation_shim.cc - #"$tcmalloc_dir/src/tcmalloc.cc", - #"$tcmalloc_dir/src/tcmalloc.h", - "$tcmalloc_dir/src/thread_cache.cc", - "$tcmalloc_dir/src/thread_cache.h", - "$tcmalloc_dir/src/windows/port.cc", - "$tcmalloc_dir/src/windows/port.h", - "debugallocation_shim.cc", - - # These are both #included by allocator_shim for maximal linking. - #"generic_allocators.cc", - #"win_allocator.cc", - ] - - # Not included on mips64el. - if (current_cpu == "mips64el") { - sources -= [ - "$tcmalloc_dir/src/base/linuxthreads.cc", - "$tcmalloc_dir/src/base/linuxthreads.h", - ] - } - - # Disable the heap checker in tcmalloc. - defines = [ "NO_HEAP_CHECK" ] - - include_dirs = [ - ".", - "$tcmalloc_dir/src/base", - "$tcmalloc_dir/src", - ] - - configs -= [ "//build/config/compiler:chromium_code" ] - configs += [ - "//build/config/compiler:no_chromium_code", - ":tcmalloc_flags", - ] - - # Thumb mode disabled due to bug in clang integrated assembler - # TODO(https://llvm.org/bugs/show_bug.cgi?id=31058) - configs -= [ "//build/config/compiler:compiler_arm_thumb" ] - configs += [ "//build/config/compiler:compiler_arm" ] - - # TODO(crbug.com/633719) Make tcmalloc work with AFDO on GCC if possible. - if (!is_clang) { - configs -= [ "//build/config/compiler:afdo" ] - } - - deps = [] - - if (enable_profiling) { - sources += [ - "$tcmalloc_dir/src/base/thread_lister.c", - "$tcmalloc_dir/src/base/thread_lister.h", - "$tcmalloc_dir/src/profile-handler.cc", - "$tcmalloc_dir/src/profile-handler.h", - "$tcmalloc_dir/src/profiledata.cc", - "$tcmalloc_dir/src/profiledata.h", - "$tcmalloc_dir/src/profiler.cc", - ] - defines += [ "ENABLE_PROFILING=1" ] - } - - if (is_linux || is_android) { - sources -= [ - "$tcmalloc_dir/src/system-alloc.h", - "$tcmalloc_dir/src/windows/port.cc", - "$tcmalloc_dir/src/windows/port.h", - ] - - # Compiling tcmalloc with -fvisibility=default is only necessary when - # not using the allocator shim, which provides the correct visibility - # annotations for those symbols which need to be exported (see - # //base/allocator/allocator_shim_override_glibc_weak_symbols.h and - # //base/allocator/allocator_shim_internals.h for the definition of - # SHIM_ALWAYS_EXPORT). - if (!use_allocator_shim) { - configs -= [ "//build/config/gcc:symbol_visibility_hidden" ] - configs += [ "//build/config/gcc:symbol_visibility_default" ] - } - - ldflags = [ - # Don't let linker rip this symbol out, otherwise the heap&cpu - # profilers will not initialize properly on startup. - "-Wl,-uIsHeapProfilerRunning,-uProfilerStart", - - # Do the same for heap leak checker. - "-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi", - "-Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl", - "-Wl,-u_ZN15HeapLeakChecker12IgnoreObjectEPKv,-u_ZN15HeapLeakChecker14UnIgnoreObjectEPKv", - ] - } - - # Make sure the allocation library is optimized as much as possible when - # we"re in release mode. - if (!is_debug) { - configs -= [ "//build/config/compiler:default_optimization" ] - configs += [ "//build/config/compiler:optimize_max" ] - } - - deps += [ "//base/third_party/dynamic_annotations" ] - } -} # use_allocator == "tcmalloc" - -buildflag_header("buildflags") { - header = "buildflags.h" - flags = [ "USE_ALLOCATOR_SHIM=$use_allocator_shim" ] -} - -# Used to shim malloc symbols on Android. see //base/allocator/README.md. -config("wrap_malloc_symbols") { - ldflags = [ - "-Wl,-wrap,calloc", - "-Wl,-wrap,free", - "-Wl,-wrap,malloc", - "-Wl,-wrap,memalign", - "-Wl,-wrap,posix_memalign", - "-Wl,-wrap,pvalloc", - "-Wl,-wrap,realloc", - "-Wl,-wrap,valloc", - ] -}
diff --git a/base/allocator/allocator_shim_unittest.cc b/base/allocator/allocator_shim_unittest.cc deleted file mode 100644 index 0a18eb2..0000000 --- a/base/allocator/allocator_shim_unittest.cc +++ /dev/null
@@ -1,460 +0,0 @@ -// 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/allocator/allocator_shim.h" - -#include <stdlib.h> -#include <string.h> - -#include <memory> -#include <new> -#include <vector> - -#include "base/allocator/partition_allocator/partition_alloc.h" -#include "base/atomicops.h" -#include "base/process/process_metrics.h" -#include "base/synchronization/waitable_event.h" -#include "base/threading/platform_thread.h" -#include "base/threading/thread_local.h" -#include "build_config.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(OS_WIN) -#include <windows.h> -#elif defined(OS_MACOSX) -#include <malloc/malloc.h> -#include "base/allocator/allocator_interception_mac.h" -#include "base/mac/mac_util.h" -#include "third_party/apple_apsl/malloc.h" -#else -#include <malloc.h> -#endif - -#if !defined(OS_WIN) -#include <unistd.h> -#endif - -// Some new Android NDKs (64 bit) does not expose (p)valloc anymore. These -// functions are implemented at the shim-layer level. -#if defined(OS_ANDROID) -extern "C" { -void* valloc(size_t size); -void* pvalloc(size_t size); -} -#endif - -namespace base { -namespace allocator { -namespace { - -using testing::MockFunction; -using testing::_; - -class AllocatorShimTest : public testing::Test { - public: - static const size_t kMaxSizeTracked = 2 * base::kSystemPageSize; - AllocatorShimTest() : testing::Test() {} - - static size_t Hash(const void* ptr) { - return reinterpret_cast<uintptr_t>(ptr) % kMaxSizeTracked; - } - - static void* MockAlloc(const AllocatorDispatch* self, - size_t size, - void* context) { - if (instance_ && size < kMaxSizeTracked) - ++(instance_->allocs_intercepted_by_size[size]); - return self->next->alloc_function(self->next, size, context); - } - - static void* MockAllocZeroInit(const AllocatorDispatch* self, - size_t n, - size_t size, - void* context) { - const size_t real_size = n * size; - if (instance_ && real_size < kMaxSizeTracked) - ++(instance_->zero_allocs_intercepted_by_size[real_size]); - return self->next->alloc_zero_initialized_function(self->next, n, size, - context); - } - - static void* MockAllocAligned(const AllocatorDispatch* self, - size_t alignment, - size_t size, - void* context) { - if (instance_) { - if (size < kMaxSizeTracked) - ++(instance_->aligned_allocs_intercepted_by_size[size]); - if (alignment < kMaxSizeTracked) - ++(instance_->aligned_allocs_intercepted_by_alignment[alignment]); - } - return self->next->alloc_aligned_function(self->next, alignment, size, - context); - } - - static void* MockRealloc(const AllocatorDispatch* self, - void* address, - size_t size, - void* context) { - if (instance_) { - // Size 0xFEED a special sentinel for the NewHandlerConcurrency test. - // Hitting it for the first time will cause a failure, causing the - // invocation of the std::new_handler. - if (size == 0xFEED) { - if (!instance_->did_fail_realloc_0xfeed_once->Get()) { - instance_->did_fail_realloc_0xfeed_once->Set(true); - return nullptr; - } else { - return address; - } - } - - if (size < kMaxSizeTracked) - ++(instance_->reallocs_intercepted_by_size[size]); - ++instance_->reallocs_intercepted_by_addr[Hash(address)]; - } - return self->next->realloc_function(self->next, address, size, context); - } - - static void MockFree(const AllocatorDispatch* self, - void* address, - void* context) { - if (instance_) { - ++instance_->frees_intercepted_by_addr[Hash(address)]; - } - self->next->free_function(self->next, address, context); - } - - static size_t MockGetSizeEstimate(const AllocatorDispatch* self, - void* address, - void* context) { - return self->next->get_size_estimate_function(self->next, address, context); - } - - static unsigned MockBatchMalloc(const AllocatorDispatch* self, - size_t size, - void** results, - unsigned num_requested, - void* context) { - if (instance_) { - instance_->batch_mallocs_intercepted_by_size[size] = - instance_->batch_mallocs_intercepted_by_size[size] + num_requested; - } - return self->next->batch_malloc_function(self->next, size, results, - num_requested, context); - } - - static void MockBatchFree(const AllocatorDispatch* self, - void** to_be_freed, - unsigned num_to_be_freed, - void* context) { - if (instance_) { - for (unsigned i = 0; i < num_to_be_freed; ++i) { - ++instance_->batch_frees_intercepted_by_addr[Hash(to_be_freed[i])]; - } - } - self->next->batch_free_function(self->next, to_be_freed, num_to_be_freed, - context); - } - - static void MockFreeDefiniteSize(const AllocatorDispatch* self, - void* ptr, - size_t size, - void* context) { - if (instance_) { - ++instance_->frees_intercepted_by_addr[Hash(ptr)]; - ++instance_->free_definite_sizes_intercepted_by_size[size]; - } - self->next->free_definite_size_function(self->next, ptr, size, context); - } - - static void NewHandler() { - if (!instance_) - return; - subtle::Barrier_AtomicIncrement(&instance_->num_new_handler_calls, 1); - } - - int32_t GetNumberOfNewHandlerCalls() { - return subtle::Acquire_Load(&instance_->num_new_handler_calls); - } - - void SetUp() override { - const size_t array_size = kMaxSizeTracked * sizeof(size_t); - memset(&allocs_intercepted_by_size, 0, array_size); - memset(&zero_allocs_intercepted_by_size, 0, array_size); - memset(&aligned_allocs_intercepted_by_size, 0, array_size); - memset(&aligned_allocs_intercepted_by_alignment, 0, array_size); - memset(&reallocs_intercepted_by_size, 0, array_size); - memset(&frees_intercepted_by_addr, 0, array_size); - memset(&batch_mallocs_intercepted_by_size, 0, array_size); - memset(&batch_frees_intercepted_by_addr, 0, array_size); - memset(&free_definite_sizes_intercepted_by_size, 0, array_size); - did_fail_realloc_0xfeed_once.reset(new ThreadLocalBoolean()); - subtle::Release_Store(&num_new_handler_calls, 0); - instance_ = this; - -#if defined(OS_MACOSX) - InitializeAllocatorShim(); -#endif - } - - void TearDown() override { - instance_ = nullptr; -#if defined(OS_MACOSX) - UninterceptMallocZonesForTesting(); -#endif - } - - protected: - size_t allocs_intercepted_by_size[kMaxSizeTracked]; - size_t zero_allocs_intercepted_by_size[kMaxSizeTracked]; - size_t aligned_allocs_intercepted_by_size[kMaxSizeTracked]; - size_t aligned_allocs_intercepted_by_alignment[kMaxSizeTracked]; - size_t reallocs_intercepted_by_size[kMaxSizeTracked]; - size_t reallocs_intercepted_by_addr[kMaxSizeTracked]; - size_t frees_intercepted_by_addr[kMaxSizeTracked]; - size_t batch_mallocs_intercepted_by_size[kMaxSizeTracked]; - size_t batch_frees_intercepted_by_addr[kMaxSizeTracked]; - size_t free_definite_sizes_intercepted_by_size[kMaxSizeTracked]; - std::unique_ptr<ThreadLocalBoolean> did_fail_realloc_0xfeed_once; - subtle::Atomic32 num_new_handler_calls; - - private: - static AllocatorShimTest* instance_; -}; - -struct TestStruct1 { - uint32_t ignored; - uint8_t ignored_2; -}; - -struct TestStruct2 { - uint64_t ignored; - uint8_t ignored_3; -}; - -class ThreadDelegateForNewHandlerTest : public PlatformThread::Delegate { - public: - ThreadDelegateForNewHandlerTest(WaitableEvent* event) : event_(event) {} - - void ThreadMain() override { - event_->Wait(); - void* temp = malloc(1); - void* res = realloc(temp, 0xFEED); - EXPECT_EQ(temp, res); - } - - private: - WaitableEvent* event_; -}; - -AllocatorShimTest* AllocatorShimTest::instance_ = nullptr; - -AllocatorDispatch g_mock_dispatch = { - &AllocatorShimTest::MockAlloc, /* alloc_function */ - &AllocatorShimTest::MockAllocZeroInit, /* alloc_zero_initialized_function */ - &AllocatorShimTest::MockAllocAligned, /* alloc_aligned_function */ - &AllocatorShimTest::MockRealloc, /* realloc_function */ - &AllocatorShimTest::MockFree, /* free_function */ - &AllocatorShimTest::MockGetSizeEstimate, /* get_size_estimate_function */ - &AllocatorShimTest::MockBatchMalloc, /* batch_malloc_function */ - &AllocatorShimTest::MockBatchFree, /* batch_free_function */ - &AllocatorShimTest::MockFreeDefiniteSize, /* free_definite_size_function */ - nullptr, /* next */ -}; - -TEST_F(AllocatorShimTest, InterceptLibcSymbols) { - InsertAllocatorDispatch(&g_mock_dispatch); - - void* alloc_ptr = malloc(19); - ASSERT_NE(nullptr, alloc_ptr); - ASSERT_GE(allocs_intercepted_by_size[19], 1u); - - void* zero_alloc_ptr = calloc(2, 23); - ASSERT_NE(nullptr, zero_alloc_ptr); - ASSERT_GE(zero_allocs_intercepted_by_size[2 * 23], 1u); - -#if !defined(OS_WIN) - const size_t kPageSize = base::GetPageSize(); - void* posix_memalign_ptr = nullptr; - int res = posix_memalign(&posix_memalign_ptr, 256, 59); - ASSERT_EQ(0, res); - ASSERT_NE(nullptr, posix_memalign_ptr); - ASSERT_EQ(0u, reinterpret_cast<uintptr_t>(posix_memalign_ptr) % 256); - ASSERT_GE(aligned_allocs_intercepted_by_alignment[256], 1u); - ASSERT_GE(aligned_allocs_intercepted_by_size[59], 1u); - - void* valloc_ptr = valloc(61); - ASSERT_NE(nullptr, valloc_ptr); - ASSERT_EQ(0u, reinterpret_cast<uintptr_t>(valloc_ptr) % kPageSize); - ASSERT_GE(aligned_allocs_intercepted_by_alignment[kPageSize], 1u); - ASSERT_GE(aligned_allocs_intercepted_by_size[61], 1u); -#endif // !OS_WIN - -#if !defined(OS_WIN) && !defined(OS_MACOSX) - void* memalign_ptr = memalign(128, 53); - ASSERT_NE(nullptr, memalign_ptr); - ASSERT_EQ(0u, reinterpret_cast<uintptr_t>(memalign_ptr) % 128); - ASSERT_GE(aligned_allocs_intercepted_by_alignment[128], 1u); - ASSERT_GE(aligned_allocs_intercepted_by_size[53], 1u); - - void* pvalloc_ptr = pvalloc(67); - ASSERT_NE(nullptr, pvalloc_ptr); - ASSERT_EQ(0u, reinterpret_cast<uintptr_t>(pvalloc_ptr) % kPageSize); - ASSERT_GE(aligned_allocs_intercepted_by_alignment[kPageSize], 1u); - // pvalloc rounds the size up to the next page. - ASSERT_GE(aligned_allocs_intercepted_by_size[kPageSize], 1u); -#endif // !OS_WIN && !OS_MACOSX - - char* realloc_ptr = static_cast<char*>(malloc(10)); - strcpy(realloc_ptr, "foobar"); - void* old_realloc_ptr = realloc_ptr; - realloc_ptr = static_cast<char*>(realloc(realloc_ptr, 73)); - ASSERT_GE(reallocs_intercepted_by_size[73], 1u); - ASSERT_GE(reallocs_intercepted_by_addr[Hash(old_realloc_ptr)], 1u); - ASSERT_EQ(0, strcmp(realloc_ptr, "foobar")); - - free(alloc_ptr); - ASSERT_GE(frees_intercepted_by_addr[Hash(alloc_ptr)], 1u); - - free(zero_alloc_ptr); - ASSERT_GE(frees_intercepted_by_addr[Hash(zero_alloc_ptr)], 1u); - -#if !defined(OS_WIN) && !defined(OS_MACOSX) - free(memalign_ptr); - ASSERT_GE(frees_intercepted_by_addr[Hash(memalign_ptr)], 1u); - - free(pvalloc_ptr); - ASSERT_GE(frees_intercepted_by_addr[Hash(pvalloc_ptr)], 1u); -#endif // !OS_WIN && !OS_MACOSX - -#if !defined(OS_WIN) - free(posix_memalign_ptr); - ASSERT_GE(frees_intercepted_by_addr[Hash(posix_memalign_ptr)], 1u); - - free(valloc_ptr); - ASSERT_GE(frees_intercepted_by_addr[Hash(valloc_ptr)], 1u); -#endif // !OS_WIN - - free(realloc_ptr); - ASSERT_GE(frees_intercepted_by_addr[Hash(realloc_ptr)], 1u); - - RemoveAllocatorDispatchForTesting(&g_mock_dispatch); - - void* non_hooked_ptr = malloc(4095); - ASSERT_NE(nullptr, non_hooked_ptr); - ASSERT_EQ(0u, allocs_intercepted_by_size[4095]); - free(non_hooked_ptr); -} - -#if defined(OS_MACOSX) -TEST_F(AllocatorShimTest, InterceptLibcSymbolsBatchMallocFree) { - InsertAllocatorDispatch(&g_mock_dispatch); - - unsigned count = 13; - std::vector<void*> results; - results.resize(count); - unsigned result_count = malloc_zone_batch_malloc(malloc_default_zone(), 99, - results.data(), count); - ASSERT_EQ(count, result_count); - - // TODO(erikchen): On macOS 10.12+, batch_malloc in the default zone may - // forward to another zone, which we've also shimmed, resulting in - // MockBatchMalloc getting called twice as often as we'd expect. This - // re-entrancy into the allocator shim is a bug that needs to be fixed. - // https://crbug.com/693237. - // ASSERT_EQ(count, batch_mallocs_intercepted_by_size[99]); - - std::vector<void*> results_copy(results); - malloc_zone_batch_free(malloc_default_zone(), results.data(), count); - for (void* result : results_copy) { - ASSERT_GE(batch_frees_intercepted_by_addr[Hash(result)], 1u); - } - RemoveAllocatorDispatchForTesting(&g_mock_dispatch); -} - -TEST_F(AllocatorShimTest, InterceptLibcSymbolsFreeDefiniteSize) { - InsertAllocatorDispatch(&g_mock_dispatch); - - void* alloc_ptr = malloc(19); - ASSERT_NE(nullptr, alloc_ptr); - ASSERT_GE(allocs_intercepted_by_size[19], 1u); - - ChromeMallocZone* default_zone = - reinterpret_cast<ChromeMallocZone*>(malloc_default_zone()); - default_zone->free_definite_size(malloc_default_zone(), alloc_ptr, 19); - ASSERT_GE(free_definite_sizes_intercepted_by_size[19], 1u); - RemoveAllocatorDispatchForTesting(&g_mock_dispatch); -} -#endif // defined(OS_MACOSX) - -TEST_F(AllocatorShimTest, InterceptCppSymbols) { - InsertAllocatorDispatch(&g_mock_dispatch); - - TestStruct1* new_ptr = new TestStruct1; - ASSERT_NE(nullptr, new_ptr); - ASSERT_GE(allocs_intercepted_by_size[sizeof(TestStruct1)], 1u); - - TestStruct1* new_array_ptr = new TestStruct1[3]; - ASSERT_NE(nullptr, new_array_ptr); - ASSERT_GE(allocs_intercepted_by_size[sizeof(TestStruct1) * 3], 1u); - - TestStruct2* new_nt_ptr = new (std::nothrow) TestStruct2; - ASSERT_NE(nullptr, new_nt_ptr); - ASSERT_GE(allocs_intercepted_by_size[sizeof(TestStruct2)], 1u); - - TestStruct2* new_array_nt_ptr = new TestStruct2[3]; - ASSERT_NE(nullptr, new_array_nt_ptr); - ASSERT_GE(allocs_intercepted_by_size[sizeof(TestStruct2) * 3], 1u); - - delete new_ptr; - ASSERT_GE(frees_intercepted_by_addr[Hash(new_ptr)], 1u); - - delete[] new_array_ptr; - ASSERT_GE(frees_intercepted_by_addr[Hash(new_array_ptr)], 1u); - - delete new_nt_ptr; - ASSERT_GE(frees_intercepted_by_addr[Hash(new_nt_ptr)], 1u); - - delete[] new_array_nt_ptr; - ASSERT_GE(frees_intercepted_by_addr[Hash(new_array_nt_ptr)], 1u); - - RemoveAllocatorDispatchForTesting(&g_mock_dispatch); -} - -// This test exercises the case of concurrent OOM failure, which would end up -// invoking std::new_handler concurrently. This is to cover the CallNewHandler() -// paths of allocator_shim.cc and smoke-test its thread safey. -// The test creates kNumThreads threads. Each of them mallocs some memory, and -// then does a realloc(<new memory>, 0xFEED). -// The shim intercepts such realloc and makes it fail only once on each thread. -// We expect to see excactly kNumThreads invocations of the new_handler. -TEST_F(AllocatorShimTest, NewHandlerConcurrency) { - const int kNumThreads = 32; - PlatformThreadHandle threads[kNumThreads]; - - // The WaitableEvent here is used to attempt to trigger all the threads at - // the same time, after they have been initialized. - WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - - ThreadDelegateForNewHandlerTest mock_thread_main(&event); - - for (int i = 0; i < kNumThreads; ++i) - PlatformThread::Create(0, &mock_thread_main, &threads[i]); - - std::set_new_handler(&AllocatorShimTest::NewHandler); - SetCallNewHandlerOnMallocFailure(true); // It's going to fail on realloc(). - InsertAllocatorDispatch(&g_mock_dispatch); - event.Signal(); - for (int i = 0; i < kNumThreads; ++i) - PlatformThread::Join(threads[i]); - RemoveAllocatorDispatchForTesting(&g_mock_dispatch); - ASSERT_EQ(kNumThreads, GetNumberOfNewHandlerCalls()); -} - -} // namespace -} // namespace allocator -} // namespace base
diff --git a/base/allocator/malloc_zone_functions_mac_unittest.cc b/base/allocator/malloc_zone_functions_mac_unittest.cc deleted file mode 100644 index 09aa429..0000000 --- a/base/allocator/malloc_zone_functions_mac_unittest.cc +++ /dev/null
@@ -1,57 +0,0 @@ -// 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/allocator/malloc_zone_functions_mac.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace allocator { - -class MallocZoneFunctionsTest : public testing::Test { - protected: - void TearDown() override { ClearAllMallocZonesForTesting(); } -}; - -TEST_F(MallocZoneFunctionsTest, TestDefaultZoneMallocFree) { - ChromeMallocZone* malloc_zone = - reinterpret_cast<ChromeMallocZone*>(malloc_default_zone()); - StoreMallocZone(malloc_zone); - int* test = reinterpret_cast<int*>( - g_malloc_zones[0].malloc(malloc_default_zone(), 33)); - test[0] = 1; - test[1] = 2; - g_malloc_zones[0].free(malloc_default_zone(), test); -} - -TEST_F(MallocZoneFunctionsTest, IsZoneAlreadyStored) { - ChromeMallocZone* malloc_zone = - reinterpret_cast<ChromeMallocZone*>(malloc_default_zone()); - EXPECT_FALSE(IsMallocZoneAlreadyStored(malloc_zone)); - StoreMallocZone(malloc_zone); - EXPECT_TRUE(IsMallocZoneAlreadyStored(malloc_zone)); -} - -TEST_F(MallocZoneFunctionsTest, CannotDoubleStoreZone) { - ChromeMallocZone* malloc_zone = - reinterpret_cast<ChromeMallocZone*>(malloc_default_zone()); - StoreMallocZone(malloc_zone); - StoreMallocZone(malloc_zone); - EXPECT_EQ(1, GetMallocZoneCountForTesting()); -} - -TEST_F(MallocZoneFunctionsTest, CannotStoreMoreThanMaxZones) { - std::vector<ChromeMallocZone> zones; - zones.resize(kMaxZoneCount * 2); - for (int i = 0; i < kMaxZoneCount * 2; ++i) { - ChromeMallocZone& zone = zones[i]; - memcpy(&zone, malloc_default_zone(), sizeof(ChromeMallocZone)); - StoreMallocZone(&zone); - } - - int max_zone_count = kMaxZoneCount; - EXPECT_EQ(max_zone_count, GetMallocZoneCountForTesting()); -} - -} // namespace allocator -} // namespace base
diff --git a/base/allocator/partition_allocator/address_space_randomization_unittest.cc b/base/allocator/partition_allocator/address_space_randomization_unittest.cc deleted file mode 100644 index a9fe1ce..0000000 --- a/base/allocator/partition_allocator/address_space_randomization_unittest.cc +++ /dev/null
@@ -1,244 +0,0 @@ -// 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/allocator/partition_allocator/address_space_randomization.h" - -#include "base/allocator/partition_allocator/page_allocator.h" -#include "base/bit_cast.h" -#include "base/bits.h" -#include "base/sys_info.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(OS_WIN) -#include <windows.h> -#include "base/win/windows_version.h" -// VersionHelpers.h must be included after windows.h. -#include <VersionHelpers.h> -#endif - -namespace base { - -namespace { - -uintptr_t GetMask() { - uintptr_t mask = internal::kASLRMask; -#if defined(ARCH_CPU_64_BITS) -// Sanitizers use their own kASLRMask constant. -#if defined(OS_WIN) && !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) - if (!IsWindows8Point1OrGreater()) { - mask = internal::kASLRMaskBefore8_10; - } -#endif // defined(OS_WIN) && !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)) -#elif defined(ARCH_CPU_32_BITS) -#if defined(OS_WIN) - BOOL is_wow64 = FALSE; - if (!IsWow64Process(GetCurrentProcess(), &is_wow64)) - is_wow64 = FALSE; - if (!is_wow64) { - mask = 0; - } -#endif // defined(OS_WIN) -#endif // defined(ARCH_CPU_32_BITS) - return mask; -} - -const size_t kSamples = 100; - -uintptr_t GetAddressBits() { - return reinterpret_cast<uintptr_t>(base::GetRandomPageBase()); -} - -uintptr_t GetRandomBits() { - return GetAddressBits() - internal::kASLROffset; -} - -} // namespace - -// Configurations without ASLR are tested here. -TEST(AddressSpaceRandomizationTest, DisabledASLR) { - uintptr_t mask = GetMask(); - if (!mask) { -#if defined(OS_WIN) && defined(ARCH_CPU_32_BITS) - // ASLR should be turned off on 32-bit Windows. - EXPECT_EQ(nullptr, base::GetRandomPageBase()); -#else - // Otherwise, nullptr is very unexpected. - EXPECT_NE(nullptr, base::GetRandomPageBase()); -#endif - } -} - -TEST(AddressSpaceRandomizationTest, Alignment) { - uintptr_t mask = GetMask(); - if (!mask) - return; - - for (size_t i = 0; i < kSamples; ++i) { - uintptr_t address = GetAddressBits(); - EXPECT_EQ(0ULL, (address & kPageAllocationGranularityOffsetMask)); - } -} - -TEST(AddressSpaceRandomizationTest, Range) { - uintptr_t mask = GetMask(); - if (!mask) - return; - - uintptr_t min = internal::kASLROffset; - uintptr_t max = internal::kASLROffset + internal::kASLRMask; - for (size_t i = 0; i < kSamples; ++i) { - uintptr_t address = GetAddressBits(); - EXPECT_LE(min, address); - EXPECT_GE(max + mask, address); - } -} - -TEST(AddressSpaceRandomizationTest, Predictable) { - uintptr_t mask = GetMask(); - if (!mask) - return; - - const uintptr_t kInitialSeed = 0xfeed5eedULL; - base::SetRandomPageBaseSeed(kInitialSeed); - - std::vector<uintptr_t> sequence; - for (size_t i = 0; i < kSamples; ++i) { - uintptr_t address = reinterpret_cast<uintptr_t>(base::GetRandomPageBase()); - sequence.push_back(address); - } - - base::SetRandomPageBaseSeed(kInitialSeed); - - for (size_t i = 0; i < kSamples; ++i) { - uintptr_t address = reinterpret_cast<uintptr_t>(base::GetRandomPageBase()); - EXPECT_EQ(address, sequence[i]); - } -} - -// This randomness test is adapted from V8's PRNG tests. - -// Chi squared for getting m 0s out of n bits. -double ChiSquared(int m, int n) { - double ys_minus_np1 = (m - n / 2.0); - double chi_squared_1 = ys_minus_np1 * ys_minus_np1 * 2.0 / n; - double ys_minus_np2 = ((n - m) - n / 2.0); - double chi_squared_2 = ys_minus_np2 * ys_minus_np2 * 2.0 / n; - return chi_squared_1 + chi_squared_2; -} - -// Test for correlations between recent bits from the PRNG, or bits that are -// biased. -void RandomBitCorrelation(int random_bit) { - uintptr_t mask = GetMask(); - if ((mask & (1ULL << random_bit)) == 0) - return; // bit is always 0. - -#ifdef DEBUG - constexpr int kHistory = 2; - constexpr int kRepeats = 1000; -#else - constexpr int kHistory = 8; - constexpr int kRepeats = 10000; -#endif - constexpr int kPointerBits = 8 * sizeof(void*); - uintptr_t history[kHistory]; - // The predictor bit is either constant 0 or 1, or one of the bits from the - // history. - for (int predictor_bit = -2; predictor_bit < kPointerBits; predictor_bit++) { - // The predicted bit is one of the bits from the PRNG. - for (int ago = 0; ago < kHistory; ago++) { - // We don't want to check whether each bit predicts itself. - if (ago == 0 && predictor_bit == random_bit) - continue; - - // Enter the new random value into the history. - for (int i = ago; i >= 0; i--) { - history[i] = GetRandomBits(); - } - - // Find out how many of the bits are the same as the prediction bit. - int m = 0; - for (int i = 0; i < kRepeats; i++) { - uintptr_t random = GetRandomBits(); - for (int j = ago - 1; j >= 0; j--) - history[j + 1] = history[j]; - history[0] = random; - - int predicted; - if (predictor_bit >= 0) { - predicted = (history[ago] >> predictor_bit) & 1; - } else { - predicted = predictor_bit == -2 ? 0 : 1; - } - int bit = (random >> random_bit) & 1; - if (bit == predicted) - m++; - } - - // Chi squared analysis for k = 2 (2, states: same/not-same) and one - // degree of freedom (k - 1). - double chi_squared = ChiSquared(m, kRepeats); - // For 1 degree of freedom this corresponds to 1 in a million. We are - // running ~8000 tests, so that would be surprising. - CHECK_GE(24, chi_squared); - // If the predictor bit is a fixed 0 or 1 then it makes no sense to - // repeat the test with a different age. - if (predictor_bit < 0) - break; - } - } -} - -// Tests are fairly slow, so give each random bit its own test. -#define TEST_RANDOM_BIT(BIT) \ - TEST(AddressSpaceRandomizationTest, RandomBitCorrelations##BIT) { \ - RandomBitCorrelation(BIT); \ - } - -// The first 12 bits on all platforms are always 0. -TEST_RANDOM_BIT(12) -TEST_RANDOM_BIT(13) -TEST_RANDOM_BIT(14) -TEST_RANDOM_BIT(15) -TEST_RANDOM_BIT(16) -TEST_RANDOM_BIT(17) -TEST_RANDOM_BIT(18) -TEST_RANDOM_BIT(19) -TEST_RANDOM_BIT(20) -TEST_RANDOM_BIT(21) -TEST_RANDOM_BIT(22) -TEST_RANDOM_BIT(23) -TEST_RANDOM_BIT(24) -TEST_RANDOM_BIT(25) -TEST_RANDOM_BIT(26) -TEST_RANDOM_BIT(27) -TEST_RANDOM_BIT(28) -TEST_RANDOM_BIT(29) -TEST_RANDOM_BIT(30) -TEST_RANDOM_BIT(31) -#if defined(ARCH_CPU_64_BITS) -TEST_RANDOM_BIT(32) -TEST_RANDOM_BIT(33) -TEST_RANDOM_BIT(34) -TEST_RANDOM_BIT(35) -TEST_RANDOM_BIT(36) -TEST_RANDOM_BIT(37) -TEST_RANDOM_BIT(38) -TEST_RANDOM_BIT(39) -TEST_RANDOM_BIT(40) -TEST_RANDOM_BIT(41) -TEST_RANDOM_BIT(42) -TEST_RANDOM_BIT(43) -TEST_RANDOM_BIT(44) -TEST_RANDOM_BIT(45) -TEST_RANDOM_BIT(46) -TEST_RANDOM_BIT(47) -TEST_RANDOM_BIT(48) -// No platforms have more than 48 address bits. -#endif // defined(ARCH_CPU_64_BITS) - -#undef TEST_RANDOM_BIT - -} // namespace base
diff --git a/base/allocator/partition_allocator/page_allocator_unittest.cc b/base/allocator/partition_allocator/page_allocator_unittest.cc deleted file mode 100644 index ad14c06..0000000 --- a/base/allocator/partition_allocator/page_allocator_unittest.cc +++ /dev/null
@@ -1,224 +0,0 @@ -// 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/allocator/partition_allocator/page_allocator.h" - -#include <stdlib.h> -#include <string.h> - -#include "base/allocator/partition_allocator/address_space_randomization.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(OS_POSIX) && !defined(OS_FUCHSIA) -#include <setjmp.h> -#include <signal.h> -#include <sys/mman.h> -#include <sys/time.h> -#endif // defined(OS_POSIX) && !defined(OS_FUCHSIA) - -#if !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) - -namespace base { - -namespace { - -// Any number of bytes that can be allocated with no trouble. -constexpr size_t kEasyAllocSize = - (1024 * 1024) & ~(kPageAllocationGranularity - 1); - -// A huge amount of memory, greater than or equal to the ASLR space. -constexpr size_t kHugeMemoryAmount = - std::max(internal::kASLRMask, std::size_t{2} * internal::kASLRMask); - -} // namespace - -TEST(PageAllocatorTest, Rounding) { - EXPECT_EQ(0u, RoundUpToSystemPage(0u)); - EXPECT_EQ(kSystemPageSize, RoundUpToSystemPage(1)); - EXPECT_EQ(kSystemPageSize, RoundUpToSystemPage(kSystemPageSize - 1)); - EXPECT_EQ(kSystemPageSize, RoundUpToSystemPage(kSystemPageSize)); - EXPECT_EQ(2 * kSystemPageSize, RoundUpToSystemPage(kSystemPageSize + 1)); - EXPECT_EQ(0u, RoundDownToSystemPage(0u)); - EXPECT_EQ(0u, RoundDownToSystemPage(kSystemPageSize - 1)); - EXPECT_EQ(kSystemPageSize, RoundDownToSystemPage(kSystemPageSize)); - EXPECT_EQ(kSystemPageSize, RoundDownToSystemPage(kSystemPageSize + 1)); - EXPECT_EQ(kSystemPageSize, RoundDownToSystemPage(2 * kSystemPageSize - 1)); - EXPECT_EQ(0u, RoundUpToPageAllocationGranularity(0u)); - EXPECT_EQ(kPageAllocationGranularity, RoundUpToPageAllocationGranularity(1)); - EXPECT_EQ(kPageAllocationGranularity, - RoundUpToPageAllocationGranularity(kPageAllocationGranularity - 1)); - EXPECT_EQ(kPageAllocationGranularity, - RoundUpToPageAllocationGranularity(kPageAllocationGranularity)); - EXPECT_EQ(2 * kPageAllocationGranularity, - RoundUpToPageAllocationGranularity(kPageAllocationGranularity + 1)); - EXPECT_EQ(0u, RoundDownToPageAllocationGranularity(0u)); - EXPECT_EQ( - 0u, RoundDownToPageAllocationGranularity(kPageAllocationGranularity - 1)); - EXPECT_EQ(kPageAllocationGranularity, - RoundDownToPageAllocationGranularity(kPageAllocationGranularity)); - EXPECT_EQ(kPageAllocationGranularity, RoundDownToPageAllocationGranularity( - kPageAllocationGranularity + 1)); - EXPECT_EQ( - kPageAllocationGranularity, - RoundDownToPageAllocationGranularity(2 * kPageAllocationGranularity - 1)); -} - -// Test that failed page allocations invoke base::ReleaseReservation(). -// We detect this by making a reservation and ensuring that after failure, we -// can make a new reservation. -TEST(PageAllocatorTest, AllocFailure) { - // Release any reservation made by another test. - ReleaseReservation(); - - // We can make a reservation. - EXPECT_TRUE(ReserveAddressSpace(kEasyAllocSize)); - - // We can't make another reservation until we trigger an allocation failure. - EXPECT_FALSE(ReserveAddressSpace(kEasyAllocSize)); - - size_t size = kHugeMemoryAmount; - // Skip the test for sanitizers and platforms with ASLR turned off. - if (size == 0) - return; - - void* result = AllocPages(nullptr, size, kPageAllocationGranularity, - PageInaccessible, PageTag::kChromium, false); - if (result == nullptr) { - // We triggered allocation failure. Our reservation should have been - // released, and we should be able to make a new reservation. - EXPECT_TRUE(ReserveAddressSpace(kEasyAllocSize)); - ReleaseReservation(); - return; - } - // We couldn't fail. Make sure reservation is still there. - EXPECT_FALSE(ReserveAddressSpace(kEasyAllocSize)); -} - -// TODO(crbug.com/765801): Test failed on chromium.win/Win10 Tests x64. -#if defined(OS_WIN) && defined(ARCH_CPU_64_BITS) -#define MAYBE_ReserveAddressSpace DISABLED_ReserveAddressSpace -#else -#define MAYBE_ReserveAddressSpace ReserveAddressSpace -#endif // defined(OS_WIN) && defined(ARCH_CPU_64_BITS) - -// Test that reserving address space can fail. -TEST(PageAllocatorTest, MAYBE_ReserveAddressSpace) { - // Release any reservation made by another test. - ReleaseReservation(); - - size_t size = kHugeMemoryAmount; - // Skip the test for sanitizers and platforms with ASLR turned off. - if (size == 0) - return; - - bool success = ReserveAddressSpace(size); - if (!success) { - EXPECT_TRUE(ReserveAddressSpace(kEasyAllocSize)); - return; - } - // We couldn't fail. Make sure reservation is still there. - EXPECT_FALSE(ReserveAddressSpace(kEasyAllocSize)); -} - -TEST(PageAllocatorTest, AllocAndFreePages) { - void* buffer = AllocPages(nullptr, kPageAllocationGranularity, - kPageAllocationGranularity, PageReadWrite, - PageTag::kChromium, true); - EXPECT_TRUE(buffer); - int* buffer0 = reinterpret_cast<int*>(buffer); - *buffer0 = 42; - EXPECT_EQ(42, *buffer0); - FreePages(buffer, kPageAllocationGranularity); -} - -// Test permission setting on POSIX, where we can set a trap handler. -#if defined(OS_POSIX) && !defined(OS_FUCHSIA) - -namespace { -sigjmp_buf g_continuation; - -void SignalHandler(int signal, siginfo_t* info, void*) { - siglongjmp(g_continuation, 1); -} -} // namespace - -// On Mac, sometimes we get SIGBUS instead of SIGSEGV, so handle that too. -#if defined(OS_MACOSX) -#define EXTRA_FAULT_BEGIN_ACTION() \ - struct sigaction old_bus_action; \ - sigaction(SIGBUS, &action, &old_bus_action); -#define EXTRA_FAULT_END_ACTION() sigaction(SIGBUS, &old_bus_action, nullptr); -#else -#define EXTRA_FAULT_BEGIN_ACTION() -#define EXTRA_FAULT_END_ACTION() -#endif - -// Install a signal handler so we can catch the fault we're about to trigger. -#define FAULT_TEST_BEGIN() \ - struct sigaction action = {}; \ - struct sigaction old_action = {}; \ - action.sa_sigaction = SignalHandler; \ - sigemptyset(&action.sa_mask); \ - action.sa_flags = SA_SIGINFO; \ - sigaction(SIGSEGV, &action, &old_action); \ - EXTRA_FAULT_BEGIN_ACTION(); \ - int const save_sigs = 1; \ - if (!sigsetjmp(g_continuation, save_sigs)) { -// Fault generating code goes here... - -// Handle when sigsetjmp returns nonzero (we are returning from our handler). -#define FAULT_TEST_END() \ - } \ - else { \ - sigaction(SIGSEGV, &old_action, nullptr); \ - EXTRA_FAULT_END_ACTION(); \ - } - -TEST(PageAllocatorTest, InaccessiblePages) { - void* buffer = AllocPages(nullptr, kPageAllocationGranularity, - kPageAllocationGranularity, PageInaccessible, - PageTag::kChromium, true); - EXPECT_TRUE(buffer); - - FAULT_TEST_BEGIN(); - - // Reading from buffer should fault. - int* buffer0 = reinterpret_cast<int*>(buffer); - int buffer0_contents = *buffer0; - EXPECT_EQ(buffer0_contents, *buffer0); - EXPECT_TRUE(false); - - FAULT_TEST_END(); - - FreePages(buffer, kPageAllocationGranularity); -} - -TEST(PageAllocatorTest, ReadExecutePages) { - void* buffer = AllocPages(nullptr, kPageAllocationGranularity, - kPageAllocationGranularity, PageReadExecute, - PageTag::kChromium, true); - EXPECT_TRUE(buffer); - int* buffer0 = reinterpret_cast<int*>(buffer); - // Reading from buffer should succeed. - int buffer0_contents = *buffer0; - - FAULT_TEST_BEGIN(); - - // Writing to buffer should fault. - *buffer0 = ~buffer0_contents; - EXPECT_TRUE(false); - - FAULT_TEST_END(); - - // Make sure no write occurred. - EXPECT_EQ(buffer0_contents, *buffer0); - FreePages(buffer, kPageAllocationGranularity); -} - -#endif // defined(OS_POSIX) && !defined(OS_FUCHSIA) - -} // namespace base - -#endif // !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
diff --git a/base/allocator/partition_allocator/partition_alloc_unittest.cc b/base/allocator/partition_allocator/partition_alloc_unittest.cc deleted file mode 100644 index 994f339..0000000 --- a/base/allocator/partition_allocator/partition_alloc_unittest.cc +++ /dev/null
@@ -1,2129 +0,0 @@ -// 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/allocator/partition_allocator/partition_alloc.h" - -#include <stdlib.h> -#include <string.h> - -#include <memory> -#include <vector> - -#include "base/allocator/partition_allocator/address_space_randomization.h" -#include "base/bit_cast.h" -#include "base/bits.h" -#include "base/sys_info.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(OS_POSIX) -#include <sys/mman.h> -#if !defined(OS_FUCHSIA) -#include <sys/resource.h> -#endif -#include <sys/time.h> -#endif // defined(OS_POSIX) - -#if !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) - -// Because there is so much deep inspection of the internal objects, -// explicitly annotating the namespaces for commonly expected objects makes the -// code unreadable. Prefer using directives instead. -using base::internal::PartitionBucket; -using base::internal::PartitionPage; - -namespace { - -constexpr size_t kTestMaxAllocation = base::kSystemPageSize; - -bool IsLargeMemoryDevice() { - // Treat any device with 2GiB or more of physical memory as a "large memory - // device". We check for slightly less than 2GiB so that devices with a small - // amount of memory not accessible to the OS still count as "large". - return base::SysInfo::AmountOfPhysicalMemory() >= 2040LL * 1024 * 1024; -} - -bool SetAddressSpaceLimit() { -#if !defined(ARCH_CPU_64_BITS) || !defined(OS_POSIX) - // 32 bits => address space is limited already. - return true; -#elif defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_FUCHSIA) - // macOS will accept, but not enforce, |RLIMIT_AS| changes. See - // https://crbug.com/435269 and rdar://17576114. - // - // Note: This number must be not less than 6 GB, because with - // sanitizer_coverage_flags=edge, it reserves > 5 GB of address space. See - // https://crbug.com/674665. - const size_t kAddressSpaceLimit = static_cast<size_t>(6144) * 1024 * 1024; - struct rlimit limit; - if (getrlimit(RLIMIT_AS, &limit) != 0) - return false; - if (limit.rlim_cur == RLIM_INFINITY || limit.rlim_cur > kAddressSpaceLimit) { - limit.rlim_cur = kAddressSpaceLimit; - if (setrlimit(RLIMIT_AS, &limit) != 0) - return false; - } - return true; -#else - return false; -#endif -} - -bool ClearAddressSpaceLimit() { -#if !defined(ARCH_CPU_64_BITS) || !defined(OS_POSIX) || defined(OS_FUCHSIA) - return true; -#elif defined(OS_POSIX) - struct rlimit limit; - if (getrlimit(RLIMIT_AS, &limit) != 0) - return false; - limit.rlim_cur = limit.rlim_max; - if (setrlimit(RLIMIT_AS, &limit) != 0) - return false; - return true; -#else - return false; -#endif -} - -} // namespace - -namespace base { - -// NOTE: Though this test actually excercises interfaces inside the ::base -// namespace, the unittest is inside the ::base::internal spaces because a -// portion of the test expectations require inspecting objects and behavior -// in the ::base::internal namespace. An alternate formulation would be to -// explicitly add using statements for each inspected type but this felt more -// readable. -namespace internal { - -const size_t kTestAllocSize = 16; -#if !DCHECK_IS_ON() -const size_t kPointerOffset = 0; -const size_t kExtraAllocSize = 0; -#else -const size_t kPointerOffset = kCookieSize; -const size_t kExtraAllocSize = kCookieSize * 2; -#endif -const size_t kRealAllocSize = kTestAllocSize + kExtraAllocSize; -const size_t kTestBucketIndex = kRealAllocSize >> kBucketShift; - -const char* type_name = nullptr; - -class PartitionAllocTest : public testing::Test { - protected: - PartitionAllocTest() = default; - - ~PartitionAllocTest() override = default; - - void SetUp() override { - allocator.init(); - generic_allocator.init(); - } - - PartitionPage* GetFullPage(size_t size) { - size_t real_size = size + kExtraAllocSize; - size_t bucket_index = real_size >> kBucketShift; - PartitionBucket* bucket = &allocator.root()->buckets()[bucket_index]; - size_t num_slots = - (bucket->num_system_pages_per_slot_span * kSystemPageSize) / real_size; - void* first = nullptr; - void* last = nullptr; - size_t i; - for (i = 0; i < num_slots; ++i) { - void* ptr = allocator.root()->Alloc(size, type_name); - EXPECT_TRUE(ptr); - if (!i) - first = PartitionCookieFreePointerAdjust(ptr); - else if (i == num_slots - 1) - last = PartitionCookieFreePointerAdjust(ptr); - } - EXPECT_EQ(PartitionPage::FromPointer(first), - PartitionPage::FromPointer(last)); - if (bucket->num_system_pages_per_slot_span == - kNumSystemPagesPerPartitionPage) - EXPECT_EQ(reinterpret_cast<size_t>(first) & kPartitionPageBaseMask, - reinterpret_cast<size_t>(last) & kPartitionPageBaseMask); - EXPECT_EQ(num_slots, static_cast<size_t>( - bucket->active_pages_head->num_allocated_slots)); - EXPECT_EQ(nullptr, bucket->active_pages_head->freelist_head); - EXPECT_TRUE(bucket->active_pages_head); - EXPECT_TRUE(bucket->active_pages_head != - PartitionPage::get_sentinel_page()); - return bucket->active_pages_head; - } - - void CycleFreeCache(size_t size) { - size_t real_size = size + kExtraAllocSize; - size_t bucket_index = real_size >> kBucketShift; - PartitionBucket* bucket = &allocator.root()->buckets()[bucket_index]; - DCHECK(!bucket->active_pages_head->num_allocated_slots); - - for (size_t i = 0; i < kMaxFreeableSpans; ++i) { - void* ptr = allocator.root()->Alloc(size, type_name); - EXPECT_EQ(1, bucket->active_pages_head->num_allocated_slots); - PartitionFree(ptr); - EXPECT_EQ(0, bucket->active_pages_head->num_allocated_slots); - EXPECT_NE(-1, bucket->active_pages_head->empty_cache_index); - } - } - - void CycleGenericFreeCache(size_t size) { - for (size_t i = 0; i < kMaxFreeableSpans; ++i) { - void* ptr = generic_allocator.root()->Alloc(size, type_name); - PartitionPage* page = - PartitionPage::FromPointer(PartitionCookieFreePointerAdjust(ptr)); - PartitionBucket* bucket = page->bucket; - EXPECT_EQ(1, bucket->active_pages_head->num_allocated_slots); - generic_allocator.root()->Free(ptr); - EXPECT_EQ(0, bucket->active_pages_head->num_allocated_slots); - EXPECT_NE(-1, bucket->active_pages_head->empty_cache_index); - } - } - - void DoReturnNullTest(size_t allocSize, bool use_realloc) { - // TODO(crbug.com/678782): Where necessary and possible, disable the - // platform's OOM-killing behavior. OOM-killing makes this test flaky on - // low-memory devices. - if (!IsLargeMemoryDevice()) { - LOG(WARNING) - << "Skipping test on this device because of crbug.com/678782"; - return; - } - - ASSERT_TRUE(SetAddressSpaceLimit()); - - // Work out the number of allocations for 6 GB of memory. - const int numAllocations = (6 * 1024 * 1024) / (allocSize / 1024); - - void** ptrs = reinterpret_cast<void**>(generic_allocator.root()->Alloc( - numAllocations * sizeof(void*), type_name)); - int i; - - for (i = 0; i < numAllocations; ++i) { - if (use_realloc) { - ptrs[i] = PartitionAllocGenericFlags( - generic_allocator.root(), PartitionAllocReturnNull, 1, type_name); - ptrs[i] = PartitionReallocGenericFlags(generic_allocator.root(), - PartitionAllocReturnNull, - ptrs[i], allocSize, type_name); - } else { - ptrs[i] = PartitionAllocGenericFlags(generic_allocator.root(), - PartitionAllocReturnNull, - allocSize, type_name); - } - if (!i) - EXPECT_TRUE(ptrs[0]); - if (!ptrs[i]) { - ptrs[i] = PartitionAllocGenericFlags(generic_allocator.root(), - PartitionAllocReturnNull, - allocSize, type_name); - EXPECT_FALSE(ptrs[i]); - break; - } - } - - // We shouldn't succeed in allocating all 6 GB of memory. If we do, then - // we're not actually testing anything here. - EXPECT_LT(i, numAllocations); - - // Free, reallocate and free again each block we allocated. We do this to - // check that freeing memory also works correctly after a failed allocation. - for (--i; i >= 0; --i) { - generic_allocator.root()->Free(ptrs[i]); - ptrs[i] = PartitionAllocGenericFlags(generic_allocator.root(), - PartitionAllocReturnNull, allocSize, - type_name); - EXPECT_TRUE(ptrs[i]); - generic_allocator.root()->Free(ptrs[i]); - } - - generic_allocator.root()->Free(ptrs); - - EXPECT_TRUE(ClearAddressSpaceLimit()); - } - - SizeSpecificPartitionAllocator<kTestMaxAllocation> allocator; - PartitionAllocatorGeneric generic_allocator; -}; - -class PartitionAllocDeathTest : public PartitionAllocTest {}; - -namespace { - -void FreeFullPage(PartitionPage* page) { - size_t size = page->bucket->slot_size; - size_t num_slots = - (page->bucket->num_system_pages_per_slot_span * kSystemPageSize) / size; - EXPECT_EQ(num_slots, static_cast<size_t>(abs(page->num_allocated_slots))); - char* ptr = reinterpret_cast<char*>(PartitionPage::ToPointer(page)); - size_t i; - for (i = 0; i < num_slots; ++i) { - PartitionFree(ptr + kPointerOffset); - ptr += size; - } -} - -#if defined(OS_LINUX) -bool CheckPageInCore(void* ptr, bool in_core) { - unsigned char ret = 0; - EXPECT_EQ(0, mincore(ptr, kSystemPageSize, &ret)); - return in_core == (ret & 1); -} - -#define CHECK_PAGE_IN_CORE(ptr, in_core) \ - EXPECT_TRUE(CheckPageInCore(ptr, in_core)) -#else -#define CHECK_PAGE_IN_CORE(ptr, in_core) (void)(0) -#endif // defined(OS_LINUX) - -class MockPartitionStatsDumper : public PartitionStatsDumper { - public: - MockPartitionStatsDumper() - : total_resident_bytes(0), - total_active_bytes(0), - total_decommittable_bytes(0), - total_discardable_bytes(0) {} - - void PartitionDumpTotals(const char* partition_name, - const PartitionMemoryStats* stats) override { - EXPECT_GE(stats->total_mmapped_bytes, stats->total_resident_bytes); - EXPECT_EQ(total_resident_bytes, stats->total_resident_bytes); - EXPECT_EQ(total_active_bytes, stats->total_active_bytes); - EXPECT_EQ(total_decommittable_bytes, stats->total_decommittable_bytes); - EXPECT_EQ(total_discardable_bytes, stats->total_discardable_bytes); - } - - void PartitionsDumpBucketStats( - const char* partition_name, - const PartitionBucketMemoryStats* stats) override { - (void)partition_name; - EXPECT_TRUE(stats->is_valid); - EXPECT_EQ(0u, stats->bucket_slot_size & kAllocationGranularityMask); - bucket_stats.push_back(*stats); - total_resident_bytes += stats->resident_bytes; - total_active_bytes += stats->active_bytes; - total_decommittable_bytes += stats->decommittable_bytes; - total_discardable_bytes += stats->discardable_bytes; - } - - bool IsMemoryAllocationRecorded() { - return total_resident_bytes != 0 && total_active_bytes != 0; - } - - const PartitionBucketMemoryStats* GetBucketStats(size_t bucket_size) { - for (size_t i = 0; i < bucket_stats.size(); ++i) { - if (bucket_stats[i].bucket_slot_size == bucket_size) - return &bucket_stats[i]; - } - return nullptr; - } - - private: - size_t total_resident_bytes; - size_t total_active_bytes; - size_t total_decommittable_bytes; - size_t total_discardable_bytes; - - std::vector<PartitionBucketMemoryStats> bucket_stats; -}; - -} // namespace - -// Check that the most basic of allocate / free pairs work. -TEST_F(PartitionAllocTest, Basic) { - PartitionBucket* bucket = &allocator.root()->buckets()[kTestBucketIndex]; - PartitionPage* seedPage = PartitionPage::get_sentinel_page(); - - EXPECT_FALSE(bucket->empty_pages_head); - EXPECT_FALSE(bucket->decommitted_pages_head); - EXPECT_EQ(seedPage, bucket->active_pages_head); - EXPECT_EQ(nullptr, bucket->active_pages_head->next_page); - - void* ptr = allocator.root()->Alloc(kTestAllocSize, type_name); - EXPECT_TRUE(ptr); - EXPECT_EQ(kPointerOffset, - reinterpret_cast<size_t>(ptr) & kPartitionPageOffsetMask); - // Check that the offset appears to include a guard page. - EXPECT_EQ(kPartitionPageSize + kPointerOffset, - reinterpret_cast<size_t>(ptr) & kSuperPageOffsetMask); - - PartitionFree(ptr); - // Expect that the last active page gets noticed as empty but doesn't get - // decommitted. - EXPECT_TRUE(bucket->empty_pages_head); - EXPECT_FALSE(bucket->decommitted_pages_head); -} - -// Test multiple allocations, and freelist handling. -TEST_F(PartitionAllocTest, MultiAlloc) { - char* ptr1 = reinterpret_cast<char*>( - allocator.root()->Alloc(kTestAllocSize, type_name)); - char* ptr2 = reinterpret_cast<char*>( - allocator.root()->Alloc(kTestAllocSize, type_name)); - EXPECT_TRUE(ptr1); - EXPECT_TRUE(ptr2); - ptrdiff_t diff = ptr2 - ptr1; - EXPECT_EQ(static_cast<ptrdiff_t>(kRealAllocSize), diff); - - // Check that we re-use the just-freed slot. - PartitionFree(ptr2); - ptr2 = reinterpret_cast<char*>( - allocator.root()->Alloc(kTestAllocSize, type_name)); - EXPECT_TRUE(ptr2); - diff = ptr2 - ptr1; - EXPECT_EQ(static_cast<ptrdiff_t>(kRealAllocSize), diff); - PartitionFree(ptr1); - ptr1 = reinterpret_cast<char*>( - allocator.root()->Alloc(kTestAllocSize, type_name)); - EXPECT_TRUE(ptr1); - diff = ptr2 - ptr1; - EXPECT_EQ(static_cast<ptrdiff_t>(kRealAllocSize), diff); - - char* ptr3 = reinterpret_cast<char*>( - allocator.root()->Alloc(kTestAllocSize, type_name)); - EXPECT_TRUE(ptr3); - diff = ptr3 - ptr1; - EXPECT_EQ(static_cast<ptrdiff_t>(kRealAllocSize * 2), diff); - - PartitionFree(ptr1); - PartitionFree(ptr2); - PartitionFree(ptr3); -} - -// Test a bucket with multiple pages. -TEST_F(PartitionAllocTest, MultiPages) { - PartitionBucket* bucket = &allocator.root()->buckets()[kTestBucketIndex]; - - PartitionPage* page = GetFullPage(kTestAllocSize); - FreeFullPage(page); - EXPECT_TRUE(bucket->empty_pages_head); - EXPECT_EQ(PartitionPage::get_sentinel_page(), bucket->active_pages_head); - EXPECT_EQ(nullptr, page->next_page); - EXPECT_EQ(0, page->num_allocated_slots); - - page = GetFullPage(kTestAllocSize); - PartitionPage* page2 = GetFullPage(kTestAllocSize); - - EXPECT_EQ(page2, bucket->active_pages_head); - EXPECT_EQ(nullptr, page2->next_page); - EXPECT_EQ(reinterpret_cast<uintptr_t>(PartitionPage::ToPointer(page)) & - kSuperPageBaseMask, - reinterpret_cast<uintptr_t>(PartitionPage::ToPointer(page2)) & - kSuperPageBaseMask); - - // Fully free the non-current page. This will leave us with no current - // active page because one is empty and the other is full. - FreeFullPage(page); - EXPECT_EQ(0, page->num_allocated_slots); - EXPECT_TRUE(bucket->empty_pages_head); - EXPECT_EQ(PartitionPage::get_sentinel_page(), bucket->active_pages_head); - - // Allocate a new page, it should pull from the freelist. - page = GetFullPage(kTestAllocSize); - EXPECT_FALSE(bucket->empty_pages_head); - EXPECT_EQ(page, bucket->active_pages_head); - - FreeFullPage(page); - FreeFullPage(page2); - EXPECT_EQ(0, page->num_allocated_slots); - EXPECT_EQ(0, page2->num_allocated_slots); - EXPECT_EQ(0, page2->num_unprovisioned_slots); - EXPECT_NE(-1, page2->empty_cache_index); -} - -// Test some finer aspects of internal page transitions. -TEST_F(PartitionAllocTest, PageTransitions) { - PartitionBucket* bucket = &allocator.root()->buckets()[kTestBucketIndex]; - - PartitionPage* page1 = GetFullPage(kTestAllocSize); - EXPECT_EQ(page1, bucket->active_pages_head); - EXPECT_EQ(nullptr, page1->next_page); - PartitionPage* page2 = GetFullPage(kTestAllocSize); - EXPECT_EQ(page2, bucket->active_pages_head); - EXPECT_EQ(nullptr, page2->next_page); - - // Bounce page1 back into the non-full list then fill it up again. - char* ptr = - reinterpret_cast<char*>(PartitionPage::ToPointer(page1)) + kPointerOffset; - PartitionFree(ptr); - EXPECT_EQ(page1, bucket->active_pages_head); - (void)allocator.root()->Alloc(kTestAllocSize, type_name); - EXPECT_EQ(page1, bucket->active_pages_head); - EXPECT_EQ(page2, bucket->active_pages_head->next_page); - - // Allocating another page at this point should cause us to scan over page1 - // (which is both full and NOT our current page), and evict it from the - // freelist. Older code had a O(n^2) condition due to failure to do this. - PartitionPage* page3 = GetFullPage(kTestAllocSize); - EXPECT_EQ(page3, bucket->active_pages_head); - EXPECT_EQ(nullptr, page3->next_page); - - // Work out a pointer into page2 and free it. - ptr = - reinterpret_cast<char*>(PartitionPage::ToPointer(page2)) + kPointerOffset; - PartitionFree(ptr); - // Trying to allocate at this time should cause us to cycle around to page2 - // and find the recently freed slot. - char* newPtr = reinterpret_cast<char*>( - allocator.root()->Alloc(kTestAllocSize, type_name)); - EXPECT_EQ(ptr, newPtr); - EXPECT_EQ(page2, bucket->active_pages_head); - EXPECT_EQ(page3, page2->next_page); - - // Work out a pointer into page1 and free it. This should pull the page - // back into the list of available pages. - ptr = - reinterpret_cast<char*>(PartitionPage::ToPointer(page1)) + kPointerOffset; - PartitionFree(ptr); - // This allocation should be satisfied by page1. - newPtr = reinterpret_cast<char*>( - allocator.root()->Alloc(kTestAllocSize, type_name)); - EXPECT_EQ(ptr, newPtr); - EXPECT_EQ(page1, bucket->active_pages_head); - EXPECT_EQ(page2, page1->next_page); - - FreeFullPage(page3); - FreeFullPage(page2); - FreeFullPage(page1); - - // Allocating whilst in this state exposed a bug, so keep the test. - ptr = reinterpret_cast<char*>( - allocator.root()->Alloc(kTestAllocSize, type_name)); - PartitionFree(ptr); -} - -// Test some corner cases relating to page transitions in the internal -// free page list metadata bucket. -TEST_F(PartitionAllocTest, FreePageListPageTransitions) { - PartitionBucket* bucket = &allocator.root()->buckets()[kTestBucketIndex]; - - size_t numToFillFreeListPage = - kPartitionPageSize / (sizeof(PartitionPage) + kExtraAllocSize); - // The +1 is because we need to account for the fact that the current page - // never gets thrown on the freelist. - ++numToFillFreeListPage; - auto pages = std::make_unique<PartitionPage* []>(numToFillFreeListPage); - - size_t i; - for (i = 0; i < numToFillFreeListPage; ++i) { - pages[i] = GetFullPage(kTestAllocSize); - } - EXPECT_EQ(pages[numToFillFreeListPage - 1], bucket->active_pages_head); - for (i = 0; i < numToFillFreeListPage; ++i) - FreeFullPage(pages[i]); - EXPECT_EQ(PartitionPage::get_sentinel_page(), bucket->active_pages_head); - EXPECT_TRUE(bucket->empty_pages_head); - - // Allocate / free in a different bucket size so we get control of a - // different free page list. We need two pages because one will be the last - // active page and not get freed. - PartitionPage* page1 = GetFullPage(kTestAllocSize * 2); - PartitionPage* page2 = GetFullPage(kTestAllocSize * 2); - FreeFullPage(page1); - FreeFullPage(page2); - - for (i = 0; i < numToFillFreeListPage; ++i) { - pages[i] = GetFullPage(kTestAllocSize); - } - EXPECT_EQ(pages[numToFillFreeListPage - 1], bucket->active_pages_head); - - for (i = 0; i < numToFillFreeListPage; ++i) - FreeFullPage(pages[i]); - EXPECT_EQ(PartitionPage::get_sentinel_page(), bucket->active_pages_head); - EXPECT_TRUE(bucket->empty_pages_head); -} - -// Test a large series of allocations that cross more than one underlying -// 64KB super page allocation. -TEST_F(PartitionAllocTest, MultiPageAllocs) { - // This is guaranteed to cross a super page boundary because the first - // partition page "slot" will be taken up by a guard page. - size_t numPagesNeeded = kNumPartitionPagesPerSuperPage; - // The super page should begin and end in a guard so we one less page in - // order to allocate a single page in the new super page. - --numPagesNeeded; - - EXPECT_GT(numPagesNeeded, 1u); - auto pages = std::make_unique<PartitionPage* []>(numPagesNeeded); - uintptr_t firstSuperPageBase = 0; - size_t i; - for (i = 0; i < numPagesNeeded; ++i) { - pages[i] = GetFullPage(kTestAllocSize); - void* storagePtr = PartitionPage::ToPointer(pages[i]); - if (!i) - firstSuperPageBase = - reinterpret_cast<uintptr_t>(storagePtr) & kSuperPageBaseMask; - if (i == numPagesNeeded - 1) { - uintptr_t secondSuperPageBase = - reinterpret_cast<uintptr_t>(storagePtr) & kSuperPageBaseMask; - uintptr_t secondSuperPageOffset = - reinterpret_cast<uintptr_t>(storagePtr) & kSuperPageOffsetMask; - EXPECT_FALSE(secondSuperPageBase == firstSuperPageBase); - // Check that we allocated a guard page for the second page. - EXPECT_EQ(kPartitionPageSize, secondSuperPageOffset); - } - } - for (i = 0; i < numPagesNeeded; ++i) - FreeFullPage(pages[i]); -} - -// Test the generic allocation functions that can handle arbitrary sizes and -// reallocing etc. -TEST_F(PartitionAllocTest, GenericAlloc) { - void* ptr = generic_allocator.root()->Alloc(1, type_name); - EXPECT_TRUE(ptr); - generic_allocator.root()->Free(ptr); - ptr = generic_allocator.root()->Alloc(kGenericMaxBucketed + 1, type_name); - EXPECT_TRUE(ptr); - generic_allocator.root()->Free(ptr); - - ptr = generic_allocator.root()->Alloc(1, type_name); - EXPECT_TRUE(ptr); - void* origPtr = ptr; - char* charPtr = static_cast<char*>(ptr); - *charPtr = 'A'; - - // Change the size of the realloc, remaining inside the same bucket. - void* newPtr = generic_allocator.root()->Realloc(ptr, 2, type_name); - EXPECT_EQ(ptr, newPtr); - newPtr = generic_allocator.root()->Realloc(ptr, 1, type_name); - EXPECT_EQ(ptr, newPtr); - newPtr = - generic_allocator.root()->Realloc(ptr, kGenericSmallestBucket, type_name); - EXPECT_EQ(ptr, newPtr); - - // Change the size of the realloc, switching buckets. - newPtr = generic_allocator.root()->Realloc(ptr, kGenericSmallestBucket + 1, - type_name); - EXPECT_NE(newPtr, ptr); - // Check that the realloc copied correctly. - char* newCharPtr = static_cast<char*>(newPtr); - EXPECT_EQ(*newCharPtr, 'A'); -#if DCHECK_IS_ON() - // Subtle: this checks for an old bug where we copied too much from the - // source of the realloc. The condition can be detected by a trashing of - // the uninitialized value in the space of the upsized allocation. - EXPECT_EQ(kUninitializedByte, - static_cast<unsigned char>(*(newCharPtr + kGenericSmallestBucket))); -#endif - *newCharPtr = 'B'; - // The realloc moved. To check that the old allocation was freed, we can - // do an alloc of the old allocation size and check that the old allocation - // address is at the head of the freelist and reused. - void* reusedPtr = generic_allocator.root()->Alloc(1, type_name); - EXPECT_EQ(reusedPtr, origPtr); - generic_allocator.root()->Free(reusedPtr); - - // Downsize the realloc. - ptr = newPtr; - newPtr = generic_allocator.root()->Realloc(ptr, 1, type_name); - EXPECT_EQ(newPtr, origPtr); - newCharPtr = static_cast<char*>(newPtr); - EXPECT_EQ(*newCharPtr, 'B'); - *newCharPtr = 'C'; - - // Upsize the realloc to outside the partition. - ptr = newPtr; - newPtr = generic_allocator.root()->Realloc(ptr, kGenericMaxBucketed + 1, - type_name); - EXPECT_NE(newPtr, ptr); - newCharPtr = static_cast<char*>(newPtr); - EXPECT_EQ(*newCharPtr, 'C'); - *newCharPtr = 'D'; - - // Upsize and downsize the realloc, remaining outside the partition. - ptr = newPtr; - newPtr = generic_allocator.root()->Realloc(ptr, kGenericMaxBucketed * 10, - type_name); - newCharPtr = static_cast<char*>(newPtr); - EXPECT_EQ(*newCharPtr, 'D'); - *newCharPtr = 'E'; - ptr = newPtr; - newPtr = generic_allocator.root()->Realloc(ptr, kGenericMaxBucketed * 2, - type_name); - newCharPtr = static_cast<char*>(newPtr); - EXPECT_EQ(*newCharPtr, 'E'); - *newCharPtr = 'F'; - - // Downsize the realloc to inside the partition. - ptr = newPtr; - newPtr = generic_allocator.root()->Realloc(ptr, 1, type_name); - EXPECT_NE(newPtr, ptr); - EXPECT_EQ(newPtr, origPtr); - newCharPtr = static_cast<char*>(newPtr); - EXPECT_EQ(*newCharPtr, 'F'); - - generic_allocator.root()->Free(newPtr); -} - -// Test the generic allocation functions can handle some specific sizes of -// interest. -TEST_F(PartitionAllocTest, GenericAllocSizes) { - void* ptr = generic_allocator.root()->Alloc(0, type_name); - EXPECT_TRUE(ptr); - generic_allocator.root()->Free(ptr); - - // kPartitionPageSize is interesting because it results in just one - // allocation per page, which tripped up some corner cases. - size_t size = kPartitionPageSize - kExtraAllocSize; - ptr = generic_allocator.root()->Alloc(size, type_name); - EXPECT_TRUE(ptr); - void* ptr2 = generic_allocator.root()->Alloc(size, type_name); - EXPECT_TRUE(ptr2); - generic_allocator.root()->Free(ptr); - // Should be freeable at this point. - PartitionPage* page = - PartitionPage::FromPointer(PartitionCookieFreePointerAdjust(ptr)); - EXPECT_NE(-1, page->empty_cache_index); - generic_allocator.root()->Free(ptr2); - - size = (((kPartitionPageSize * kMaxPartitionPagesPerSlotSpan) - - kSystemPageSize) / - 2) - - kExtraAllocSize; - ptr = generic_allocator.root()->Alloc(size, type_name); - EXPECT_TRUE(ptr); - memset(ptr, 'A', size); - ptr2 = generic_allocator.root()->Alloc(size, type_name); - EXPECT_TRUE(ptr2); - void* ptr3 = generic_allocator.root()->Alloc(size, type_name); - EXPECT_TRUE(ptr3); - void* ptr4 = generic_allocator.root()->Alloc(size, type_name); - EXPECT_TRUE(ptr4); - - page = PartitionPage::FromPointer(PartitionCookieFreePointerAdjust(ptr)); - PartitionPage* page2 = - PartitionPage::FromPointer(PartitionCookieFreePointerAdjust(ptr3)); - EXPECT_NE(page, page2); - - generic_allocator.root()->Free(ptr); - generic_allocator.root()->Free(ptr3); - generic_allocator.root()->Free(ptr2); - // Should be freeable at this point. - EXPECT_NE(-1, page->empty_cache_index); - EXPECT_EQ(0, page->num_allocated_slots); - EXPECT_EQ(0, page->num_unprovisioned_slots); - void* newPtr = generic_allocator.root()->Alloc(size, type_name); - EXPECT_EQ(ptr3, newPtr); - newPtr = generic_allocator.root()->Alloc(size, type_name); - EXPECT_EQ(ptr2, newPtr); -#if defined(OS_LINUX) && !DCHECK_IS_ON() - // On Linux, we have a guarantee that freelisting a page should cause its - // contents to be nulled out. We check for null here to detect an bug we - // had where a large slot size was causing us to not properly free all - // resources back to the system. - // We only run the check when asserts are disabled because when they are - // enabled, the allocated area is overwritten with an "uninitialized" - // byte pattern. - EXPECT_EQ(0, *(reinterpret_cast<char*>(newPtr) + (size - 1))); -#endif - generic_allocator.root()->Free(newPtr); - generic_allocator.root()->Free(ptr3); - generic_allocator.root()->Free(ptr4); - - // Can we allocate a massive (512MB) size? - // Allocate 512MB, but +1, to test for cookie writing alignment issues. - // Test this only if the device has enough memory or it might fail due - // to OOM. - if (IsLargeMemoryDevice()) { - ptr = generic_allocator.root()->Alloc(512 * 1024 * 1024 + 1, type_name); - generic_allocator.root()->Free(ptr); - } - - // Check a more reasonable, but still direct mapped, size. - // Chop a system page and a byte off to test for rounding errors. - size = 20 * 1024 * 1024; - size -= kSystemPageSize; - size -= 1; - ptr = generic_allocator.root()->Alloc(size, type_name); - char* charPtr = reinterpret_cast<char*>(ptr); - *(charPtr + (size - 1)) = 'A'; - generic_allocator.root()->Free(ptr); - - // Can we free null? - generic_allocator.root()->Free(nullptr); - - // Do we correctly get a null for a failed allocation? - EXPECT_EQ(nullptr, PartitionAllocGenericFlags( - generic_allocator.root(), PartitionAllocReturnNull, - 3u * 1024 * 1024 * 1024, type_name)); -} - -// Test that we can fetch the real allocated size after an allocation. -TEST_F(PartitionAllocTest, GenericAllocGetSize) { - void* ptr; - size_t requested_size, actual_size, predicted_size; - - EXPECT_TRUE(PartitionAllocSupportsGetSize()); - - // Allocate something small. - requested_size = 511 - kExtraAllocSize; - predicted_size = generic_allocator.root()->ActualSize(requested_size); - ptr = generic_allocator.root()->Alloc(requested_size, type_name); - EXPECT_TRUE(ptr); - actual_size = PartitionAllocGetSize(ptr); - EXPECT_EQ(predicted_size, actual_size); - EXPECT_LT(requested_size, actual_size); - generic_allocator.root()->Free(ptr); - - // Allocate a size that should be a perfect match for a bucket, because it - // is an exact power of 2. - requested_size = (256 * 1024) - kExtraAllocSize; - predicted_size = generic_allocator.root()->ActualSize(requested_size); - ptr = generic_allocator.root()->Alloc(requested_size, type_name); - EXPECT_TRUE(ptr); - actual_size = PartitionAllocGetSize(ptr); - EXPECT_EQ(predicted_size, actual_size); - EXPECT_EQ(requested_size, actual_size); - generic_allocator.root()->Free(ptr); - - // Allocate a size that is a system page smaller than a bucket. GetSize() - // should return a larger size than we asked for now. - size_t num = 64; - while (num * kSystemPageSize >= 1024 * 1024) { - num /= 2; - } - requested_size = num * kSystemPageSize - kSystemPageSize - kExtraAllocSize; - predicted_size = generic_allocator.root()->ActualSize(requested_size); - ptr = generic_allocator.root()->Alloc(requested_size, type_name); - EXPECT_TRUE(ptr); - actual_size = PartitionAllocGetSize(ptr); - EXPECT_EQ(predicted_size, actual_size); - EXPECT_EQ(requested_size + kSystemPageSize, actual_size); - // Check that we can write at the end of the reported size too. - char* charPtr = reinterpret_cast<char*>(ptr); - *(charPtr + (actual_size - 1)) = 'A'; - generic_allocator.root()->Free(ptr); - - // Allocate something very large, and uneven. - if (IsLargeMemoryDevice()) { - requested_size = 512 * 1024 * 1024 - 1; - predicted_size = generic_allocator.root()->ActualSize(requested_size); - ptr = generic_allocator.root()->Alloc(requested_size, type_name); - EXPECT_TRUE(ptr); - actual_size = PartitionAllocGetSize(ptr); - EXPECT_EQ(predicted_size, actual_size); - EXPECT_LT(requested_size, actual_size); - generic_allocator.root()->Free(ptr); - } - - // Too large allocation. - requested_size = kGenericMaxDirectMapped + 1; - predicted_size = generic_allocator.root()->ActualSize(requested_size); - EXPECT_EQ(requested_size, predicted_size); -} - -// Test the realloc() contract. -TEST_F(PartitionAllocTest, Realloc) { - // realloc(0, size) should be equivalent to malloc(). - void* ptr = - generic_allocator.root()->Realloc(nullptr, kTestAllocSize, type_name); - memset(ptr, 'A', kTestAllocSize); - PartitionPage* page = - PartitionPage::FromPointer(PartitionCookieFreePointerAdjust(ptr)); - // realloc(ptr, 0) should be equivalent to free(). - void* ptr2 = generic_allocator.root()->Realloc(ptr, 0, type_name); - EXPECT_EQ(nullptr, ptr2); - EXPECT_EQ(PartitionCookieFreePointerAdjust(ptr), page->freelist_head); - - // Test that growing an allocation with realloc() copies everything from the - // old allocation. - size_t size = kSystemPageSize - kExtraAllocSize; - EXPECT_EQ(size, generic_allocator.root()->ActualSize(size)); - ptr = generic_allocator.root()->Alloc(size, type_name); - memset(ptr, 'A', size); - ptr2 = generic_allocator.root()->Realloc(ptr, size + 1, type_name); - EXPECT_NE(ptr, ptr2); - char* charPtr2 = static_cast<char*>(ptr2); - EXPECT_EQ('A', charPtr2[0]); - EXPECT_EQ('A', charPtr2[size - 1]); -#if DCHECK_IS_ON() - EXPECT_EQ(kUninitializedByte, static_cast<unsigned char>(charPtr2[size])); -#endif - - // Test that shrinking an allocation with realloc() also copies everything - // from the old allocation. - ptr = generic_allocator.root()->Realloc(ptr2, size - 1, type_name); - EXPECT_NE(ptr2, ptr); - char* charPtr = static_cast<char*>(ptr); - EXPECT_EQ('A', charPtr[0]); - EXPECT_EQ('A', charPtr[size - 2]); -#if DCHECK_IS_ON() - EXPECT_EQ(kUninitializedByte, static_cast<unsigned char>(charPtr[size - 1])); -#endif - - generic_allocator.root()->Free(ptr); - - // Test that shrinking a direct mapped allocation happens in-place. - size = kGenericMaxBucketed + 16 * kSystemPageSize; - ptr = generic_allocator.root()->Alloc(size, type_name); - size_t actual_size = PartitionAllocGetSize(ptr); - ptr2 = generic_allocator.root()->Realloc( - ptr, kGenericMaxBucketed + 8 * kSystemPageSize, type_name); - EXPECT_EQ(ptr, ptr2); - EXPECT_EQ(actual_size - 8 * kSystemPageSize, PartitionAllocGetSize(ptr2)); - - // Test that a previously in-place shrunk direct mapped allocation can be - // expanded up again within its original size. - ptr = generic_allocator.root()->Realloc(ptr2, size - kSystemPageSize, - type_name); - EXPECT_EQ(ptr2, ptr); - EXPECT_EQ(actual_size - kSystemPageSize, PartitionAllocGetSize(ptr)); - - // Test that a direct mapped allocation is performed not in-place when the - // new size is small enough. - ptr2 = generic_allocator.root()->Realloc(ptr, kSystemPageSize, type_name); - EXPECT_NE(ptr, ptr2); - - generic_allocator.root()->Free(ptr2); -} - -// Tests the handing out of freelists for partial pages. -TEST_F(PartitionAllocTest, PartialPageFreelists) { - size_t big_size = allocator.root()->max_allocation - kExtraAllocSize; - EXPECT_EQ(kSystemPageSize - kAllocationGranularity, - big_size + kExtraAllocSize); - size_t bucket_index = (big_size + kExtraAllocSize) >> kBucketShift; - PartitionBucket* bucket = &allocator.root()->buckets()[bucket_index]; - EXPECT_EQ(nullptr, bucket->empty_pages_head); - - void* ptr = allocator.root()->Alloc(big_size, type_name); - EXPECT_TRUE(ptr); - - PartitionPage* page = - PartitionPage::FromPointer(PartitionCookieFreePointerAdjust(ptr)); - size_t totalSlots = - (page->bucket->num_system_pages_per_slot_span * kSystemPageSize) / - (big_size + kExtraAllocSize); - EXPECT_EQ(4u, totalSlots); - // The freelist should have one entry, because we were able to exactly fit - // one object slot and one freelist pointer (the null that the head points - // to) into a system page. - EXPECT_TRUE(page->freelist_head); - EXPECT_EQ(1, page->num_allocated_slots); - EXPECT_EQ(2, page->num_unprovisioned_slots); - - void* ptr2 = allocator.root()->Alloc(big_size, type_name); - EXPECT_TRUE(ptr2); - EXPECT_FALSE(page->freelist_head); - EXPECT_EQ(2, page->num_allocated_slots); - EXPECT_EQ(2, page->num_unprovisioned_slots); - - void* ptr3 = allocator.root()->Alloc(big_size, type_name); - EXPECT_TRUE(ptr3); - EXPECT_TRUE(page->freelist_head); - EXPECT_EQ(3, page->num_allocated_slots); - EXPECT_EQ(0, page->num_unprovisioned_slots); - - void* ptr4 = allocator.root()->Alloc(big_size, type_name); - EXPECT_TRUE(ptr4); - EXPECT_FALSE(page->freelist_head); - EXPECT_EQ(4, page->num_allocated_slots); - EXPECT_EQ(0, page->num_unprovisioned_slots); - - void* ptr5 = allocator.root()->Alloc(big_size, type_name); - EXPECT_TRUE(ptr5); - - PartitionPage* page2 = - PartitionPage::FromPointer(PartitionCookieFreePointerAdjust(ptr5)); - EXPECT_EQ(1, page2->num_allocated_slots); - - // Churn things a little whilst there's a partial page freelist. - PartitionFree(ptr); - ptr = allocator.root()->Alloc(big_size, type_name); - void* ptr6 = allocator.root()->Alloc(big_size, type_name); - - PartitionFree(ptr); - PartitionFree(ptr2); - PartitionFree(ptr3); - PartitionFree(ptr4); - PartitionFree(ptr5); - PartitionFree(ptr6); - EXPECT_NE(-1, page->empty_cache_index); - EXPECT_NE(-1, page2->empty_cache_index); - EXPECT_TRUE(page2->freelist_head); - EXPECT_EQ(0, page2->num_allocated_slots); - - // And test a couple of sizes that do not cross kSystemPageSize with a single - // allocation. - size_t mediumSize = (kSystemPageSize / 2) - kExtraAllocSize; - bucket_index = (mediumSize + kExtraAllocSize) >> kBucketShift; - bucket = &allocator.root()->buckets()[bucket_index]; - EXPECT_EQ(nullptr, bucket->empty_pages_head); - - ptr = allocator.root()->Alloc(mediumSize, type_name); - EXPECT_TRUE(ptr); - page = PartitionPage::FromPointer(PartitionCookieFreePointerAdjust(ptr)); - EXPECT_EQ(1, page->num_allocated_slots); - totalSlots = - (page->bucket->num_system_pages_per_slot_span * kSystemPageSize) / - (mediumSize + kExtraAllocSize); - size_t firstPageSlots = kSystemPageSize / (mediumSize + kExtraAllocSize); - EXPECT_EQ(2u, firstPageSlots); - EXPECT_EQ(totalSlots - firstPageSlots, page->num_unprovisioned_slots); - - PartitionFree(ptr); - - size_t smallSize = (kSystemPageSize / 4) - kExtraAllocSize; - bucket_index = (smallSize + kExtraAllocSize) >> kBucketShift; - bucket = &allocator.root()->buckets()[bucket_index]; - EXPECT_EQ(nullptr, bucket->empty_pages_head); - - ptr = allocator.root()->Alloc(smallSize, type_name); - EXPECT_TRUE(ptr); - page = PartitionPage::FromPointer(PartitionCookieFreePointerAdjust(ptr)); - EXPECT_EQ(1, page->num_allocated_slots); - totalSlots = - (page->bucket->num_system_pages_per_slot_span * kSystemPageSize) / - (smallSize + kExtraAllocSize); - firstPageSlots = kSystemPageSize / (smallSize + kExtraAllocSize); - EXPECT_EQ(totalSlots - firstPageSlots, page->num_unprovisioned_slots); - - PartitionFree(ptr); - EXPECT_TRUE(page->freelist_head); - EXPECT_EQ(0, page->num_allocated_slots); - - size_t verySmallSize = 32 - kExtraAllocSize; - bucket_index = (verySmallSize + kExtraAllocSize) >> kBucketShift; - bucket = &allocator.root()->buckets()[bucket_index]; - EXPECT_EQ(nullptr, bucket->empty_pages_head); - - ptr = allocator.root()->Alloc(verySmallSize, type_name); - EXPECT_TRUE(ptr); - page = PartitionPage::FromPointer(PartitionCookieFreePointerAdjust(ptr)); - EXPECT_EQ(1, page->num_allocated_slots); - totalSlots = - (page->bucket->num_system_pages_per_slot_span * kSystemPageSize) / - (verySmallSize + kExtraAllocSize); - firstPageSlots = kSystemPageSize / (verySmallSize + kExtraAllocSize); - EXPECT_EQ(totalSlots - firstPageSlots, page->num_unprovisioned_slots); - - PartitionFree(ptr); - EXPECT_TRUE(page->freelist_head); - EXPECT_EQ(0, page->num_allocated_slots); - - // And try an allocation size (against the generic allocator) that is - // larger than a system page. - size_t pageAndAHalfSize = - (kSystemPageSize + (kSystemPageSize / 2)) - kExtraAllocSize; - ptr = generic_allocator.root()->Alloc(pageAndAHalfSize, type_name); - EXPECT_TRUE(ptr); - page = PartitionPage::FromPointer(PartitionCookieFreePointerAdjust(ptr)); - EXPECT_EQ(1, page->num_allocated_slots); - EXPECT_TRUE(page->freelist_head); - totalSlots = - (page->bucket->num_system_pages_per_slot_span * kSystemPageSize) / - (pageAndAHalfSize + kExtraAllocSize); - EXPECT_EQ(totalSlots - 2, page->num_unprovisioned_slots); - generic_allocator.root()->Free(ptr); - - // And then make sure than exactly the page size only faults one page. - size_t pageSize = kSystemPageSize - kExtraAllocSize; - ptr = generic_allocator.root()->Alloc(pageSize, type_name); - EXPECT_TRUE(ptr); - page = PartitionPage::FromPointer(PartitionCookieFreePointerAdjust(ptr)); - EXPECT_EQ(1, page->num_allocated_slots); - EXPECT_FALSE(page->freelist_head); - totalSlots = - (page->bucket->num_system_pages_per_slot_span * kSystemPageSize) / - (pageSize + kExtraAllocSize); - EXPECT_EQ(totalSlots - 1, page->num_unprovisioned_slots); - generic_allocator.root()->Free(ptr); -} - -// Test some of the fragmentation-resistant properties of the allocator. -TEST_F(PartitionAllocTest, PageRefilling) { - PartitionBucket* bucket = &allocator.root()->buckets()[kTestBucketIndex]; - - // Grab two full pages and a non-full page. - PartitionPage* page1 = GetFullPage(kTestAllocSize); - PartitionPage* page2 = GetFullPage(kTestAllocSize); - void* ptr = allocator.root()->Alloc(kTestAllocSize, type_name); - EXPECT_TRUE(ptr); - EXPECT_NE(page1, bucket->active_pages_head); - EXPECT_NE(page2, bucket->active_pages_head); - PartitionPage* page = - PartitionPage::FromPointer(PartitionCookieFreePointerAdjust(ptr)); - EXPECT_EQ(1, page->num_allocated_slots); - - // Work out a pointer into page2 and free it; and then page1 and free it. - char* ptr2 = - reinterpret_cast<char*>(PartitionPage::ToPointer(page1)) + kPointerOffset; - PartitionFree(ptr2); - ptr2 = - reinterpret_cast<char*>(PartitionPage::ToPointer(page2)) + kPointerOffset; - PartitionFree(ptr2); - - // If we perform two allocations from the same bucket now, we expect to - // refill both the nearly full pages. - (void)allocator.root()->Alloc(kTestAllocSize, type_name); - (void)allocator.root()->Alloc(kTestAllocSize, type_name); - EXPECT_EQ(1, page->num_allocated_slots); - - FreeFullPage(page2); - FreeFullPage(page1); - PartitionFree(ptr); -} - -// Basic tests to ensure that allocations work for partial page buckets. -TEST_F(PartitionAllocTest, PartialPages) { - // Find a size that is backed by a partial partition page. - size_t size = sizeof(void*); - PartitionBucket* bucket = nullptr; - while (size < kTestMaxAllocation) { - bucket = &allocator.root()->buckets()[size >> kBucketShift]; - if (bucket->num_system_pages_per_slot_span % - kNumSystemPagesPerPartitionPage) - break; - size += sizeof(void*); - } - EXPECT_LT(size, kTestMaxAllocation); - - PartitionPage* page1 = GetFullPage(size); - PartitionPage* page2 = GetFullPage(size); - FreeFullPage(page2); - FreeFullPage(page1); -} - -// Test correct handling if our mapping collides with another. -TEST_F(PartitionAllocTest, MappingCollision) { - // The -2 is because the first and last partition pages in a super page are - // guard pages. - size_t numPartitionPagesNeeded = kNumPartitionPagesPerSuperPage - 2; - auto firstSuperPagePages = - std::make_unique<PartitionPage* []>(numPartitionPagesNeeded); - auto secondSuperPagePages = - std::make_unique<PartitionPage* []>(numPartitionPagesNeeded); - - size_t i; - for (i = 0; i < numPartitionPagesNeeded; ++i) - firstSuperPagePages[i] = GetFullPage(kTestAllocSize); - - char* pageBase = - reinterpret_cast<char*>(PartitionPage::ToPointer(firstSuperPagePages[0])); - EXPECT_EQ(kPartitionPageSize, - reinterpret_cast<uintptr_t>(pageBase) & kSuperPageOffsetMask); - pageBase -= kPartitionPageSize; - // Map a single system page either side of the mapping for our allocations, - // with the goal of tripping up alignment of the next mapping. - void* map1 = AllocPages(pageBase - kPageAllocationGranularity, - kPageAllocationGranularity, - kPageAllocationGranularity, PageInaccessible); - EXPECT_TRUE(map1); - void* map2 = AllocPages(pageBase + kSuperPageSize, kPageAllocationGranularity, - kPageAllocationGranularity, PageInaccessible); - EXPECT_TRUE(map2); - - for (i = 0; i < numPartitionPagesNeeded; ++i) - secondSuperPagePages[i] = GetFullPage(kTestAllocSize); - - FreePages(map1, kPageAllocationGranularity); - FreePages(map2, kPageAllocationGranularity); - - pageBase = reinterpret_cast<char*>( - PartitionPage::ToPointer(secondSuperPagePages[0])); - EXPECT_EQ(kPartitionPageSize, - reinterpret_cast<uintptr_t>(pageBase) & kSuperPageOffsetMask); - pageBase -= kPartitionPageSize; - // Map a single system page either side of the mapping for our allocations, - // with the goal of tripping up alignment of the next mapping. - map1 = AllocPages(pageBase - kPageAllocationGranularity, - kPageAllocationGranularity, kPageAllocationGranularity, - PageReadWrite); - EXPECT_TRUE(map1); - map2 = AllocPages(pageBase + kSuperPageSize, kPageAllocationGranularity, - kPageAllocationGranularity, PageReadWrite); - EXPECT_TRUE(map2); - EXPECT_TRUE( - SetSystemPagesAccess(map1, kPageAllocationGranularity, PageInaccessible)); - EXPECT_TRUE( - SetSystemPagesAccess(map2, kPageAllocationGranularity, PageInaccessible)); - - PartitionPage* pageInThirdSuperPage = GetFullPage(kTestAllocSize); - FreePages(map1, kPageAllocationGranularity); - FreePages(map2, kPageAllocationGranularity); - - EXPECT_EQ(0u, reinterpret_cast<uintptr_t>( - PartitionPage::ToPointer(pageInThirdSuperPage)) & - kPartitionPageOffsetMask); - - // And make sure we really did get a page in a new superpage. - EXPECT_NE(reinterpret_cast<uintptr_t>( - PartitionPage::ToPointer(firstSuperPagePages[0])) & - kSuperPageBaseMask, - reinterpret_cast<uintptr_t>( - PartitionPage::ToPointer(pageInThirdSuperPage)) & - kSuperPageBaseMask); - EXPECT_NE(reinterpret_cast<uintptr_t>( - PartitionPage::ToPointer(secondSuperPagePages[0])) & - kSuperPageBaseMask, - reinterpret_cast<uintptr_t>( - PartitionPage::ToPointer(pageInThirdSuperPage)) & - kSuperPageBaseMask); - - FreeFullPage(pageInThirdSuperPage); - for (i = 0; i < numPartitionPagesNeeded; ++i) { - FreeFullPage(firstSuperPagePages[i]); - FreeFullPage(secondSuperPagePages[i]); - } -} - -// Tests that pages in the free page cache do get freed as appropriate. -TEST_F(PartitionAllocTest, FreeCache) { - EXPECT_EQ(0U, allocator.root()->total_size_of_committed_pages); - - size_t big_size = allocator.root()->max_allocation - kExtraAllocSize; - size_t bucket_index = (big_size + kExtraAllocSize) >> kBucketShift; - PartitionBucket* bucket = &allocator.root()->buckets()[bucket_index]; - - void* ptr = allocator.root()->Alloc(big_size, type_name); - EXPECT_TRUE(ptr); - PartitionPage* page = - PartitionPage::FromPointer(PartitionCookieFreePointerAdjust(ptr)); - EXPECT_EQ(nullptr, bucket->empty_pages_head); - EXPECT_EQ(1, page->num_allocated_slots); - EXPECT_EQ(kPartitionPageSize, - allocator.root()->total_size_of_committed_pages); - PartitionFree(ptr); - EXPECT_EQ(0, page->num_allocated_slots); - EXPECT_NE(-1, page->empty_cache_index); - EXPECT_TRUE(page->freelist_head); - - CycleFreeCache(kTestAllocSize); - - // Flushing the cache should have really freed the unused page. - EXPECT_FALSE(page->freelist_head); - EXPECT_EQ(-1, page->empty_cache_index); - EXPECT_EQ(0, page->num_allocated_slots); - PartitionBucket* cycle_free_cache_bucket = - &allocator.root()->buckets()[kTestBucketIndex]; - EXPECT_EQ( - cycle_free_cache_bucket->num_system_pages_per_slot_span * kSystemPageSize, - allocator.root()->total_size_of_committed_pages); - - // Check that an allocation works ok whilst in this state (a free'd page - // as the active pages head). - ptr = allocator.root()->Alloc(big_size, type_name); - EXPECT_FALSE(bucket->empty_pages_head); - PartitionFree(ptr); - - // Also check that a page that is bouncing immediately between empty and - // used does not get freed. - for (size_t i = 0; i < kMaxFreeableSpans * 2; ++i) { - ptr = allocator.root()->Alloc(big_size, type_name); - EXPECT_TRUE(page->freelist_head); - PartitionFree(ptr); - EXPECT_TRUE(page->freelist_head); - } - EXPECT_EQ(kPartitionPageSize, - allocator.root()->total_size_of_committed_pages); -} - -// Tests for a bug we had with losing references to free pages. -TEST_F(PartitionAllocTest, LostFreePagesBug) { - size_t size = kPartitionPageSize - kExtraAllocSize; - - void* ptr = generic_allocator.root()->Alloc(size, type_name); - EXPECT_TRUE(ptr); - void* ptr2 = generic_allocator.root()->Alloc(size, type_name); - EXPECT_TRUE(ptr2); - - PartitionPage* page = - PartitionPage::FromPointer(PartitionCookieFreePointerAdjust(ptr)); - PartitionPage* page2 = - PartitionPage::FromPointer(PartitionCookieFreePointerAdjust(ptr2)); - PartitionBucket* bucket = page->bucket; - - EXPECT_EQ(nullptr, bucket->empty_pages_head); - EXPECT_EQ(-1, page->num_allocated_slots); - EXPECT_EQ(1, page2->num_allocated_slots); - - generic_allocator.root()->Free(ptr); - generic_allocator.root()->Free(ptr2); - - EXPECT_TRUE(bucket->empty_pages_head); - EXPECT_TRUE(bucket->empty_pages_head->next_page); - EXPECT_EQ(0, page->num_allocated_slots); - EXPECT_EQ(0, page2->num_allocated_slots); - EXPECT_TRUE(page->freelist_head); - EXPECT_TRUE(page2->freelist_head); - - CycleGenericFreeCache(kTestAllocSize); - - EXPECT_FALSE(page->freelist_head); - EXPECT_FALSE(page2->freelist_head); - - EXPECT_TRUE(bucket->empty_pages_head); - EXPECT_TRUE(bucket->empty_pages_head->next_page); - EXPECT_EQ(PartitionPage::get_sentinel_page(), bucket->active_pages_head); - - // At this moment, we have two decommitted pages, on the empty list. - ptr = generic_allocator.root()->Alloc(size, type_name); - EXPECT_TRUE(ptr); - generic_allocator.root()->Free(ptr); - - EXPECT_EQ(PartitionPage::get_sentinel_page(), bucket->active_pages_head); - EXPECT_TRUE(bucket->empty_pages_head); - EXPECT_TRUE(bucket->decommitted_pages_head); - - CycleGenericFreeCache(kTestAllocSize); - - // We're now set up to trigger a historical bug by scanning over the active - // pages list. The current code gets into a different state, but we'll keep - // the test as being an interesting corner case. - ptr = generic_allocator.root()->Alloc(size, type_name); - EXPECT_TRUE(ptr); - generic_allocator.root()->Free(ptr); - - EXPECT_TRUE(bucket->active_pages_head); - EXPECT_TRUE(bucket->empty_pages_head); - EXPECT_TRUE(bucket->decommitted_pages_head); -} - -// Unit tests that check if an allocation fails in "return null" mode, -// repeating it doesn't crash, and still returns null. The tests need to -// stress memory subsystem limits to do so, hence they try to allocate -// 6 GB of memory, each with a different per-allocation block sizes. -// -// On 64-bit systems we need to restrict the address space to force allocation -// failure, so these tests run only on POSIX systems that provide setrlimit(), -// and use it to limit address space to 6GB. -// -// Disable these tests on Android because, due to the allocation-heavy behavior, -// they tend to get OOM-killed rather than pass. -// TODO(https://crbug.com/779645): Fuchsia currently sets OS_POSIX, but does -// not provide a working setrlimit(). -#if !defined(ARCH_CPU_64_BITS) || \ - (defined(OS_POSIX) && \ - !(defined(OS_FUCHSIA) || defined(OS_MACOSX) || defined(OS_ANDROID))) - -// This is defined as a separate test class because RepeatedReturnNull -// test exhausts the process memory, and breaks any test in the same -// class that runs after it. -class PartitionAllocReturnNullTest : public PartitionAllocTest {}; - -// Test "return null" for larger, direct-mapped allocations first. As a -// direct-mapped allocation's pages are unmapped and freed on release, this -// test is performd first for these "return null" tests in order to leave -// sufficient unreserved virtual memory around for the later one(s). -TEST_F(PartitionAllocReturnNullTest, RepeatedReturnNullDirect) { - // A direct-mapped allocation size. - DoReturnNullTest(32 * 1024 * 1024, false); -} - -// Test "return null" with a 512 kB block size. -TEST_F(PartitionAllocReturnNullTest, RepeatedReturnNull) { - // A single-slot but non-direct-mapped allocation size. - DoReturnNullTest(512 * 1024, false); -} - -// Repeating the above tests using Realloc instead of Alloc. -class PartitionReallocReturnNullTest : public PartitionAllocTest {}; - -TEST_F(PartitionReallocReturnNullTest, RepeatedReturnNullDirect) { - DoReturnNullTest(32 * 1024 * 1024, true); -} - -TEST_F(PartitionReallocReturnNullTest, RepeatedReturnNull) { - DoReturnNullTest(512 * 1024, true); -} - -#endif // !defined(ARCH_CPU_64_BITS) || (defined(OS_POSIX) && - // !(defined(OS_FUCHSIA) || defined(OS_MACOSX) || defined(OS_ANDROID))) - -// Death tests misbehave on Android, http://crbug.com/643760. -#if defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID) - -// Make sure that malloc(-1) dies. -// In the past, we had an integer overflow that would alias malloc(-1) to -// malloc(0), which is not good. -TEST_F(PartitionAllocDeathTest, LargeAllocs) { - // Largest alloc. - EXPECT_DEATH( - generic_allocator.root()->Alloc(static_cast<size_t>(-1), type_name), ""); - // And the smallest allocation we expect to die. - EXPECT_DEATH( - generic_allocator.root()->Alloc(kGenericMaxDirectMapped + 1, type_name), - ""); -} - -// Check that our immediate double-free detection works. -TEST_F(PartitionAllocDeathTest, ImmediateDoubleFree) { - void* ptr = generic_allocator.root()->Alloc(kTestAllocSize, type_name); - EXPECT_TRUE(ptr); - generic_allocator.root()->Free(ptr); - - EXPECT_DEATH(generic_allocator.root()->Free(ptr), ""); -} - -// Check that our refcount-based double-free detection works. -TEST_F(PartitionAllocDeathTest, RefcountDoubleFree) { - void* ptr = generic_allocator.root()->Alloc(kTestAllocSize, type_name); - EXPECT_TRUE(ptr); - void* ptr2 = generic_allocator.root()->Alloc(kTestAllocSize, type_name); - EXPECT_TRUE(ptr2); - generic_allocator.root()->Free(ptr); - generic_allocator.root()->Free(ptr2); - // This is not an immediate double-free so our immediate detection won't - // fire. However, it does take the "refcount" of the partition page to -1, - // which is illegal and should be trapped. - EXPECT_DEATH(generic_allocator.root()->Free(ptr), ""); -} - -// Check that guard pages are present where expected. -TEST_F(PartitionAllocDeathTest, GuardPages) { -// PartitionAlloc adds kPartitionPageSize to the requested size -// (for metadata), and then rounds that size to kPageAllocationGranularity. -// To be able to reliably write one past a direct allocation, choose a size -// that's -// a) larger than kGenericMaxBucketed (to make the allocation direct) -// b) aligned at kPageAllocationGranularity boundaries after -// kPartitionPageSize has been added to it. -// (On 32-bit, PartitionAlloc adds another kSystemPageSize to the -// allocation size before rounding, but there it marks the memory right -// after size as inaccessible, so it's fine to write 1 past the size we -// hand to PartitionAlloc and we don't need to worry about allocation -// granularities.) -#define ALIGN(N, A) (((N) + (A)-1) / (A) * (A)) - const int kSize = ALIGN(kGenericMaxBucketed + 1 + kPartitionPageSize, - kPageAllocationGranularity) - - kPartitionPageSize; -#undef ALIGN - static_assert(kSize > kGenericMaxBucketed, - "allocation not large enough for direct allocation"); - size_t size = kSize - kExtraAllocSize; - void* ptr = generic_allocator.root()->Alloc(size, type_name); - - EXPECT_TRUE(ptr); - char* charPtr = reinterpret_cast<char*>(ptr) - kPointerOffset; - - EXPECT_DEATH(*(charPtr - 1) = 'A', ""); - EXPECT_DEATH(*(charPtr + size + kExtraAllocSize) = 'A', ""); - - generic_allocator.root()->Free(ptr); -} - -// Check that a bad free() is caught where the free() refers to an unused -// partition page of a large allocation. -TEST_F(PartitionAllocDeathTest, FreeWrongPartitionPage) { - // This large size will result in a direct mapped allocation with guard - // pages at either end. - void* ptr = - generic_allocator.root()->Alloc(kPartitionPageSize * 2, type_name); - EXPECT_TRUE(ptr); - char* badPtr = reinterpret_cast<char*>(ptr) + kPartitionPageSize; - - EXPECT_DEATH(generic_allocator.root()->Free(badPtr), ""); - - generic_allocator.root()->Free(ptr); -} - -#endif // !defined(OS_ANDROID) && !defined(OS_IOS) - -// Tests that |PartitionDumpStatsGeneric| and |PartitionDumpStats| run without -// crashing and return non-zero values when memory is allocated. -TEST_F(PartitionAllocTest, DumpMemoryStats) { - { - void* ptr = allocator.root()->Alloc(kTestAllocSize, type_name); - MockPartitionStatsDumper mockStatsDumper; - allocator.root()->DumpStats("mock_allocator", false /* detailed dump */, - &mockStatsDumper); - EXPECT_TRUE(mockStatsDumper.IsMemoryAllocationRecorded()); - PartitionFree(ptr); - } - - // This series of tests checks the active -> empty -> decommitted states. - { - { - void* ptr = - generic_allocator.root()->Alloc(2048 - kExtraAllocSize, type_name); - MockPartitionStatsDumper dumper; - generic_allocator.root()->DumpStats("mock_generic_allocator", - false /* detailed dump */, &dumper); - EXPECT_TRUE(dumper.IsMemoryAllocationRecorded()); - - const PartitionBucketMemoryStats* stats = dumper.GetBucketStats(2048); - EXPECT_TRUE(stats); - EXPECT_TRUE(stats->is_valid); - EXPECT_EQ(2048u, stats->bucket_slot_size); - EXPECT_EQ(2048u, stats->active_bytes); - EXPECT_EQ(kSystemPageSize, stats->resident_bytes); - EXPECT_EQ(0u, stats->decommittable_bytes); - EXPECT_EQ(0u, stats->discardable_bytes); - EXPECT_EQ(0u, stats->num_full_pages); - EXPECT_EQ(1u, stats->num_active_pages); - EXPECT_EQ(0u, stats->num_empty_pages); - EXPECT_EQ(0u, stats->num_decommitted_pages); - generic_allocator.root()->Free(ptr); - } - - { - MockPartitionStatsDumper dumper; - generic_allocator.root()->DumpStats("mock_generic_allocator", - false /* detailed dump */, &dumper); - EXPECT_FALSE(dumper.IsMemoryAllocationRecorded()); - - const PartitionBucketMemoryStats* stats = dumper.GetBucketStats(2048); - EXPECT_TRUE(stats); - EXPECT_TRUE(stats->is_valid); - EXPECT_EQ(2048u, stats->bucket_slot_size); - EXPECT_EQ(0u, stats->active_bytes); - EXPECT_EQ(kSystemPageSize, stats->resident_bytes); - EXPECT_EQ(kSystemPageSize, stats->decommittable_bytes); - EXPECT_EQ(0u, stats->discardable_bytes); - EXPECT_EQ(0u, stats->num_full_pages); - EXPECT_EQ(0u, stats->num_active_pages); - EXPECT_EQ(1u, stats->num_empty_pages); - EXPECT_EQ(0u, stats->num_decommitted_pages); - } - - // TODO(crbug.com/722911): Commenting this out causes this test to fail when - // run singly (--gtest_filter=PartitionAllocTest.DumpMemoryStats), but not - // when run with the others (--gtest_filter=PartitionAllocTest.*). - CycleGenericFreeCache(kTestAllocSize); - - { - MockPartitionStatsDumper dumper; - generic_allocator.root()->DumpStats("mock_generic_allocator", - false /* detailed dump */, &dumper); - EXPECT_FALSE(dumper.IsMemoryAllocationRecorded()); - - const PartitionBucketMemoryStats* stats = dumper.GetBucketStats(2048); - EXPECT_TRUE(stats); - EXPECT_TRUE(stats->is_valid); - EXPECT_EQ(2048u, stats->bucket_slot_size); - EXPECT_EQ(0u, stats->active_bytes); - EXPECT_EQ(0u, stats->resident_bytes); - EXPECT_EQ(0u, stats->decommittable_bytes); - EXPECT_EQ(0u, stats->discardable_bytes); - EXPECT_EQ(0u, stats->num_full_pages); - EXPECT_EQ(0u, stats->num_active_pages); - EXPECT_EQ(0u, stats->num_empty_pages); - EXPECT_EQ(1u, stats->num_decommitted_pages); - } - } - - // This test checks for correct empty page list accounting. - { - size_t size = kPartitionPageSize - kExtraAllocSize; - void* ptr1 = generic_allocator.root()->Alloc(size, type_name); - void* ptr2 = generic_allocator.root()->Alloc(size, type_name); - generic_allocator.root()->Free(ptr1); - generic_allocator.root()->Free(ptr2); - - CycleGenericFreeCache(kTestAllocSize); - - ptr1 = generic_allocator.root()->Alloc(size, type_name); - - { - MockPartitionStatsDumper dumper; - generic_allocator.root()->DumpStats("mock_generic_allocator", - false /* detailed dump */, &dumper); - EXPECT_TRUE(dumper.IsMemoryAllocationRecorded()); - - const PartitionBucketMemoryStats* stats = - dumper.GetBucketStats(kPartitionPageSize); - EXPECT_TRUE(stats); - EXPECT_TRUE(stats->is_valid); - EXPECT_EQ(kPartitionPageSize, stats->bucket_slot_size); - EXPECT_EQ(kPartitionPageSize, stats->active_bytes); - EXPECT_EQ(kPartitionPageSize, stats->resident_bytes); - EXPECT_EQ(0u, stats->decommittable_bytes); - EXPECT_EQ(0u, stats->discardable_bytes); - EXPECT_EQ(1u, stats->num_full_pages); - EXPECT_EQ(0u, stats->num_active_pages); - EXPECT_EQ(0u, stats->num_empty_pages); - EXPECT_EQ(1u, stats->num_decommitted_pages); - } - generic_allocator.root()->Free(ptr1); - } - - // This test checks for correct direct mapped accounting. - { - size_t size_smaller = kGenericMaxBucketed + 1; - size_t size_bigger = (kGenericMaxBucketed * 2) + 1; - size_t real_size_smaller = - (size_smaller + kSystemPageOffsetMask) & kSystemPageBaseMask; - size_t real_size_bigger = - (size_bigger + kSystemPageOffsetMask) & kSystemPageBaseMask; - void* ptr = generic_allocator.root()->Alloc(size_smaller, type_name); - void* ptr2 = generic_allocator.root()->Alloc(size_bigger, type_name); - - { - MockPartitionStatsDumper dumper; - generic_allocator.root()->DumpStats("mock_generic_allocator", - false /* detailed dump */, &dumper); - EXPECT_TRUE(dumper.IsMemoryAllocationRecorded()); - - const PartitionBucketMemoryStats* stats = - dumper.GetBucketStats(real_size_smaller); - EXPECT_TRUE(stats); - EXPECT_TRUE(stats->is_valid); - EXPECT_TRUE(stats->is_direct_map); - EXPECT_EQ(real_size_smaller, stats->bucket_slot_size); - EXPECT_EQ(real_size_smaller, stats->active_bytes); - EXPECT_EQ(real_size_smaller, stats->resident_bytes); - EXPECT_EQ(0u, stats->decommittable_bytes); - EXPECT_EQ(0u, stats->discardable_bytes); - EXPECT_EQ(1u, stats->num_full_pages); - EXPECT_EQ(0u, stats->num_active_pages); - EXPECT_EQ(0u, stats->num_empty_pages); - EXPECT_EQ(0u, stats->num_decommitted_pages); - - stats = dumper.GetBucketStats(real_size_bigger); - EXPECT_TRUE(stats); - EXPECT_TRUE(stats->is_valid); - EXPECT_TRUE(stats->is_direct_map); - EXPECT_EQ(real_size_bigger, stats->bucket_slot_size); - EXPECT_EQ(real_size_bigger, stats->active_bytes); - EXPECT_EQ(real_size_bigger, stats->resident_bytes); - EXPECT_EQ(0u, stats->decommittable_bytes); - EXPECT_EQ(0u, stats->discardable_bytes); - EXPECT_EQ(1u, stats->num_full_pages); - EXPECT_EQ(0u, stats->num_active_pages); - EXPECT_EQ(0u, stats->num_empty_pages); - EXPECT_EQ(0u, stats->num_decommitted_pages); - } - - generic_allocator.root()->Free(ptr2); - generic_allocator.root()->Free(ptr); - - // Whilst we're here, allocate again and free with different ordering to - // give a workout to our linked list code. - ptr = generic_allocator.root()->Alloc(size_smaller, type_name); - ptr2 = generic_allocator.root()->Alloc(size_bigger, type_name); - generic_allocator.root()->Free(ptr); - generic_allocator.root()->Free(ptr2); - } - - // This test checks large-but-not-quite-direct allocations. - { - constexpr size_t requested_size = 16 * kSystemPageSize; - void* ptr = generic_allocator.root()->Alloc(requested_size + 1, type_name); - - { - MockPartitionStatsDumper dumper; - generic_allocator.root()->DumpStats("mock_generic_allocator", - false /* detailed dump */, &dumper); - EXPECT_TRUE(dumper.IsMemoryAllocationRecorded()); - - size_t slot_size = - requested_size + (requested_size / kGenericNumBucketsPerOrder); - const PartitionBucketMemoryStats* stats = - dumper.GetBucketStats(slot_size); - EXPECT_TRUE(stats); - EXPECT_TRUE(stats->is_valid); - EXPECT_FALSE(stats->is_direct_map); - EXPECT_EQ(slot_size, stats->bucket_slot_size); - EXPECT_EQ(requested_size + 1 + kExtraAllocSize, stats->active_bytes); - EXPECT_EQ(slot_size, stats->resident_bytes); - EXPECT_EQ(0u, stats->decommittable_bytes); - EXPECT_EQ(kSystemPageSize, stats->discardable_bytes); - EXPECT_EQ(1u, stats->num_full_pages); - EXPECT_EQ(0u, stats->num_active_pages); - EXPECT_EQ(0u, stats->num_empty_pages); - EXPECT_EQ(0u, stats->num_decommitted_pages); - } - - generic_allocator.root()->Free(ptr); - - { - MockPartitionStatsDumper dumper; - generic_allocator.root()->DumpStats("mock_generic_allocator", - false /* detailed dump */, &dumper); - EXPECT_FALSE(dumper.IsMemoryAllocationRecorded()); - - size_t slot_size = - requested_size + (requested_size / kGenericNumBucketsPerOrder); - const PartitionBucketMemoryStats* stats = - dumper.GetBucketStats(slot_size); - EXPECT_TRUE(stats); - EXPECT_TRUE(stats->is_valid); - EXPECT_FALSE(stats->is_direct_map); - EXPECT_EQ(slot_size, stats->bucket_slot_size); - EXPECT_EQ(0u, stats->active_bytes); - EXPECT_EQ(slot_size, stats->resident_bytes); - EXPECT_EQ(slot_size, stats->decommittable_bytes); - EXPECT_EQ(0u, stats->num_full_pages); - EXPECT_EQ(0u, stats->num_active_pages); - EXPECT_EQ(1u, stats->num_empty_pages); - EXPECT_EQ(0u, stats->num_decommitted_pages); - } - - void* ptr2 = generic_allocator.root()->Alloc( - requested_size + kSystemPageSize + 1, type_name); - EXPECT_EQ(ptr, ptr2); - - { - MockPartitionStatsDumper dumper; - generic_allocator.root()->DumpStats("mock_generic_allocator", - false /* detailed dump */, &dumper); - EXPECT_TRUE(dumper.IsMemoryAllocationRecorded()); - - size_t slot_size = - requested_size + (requested_size / kGenericNumBucketsPerOrder); - const PartitionBucketMemoryStats* stats = - dumper.GetBucketStats(slot_size); - EXPECT_TRUE(stats); - EXPECT_TRUE(stats->is_valid); - EXPECT_FALSE(stats->is_direct_map); - EXPECT_EQ(slot_size, stats->bucket_slot_size); - EXPECT_EQ(requested_size + kSystemPageSize + 1 + kExtraAllocSize, - stats->active_bytes); - EXPECT_EQ(slot_size, stats->resident_bytes); - EXPECT_EQ(0u, stats->decommittable_bytes); - EXPECT_EQ(0u, stats->discardable_bytes); - EXPECT_EQ(1u, stats->num_full_pages); - EXPECT_EQ(0u, stats->num_active_pages); - EXPECT_EQ(0u, stats->num_empty_pages); - EXPECT_EQ(0u, stats->num_decommitted_pages); - } - - generic_allocator.root()->Free(ptr2); - } -} - -// Tests the API to purge freeable memory. -TEST_F(PartitionAllocTest, Purge) { - char* ptr = reinterpret_cast<char*>( - generic_allocator.root()->Alloc(2048 - kExtraAllocSize, type_name)); - generic_allocator.root()->Free(ptr); - { - MockPartitionStatsDumper dumper; - generic_allocator.root()->DumpStats("mock_generic_allocator", - false /* detailed dump */, &dumper); - EXPECT_FALSE(dumper.IsMemoryAllocationRecorded()); - - const PartitionBucketMemoryStats* stats = dumper.GetBucketStats(2048); - EXPECT_TRUE(stats); - EXPECT_TRUE(stats->is_valid); - EXPECT_EQ(kSystemPageSize, stats->decommittable_bytes); - EXPECT_EQ(kSystemPageSize, stats->resident_bytes); - } - generic_allocator.root()->PurgeMemory(PartitionPurgeDecommitEmptyPages); - { - MockPartitionStatsDumper dumper; - generic_allocator.root()->DumpStats("mock_generic_allocator", - false /* detailed dump */, &dumper); - EXPECT_FALSE(dumper.IsMemoryAllocationRecorded()); - - const PartitionBucketMemoryStats* stats = dumper.GetBucketStats(2048); - EXPECT_TRUE(stats); - EXPECT_TRUE(stats->is_valid); - EXPECT_EQ(0u, stats->decommittable_bytes); - EXPECT_EQ(0u, stats->resident_bytes); - } - // Calling purge again here is a good way of testing we didn't mess up the - // state of the free cache ring. - generic_allocator.root()->PurgeMemory(PartitionPurgeDecommitEmptyPages); - - char* bigPtr = reinterpret_cast<char*>( - generic_allocator.root()->Alloc(256 * 1024, type_name)); - generic_allocator.root()->Free(bigPtr); - generic_allocator.root()->PurgeMemory(PartitionPurgeDecommitEmptyPages); - - CHECK_PAGE_IN_CORE(ptr - kPointerOffset, false); - CHECK_PAGE_IN_CORE(bigPtr - kPointerOffset, false); -} - -// Tests that we prefer to allocate into a non-empty partition page over an -// empty one. This is an important aspect of minimizing memory usage for some -// allocation sizes, particularly larger ones. -TEST_F(PartitionAllocTest, PreferActiveOverEmpty) { - size_t size = (kSystemPageSize * 2) - kExtraAllocSize; - // Allocate 3 full slot spans worth of 8192-byte allocations. - // Each slot span for this size is 16384 bytes, or 1 partition page and 2 - // slots. - void* ptr1 = generic_allocator.root()->Alloc(size, type_name); - void* ptr2 = generic_allocator.root()->Alloc(size, type_name); - void* ptr3 = generic_allocator.root()->Alloc(size, type_name); - void* ptr4 = generic_allocator.root()->Alloc(size, type_name); - void* ptr5 = generic_allocator.root()->Alloc(size, type_name); - void* ptr6 = generic_allocator.root()->Alloc(size, type_name); - - PartitionPage* page1 = - PartitionPage::FromPointer(PartitionCookieFreePointerAdjust(ptr1)); - PartitionPage* page2 = - PartitionPage::FromPointer(PartitionCookieFreePointerAdjust(ptr3)); - PartitionPage* page3 = - PartitionPage::FromPointer(PartitionCookieFreePointerAdjust(ptr6)); - EXPECT_NE(page1, page2); - EXPECT_NE(page2, page3); - PartitionBucket* bucket = page1->bucket; - EXPECT_EQ(page3, bucket->active_pages_head); - - // Free up the 2nd slot in each slot span. - // This leaves the active list containing 3 pages, each with 1 used and 1 - // free slot. The active page will be the one containing ptr1. - generic_allocator.root()->Free(ptr6); - generic_allocator.root()->Free(ptr4); - generic_allocator.root()->Free(ptr2); - EXPECT_EQ(page1, bucket->active_pages_head); - - // Empty the middle page in the active list. - generic_allocator.root()->Free(ptr3); - EXPECT_EQ(page1, bucket->active_pages_head); - - // Empty the the first page in the active list -- also the current page. - generic_allocator.root()->Free(ptr1); - - // A good choice here is to re-fill the third page since the first two are - // empty. We used to fail that. - void* ptr7 = generic_allocator.root()->Alloc(size, type_name); - EXPECT_EQ(ptr6, ptr7); - EXPECT_EQ(page3, bucket->active_pages_head); - - generic_allocator.root()->Free(ptr5); - generic_allocator.root()->Free(ptr7); -} - -// Tests the API to purge discardable memory. -TEST_F(PartitionAllocTest, PurgeDiscardable) { - // Free the second of two 4096 byte allocations and then purge. - { - void* ptr1 = generic_allocator.root()->Alloc( - kSystemPageSize - kExtraAllocSize, type_name); - char* ptr2 = reinterpret_cast<char*>(generic_allocator.root()->Alloc( - kSystemPageSize - kExtraAllocSize, type_name)); - generic_allocator.root()->Free(ptr2); - PartitionPage* page = - PartitionPage::FromPointer(PartitionCookieFreePointerAdjust(ptr1)); - EXPECT_EQ(2u, page->num_unprovisioned_slots); - { - MockPartitionStatsDumper dumper; - generic_allocator.root()->DumpStats("mock_generic_allocator", - false /* detailed dump */, &dumper); - EXPECT_TRUE(dumper.IsMemoryAllocationRecorded()); - - const PartitionBucketMemoryStats* stats = - dumper.GetBucketStats(kSystemPageSize); - EXPECT_TRUE(stats); - EXPECT_TRUE(stats->is_valid); - EXPECT_EQ(0u, stats->decommittable_bytes); - EXPECT_EQ(kSystemPageSize, stats->discardable_bytes); - EXPECT_EQ(kSystemPageSize, stats->active_bytes); - EXPECT_EQ(2 * kSystemPageSize, stats->resident_bytes); - } - CHECK_PAGE_IN_CORE(ptr2 - kPointerOffset, true); - generic_allocator.root()->PurgeMemory( - PartitionPurgeDiscardUnusedSystemPages); - CHECK_PAGE_IN_CORE(ptr2 - kPointerOffset, false); - EXPECT_EQ(3u, page->num_unprovisioned_slots); - - generic_allocator.root()->Free(ptr1); - } - // Free the first of two 4096 byte allocations and then purge. - { - char* ptr1 = reinterpret_cast<char*>(generic_allocator.root()->Alloc( - kSystemPageSize - kExtraAllocSize, type_name)); - void* ptr2 = generic_allocator.root()->Alloc( - kSystemPageSize - kExtraAllocSize, type_name); - generic_allocator.root()->Free(ptr1); - { - MockPartitionStatsDumper dumper; - generic_allocator.root()->DumpStats("mock_generic_allocator", - false /* detailed dump */, &dumper); - EXPECT_TRUE(dumper.IsMemoryAllocationRecorded()); - - const PartitionBucketMemoryStats* stats = - dumper.GetBucketStats(kSystemPageSize); - EXPECT_TRUE(stats); - EXPECT_TRUE(stats->is_valid); - EXPECT_EQ(0u, stats->decommittable_bytes); -#if defined(OS_WIN) - EXPECT_EQ(0u, stats->discardable_bytes); -#else - EXPECT_EQ(kSystemPageSize, stats->discardable_bytes); -#endif - EXPECT_EQ(kSystemPageSize, stats->active_bytes); - EXPECT_EQ(2 * kSystemPageSize, stats->resident_bytes); - } - CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset, true); - generic_allocator.root()->PurgeMemory( - PartitionPurgeDiscardUnusedSystemPages); - CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset, false); - - generic_allocator.root()->Free(ptr2); - } - { - constexpr size_t requested_size = 2.25 * kSystemPageSize; - char* ptr1 = reinterpret_cast<char*>(generic_allocator.root()->Alloc( - requested_size - kExtraAllocSize, type_name)); - void* ptr2 = generic_allocator.root()->Alloc( - requested_size - kExtraAllocSize, type_name); - void* ptr3 = generic_allocator.root()->Alloc( - requested_size - kExtraAllocSize, type_name); - void* ptr4 = generic_allocator.root()->Alloc( - requested_size - kExtraAllocSize, type_name); - memset(ptr1, 'A', requested_size - kExtraAllocSize); - memset(ptr2, 'A', requested_size - kExtraAllocSize); - generic_allocator.root()->Free(ptr2); - generic_allocator.root()->Free(ptr1); - { - MockPartitionStatsDumper dumper; - generic_allocator.root()->DumpStats("mock_generic_allocator", - false /* detailed dump */, &dumper); - EXPECT_TRUE(dumper.IsMemoryAllocationRecorded()); - - const PartitionBucketMemoryStats* stats = - dumper.GetBucketStats(requested_size); - EXPECT_TRUE(stats); - EXPECT_TRUE(stats->is_valid); - EXPECT_EQ(0u, stats->decommittable_bytes); - EXPECT_EQ(2 * kSystemPageSize, stats->discardable_bytes); - EXPECT_EQ(requested_size * 2, stats->active_bytes); - EXPECT_EQ(9 * kSystemPageSize, stats->resident_bytes); - } - CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset, true); - CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset + kSystemPageSize, true); - CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset + (kSystemPageSize * 2), true); - CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset + (kSystemPageSize * 3), true); - CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset + (kSystemPageSize * 4), true); - generic_allocator.root()->PurgeMemory( - PartitionPurgeDiscardUnusedSystemPages); - CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset, true); - CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset + kSystemPageSize, false); - CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset + (kSystemPageSize * 2), true); - CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset + (kSystemPageSize * 3), false); - CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset + (kSystemPageSize * 4), true); - - generic_allocator.root()->Free(ptr3); - generic_allocator.root()->Free(ptr4); - } - -// When kSystemPageSize = 16384 (as on _MIPS_ARCH_LOONGSON), 64 * -// kSystemPageSize (see the #else branch below) caused this test to OOM. -// Therefore, for systems with 16 KiB pages, use 32 * kSystemPageSize. -// -// TODO(palmer): Refactor this to branch on page size instead of architecture, -// for clarity of purpose and for applicability to more architectures. -#if defined(_MIPS_ARCH_LOONGSON) - { - char* ptr1 = reinterpret_cast<char*>(PartitionAllocGeneric( - generic_allocator.root(), (32 * kSystemPageSize) - kExtraAllocSize, - type_name)); - memset(ptr1, 'A', (32 * kSystemPageSize) - kExtraAllocSize); - PartitionFreeGeneric(generic_allocator.root(), ptr1); - ptr1 = reinterpret_cast<char*>(PartitionAllocGeneric( - generic_allocator.root(), (31 * kSystemPageSize) - kExtraAllocSize, - type_name)); - { - MockPartitionStatsDumper dumper; - PartitionDumpStatsGeneric(generic_allocator.root(), - "mock_generic_allocator", - false /* detailed dump */, &dumper); - EXPECT_TRUE(dumper.IsMemoryAllocationRecorded()); - - const PartitionBucketMemoryStats* stats = - dumper.GetBucketStats(32 * kSystemPageSize); - EXPECT_TRUE(stats); - EXPECT_TRUE(stats->is_valid); - EXPECT_EQ(0u, stats->decommittable_bytes); - EXPECT_EQ(kSystemPageSize, stats->discardable_bytes); - EXPECT_EQ(31 * kSystemPageSize, stats->active_bytes); - EXPECT_EQ(32 * kSystemPageSize, stats->resident_bytes); - } - CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 30), true); - CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 31), true); - PartitionPurgeMemoryGeneric(generic_allocator.root(), - PartitionPurgeDiscardUnusedSystemPages); - CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 30), true); - CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 31), false); - - PartitionFreeGeneric(generic_allocator.root(), ptr1); - } -#else - { - char* ptr1 = reinterpret_cast<char*>(generic_allocator.root()->Alloc( - (64 * kSystemPageSize) - kExtraAllocSize, type_name)); - memset(ptr1, 'A', (64 * kSystemPageSize) - kExtraAllocSize); - generic_allocator.root()->Free(ptr1); - ptr1 = reinterpret_cast<char*>(generic_allocator.root()->Alloc( - (61 * kSystemPageSize) - kExtraAllocSize, type_name)); - { - MockPartitionStatsDumper dumper; - generic_allocator.root()->DumpStats("mock_generic_allocator", - false /* detailed dump */, &dumper); - EXPECT_TRUE(dumper.IsMemoryAllocationRecorded()); - - const PartitionBucketMemoryStats* stats = - dumper.GetBucketStats(64 * kSystemPageSize); - EXPECT_TRUE(stats); - EXPECT_TRUE(stats->is_valid); - EXPECT_EQ(0u, stats->decommittable_bytes); - EXPECT_EQ(3 * kSystemPageSize, stats->discardable_bytes); - EXPECT_EQ(61 * kSystemPageSize, stats->active_bytes); - EXPECT_EQ(64 * kSystemPageSize, stats->resident_bytes); - } - CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset + (kSystemPageSize * 60), true); - CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset + (kSystemPageSize * 61), true); - CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset + (kSystemPageSize * 62), true); - CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset + (kSystemPageSize * 63), true); - generic_allocator.root()->PurgeMemory( - PartitionPurgeDiscardUnusedSystemPages); - CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset + (kSystemPageSize * 60), true); - CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset + (kSystemPageSize * 61), false); - CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset + (kSystemPageSize * 62), false); - CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset + (kSystemPageSize * 63), false); - - generic_allocator.root()->Free(ptr1); - } -#endif - // This sub-test tests truncation of the provisioned slots in a trickier - // case where the freelist is rewritten. - generic_allocator.root()->PurgeMemory(PartitionPurgeDecommitEmptyPages); - { - char* ptr1 = reinterpret_cast<char*>(generic_allocator.root()->Alloc( - kSystemPageSize - kExtraAllocSize, type_name)); - void* ptr2 = generic_allocator.root()->Alloc( - kSystemPageSize - kExtraAllocSize, type_name); - void* ptr3 = generic_allocator.root()->Alloc( - kSystemPageSize - kExtraAllocSize, type_name); - void* ptr4 = generic_allocator.root()->Alloc( - kSystemPageSize - kExtraAllocSize, type_name); - ptr1[0] = 'A'; - ptr1[kSystemPageSize] = 'A'; - ptr1[kSystemPageSize * 2] = 'A'; - ptr1[kSystemPageSize * 3] = 'A'; - PartitionPage* page = - PartitionPage::FromPointer(PartitionCookieFreePointerAdjust(ptr1)); - generic_allocator.root()->Free(ptr2); - generic_allocator.root()->Free(ptr4); - generic_allocator.root()->Free(ptr1); - EXPECT_EQ(0u, page->num_unprovisioned_slots); - - { - MockPartitionStatsDumper dumper; - generic_allocator.root()->DumpStats("mock_generic_allocator", - false /* detailed dump */, &dumper); - EXPECT_TRUE(dumper.IsMemoryAllocationRecorded()); - - const PartitionBucketMemoryStats* stats = - dumper.GetBucketStats(kSystemPageSize); - EXPECT_TRUE(stats); - EXPECT_TRUE(stats->is_valid); - EXPECT_EQ(0u, stats->decommittable_bytes); -#if defined(OS_WIN) - EXPECT_EQ(kSystemPageSize, stats->discardable_bytes); -#else - EXPECT_EQ(2 * kSystemPageSize, stats->discardable_bytes); -#endif - EXPECT_EQ(kSystemPageSize, stats->active_bytes); - EXPECT_EQ(4 * kSystemPageSize, stats->resident_bytes); - } - CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset, true); - CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset + kSystemPageSize, true); - CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset + (kSystemPageSize * 2), true); - CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset + (kSystemPageSize * 3), true); - generic_allocator.root()->PurgeMemory( - PartitionPurgeDiscardUnusedSystemPages); - EXPECT_EQ(1u, page->num_unprovisioned_slots); - CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset, true); - CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset + kSystemPageSize, false); - CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset + (kSystemPageSize * 2), true); - CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset + (kSystemPageSize * 3), false); - - // Let's check we didn't brick the freelist. - void* ptr1b = generic_allocator.root()->Alloc( - kSystemPageSize - kExtraAllocSize, type_name); - EXPECT_EQ(ptr1, ptr1b); - void* ptr2b = generic_allocator.root()->Alloc( - kSystemPageSize - kExtraAllocSize, type_name); - EXPECT_EQ(ptr2, ptr2b); - EXPECT_FALSE(page->freelist_head); - - generic_allocator.root()->Free(ptr1); - generic_allocator.root()->Free(ptr2); - generic_allocator.root()->Free(ptr3); - } - // This sub-test is similar, but tests a double-truncation. - generic_allocator.root()->PurgeMemory(PartitionPurgeDecommitEmptyPages); - { - char* ptr1 = reinterpret_cast<char*>(generic_allocator.root()->Alloc( - kSystemPageSize - kExtraAllocSize, type_name)); - void* ptr2 = generic_allocator.root()->Alloc( - kSystemPageSize - kExtraAllocSize, type_name); - void* ptr3 = generic_allocator.root()->Alloc( - kSystemPageSize - kExtraAllocSize, type_name); - void* ptr4 = generic_allocator.root()->Alloc( - kSystemPageSize - kExtraAllocSize, type_name); - ptr1[0] = 'A'; - ptr1[kSystemPageSize] = 'A'; - ptr1[kSystemPageSize * 2] = 'A'; - ptr1[kSystemPageSize * 3] = 'A'; - PartitionPage* page = - PartitionPage::FromPointer(PartitionCookieFreePointerAdjust(ptr1)); - generic_allocator.root()->Free(ptr4); - generic_allocator.root()->Free(ptr3); - EXPECT_EQ(0u, page->num_unprovisioned_slots); - - { - MockPartitionStatsDumper dumper; - generic_allocator.root()->DumpStats("mock_generic_allocator", - false /* detailed dump */, &dumper); - EXPECT_TRUE(dumper.IsMemoryAllocationRecorded()); - - const PartitionBucketMemoryStats* stats = - dumper.GetBucketStats(kSystemPageSize); - EXPECT_TRUE(stats); - EXPECT_TRUE(stats->is_valid); - EXPECT_EQ(0u, stats->decommittable_bytes); - EXPECT_EQ(2 * kSystemPageSize, stats->discardable_bytes); - EXPECT_EQ(2 * kSystemPageSize, stats->active_bytes); - EXPECT_EQ(4 * kSystemPageSize, stats->resident_bytes); - } - CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset, true); - CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset + kSystemPageSize, true); - CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset + (kSystemPageSize * 2), true); - CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset + (kSystemPageSize * 3), true); - generic_allocator.root()->PurgeMemory( - PartitionPurgeDiscardUnusedSystemPages); - EXPECT_EQ(2u, page->num_unprovisioned_slots); - CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset, true); - CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset + kSystemPageSize, true); - CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset + (kSystemPageSize * 2), false); - CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset + (kSystemPageSize * 3), false); - - EXPECT_FALSE(page->freelist_head); - - generic_allocator.root()->Free(ptr1); - generic_allocator.root()->Free(ptr2); - } -} - -TEST_F(PartitionAllocTest, ReallocMovesCookies) { - // Resize so as to be sure to hit a "resize in place" case, and ensure that - // use of the entire result is compatible with the debug mode's cookies, even - // when the bucket size is large enough to span more than one partition page - // and we can track the "raw" size. See https://crbug.com/709271 - static constexpr size_t kSize = - base::kMaxSystemPagesPerSlotSpan * base::kSystemPageSize; - void* ptr = generic_allocator.root()->Alloc(kSize + 1, type_name); - EXPECT_TRUE(ptr); - - memset(ptr, 0xbd, kSize + 1); - ptr = generic_allocator.root()->Realloc(ptr, kSize + 2, type_name); - EXPECT_TRUE(ptr); - - memset(ptr, 0xbd, kSize + 2); - generic_allocator.root()->Free(ptr); -} - -TEST_F(PartitionAllocTest, SmallReallocDoesNotMoveTrailingCookie) { - // For crbug.com/781473 - static constexpr size_t kSize = 264; - void* ptr = generic_allocator.root()->Alloc(kSize, type_name); - EXPECT_TRUE(ptr); - - ptr = generic_allocator.root()->Realloc(ptr, kSize + 16, type_name); - EXPECT_TRUE(ptr); - - generic_allocator.root()->Free(ptr); -} - -} // namespace internal -} // namespace base - -#endif // !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
diff --git a/base/allocator/partition_allocator/spin_lock_unittest.cc b/base/allocator/partition_allocator/spin_lock_unittest.cc deleted file mode 100644 index 6a1fd6b..0000000 --- a/base/allocator/partition_allocator/spin_lock_unittest.cc +++ /dev/null
@@ -1,61 +0,0 @@ -// 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/allocator/partition_allocator/spin_lock.h" - -#include <memory> -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/threading/thread.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -static const size_t kBufferSize = 16; - -static subtle::SpinLock g_lock; - -static void FillBuffer(volatile char* buffer, char fill_pattern) { - for (size_t i = 0; i < kBufferSize; ++i) - buffer[i] = fill_pattern; -} - -static void ChangeAndCheckBuffer(volatile char* buffer) { - FillBuffer(buffer, '\0'); - int total = 0; - for (size_t i = 0; i < kBufferSize; ++i) - total += buffer[i]; - - EXPECT_EQ(0, total); - - // This will mess with the other thread's calculation if we accidentally get - // concurrency. - FillBuffer(buffer, '!'); -} - -static void ThreadMain(volatile char* buffer) { - for (int i = 0; i < 500000; ++i) { - subtle::SpinLock::Guard guard(g_lock); - ChangeAndCheckBuffer(buffer); - } -} - -TEST(SpinLockTest, Torture) { - char shared_buffer[kBufferSize]; - - Thread thread1("thread1"); - Thread thread2("thread2"); - - thread1.StartAndWaitForTesting(); - thread2.StartAndWaitForTesting(); - - thread1.task_runner()->PostTask( - FROM_HERE, - BindOnce(&ThreadMain, Unretained(static_cast<char*>(shared_buffer)))); - thread2.task_runner()->PostTask( - FROM_HERE, - BindOnce(&ThreadMain, Unretained(static_cast<char*>(shared_buffer)))); -} - -} // namespace base
diff --git a/base/allocator/tcmalloc_unittest.cc b/base/allocator/tcmalloc_unittest.cc deleted file mode 100644 index 4b5b664..0000000 --- a/base/allocator/tcmalloc_unittest.cc +++ /dev/null
@@ -1,235 +0,0 @@ -// 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 <stddef.h> -#include <stdio.h> - -#include "base/compiler_specific.h" -#include "base/logging.h" -#include "base/process/process_metrics.h" -#include "base/sys_info.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(USE_TCMALLOC) -namespace { - -using std::min; - -#ifdef NDEBUG -// We wrap malloc and free in noinline functions to ensure that we test the real -// implementation of the allocator. Otherwise, the compiler may specifically -// recognize the calls to malloc and free in our tests and optimize them away. -NOINLINE void* TCMallocDoMallocForTest(size_t size) { - return malloc(size); -} - -NOINLINE void TCMallocDoFreeForTest(void* ptr) { - free(ptr); -} -#endif - -// Fill a buffer of the specified size with a predetermined pattern -static void Fill(unsigned char* buffer, int n) { - for (int i = 0; i < n; i++) { - buffer[i] = (i & 0xff); - } -} - -// Check that the specified buffer has the predetermined pattern -// generated by Fill() -static bool Valid(unsigned char* buffer, int n) { - for (int i = 0; i < n; i++) { - if (buffer[i] != (i & 0xff)) { - return false; - } - } - return true; -} - -// Return the next interesting size/delta to check. Returns -1 if no more. -static int NextSize(int size) { - if (size < 100) - return size + 1; - - if (size < 100000) { - // Find next power of two - int power = 1; - while (power < size) - power <<= 1; - - // Yield (power-1, power, power+1) - if (size < power - 1) - return power - 1; - - if (size == power - 1) - return power; - - CHECK_EQ(size, power); - return power + 1; - } else { - return -1; - } -} - -static void TestCalloc(size_t n, size_t s, bool ok) { - char* p = reinterpret_cast<char*>(calloc(n, s)); - if (!ok) { - EXPECT_EQ(nullptr, p) << "calloc(n, s) should not succeed"; - } else { - EXPECT_NE(reinterpret_cast<void*>(NULL), p) - << "calloc(n, s) should succeed"; - for (size_t i = 0; i < n * s; i++) { - EXPECT_EQ('\0', p[i]); - } - free(p); - } -} - -bool IsLowMemoryDevice() { - return base::SysInfo::AmountOfPhysicalMemory() <= 256LL * 1024 * 1024; -} - -} // namespace - -TEST(TCMallocTest, Malloc) { - // Try allocating data with a bunch of alignments and sizes - for (int size = 1; size < 1048576; size *= 2) { - unsigned char* ptr = reinterpret_cast<unsigned char*>(malloc(size)); - // Should be 2 byte aligned - EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & 1); - Fill(ptr, size); - EXPECT_TRUE(Valid(ptr, size)); - free(ptr); - } -} - -TEST(TCMallocTest, Calloc) { - TestCalloc(0, 0, true); - TestCalloc(0, 1, true); - TestCalloc(1, 1, true); - TestCalloc(1 << 10, 0, true); - TestCalloc(1 << 20, 0, true); - TestCalloc(0, 1 << 10, true); - TestCalloc(0, 1 << 20, true); - TestCalloc(1 << 20, 2, true); - TestCalloc(2, 1 << 20, true); - TestCalloc(1000, 1000, true); -} - -#ifdef NDEBUG -// This makes sure that reallocing a small number of bytes in either -// direction doesn't cause us to allocate new memory. Tcmalloc in debug mode -// does not follow this. -TEST(TCMallocTest, ReallocSmallDelta) { - int start_sizes[] = {100, 1000, 10000, 100000}; - int deltas[] = {1, -2, 4, -8, 16, -32, 64, -128}; - - for (unsigned s = 0; s < sizeof(start_sizes) / sizeof(*start_sizes); ++s) { - void* p = malloc(start_sizes[s]); - ASSERT_TRUE(p); - // The larger the start-size, the larger the non-reallocing delta. - for (unsigned d = 0; d < s * 2; ++d) { - void* new_p = realloc(p, start_sizes[s] + deltas[d]); - ASSERT_EQ(p, new_p); // realloc should not allocate new memory - } - // Test again, but this time reallocing smaller first. - for (unsigned d = 0; d < s * 2; ++d) { - void* new_p = realloc(p, start_sizes[s] - deltas[d]); - ASSERT_EQ(p, new_p); // realloc should not allocate new memory - } - free(p); - } -} -#endif - -TEST(TCMallocTest, Realloc) { - for (int src_size = 0; src_size >= 0; src_size = NextSize(src_size)) { - for (int dst_size = 0; dst_size >= 0; dst_size = NextSize(dst_size)) { - unsigned char* src = reinterpret_cast<unsigned char*>(malloc(src_size)); - Fill(src, src_size); - unsigned char* dst = - reinterpret_cast<unsigned char*>(realloc(src, dst_size)); - EXPECT_TRUE(Valid(dst, min(src_size, dst_size))); - Fill(dst, dst_size); - EXPECT_TRUE(Valid(dst, dst_size)); - if (dst != nullptr) - free(dst); - } - } - - // The logic below tries to allocate kNumEntries * 9000 ~= 130 MB of memory. - // This would cause the test to crash on low memory devices with no VM - // overcommit (e.g., chromecast). - if (IsLowMemoryDevice()) - return; - - // Now make sure realloc works correctly even when we overflow the - // packed cache, so some entries are evicted from the cache. - // The cache has 2^12 entries, keyed by page number. - const int kNumEntries = 1 << 14; - int** p = reinterpret_cast<int**>(malloc(sizeof(*p) * kNumEntries)); - int sum = 0; - for (int i = 0; i < kNumEntries; i++) { - // no page size is likely to be bigger than 8192? - p[i] = reinterpret_cast<int*>(malloc(8192)); - p[i][1000] = i; // use memory deep in the heart of p - } - for (int i = 0; i < kNumEntries; i++) { - p[i] = reinterpret_cast<int*>(realloc(p[i], 9000)); - } - for (int i = 0; i < kNumEntries; i++) { - sum += p[i][1000]; - free(p[i]); - } - EXPECT_EQ(kNumEntries / 2 * (kNumEntries - 1), sum); // assume kNE is even - free(p); -} - -#ifdef NDEBUG -TEST(TCMallocFreeTest, BadPointerInFirstPageOfTheLargeObject) { - const size_t kPageSize = base::GetPageSize(); - char* p = - reinterpret_cast<char*>(TCMallocDoMallocForTest(10 * kPageSize + 1)); - for (unsigned offset = 1; offset < kPageSize; offset <<= 1) { - ASSERT_DEATH(TCMallocDoFreeForTest(p + offset), - "Pointer is not pointing to the start of a span"); - } - TCMallocDoFreeForTest(p); -} - -// TODO(ssid): Fix flakiness and enable the test, crbug.com/571549. -TEST(TCMallocFreeTest, DISABLED_BadPageAlignedPointerInsideLargeObject) { - const size_t kPageSize = base::GetPageSize(); - const size_t kMaxSize = 10 * kPageSize; - char* p = reinterpret_cast<char*>(TCMallocDoMallocForTest(kMaxSize + 1)); - - for (unsigned offset = kPageSize; offset < kMaxSize; offset += kPageSize) { - // Only the first and last page of a span are in heap map. So for others - // tcmalloc will give a general error of invalid pointer. - ASSERT_DEATH(TCMallocDoFreeForTest(p + offset), ""); - } - ASSERT_DEATH(TCMallocDoFreeForTest(p + kMaxSize), - "Pointer is not pointing to the start of a span"); - TCMallocDoFreeForTest(p); -} - -TEST(TCMallocFreeTest, DoubleFreeLargeObject) { - const size_t kMaxSize = 10 * base::GetPageSize(); - char* p = reinterpret_cast<char*>(TCMallocDoMallocForTest(kMaxSize + 1)); - ASSERT_DEATH(TCMallocDoFreeForTest(p); TCMallocDoFreeForTest(p), - "Object was not in-use"); -} - -TEST(TCMallocFreeTest, DoubleFreeSmallObject) { - const size_t kPageSize = base::GetPageSize(); - for (size_t size = 1; size <= kPageSize; size <<= 1) { - char* p = reinterpret_cast<char*>(TCMallocDoMallocForTest(size)); - ASSERT_DEATH(TCMallocDoFreeForTest(p); TCMallocDoFreeForTest(p), - "Circular loop in list detected"); - } -} -#endif // NDEBUG - -#endif
diff --git a/base/at_exit_unittest.cc b/base/at_exit_unittest.cc deleted file mode 100644 index 3de061f..0000000 --- a/base/at_exit_unittest.cc +++ /dev/null
@@ -1,87 +0,0 @@ -// 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/at_exit.h" -#include "base/bind.h" - -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -int g_test_counter_1 = 0; -int g_test_counter_2 = 0; - -void IncrementTestCounter1(void* unused) { - ++g_test_counter_1; -} - -void IncrementTestCounter2(void* unused) { - ++g_test_counter_2; -} - -void ZeroTestCounters() { - g_test_counter_1 = 0; - g_test_counter_2 = 0; -} - -void ExpectCounter1IsZero(void* unused) { - EXPECT_EQ(0, g_test_counter_1); -} - -void ExpectParamIsNull(void* param) { - EXPECT_EQ(nullptr, param); -} - -void ExpectParamIsCounter(void* param) { - EXPECT_EQ(&g_test_counter_1, param); -} - -} // namespace - -class AtExitTest : public testing::Test { - private: - // Don't test the global AtExitManager, because asking it to process its - // AtExit callbacks can ruin the global state that other tests may depend on. - base::ShadowingAtExitManager exit_manager_; -}; - -TEST_F(AtExitTest, Basic) { - ZeroTestCounters(); - base::AtExitManager::RegisterCallback(&IncrementTestCounter1, nullptr); - base::AtExitManager::RegisterCallback(&IncrementTestCounter2, nullptr); - base::AtExitManager::RegisterCallback(&IncrementTestCounter1, nullptr); - - EXPECT_EQ(0, g_test_counter_1); - EXPECT_EQ(0, g_test_counter_2); - base::AtExitManager::ProcessCallbacksNow(); - EXPECT_EQ(2, g_test_counter_1); - EXPECT_EQ(1, g_test_counter_2); -} - -TEST_F(AtExitTest, LIFOOrder) { - ZeroTestCounters(); - base::AtExitManager::RegisterCallback(&IncrementTestCounter1, nullptr); - base::AtExitManager::RegisterCallback(&ExpectCounter1IsZero, nullptr); - base::AtExitManager::RegisterCallback(&IncrementTestCounter2, nullptr); - - EXPECT_EQ(0, g_test_counter_1); - EXPECT_EQ(0, g_test_counter_2); - base::AtExitManager::ProcessCallbacksNow(); - EXPECT_EQ(1, g_test_counter_1); - EXPECT_EQ(1, g_test_counter_2); -} - -TEST_F(AtExitTest, Param) { - base::AtExitManager::RegisterCallback(&ExpectParamIsNull, nullptr); - base::AtExitManager::RegisterCallback(&ExpectParamIsCounter, - &g_test_counter_1); - base::AtExitManager::ProcessCallbacksNow(); -} - -TEST_F(AtExitTest, Task) { - ZeroTestCounters(); - base::AtExitManager::RegisterTask(base::Bind(&ExpectParamIsCounter, - &g_test_counter_1)); - base::AtExitManager::ProcessCallbacksNow(); -}
diff --git a/base/atomicops_unittest.cc b/base/atomicops_unittest.cc deleted file mode 100644 index 7298609..0000000 --- a/base/atomicops_unittest.cc +++ /dev/null
@@ -1,248 +0,0 @@ -// 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/atomicops.h" - -#include <stdint.h> -#include <string.h> - -#include "testing/gtest/include/gtest/gtest.h" - -template <class AtomicType> -static void TestAtomicIncrement() { - // For now, we just test single threaded execution - - // use a guard value to make sure the NoBarrier_AtomicIncrement doesn't go - // outside the expected address bounds. This is in particular to - // test that some future change to the asm code doesn't cause the - // 32-bit NoBarrier_AtomicIncrement doesn't do the wrong thing on 64-bit - // machines. - struct { - AtomicType prev_word; - AtomicType count; - AtomicType next_word; - } s; - - AtomicType prev_word_value, next_word_value; - memset(&prev_word_value, 0xFF, sizeof(AtomicType)); - memset(&next_word_value, 0xEE, sizeof(AtomicType)); - - s.prev_word = prev_word_value; - s.count = 0; - s.next_word = next_word_value; - - EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 1), 1); - EXPECT_EQ(s.count, 1); - EXPECT_EQ(s.prev_word, prev_word_value); - EXPECT_EQ(s.next_word, next_word_value); - - EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 2), 3); - EXPECT_EQ(s.count, 3); - EXPECT_EQ(s.prev_word, prev_word_value); - EXPECT_EQ(s.next_word, next_word_value); - - EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 3), 6); - EXPECT_EQ(s.count, 6); - EXPECT_EQ(s.prev_word, prev_word_value); - EXPECT_EQ(s.next_word, next_word_value); - - EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -3), 3); - EXPECT_EQ(s.count, 3); - EXPECT_EQ(s.prev_word, prev_word_value); - EXPECT_EQ(s.next_word, next_word_value); - - EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -2), 1); - EXPECT_EQ(s.count, 1); - EXPECT_EQ(s.prev_word, prev_word_value); - EXPECT_EQ(s.next_word, next_word_value); - - EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -1), 0); - EXPECT_EQ(s.count, 0); - EXPECT_EQ(s.prev_word, prev_word_value); - EXPECT_EQ(s.next_word, next_word_value); - - EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -1), -1); - EXPECT_EQ(s.count, -1); - EXPECT_EQ(s.prev_word, prev_word_value); - EXPECT_EQ(s.next_word, next_word_value); - - EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -4), -5); - EXPECT_EQ(s.count, -5); - EXPECT_EQ(s.prev_word, prev_word_value); - EXPECT_EQ(s.next_word, next_word_value); - - EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 5), 0); - EXPECT_EQ(s.count, 0); - EXPECT_EQ(s.prev_word, prev_word_value); - EXPECT_EQ(s.next_word, next_word_value); -} - - -#define NUM_BITS(T) (sizeof(T) * 8) - - -template <class AtomicType> -static void TestCompareAndSwap() { - AtomicType value = 0; - AtomicType prev = base::subtle::NoBarrier_CompareAndSwap(&value, 0, 1); - EXPECT_EQ(1, value); - EXPECT_EQ(0, prev); - - // Verify that CAS will *not* change "value" if it doesn't match the - // expected number. CAS will always return the actual value of the - // variable from before any change. - AtomicType fail = base::subtle::NoBarrier_CompareAndSwap(&value, 0, 2); - EXPECT_EQ(1, value); - EXPECT_EQ(1, fail); - - // Use test value that has non-zero bits in both halves, more for testing - // 64-bit implementation on 32-bit platforms. - const AtomicType k_test_val = (static_cast<uint64_t>(1) << - (NUM_BITS(AtomicType) - 2)) + 11; - value = k_test_val; - prev = base::subtle::NoBarrier_CompareAndSwap(&value, 0, 5); - EXPECT_EQ(k_test_val, value); - EXPECT_EQ(k_test_val, prev); - - value = k_test_val; - prev = base::subtle::NoBarrier_CompareAndSwap(&value, k_test_val, 5); - EXPECT_EQ(5, value); - EXPECT_EQ(k_test_val, prev); -} - - -template <class AtomicType> -static void TestAtomicExchange() { - AtomicType value = 0; - AtomicType new_value = base::subtle::NoBarrier_AtomicExchange(&value, 1); - EXPECT_EQ(1, value); - EXPECT_EQ(0, new_value); - - // Use test value that has non-zero bits in both halves, more for testing - // 64-bit implementation on 32-bit platforms. - const AtomicType k_test_val = (static_cast<uint64_t>(1) << - (NUM_BITS(AtomicType) - 2)) + 11; - value = k_test_val; - new_value = base::subtle::NoBarrier_AtomicExchange(&value, k_test_val); - EXPECT_EQ(k_test_val, value); - EXPECT_EQ(k_test_val, new_value); - - value = k_test_val; - new_value = base::subtle::NoBarrier_AtomicExchange(&value, 5); - EXPECT_EQ(5, value); - EXPECT_EQ(k_test_val, new_value); -} - - -template <class AtomicType> -static void TestAtomicIncrementBounds() { - // Test at rollover boundary between int_max and int_min - AtomicType test_val = (static_cast<uint64_t>(1) << - (NUM_BITS(AtomicType) - 1)); - AtomicType value = -1 ^ test_val; - AtomicType new_value = base::subtle::NoBarrier_AtomicIncrement(&value, 1); - EXPECT_EQ(test_val, value); - EXPECT_EQ(value, new_value); - - base::subtle::NoBarrier_AtomicIncrement(&value, -1); - EXPECT_EQ(-1 ^ test_val, value); - - // Test at 32-bit boundary for 64-bit atomic type. - test_val = static_cast<uint64_t>(1) << (NUM_BITS(AtomicType) / 2); - value = test_val - 1; - new_value = base::subtle::NoBarrier_AtomicIncrement(&value, 1); - EXPECT_EQ(test_val, value); - EXPECT_EQ(value, new_value); - - base::subtle::NoBarrier_AtomicIncrement(&value, -1); - EXPECT_EQ(test_val - 1, value); -} - -// Return an AtomicType with the value 0xa5a5a5.. -template <class AtomicType> -static AtomicType TestFillValue() { - AtomicType val = 0; - memset(&val, 0xa5, sizeof(AtomicType)); - return val; -} - -// This is a simple sanity check that values are correct. Not testing -// atomicity -template <class AtomicType> -static void TestStore() { - const AtomicType kVal1 = TestFillValue<AtomicType>(); - const AtomicType kVal2 = static_cast<AtomicType>(-1); - - AtomicType value; - - base::subtle::NoBarrier_Store(&value, kVal1); - EXPECT_EQ(kVal1, value); - base::subtle::NoBarrier_Store(&value, kVal2); - EXPECT_EQ(kVal2, value); - - base::subtle::Acquire_Store(&value, kVal1); - EXPECT_EQ(kVal1, value); - base::subtle::Acquire_Store(&value, kVal2); - EXPECT_EQ(kVal2, value); - - base::subtle::Release_Store(&value, kVal1); - EXPECT_EQ(kVal1, value); - base::subtle::Release_Store(&value, kVal2); - EXPECT_EQ(kVal2, value); -} - -// This is a simple sanity check that values are correct. Not testing -// atomicity -template <class AtomicType> -static void TestLoad() { - const AtomicType kVal1 = TestFillValue<AtomicType>(); - const AtomicType kVal2 = static_cast<AtomicType>(-1); - - AtomicType value; - - value = kVal1; - EXPECT_EQ(kVal1, base::subtle::NoBarrier_Load(&value)); - value = kVal2; - EXPECT_EQ(kVal2, base::subtle::NoBarrier_Load(&value)); - - value = kVal1; - EXPECT_EQ(kVal1, base::subtle::Acquire_Load(&value)); - value = kVal2; - EXPECT_EQ(kVal2, base::subtle::Acquire_Load(&value)); - - value = kVal1; - EXPECT_EQ(kVal1, base::subtle::Release_Load(&value)); - value = kVal2; - EXPECT_EQ(kVal2, base::subtle::Release_Load(&value)); -} - -TEST(AtomicOpsTest, Inc) { - TestAtomicIncrement<base::subtle::Atomic32>(); - TestAtomicIncrement<base::subtle::AtomicWord>(); -} - -TEST(AtomicOpsTest, CompareAndSwap) { - TestCompareAndSwap<base::subtle::Atomic32>(); - TestCompareAndSwap<base::subtle::AtomicWord>(); -} - -TEST(AtomicOpsTest, Exchange) { - TestAtomicExchange<base::subtle::Atomic32>(); - TestAtomicExchange<base::subtle::AtomicWord>(); -} - -TEST(AtomicOpsTest, IncrementBounds) { - TestAtomicIncrementBounds<base::subtle::Atomic32>(); - TestAtomicIncrementBounds<base::subtle::AtomicWord>(); -} - -TEST(AtomicOpsTest, Store) { - TestStore<base::subtle::Atomic32>(); - TestStore<base::subtle::AtomicWord>(); -} - -TEST(AtomicOpsTest, Load) { - TestLoad<base::subtle::Atomic32>(); - TestLoad<base::subtle::AtomicWord>(); -}
diff --git a/base/barrier_closure_unittest.cc b/base/barrier_closure_unittest.cc deleted file mode 100644 index 819f6ac..0000000 --- a/base/barrier_closure_unittest.cc +++ /dev/null
@@ -1,81 +0,0 @@ -// 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/barrier_closure.h" - -#include "base/bind.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -void Increment(int* count) { (*count)++; } - -TEST(BarrierClosureTest, RunImmediatelyForZeroClosures) { - int count = 0; - base::Closure done_closure(base::Bind(&Increment, base::Unretained(&count))); - - base::Closure barrier_closure = base::BarrierClosure(0, done_closure); - EXPECT_EQ(1, count); -} - -TEST(BarrierClosureTest, RunAfterNumClosures) { - int count = 0; - base::Closure done_closure(base::Bind(&Increment, base::Unretained(&count))); - - base::Closure barrier_closure = base::BarrierClosure(2, done_closure); - EXPECT_EQ(0, count); - - barrier_closure.Run(); - EXPECT_EQ(0, count); - - barrier_closure.Run(); - EXPECT_EQ(1, count); -} - -class DestructionIndicator { - public: - // Sets |*destructed| to true in destructor. - DestructionIndicator(bool* destructed) : destructed_(destructed) { - *destructed_ = false; - } - - ~DestructionIndicator() { *destructed_ = true; } - - void DoNothing() {} - - private: - bool* destructed_; -}; - -TEST(BarrierClosureTest, ReleasesDoneClosureWhenDone) { - bool done_destructed = false; - base::Closure barrier_closure = base::BarrierClosure( - 1, - base::BindOnce(&DestructionIndicator::DoNothing, - base::Owned(new DestructionIndicator(&done_destructed)))); - EXPECT_FALSE(done_destructed); - barrier_closure.Run(); - EXPECT_TRUE(done_destructed); -} - -void ResetBarrierClosure(base::Closure* closure) { - *closure = base::Closure(); -} - -// Tests a case when |done_closure| resets a |barrier_closure|. -// |barrier_closure| is a Closure holding the |done_closure|. |done_closure| -// holds a pointer back to the |barrier_closure|. When |barrier_closure| is -// Run() it calls ResetBarrierClosure() which erases the |barrier_closure| while -// still inside of its Run(). The Run() implementation (in base::BarrierClosure) -// must not try use itself after executing ResetBarrierClosure() or this test -// would crash inside Run(). -TEST(BarrierClosureTest, KeepingClosureAliveUntilDone) { - base::Closure barrier_closure; - base::Closure done_closure = - base::Bind(ResetBarrierClosure, &barrier_closure); - barrier_closure = base::BarrierClosure(1, done_closure); - barrier_closure.Run(); -} - -} // namespace
diff --git a/base/base64_unittest.cc b/base/base64_unittest.cc deleted file mode 100644 index 91651f4..0000000 --- a/base/base64_unittest.cc +++ /dev/null
@@ -1,40 +0,0 @@ -// 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/base64.h" - -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(Base64Test, Basic) { - const std::string kText = "hello world"; - const std::string kBase64Text = "aGVsbG8gd29ybGQ="; - - std::string encoded; - std::string decoded; - bool ok; - - Base64Encode(kText, &encoded); - EXPECT_EQ(kBase64Text, encoded); - - ok = Base64Decode(encoded, &decoded); - EXPECT_TRUE(ok); - EXPECT_EQ(kText, decoded); -} - -TEST(Base64Test, InPlace) { - const std::string kText = "hello world"; - const std::string kBase64Text = "aGVsbG8gd29ybGQ="; - std::string text(kText); - - Base64Encode(text, &text); - EXPECT_EQ(kBase64Text, text); - - bool ok = Base64Decode(text, &text); - EXPECT_TRUE(ok); - EXPECT_EQ(text, kText); -} - -} // namespace base
diff --git a/base/base64url_unittest.cc b/base/base64url_unittest.cc deleted file mode 100644 index 45aa4a8..0000000 --- a/base/base64url_unittest.cc +++ /dev/null
@@ -1,115 +0,0 @@ -// 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/base64url.h" - -#include "base/macros.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -TEST(Base64UrlTest, EncodeIncludePaddingPolicy) { - std::string output; - Base64UrlEncode("hello?world", Base64UrlEncodePolicy::INCLUDE_PADDING, - &output); - - // Base64 version: aGVsbG8/d29ybGQ= - EXPECT_EQ("aGVsbG8_d29ybGQ=", output); - - // Test for behavior for very short and empty strings. - Base64UrlEncode("??", Base64UrlEncodePolicy::INCLUDE_PADDING, &output); - EXPECT_EQ("Pz8=", output); - - Base64UrlEncode("", Base64UrlEncodePolicy::INCLUDE_PADDING, &output); - EXPECT_EQ("", output); -} - -TEST(Base64UrlTest, EncodeOmitPaddingPolicy) { - std::string output; - Base64UrlEncode("hello?world", Base64UrlEncodePolicy::OMIT_PADDING, &output); - - // base64 version: aGVsbG8/d29ybGQ= - EXPECT_EQ("aGVsbG8_d29ybGQ", output); - - // Test for behavior for very short and empty strings. - Base64UrlEncode("??", Base64UrlEncodePolicy::OMIT_PADDING, &output); - EXPECT_EQ("Pz8", output); - - Base64UrlEncode("", Base64UrlEncodePolicy::OMIT_PADDING, &output); - EXPECT_EQ("", output); -} - -TEST(Base64UrlTest, DecodeRequirePaddingPolicy) { - std::string output; - ASSERT_TRUE(Base64UrlDecode("aGVsbG8_d29ybGQ=", - Base64UrlDecodePolicy::REQUIRE_PADDING, &output)); - - EXPECT_EQ("hello?world", output); - - ASSERT_FALSE(Base64UrlDecode( - "aGVsbG8_d29ybGQ", Base64UrlDecodePolicy::REQUIRE_PADDING, &output)); - - // Test for behavior for very short and empty strings. - ASSERT_TRUE( - Base64UrlDecode("Pz8=", Base64UrlDecodePolicy::REQUIRE_PADDING, &output)); - EXPECT_EQ("??", output); - - ASSERT_TRUE( - Base64UrlDecode("", Base64UrlDecodePolicy::REQUIRE_PADDING, &output)); - EXPECT_EQ("", output); -} - -TEST(Base64UrlTest, DecodeIgnorePaddingPolicy) { - std::string output; - ASSERT_TRUE(Base64UrlDecode("aGVsbG8_d29ybGQ", - Base64UrlDecodePolicy::IGNORE_PADDING, &output)); - - EXPECT_EQ("hello?world", output); - - // Including the padding is accepted as well. - ASSERT_TRUE(Base64UrlDecode("aGVsbG8_d29ybGQ=", - Base64UrlDecodePolicy::IGNORE_PADDING, &output)); - - EXPECT_EQ("hello?world", output); -} - -TEST(Base64UrlTest, DecodeDisallowPaddingPolicy) { - std::string output; - ASSERT_FALSE(Base64UrlDecode( - "aGVsbG8_d29ybGQ=", Base64UrlDecodePolicy::DISALLOW_PADDING, &output)); - - // The policy will allow the input when padding has been omitted. - ASSERT_TRUE(Base64UrlDecode( - "aGVsbG8_d29ybGQ", Base64UrlDecodePolicy::DISALLOW_PADDING, &output)); - - EXPECT_EQ("hello?world", output); -} - -TEST(Base64UrlTest, DecodeDisallowsBase64Alphabet) { - std::string output; - - // The "/" character is part of the conventional base64 alphabet, but has been - // substituted with "_" in the base64url alphabet. - ASSERT_FALSE(Base64UrlDecode( - "aGVsbG8/d29ybGQ=", Base64UrlDecodePolicy::REQUIRE_PADDING, &output)); -} - -TEST(Base64UrlTest, DecodeDisallowsPaddingOnly) { - std::string output; - - ASSERT_FALSE(Base64UrlDecode( - "=", Base64UrlDecodePolicy::IGNORE_PADDING, &output)); - ASSERT_FALSE(Base64UrlDecode( - "==", Base64UrlDecodePolicy::IGNORE_PADDING, &output)); - ASSERT_FALSE(Base64UrlDecode( - "===", Base64UrlDecodePolicy::IGNORE_PADDING, &output)); - ASSERT_FALSE(Base64UrlDecode( - "====", Base64UrlDecodePolicy::IGNORE_PADDING, &output)); -} - -} // namespace - -} // namespace base
diff --git a/base/big_endian_unittest.cc b/base/big_endian_unittest.cc deleted file mode 100644 index 4e1e7ce..0000000 --- a/base/big_endian_unittest.cc +++ /dev/null
@@ -1,116 +0,0 @@ -// 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/big_endian.h" - -#include <stdint.h> - -#include "base/strings/string_piece.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(BigEndianReaderTest, ReadsValues) { - char data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, - 0x1A, 0x2B, 0x3C, 0x4D, 0x5E }; - char buf[2]; - uint8_t u8; - uint16_t u16; - uint32_t u32; - uint64_t u64; - base::StringPiece piece; - BigEndianReader reader(data, sizeof(data)); - - EXPECT_TRUE(reader.Skip(2)); - EXPECT_EQ(data + 2, reader.ptr()); - EXPECT_EQ(reader.remaining(), static_cast<int>(sizeof(data)) - 2); - EXPECT_TRUE(reader.ReadBytes(buf, sizeof(buf))); - EXPECT_EQ(0x2, buf[0]); - EXPECT_EQ(0x3, buf[1]); - EXPECT_TRUE(reader.ReadU8(&u8)); - EXPECT_EQ(0x4, u8); - EXPECT_TRUE(reader.ReadU16(&u16)); - EXPECT_EQ(0x0506, u16); - EXPECT_TRUE(reader.ReadU32(&u32)); - EXPECT_EQ(0x0708090Au, u32); - EXPECT_TRUE(reader.ReadU64(&u64)); - EXPECT_EQ(0x0B0C0D0E0F1A2B3Cllu, u64); - base::StringPiece expected(reader.ptr(), 2); - EXPECT_TRUE(reader.ReadPiece(&piece, 2)); - EXPECT_EQ(2u, piece.size()); - EXPECT_EQ(expected.data(), piece.data()); -} - -TEST(BigEndianReaderTest, RespectsLength) { - char data[8]; - char buf[2]; - uint8_t u8; - uint16_t u16; - uint32_t u32; - uint64_t u64; - base::StringPiece piece; - BigEndianReader reader(data, sizeof(data)); - // 8 left - EXPECT_FALSE(reader.Skip(9)); - EXPECT_TRUE(reader.Skip(1)); - // 7 left - EXPECT_FALSE(reader.ReadU64(&u64)); - EXPECT_TRUE(reader.Skip(4)); - // 3 left - EXPECT_FALSE(reader.ReadU32(&u32)); - EXPECT_FALSE(reader.ReadPiece(&piece, 4)); - EXPECT_TRUE(reader.Skip(2)); - // 1 left - EXPECT_FALSE(reader.ReadU16(&u16)); - EXPECT_FALSE(reader.ReadBytes(buf, 2)); - EXPECT_TRUE(reader.Skip(1)); - // 0 left - EXPECT_FALSE(reader.ReadU8(&u8)); - EXPECT_EQ(0, reader.remaining()); -} - -TEST(BigEndianWriterTest, WritesValues) { - char expected[] = { 0, 0, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, - 0xF, 0x1A, 0x2B, 0x3C }; - char data[sizeof(expected)]; - char buf[] = { 0x2, 0x3 }; - memset(data, 0, sizeof(data)); - BigEndianWriter writer(data, sizeof(data)); - - EXPECT_TRUE(writer.Skip(2)); - EXPECT_TRUE(writer.WriteBytes(buf, sizeof(buf))); - EXPECT_TRUE(writer.WriteU8(0x4)); - EXPECT_TRUE(writer.WriteU16(0x0506)); - EXPECT_TRUE(writer.WriteU32(0x0708090A)); - EXPECT_TRUE(writer.WriteU64(0x0B0C0D0E0F1A2B3Cllu)); - EXPECT_EQ(0, memcmp(expected, data, sizeof(expected))); -} - -TEST(BigEndianWriterTest, RespectsLength) { - char data[8]; - char buf[2]; - uint8_t u8 = 0; - uint16_t u16 = 0; - uint32_t u32 = 0; - uint64_t u64 = 0; - BigEndianWriter writer(data, sizeof(data)); - // 8 left - EXPECT_FALSE(writer.Skip(9)); - EXPECT_TRUE(writer.Skip(1)); - // 7 left - EXPECT_FALSE(writer.WriteU64(u64)); - EXPECT_TRUE(writer.Skip(4)); - // 3 left - EXPECT_FALSE(writer.WriteU32(u32)); - EXPECT_TRUE(writer.Skip(2)); - // 1 left - EXPECT_FALSE(writer.WriteU16(u16)); - EXPECT_FALSE(writer.WriteBytes(buf, 2)); - EXPECT_TRUE(writer.Skip(1)); - // 0 left - EXPECT_FALSE(writer.WriteU8(u8)); - EXPECT_EQ(0, writer.remaining()); -} - -} // namespace base
diff --git a/base/bind_unittest.cc b/base/bind_unittest.cc deleted file mode 100644 index 5162a08..0000000 --- a/base/bind_unittest.cc +++ /dev/null
@@ -1,1496 +0,0 @@ -// 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 <memory> -#include <utility> -#include <vector> - -#include "base/callback.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "base/test/bind_test_util.h" -#include "base/test/gtest_util.h" -#include "build_config.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using ::testing::_; -using ::testing::Mock; -using ::testing::ByMove; -using ::testing::Return; -using ::testing::StrictMock; - -namespace base { -namespace { - -class IncompleteType; - -class NoRef { - public: - NoRef() = default; - - MOCK_METHOD0(VoidMethod0, void()); - MOCK_CONST_METHOD0(VoidConstMethod0, void()); - - MOCK_METHOD0(IntMethod0, int()); - MOCK_CONST_METHOD0(IntConstMethod0, int()); - - MOCK_METHOD1(VoidMethodWithIntArg, void(int)); - MOCK_METHOD0(UniquePtrMethod0, std::unique_ptr<int>()); - - private: - // Particularly important in this test to ensure no copies are made. - DISALLOW_COPY_AND_ASSIGN(NoRef); -}; - -class HasRef : public NoRef { - public: - HasRef() = default; - - MOCK_CONST_METHOD0(AddRef, void()); - MOCK_CONST_METHOD0(Release, bool()); - - private: - // Particularly important in this test to ensure no copies are made. - DISALLOW_COPY_AND_ASSIGN(HasRef); -}; - -class HasRefPrivateDtor : public HasRef { - private: - ~HasRefPrivateDtor() = default; -}; - -static const int kParentValue = 1; -static const int kChildValue = 2; - -class Parent { - public: - void AddRef() const {} - void Release() const {} - virtual void VirtualSet() { value = kParentValue; } - void NonVirtualSet() { value = kParentValue; } - int value; -}; - -class Child : public Parent { - public: - void VirtualSet() override { value = kChildValue; } - void NonVirtualSet() { value = kChildValue; } -}; - -class NoRefParent { - public: - virtual void VirtualSet() { value = kParentValue; } - void NonVirtualSet() { value = kParentValue; } - int value; -}; - -class NoRefChild : public NoRefParent { - void VirtualSet() override { value = kChildValue; } - void NonVirtualSet() { value = kChildValue; } -}; - -// Used for probing the number of copies and moves that occur if a type must be -// coerced during argument forwarding in the Run() methods. -struct DerivedCopyMoveCounter { - DerivedCopyMoveCounter(int* copies, - int* assigns, - int* move_constructs, - int* move_assigns) - : copies_(copies), - assigns_(assigns), - move_constructs_(move_constructs), - move_assigns_(move_assigns) {} - int* copies_; - int* assigns_; - int* move_constructs_; - int* move_assigns_; -}; - -// Used for probing the number of copies and moves in an argument. -class CopyMoveCounter { - public: - CopyMoveCounter(int* copies, - int* assigns, - int* move_constructs, - int* move_assigns) - : copies_(copies), - assigns_(assigns), - move_constructs_(move_constructs), - move_assigns_(move_assigns) {} - - CopyMoveCounter(const CopyMoveCounter& other) - : copies_(other.copies_), - assigns_(other.assigns_), - move_constructs_(other.move_constructs_), - move_assigns_(other.move_assigns_) { - (*copies_)++; - } - - CopyMoveCounter(CopyMoveCounter&& other) - : copies_(other.copies_), - assigns_(other.assigns_), - move_constructs_(other.move_constructs_), - move_assigns_(other.move_assigns_) { - (*move_constructs_)++; - } - - // Probing for copies from coercion. - explicit CopyMoveCounter(const DerivedCopyMoveCounter& other) - : copies_(other.copies_), - assigns_(other.assigns_), - move_constructs_(other.move_constructs_), - move_assigns_(other.move_assigns_) { - (*copies_)++; - } - - // Probing for moves from coercion. - explicit CopyMoveCounter(DerivedCopyMoveCounter&& other) - : copies_(other.copies_), - assigns_(other.assigns_), - move_constructs_(other.move_constructs_), - move_assigns_(other.move_assigns_) { - (*move_constructs_)++; - } - - const CopyMoveCounter& operator=(const CopyMoveCounter& rhs) { - copies_ = rhs.copies_; - assigns_ = rhs.assigns_; - move_constructs_ = rhs.move_constructs_; - move_assigns_ = rhs.move_assigns_; - - (*assigns_)++; - - return *this; - } - - const CopyMoveCounter& operator=(CopyMoveCounter&& rhs) { - copies_ = rhs.copies_; - assigns_ = rhs.assigns_; - move_constructs_ = rhs.move_constructs_; - move_assigns_ = rhs.move_assigns_; - - (*move_assigns_)++; - - return *this; - } - - int copies() const { - return *copies_; - } - - private: - int* copies_; - int* assigns_; - int* move_constructs_; - int* move_assigns_; -}; - -// Used for probing the number of copies in an argument. The instance is a -// copyable and non-movable type. -class CopyCounter { - public: - CopyCounter(int* copies, int* assigns) - : counter_(copies, assigns, nullptr, nullptr) {} - CopyCounter(const CopyCounter& other) = default; - CopyCounter& operator=(const CopyCounter& other) = default; - - explicit CopyCounter(const DerivedCopyMoveCounter& other) : counter_(other) {} - - int copies() const { return counter_.copies(); } - - private: - CopyMoveCounter counter_; -}; - -// Used for probing the number of moves in an argument. The instance is a -// non-copyable and movable type. -class MoveCounter { - public: - MoveCounter(int* move_constructs, int* move_assigns) - : counter_(nullptr, nullptr, move_constructs, move_assigns) {} - MoveCounter(MoveCounter&& other) : counter_(std::move(other.counter_)) {} - MoveCounter& operator=(MoveCounter&& other) { - counter_ = std::move(other.counter_); - return *this; - } - - explicit MoveCounter(DerivedCopyMoveCounter&& other) - : counter_(std::move(other)) {} - - private: - CopyMoveCounter counter_; -}; - -class DeleteCounter { - public: - explicit DeleteCounter(int* deletes) - : deletes_(deletes) { - } - - ~DeleteCounter() { - (*deletes_)++; - } - - void VoidMethod0() {} - - private: - int* deletes_; -}; - -template <typename T> -T PassThru(T scoper) { - return scoper; -} - -// Some test functions that we can Bind to. -template <typename T> -T PolymorphicIdentity(T t) { - return t; -} - -template <typename... Ts> -struct VoidPolymorphic { - static void Run(Ts... t) {} -}; - -int Identity(int n) { - return n; -} - -int ArrayGet(const int array[], int n) { - return array[n]; -} - -int Sum(int a, int b, int c, int d, int e, int f) { - return a + b + c + d + e + f; -} - -const char* CStringIdentity(const char* s) { - return s; -} - -int GetCopies(const CopyMoveCounter& counter) { - return counter.copies(); -} - -int UnwrapNoRefParent(NoRefParent p) { - return p.value; -} - -int UnwrapNoRefParentPtr(NoRefParent* p) { - return p->value; -} - -int UnwrapNoRefParentConstRef(const NoRefParent& p) { - return p.value; -} - -void RefArgSet(int &n) { - n = 2; -} - -void PtrArgSet(int *n) { - *n = 2; -} - -int FunctionWithWeakFirstParam(WeakPtr<NoRef> o, int n) { - return n; -} - -int FunctionWithScopedRefptrFirstParam(const scoped_refptr<HasRef>& o, int n) { - return n; -} - -void TakesACallback(const Closure& callback) { - callback.Run(); -} - -int Noexcept() noexcept { - return 42; -} - -class BindTest : public ::testing::Test { - public: - BindTest() { - const_has_ref_ptr_ = &has_ref_; - const_no_ref_ptr_ = &no_ref_; - static_func_mock_ptr = &static_func_mock_; - } - - ~BindTest() override = default; - - static void VoidFunc0() { - static_func_mock_ptr->VoidMethod0(); - } - - static int IntFunc0() { return static_func_mock_ptr->IntMethod0(); } - int NoexceptMethod() noexcept { return 42; } - int ConstNoexceptMethod() const noexcept { return 42; } - - protected: - StrictMock<NoRef> no_ref_; - StrictMock<HasRef> has_ref_; - const HasRef* const_has_ref_ptr_; - const NoRef* const_no_ref_ptr_; - StrictMock<NoRef> static_func_mock_; - - // Used by the static functions to perform expectations. - static StrictMock<NoRef>* static_func_mock_ptr; - - private: - DISALLOW_COPY_AND_ASSIGN(BindTest); -}; - -StrictMock<NoRef>* BindTest::static_func_mock_ptr; -StrictMock<NoRef>* g_func_mock_ptr; - -void VoidFunc0() { - g_func_mock_ptr->VoidMethod0(); -} - -int IntFunc0() { - return g_func_mock_ptr->IntMethod0(); -} - -TEST_F(BindTest, BasicTest) { - Callback<int(int, int, int)> cb = Bind(&Sum, 32, 16, 8); - EXPECT_EQ(92, cb.Run(13, 12, 11)); - - Callback<int(int, int, int, int, int, int)> c1 = Bind(&Sum); - EXPECT_EQ(69, c1.Run(14, 13, 12, 11, 10, 9)); - - Callback<int(int, int, int)> c2 = Bind(c1, 32, 16, 8); - EXPECT_EQ(86, c2.Run(11, 10, 9)); - - Callback<int()> c3 = Bind(c2, 4, 2, 1); - EXPECT_EQ(63, c3.Run()); -} - -// Test that currying the rvalue result of another Bind() works correctly. -// - rvalue should be usable as argument to Bind(). -// - multiple runs of resulting Callback remain valid. -TEST_F(BindTest, CurryingRvalueResultOfBind) { - int n = 0; - RepeatingClosure cb = BindRepeating(&TakesACallback, - BindRepeating(&PtrArgSet, &n)); - - // If we implement Bind() such that the return value has auto_ptr-like - // semantics, the second call here will fail because ownership of - // the internal BindState<> would have been transfered to a *temporary* - // constructon of a Callback object on the first call. - cb.Run(); - EXPECT_EQ(2, n); - - n = 0; - cb.Run(); - EXPECT_EQ(2, n); -} - -TEST_F(BindTest, RepeatingCallbackBasicTest) { - RepeatingCallback<int(int)> c0 = BindRepeating(&Sum, 1, 2, 4, 8, 16); - - // RepeatingCallback can run via a lvalue-reference. - EXPECT_EQ(63, c0.Run(32)); - - // It is valid to call a RepeatingCallback more than once. - EXPECT_EQ(54, c0.Run(23)); - - // BindRepeating can handle a RepeatingCallback as the target functor. - RepeatingCallback<int()> c1 = BindRepeating(c0, 11); - - // RepeatingCallback can run via a rvalue-reference. - EXPECT_EQ(42, std::move(c1).Run()); - - // BindRepeating can handle a rvalue-reference of RepeatingCallback. - EXPECT_EQ(32, BindRepeating(std::move(c0), 1).Run()); -} - -TEST_F(BindTest, OnceCallbackBasicTest) { - OnceCallback<int(int)> c0 = BindOnce(&Sum, 1, 2, 4, 8, 16); - - // OnceCallback can run via a rvalue-reference. - EXPECT_EQ(63, std::move(c0).Run(32)); - - // After running via the rvalue-reference, the value of the OnceCallback - // is undefined. The implementation simply clears the instance after the - // invocation. - EXPECT_TRUE(c0.is_null()); - - c0 = BindOnce(&Sum, 2, 3, 5, 7, 11); - - // BindOnce can handle a rvalue-reference of OnceCallback as the target - // functor. - OnceCallback<int()> c1 = BindOnce(std::move(c0), 13); - EXPECT_EQ(41, std::move(c1).Run()); - - RepeatingCallback<int(int)> c2 = BindRepeating(&Sum, 2, 3, 5, 7, 11); - EXPECT_EQ(41, BindOnce(c2, 13).Run()); -} - -// IgnoreResult adapter test. -// - Function with return value. -// - Method with return value. -// - Const Method with return. -// - Method with return value bound to WeakPtr<>. -// - Const Method with return bound to WeakPtr<>. -TEST_F(BindTest, IgnoreResultForRepeating) { - EXPECT_CALL(static_func_mock_, IntMethod0()).WillOnce(Return(1337)); - EXPECT_CALL(has_ref_, AddRef()).Times(2); - EXPECT_CALL(has_ref_, Release()).Times(2); - EXPECT_CALL(has_ref_, IntMethod0()).WillOnce(Return(10)); - EXPECT_CALL(has_ref_, IntConstMethod0()).WillOnce(Return(11)); - EXPECT_CALL(no_ref_, IntMethod0()).WillOnce(Return(12)); - EXPECT_CALL(no_ref_, IntConstMethod0()).WillOnce(Return(13)); - - RepeatingClosure normal_func_cb = BindRepeating(IgnoreResult(&IntFunc0)); - normal_func_cb.Run(); - - RepeatingClosure non_void_method_cb = - BindRepeating(IgnoreResult(&HasRef::IntMethod0), &has_ref_); - non_void_method_cb.Run(); - - RepeatingClosure non_void_const_method_cb = - BindRepeating(IgnoreResult(&HasRef::IntConstMethod0), &has_ref_); - non_void_const_method_cb.Run(); - - WeakPtrFactory<NoRef> weak_factory(&no_ref_); - WeakPtrFactory<const NoRef> const_weak_factory(const_no_ref_ptr_); - - RepeatingClosure non_void_weak_method_cb = - BindRepeating(IgnoreResult(&NoRef::IntMethod0), - weak_factory.GetWeakPtr()); - non_void_weak_method_cb.Run(); - - RepeatingClosure non_void_weak_const_method_cb = - BindRepeating(IgnoreResult(&NoRef::IntConstMethod0), - weak_factory.GetWeakPtr()); - non_void_weak_const_method_cb.Run(); - - weak_factory.InvalidateWeakPtrs(); - non_void_weak_const_method_cb.Run(); - non_void_weak_method_cb.Run(); -} - -TEST_F(BindTest, IgnoreResultForOnce) { - EXPECT_CALL(static_func_mock_, IntMethod0()).WillOnce(Return(1337)); - EXPECT_CALL(has_ref_, AddRef()).Times(2); - EXPECT_CALL(has_ref_, Release()).Times(2); - EXPECT_CALL(has_ref_, IntMethod0()).WillOnce(Return(10)); - EXPECT_CALL(has_ref_, IntConstMethod0()).WillOnce(Return(11)); - - OnceClosure normal_func_cb = BindOnce(IgnoreResult(&IntFunc0)); - std::move(normal_func_cb).Run(); - - OnceClosure non_void_method_cb = - BindOnce(IgnoreResult(&HasRef::IntMethod0), &has_ref_); - std::move(non_void_method_cb).Run(); - - OnceClosure non_void_const_method_cb = - BindOnce(IgnoreResult(&HasRef::IntConstMethod0), &has_ref_); - std::move(non_void_const_method_cb).Run(); - - WeakPtrFactory<NoRef> weak_factory(&no_ref_); - WeakPtrFactory<const NoRef> const_weak_factory(const_no_ref_ptr_); - - OnceClosure non_void_weak_method_cb = - BindOnce(IgnoreResult(&NoRef::IntMethod0), - weak_factory.GetWeakPtr()); - OnceClosure non_void_weak_const_method_cb = - BindOnce(IgnoreResult(&NoRef::IntConstMethod0), - weak_factory.GetWeakPtr()); - - weak_factory.InvalidateWeakPtrs(); - std::move(non_void_weak_const_method_cb).Run(); - std::move(non_void_weak_method_cb).Run(); -} - -// Functions that take reference parameters. -// - Forced reference parameter type still stores a copy. -// - Forced const reference parameter type still stores a copy. -TEST_F(BindTest, ReferenceArgumentBindingForRepeating) { - int n = 1; - int& ref_n = n; - const int& const_ref_n = n; - - RepeatingCallback<int()> ref_copies_cb = BindRepeating(&Identity, ref_n); - EXPECT_EQ(n, ref_copies_cb.Run()); - n++; - EXPECT_EQ(n - 1, ref_copies_cb.Run()); - - RepeatingCallback<int()> const_ref_copies_cb = - BindRepeating(&Identity, const_ref_n); - EXPECT_EQ(n, const_ref_copies_cb.Run()); - n++; - EXPECT_EQ(n - 1, const_ref_copies_cb.Run()); -} - -TEST_F(BindTest, ReferenceArgumentBindingForOnce) { - int n = 1; - int& ref_n = n; - const int& const_ref_n = n; - - OnceCallback<int()> ref_copies_cb = BindOnce(&Identity, ref_n); - n++; - EXPECT_EQ(n - 1, std::move(ref_copies_cb).Run()); - - OnceCallback<int()> const_ref_copies_cb = - BindOnce(&Identity, const_ref_n); - n++; - EXPECT_EQ(n - 1, std::move(const_ref_copies_cb).Run()); -} - -// Check that we can pass in arrays and have them be stored as a pointer. -// - Array of values stores a pointer. -// - Array of const values stores a pointer. -TEST_F(BindTest, ArrayArgumentBindingForRepeating) { - int array[4] = {1, 1, 1, 1}; - const int (*const_array_ptr)[4] = &array; - - RepeatingCallback<int()> array_cb = BindRepeating(&ArrayGet, array, 1); - EXPECT_EQ(1, array_cb.Run()); - - RepeatingCallback<int()> const_array_cb = - BindRepeating(&ArrayGet, *const_array_ptr, 1); - EXPECT_EQ(1, const_array_cb.Run()); - - array[1] = 3; - EXPECT_EQ(3, array_cb.Run()); - EXPECT_EQ(3, const_array_cb.Run()); -} - -TEST_F(BindTest, ArrayArgumentBindingForOnce) { - int array[4] = {1, 1, 1, 1}; - const int (*const_array_ptr)[4] = &array; - - OnceCallback<int()> array_cb = BindOnce(&ArrayGet, array, 1); - OnceCallback<int()> const_array_cb = - BindOnce(&ArrayGet, *const_array_ptr, 1); - - array[1] = 3; - EXPECT_EQ(3, std::move(array_cb).Run()); - EXPECT_EQ(3, std::move(const_array_cb).Run()); -} - -// WeakPtr() support. -// - Method bound to WeakPtr<> to non-const object. -// - Const method bound to WeakPtr<> to non-const object. -// - Const method bound to WeakPtr<> to const object. -// - Normal Function with WeakPtr<> as P1 can have return type and is -// not canceled. -TEST_F(BindTest, WeakPtrForRepeating) { - EXPECT_CALL(no_ref_, VoidMethod0()); - EXPECT_CALL(no_ref_, VoidConstMethod0()).Times(2); - - WeakPtrFactory<NoRef> weak_factory(&no_ref_); - WeakPtrFactory<const NoRef> const_weak_factory(const_no_ref_ptr_); - - RepeatingClosure method_cb = - BindRepeating(&NoRef::VoidMethod0, weak_factory.GetWeakPtr()); - method_cb.Run(); - - RepeatingClosure const_method_cb = - BindRepeating(&NoRef::VoidConstMethod0, const_weak_factory.GetWeakPtr()); - const_method_cb.Run(); - - RepeatingClosure const_method_const_ptr_cb = - BindRepeating(&NoRef::VoidConstMethod0, const_weak_factory.GetWeakPtr()); - const_method_const_ptr_cb.Run(); - - RepeatingCallback<int(int)> normal_func_cb = - BindRepeating(&FunctionWithWeakFirstParam, weak_factory.GetWeakPtr()); - EXPECT_EQ(1, normal_func_cb.Run(1)); - - weak_factory.InvalidateWeakPtrs(); - const_weak_factory.InvalidateWeakPtrs(); - - method_cb.Run(); - const_method_cb.Run(); - const_method_const_ptr_cb.Run(); - - // Still runs even after the pointers are invalidated. - EXPECT_EQ(2, normal_func_cb.Run(2)); -} - -TEST_F(BindTest, WeakPtrForOnce) { - WeakPtrFactory<NoRef> weak_factory(&no_ref_); - WeakPtrFactory<const NoRef> const_weak_factory(const_no_ref_ptr_); - - OnceClosure method_cb = - BindOnce(&NoRef::VoidMethod0, weak_factory.GetWeakPtr()); - OnceClosure const_method_cb = - BindOnce(&NoRef::VoidConstMethod0, const_weak_factory.GetWeakPtr()); - OnceClosure const_method_const_ptr_cb = - BindOnce(&NoRef::VoidConstMethod0, const_weak_factory.GetWeakPtr()); - Callback<int(int)> normal_func_cb = - Bind(&FunctionWithWeakFirstParam, weak_factory.GetWeakPtr()); - - weak_factory.InvalidateWeakPtrs(); - const_weak_factory.InvalidateWeakPtrs(); - - std::move(method_cb).Run(); - std::move(const_method_cb).Run(); - std::move(const_method_const_ptr_cb).Run(); - - // Still runs even after the pointers are invalidated. - EXPECT_EQ(2, std::move(normal_func_cb).Run(2)); -} - -// ConstRef() wrapper support. -// - Binding w/o ConstRef takes a copy. -// - Binding a ConstRef takes a reference. -// - Binding ConstRef to a function ConstRef does not copy on invoke. -TEST_F(BindTest, ConstRefForRepeating) { - int n = 1; - - RepeatingCallback<int()> copy_cb = BindRepeating(&Identity, n); - RepeatingCallback<int()> const_ref_cb = BindRepeating(&Identity, ConstRef(n)); - EXPECT_EQ(n, copy_cb.Run()); - EXPECT_EQ(n, const_ref_cb.Run()); - n++; - EXPECT_EQ(n - 1, copy_cb.Run()); - EXPECT_EQ(n, const_ref_cb.Run()); - - int copies = 0; - int assigns = 0; - int move_constructs = 0; - int move_assigns = 0; - CopyMoveCounter counter(&copies, &assigns, &move_constructs, &move_assigns); - RepeatingCallback<int()> all_const_ref_cb = - BindRepeating(&GetCopies, ConstRef(counter)); - EXPECT_EQ(0, all_const_ref_cb.Run()); - EXPECT_EQ(0, copies); - EXPECT_EQ(0, assigns); - EXPECT_EQ(0, move_constructs); - EXPECT_EQ(0, move_assigns); -} - -TEST_F(BindTest, ConstRefForOnce) { - int n = 1; - - OnceCallback<int()> copy_cb = BindOnce(&Identity, n); - OnceCallback<int()> const_ref_cb = BindOnce(&Identity, ConstRef(n)); - n++; - EXPECT_EQ(n - 1, std::move(copy_cb).Run()); - EXPECT_EQ(n, std::move(const_ref_cb).Run()); - - int copies = 0; - int assigns = 0; - int move_constructs = 0; - int move_assigns = 0; - CopyMoveCounter counter(&copies, &assigns, &move_constructs, &move_assigns); - OnceCallback<int()> all_const_ref_cb = - BindOnce(&GetCopies, ConstRef(counter)); - EXPECT_EQ(0, std::move(all_const_ref_cb).Run()); - EXPECT_EQ(0, copies); - EXPECT_EQ(0, assigns); - EXPECT_EQ(0, move_constructs); - EXPECT_EQ(0, move_assigns); -} - -// Test Owned() support. -TEST_F(BindTest, OwnedForRepeating) { - int deletes = 0; - DeleteCounter* counter = new DeleteCounter(&deletes); - - // If we don't capture, delete happens on Callback destruction/reset. - // return the same value. - RepeatingCallback<DeleteCounter*()> no_capture_cb = - BindRepeating(&PolymorphicIdentity<DeleteCounter*>, Owned(counter)); - ASSERT_EQ(counter, no_capture_cb.Run()); - ASSERT_EQ(counter, no_capture_cb.Run()); - EXPECT_EQ(0, deletes); - no_capture_cb.Reset(); // This should trigger a delete. - EXPECT_EQ(1, deletes); - - deletes = 0; - counter = new DeleteCounter(&deletes); - RepeatingClosure own_object_cb = - BindRepeating(&DeleteCounter::VoidMethod0, Owned(counter)); - own_object_cb.Run(); - EXPECT_EQ(0, deletes); - own_object_cb.Reset(); - EXPECT_EQ(1, deletes); -} - -TEST_F(BindTest, OwnedForOnce) { - int deletes = 0; - DeleteCounter* counter = new DeleteCounter(&deletes); - - // If we don't capture, delete happens on Callback destruction/reset. - // return the same value. - OnceCallback<DeleteCounter*()> no_capture_cb = - BindOnce(&PolymorphicIdentity<DeleteCounter*>, Owned(counter)); - EXPECT_EQ(0, deletes); - no_capture_cb.Reset(); // This should trigger a delete. - EXPECT_EQ(1, deletes); - - deletes = 0; - counter = new DeleteCounter(&deletes); - OnceClosure own_object_cb = - BindOnce(&DeleteCounter::VoidMethod0, Owned(counter)); - EXPECT_EQ(0, deletes); - own_object_cb.Reset(); - EXPECT_EQ(1, deletes); -} - -template <typename T> -class BindVariantsTest : public ::testing::Test { -}; - -struct RepeatingTestConfig { - template <typename Signature> - using CallbackType = RepeatingCallback<Signature>; - using ClosureType = RepeatingClosure; - - template <typename F, typename... Args> - static CallbackType<MakeUnboundRunType<F, Args...>> - Bind(F&& f, Args&&... args) { - return BindRepeating(std::forward<F>(f), std::forward<Args>(args)...); - } -}; - -struct OnceTestConfig { - template <typename Signature> - using CallbackType = OnceCallback<Signature>; - using ClosureType = OnceClosure; - - template <typename F, typename... Args> - static CallbackType<MakeUnboundRunType<F, Args...>> - Bind(F&& f, Args&&... args) { - return BindOnce(std::forward<F>(f), std::forward<Args>(args)...); - } -}; - -using BindVariantsTestConfig = ::testing::Types< - RepeatingTestConfig, OnceTestConfig>; -TYPED_TEST_CASE(BindVariantsTest, BindVariantsTestConfig); - -template <typename TypeParam, typename Signature> -using CallbackType = typename TypeParam::template CallbackType<Signature>; - -// Function type support. -// - Normal function. -// - Normal function bound with non-refcounted first argument. -// - Method bound to non-const object. -// - Method bound to scoped_refptr. -// - Const method bound to non-const object. -// - Const method bound to const object. -// - Derived classes can be used with pointers to non-virtual base functions. -// - Derived classes can be used with pointers to virtual base functions (and -// preserve virtual dispatch). -TYPED_TEST(BindVariantsTest, FunctionTypeSupport) { - using ClosureType = typename TypeParam::ClosureType; - - StrictMock<HasRef> has_ref; - StrictMock<NoRef> no_ref; - StrictMock<NoRef> static_func_mock; - const HasRef* const_has_ref_ptr = &has_ref; - g_func_mock_ptr = &static_func_mock; - - EXPECT_CALL(static_func_mock, VoidMethod0()); - EXPECT_CALL(has_ref, AddRef()).Times(4); - EXPECT_CALL(has_ref, Release()).Times(4); - EXPECT_CALL(has_ref, VoidMethod0()).Times(2); - EXPECT_CALL(has_ref, VoidConstMethod0()).Times(2); - - ClosureType normal_cb = TypeParam::Bind(&VoidFunc0); - CallbackType<TypeParam, NoRef*()> normal_non_refcounted_cb = - TypeParam::Bind(&PolymorphicIdentity<NoRef*>, &no_ref); - std::move(normal_cb).Run(); - EXPECT_EQ(&no_ref, std::move(normal_non_refcounted_cb).Run()); - - ClosureType method_cb = TypeParam::Bind(&HasRef::VoidMethod0, &has_ref); - ClosureType method_refptr_cb = - TypeParam::Bind(&HasRef::VoidMethod0, WrapRefCounted(&has_ref)); - ClosureType const_method_nonconst_obj_cb = - TypeParam::Bind(&HasRef::VoidConstMethod0, &has_ref); - ClosureType const_method_const_obj_cb = - TypeParam::Bind(&HasRef::VoidConstMethod0, const_has_ref_ptr); - std::move(method_cb).Run(); - std::move(method_refptr_cb).Run(); - std::move(const_method_nonconst_obj_cb).Run(); - std::move(const_method_const_obj_cb).Run(); - - Child child; - child.value = 0; - ClosureType virtual_set_cb = TypeParam::Bind(&Parent::VirtualSet, &child); - std::move(virtual_set_cb).Run(); - EXPECT_EQ(kChildValue, child.value); - - child.value = 0; - ClosureType non_virtual_set_cb = - TypeParam::Bind(&Parent::NonVirtualSet, &child); - std::move(non_virtual_set_cb).Run(); - EXPECT_EQ(kParentValue, child.value); -} - -// Return value support. -// - Function with return value. -// - Method with return value. -// - Const method with return value. -// - Move-only return value. -TYPED_TEST(BindVariantsTest, ReturnValues) { - StrictMock<NoRef> static_func_mock; - StrictMock<HasRef> has_ref; - g_func_mock_ptr = &static_func_mock; - const HasRef* const_has_ref_ptr = &has_ref; - - EXPECT_CALL(static_func_mock, IntMethod0()).WillOnce(Return(1337)); - EXPECT_CALL(has_ref, AddRef()).Times(4); - EXPECT_CALL(has_ref, Release()).Times(4); - EXPECT_CALL(has_ref, IntMethod0()).WillOnce(Return(31337)); - EXPECT_CALL(has_ref, IntConstMethod0()) - .WillOnce(Return(41337)) - .WillOnce(Return(51337)); - EXPECT_CALL(has_ref, UniquePtrMethod0()) - .WillOnce(Return(ByMove(std::make_unique<int>(42)))); - - CallbackType<TypeParam, int()> normal_cb = TypeParam::Bind(&IntFunc0); - CallbackType<TypeParam, int()> method_cb = - TypeParam::Bind(&HasRef::IntMethod0, &has_ref); - CallbackType<TypeParam, int()> const_method_nonconst_obj_cb = - TypeParam::Bind(&HasRef::IntConstMethod0, &has_ref); - CallbackType<TypeParam, int()> const_method_const_obj_cb = - TypeParam::Bind(&HasRef::IntConstMethod0, const_has_ref_ptr); - CallbackType<TypeParam, std::unique_ptr<int>()> move_only_rv_cb = - TypeParam::Bind(&HasRef::UniquePtrMethod0, &has_ref); - EXPECT_EQ(1337, std::move(normal_cb).Run()); - EXPECT_EQ(31337, std::move(method_cb).Run()); - EXPECT_EQ(41337, std::move(const_method_nonconst_obj_cb).Run()); - EXPECT_EQ(51337, std::move(const_method_const_obj_cb).Run()); - EXPECT_EQ(42, *std::move(move_only_rv_cb).Run()); -} - -// Argument binding tests. -// - Argument binding to primitive. -// - Argument binding to primitive pointer. -// - Argument binding to a literal integer. -// - Argument binding to a literal string. -// - Argument binding with template function. -// - Argument binding to an object. -// - Argument binding to pointer to incomplete type. -// - Argument gets type converted. -// - Pointer argument gets converted. -// - Const Reference forces conversion. -TYPED_TEST(BindVariantsTest, ArgumentBinding) { - int n = 2; - - EXPECT_EQ(n, TypeParam::Bind(&Identity, n).Run()); - EXPECT_EQ(&n, TypeParam::Bind(&PolymorphicIdentity<int*>, &n).Run()); - EXPECT_EQ(3, TypeParam::Bind(&Identity, 3).Run()); - EXPECT_STREQ("hi", TypeParam::Bind(&CStringIdentity, "hi").Run()); - EXPECT_EQ(4, TypeParam::Bind(&PolymorphicIdentity<int>, 4).Run()); - - NoRefParent p; - p.value = 5; - EXPECT_EQ(5, TypeParam::Bind(&UnwrapNoRefParent, p).Run()); - - IncompleteType* incomplete_ptr = reinterpret_cast<IncompleteType*>(123); - EXPECT_EQ(incomplete_ptr, - TypeParam::Bind(&PolymorphicIdentity<IncompleteType*>, - incomplete_ptr).Run()); - - NoRefChild c; - c.value = 6; - EXPECT_EQ(6, TypeParam::Bind(&UnwrapNoRefParent, c).Run()); - - c.value = 7; - EXPECT_EQ(7, TypeParam::Bind(&UnwrapNoRefParentPtr, &c).Run()); - - c.value = 8; - EXPECT_EQ(8, TypeParam::Bind(&UnwrapNoRefParentConstRef, c).Run()); -} - -// Unbound argument type support tests. -// - Unbound value. -// - Unbound pointer. -// - Unbound reference. -// - Unbound const reference. -// - Unbound unsized array. -// - Unbound sized array. -// - Unbound array-of-arrays. -TYPED_TEST(BindVariantsTest, UnboundArgumentTypeSupport) { - CallbackType<TypeParam, void(int)> unbound_value_cb = - TypeParam::Bind(&VoidPolymorphic<int>::Run); - CallbackType<TypeParam, void(int*)> unbound_pointer_cb = - TypeParam::Bind(&VoidPolymorphic<int*>::Run); - CallbackType<TypeParam, void(int&)> unbound_ref_cb = - TypeParam::Bind(&VoidPolymorphic<int&>::Run); - CallbackType<TypeParam, void(const int&)> unbound_const_ref_cb = - TypeParam::Bind(&VoidPolymorphic<const int&>::Run); - CallbackType<TypeParam, void(int[])> unbound_unsized_array_cb = - TypeParam::Bind(&VoidPolymorphic<int[]>::Run); - CallbackType<TypeParam, void(int[2])> unbound_sized_array_cb = - TypeParam::Bind(&VoidPolymorphic<int[2]>::Run); - CallbackType<TypeParam, void(int[][2])> unbound_array_of_arrays_cb = - TypeParam::Bind(&VoidPolymorphic<int[][2]>::Run); - CallbackType<TypeParam, void(int&)> unbound_ref_with_bound_arg = - TypeParam::Bind(&VoidPolymorphic<int, int&>::Run, 1); -} - -// Function with unbound reference parameter. -// - Original parameter is modified by callback. -TYPED_TEST(BindVariantsTest, UnboundReferenceSupport) { - int n = 0; - CallbackType<TypeParam, void(int&)> unbound_ref_cb = - TypeParam::Bind(&RefArgSet); - std::move(unbound_ref_cb).Run(n); - EXPECT_EQ(2, n); -} - -// Unretained() wrapper support. -// - Method bound to Unretained() non-const object. -// - Const method bound to Unretained() non-const object. -// - Const method bound to Unretained() const object. -TYPED_TEST(BindVariantsTest, Unretained) { - StrictMock<NoRef> no_ref; - const NoRef* const_no_ref_ptr = &no_ref; - - EXPECT_CALL(no_ref, VoidMethod0()); - EXPECT_CALL(no_ref, VoidConstMethod0()).Times(2); - - TypeParam::Bind(&NoRef::VoidMethod0, Unretained(&no_ref)).Run(); - TypeParam::Bind(&NoRef::VoidConstMethod0, Unretained(&no_ref)).Run(); - TypeParam::Bind(&NoRef::VoidConstMethod0, Unretained(const_no_ref_ptr)).Run(); -} - -TYPED_TEST(BindVariantsTest, ScopedRefptr) { - StrictMock<HasRef> has_ref; - EXPECT_CALL(has_ref, AddRef()).Times(1); - EXPECT_CALL(has_ref, Release()).Times(1); - - const scoped_refptr<HasRef> refptr(&has_ref); - CallbackType<TypeParam, int()> scoped_refptr_const_ref_cb = - TypeParam::Bind(&FunctionWithScopedRefptrFirstParam, - base::ConstRef(refptr), 1); - EXPECT_EQ(1, std::move(scoped_refptr_const_ref_cb).Run()); -} - -TYPED_TEST(BindVariantsTest, UniquePtrReceiver) { - std::unique_ptr<StrictMock<NoRef>> no_ref(new StrictMock<NoRef>); - EXPECT_CALL(*no_ref, VoidMethod0()).Times(1); - TypeParam::Bind(&NoRef::VoidMethod0, std::move(no_ref)).Run(); -} - -// Tests for Passed() wrapper support: -// - Passed() can be constructed from a pointer to scoper. -// - Passed() can be constructed from a scoper rvalue. -// - Using Passed() gives Callback Ownership. -// - Ownership is transferred from Callback to callee on the first Run(). -// - Callback supports unbound arguments. -template <typename T> -class BindMoveOnlyTypeTest : public ::testing::Test { -}; - -struct CustomDeleter { - void operator()(DeleteCounter* c) { delete c; } -}; - -using MoveOnlyTypesToTest = - ::testing::Types<std::unique_ptr<DeleteCounter>, - std::unique_ptr<DeleteCounter, CustomDeleter>>; -TYPED_TEST_CASE(BindMoveOnlyTypeTest, MoveOnlyTypesToTest); - -TYPED_TEST(BindMoveOnlyTypeTest, PassedToBoundCallback) { - int deletes = 0; - - TypeParam ptr(new DeleteCounter(&deletes)); - Callback<TypeParam()> callback = Bind(&PassThru<TypeParam>, Passed(&ptr)); - EXPECT_FALSE(ptr.get()); - EXPECT_EQ(0, deletes); - - // If we never invoke the Callback, it retains ownership and deletes. - callback.Reset(); - EXPECT_EQ(1, deletes); -} - -TYPED_TEST(BindMoveOnlyTypeTest, PassedWithRvalue) { - int deletes = 0; - Callback<TypeParam()> callback = Bind( - &PassThru<TypeParam>, Passed(TypeParam(new DeleteCounter(&deletes)))); - EXPECT_EQ(0, deletes); - - // If we never invoke the Callback, it retains ownership and deletes. - callback.Reset(); - EXPECT_EQ(1, deletes); -} - -// Check that ownership can be transferred back out. -TYPED_TEST(BindMoveOnlyTypeTest, ReturnMoveOnlyType) { - int deletes = 0; - DeleteCounter* counter = new DeleteCounter(&deletes); - Callback<TypeParam()> callback = - Bind(&PassThru<TypeParam>, Passed(TypeParam(counter))); - TypeParam result = callback.Run(); - ASSERT_EQ(counter, result.get()); - EXPECT_EQ(0, deletes); - - // Resetting does not delete since ownership was transferred. - callback.Reset(); - EXPECT_EQ(0, deletes); - - // Ensure that we actually did get ownership. - result.reset(); - EXPECT_EQ(1, deletes); -} - -TYPED_TEST(BindMoveOnlyTypeTest, UnboundForwarding) { - int deletes = 0; - TypeParam ptr(new DeleteCounter(&deletes)); - // Test unbound argument forwarding. - Callback<TypeParam(TypeParam)> cb_unbound = Bind(&PassThru<TypeParam>); - cb_unbound.Run(std::move(ptr)); - EXPECT_EQ(1, deletes); -} - -void VerifyVector(const std::vector<std::unique_ptr<int>>& v) { - ASSERT_EQ(1u, v.size()); - EXPECT_EQ(12345, *v[0]); -} - -std::vector<std::unique_ptr<int>> AcceptAndReturnMoveOnlyVector( - std::vector<std::unique_ptr<int>> v) { - VerifyVector(v); - return v; -} - -// Test that a vector containing move-only types can be used with Callback. -TEST_F(BindTest, BindMoveOnlyVector) { - using MoveOnlyVector = std::vector<std::unique_ptr<int>>; - - MoveOnlyVector v; - v.push_back(WrapUnique(new int(12345))); - - // Early binding should work: - base::Callback<MoveOnlyVector()> bound_cb = - base::Bind(&AcceptAndReturnMoveOnlyVector, Passed(&v)); - MoveOnlyVector intermediate_result = bound_cb.Run(); - VerifyVector(intermediate_result); - - // As should passing it as an argument to Run(): - base::Callback<MoveOnlyVector(MoveOnlyVector)> unbound_cb = - base::Bind(&AcceptAndReturnMoveOnlyVector); - MoveOnlyVector final_result = unbound_cb.Run(std::move(intermediate_result)); - VerifyVector(final_result); -} - -// Argument copy-constructor usage for non-reference copy-only parameters. -// - Bound arguments are only copied once. -// - Forwarded arguments are only copied once. -// - Forwarded arguments with coercions are only copied twice (once for the -// coercion, and one for the final dispatch). -TEST_F(BindTest, ArgumentCopies) { - int copies = 0; - int assigns = 0; - - CopyCounter counter(&copies, &assigns); - Bind(&VoidPolymorphic<CopyCounter>::Run, counter); - EXPECT_EQ(1, copies); - EXPECT_EQ(0, assigns); - - copies = 0; - assigns = 0; - Bind(&VoidPolymorphic<CopyCounter>::Run, CopyCounter(&copies, &assigns)); - EXPECT_EQ(1, copies); - EXPECT_EQ(0, assigns); - - copies = 0; - assigns = 0; - Bind(&VoidPolymorphic<CopyCounter>::Run).Run(counter); - EXPECT_EQ(2, copies); - EXPECT_EQ(0, assigns); - - copies = 0; - assigns = 0; - Bind(&VoidPolymorphic<CopyCounter>::Run).Run(CopyCounter(&copies, &assigns)); - EXPECT_EQ(1, copies); - EXPECT_EQ(0, assigns); - - copies = 0; - assigns = 0; - DerivedCopyMoveCounter derived(&copies, &assigns, nullptr, nullptr); - Bind(&VoidPolymorphic<CopyCounter>::Run).Run(CopyCounter(derived)); - EXPECT_EQ(2, copies); - EXPECT_EQ(0, assigns); - - copies = 0; - assigns = 0; - Bind(&VoidPolymorphic<CopyCounter>::Run) - .Run(CopyCounter( - DerivedCopyMoveCounter(&copies, &assigns, nullptr, nullptr))); - EXPECT_EQ(2, copies); - EXPECT_EQ(0, assigns); -} - -// Argument move-constructor usage for move-only parameters. -// - Bound arguments passed by move are not copied. -TEST_F(BindTest, ArgumentMoves) { - int move_constructs = 0; - int move_assigns = 0; - - Bind(&VoidPolymorphic<const MoveCounter&>::Run, - MoveCounter(&move_constructs, &move_assigns)); - EXPECT_EQ(1, move_constructs); - EXPECT_EQ(0, move_assigns); - - // TODO(tzik): Support binding move-only type into a non-reference parameter - // of a variant of Callback. - - move_constructs = 0; - move_assigns = 0; - Bind(&VoidPolymorphic<MoveCounter>::Run) - .Run(MoveCounter(&move_constructs, &move_assigns)); - EXPECT_EQ(1, move_constructs); - EXPECT_EQ(0, move_assigns); - - move_constructs = 0; - move_assigns = 0; - Bind(&VoidPolymorphic<MoveCounter>::Run) - .Run(MoveCounter(DerivedCopyMoveCounter( - nullptr, nullptr, &move_constructs, &move_assigns))); - EXPECT_EQ(2, move_constructs); - EXPECT_EQ(0, move_assigns); -} - -// Argument constructor usage for non-reference movable-copyable -// parameters. -// - Bound arguments passed by move are not copied. -// - Forwarded arguments are only copied once. -// - Forwarded arguments with coercions are only copied once and moved once. -TEST_F(BindTest, ArgumentCopiesAndMoves) { - int copies = 0; - int assigns = 0; - int move_constructs = 0; - int move_assigns = 0; - - CopyMoveCounter counter(&copies, &assigns, &move_constructs, &move_assigns); - Bind(&VoidPolymorphic<CopyMoveCounter>::Run, counter); - EXPECT_EQ(1, copies); - EXPECT_EQ(0, assigns); - EXPECT_EQ(0, move_constructs); - EXPECT_EQ(0, move_assigns); - - copies = 0; - assigns = 0; - move_constructs = 0; - move_assigns = 0; - Bind(&VoidPolymorphic<CopyMoveCounter>::Run, - CopyMoveCounter(&copies, &assigns, &move_constructs, &move_assigns)); - EXPECT_EQ(0, copies); - EXPECT_EQ(0, assigns); - EXPECT_EQ(1, move_constructs); - EXPECT_EQ(0, move_assigns); - - copies = 0; - assigns = 0; - move_constructs = 0; - move_assigns = 0; - Bind(&VoidPolymorphic<CopyMoveCounter>::Run).Run(counter); - EXPECT_EQ(1, copies); - EXPECT_EQ(0, assigns); - EXPECT_EQ(1, move_constructs); - EXPECT_EQ(0, move_assigns); - - copies = 0; - assigns = 0; - move_constructs = 0; - move_assigns = 0; - Bind(&VoidPolymorphic<CopyMoveCounter>::Run) - .Run(CopyMoveCounter(&copies, &assigns, &move_constructs, &move_assigns)); - EXPECT_EQ(0, copies); - EXPECT_EQ(0, assigns); - EXPECT_EQ(1, move_constructs); - EXPECT_EQ(0, move_assigns); - - DerivedCopyMoveCounter derived_counter(&copies, &assigns, &move_constructs, - &move_assigns); - copies = 0; - assigns = 0; - move_constructs = 0; - move_assigns = 0; - Bind(&VoidPolymorphic<CopyMoveCounter>::Run) - .Run(CopyMoveCounter(derived_counter)); - EXPECT_EQ(1, copies); - EXPECT_EQ(0, assigns); - EXPECT_EQ(1, move_constructs); - EXPECT_EQ(0, move_assigns); - - copies = 0; - assigns = 0; - move_constructs = 0; - move_assigns = 0; - Bind(&VoidPolymorphic<CopyMoveCounter>::Run) - .Run(CopyMoveCounter(DerivedCopyMoveCounter( - &copies, &assigns, &move_constructs, &move_assigns))); - EXPECT_EQ(0, copies); - EXPECT_EQ(0, assigns); - EXPECT_EQ(2, move_constructs); - EXPECT_EQ(0, move_assigns); -} - -TEST_F(BindTest, CapturelessLambda) { - EXPECT_FALSE(internal::IsCallableObject<void>::value); - EXPECT_FALSE(internal::IsCallableObject<int>::value); - EXPECT_FALSE(internal::IsCallableObject<void (*)()>::value); - EXPECT_FALSE(internal::IsCallableObject<void (NoRef::*)()>::value); - - auto f = []() {}; - EXPECT_TRUE(internal::IsCallableObject<decltype(f)>::value); - - int i = 0; - auto g = [i]() { (void)i; }; - EXPECT_TRUE(internal::IsCallableObject<decltype(g)>::value); - - auto h = [](int, double) { return 'k'; }; - EXPECT_TRUE((std::is_same< - char(int, double), - internal::ExtractCallableRunType<decltype(h)>>::value)); - - EXPECT_EQ(42, Bind([] { return 42; }).Run()); - EXPECT_EQ(42, Bind([](int i) { return i * 7; }, 6).Run()); - - int x = 1; - base::Callback<void(int)> cb = - Bind([](int* x, int i) { *x *= i; }, Unretained(&x)); - cb.Run(6); - EXPECT_EQ(6, x); - cb.Run(7); - EXPECT_EQ(42, x); -} - -TEST_F(BindTest, EmptyFunctor) { - struct NonEmptyFunctor { - int operator()() const { return x; } - int x = 42; - }; - - struct EmptyFunctor { - int operator()() { return 42; } - }; - - struct EmptyFunctorConst { - int operator()() const { return 42; } - }; - - EXPECT_TRUE(internal::IsCallableObject<NonEmptyFunctor>::value); - EXPECT_TRUE(internal::IsCallableObject<EmptyFunctor>::value); - EXPECT_TRUE(internal::IsCallableObject<EmptyFunctorConst>::value); - EXPECT_EQ(42, BindOnce(EmptyFunctor()).Run()); - EXPECT_EQ(42, BindOnce(EmptyFunctorConst()).Run()); - EXPECT_EQ(42, BindRepeating(EmptyFunctorConst()).Run()); -} - -TEST_F(BindTest, CapturingLambdaForTesting) { - int x = 6; - EXPECT_EQ(42, BindLambdaForTesting([=](int y) { return x * y; }).Run(7)); - - auto f = [x](std::unique_ptr<int> y) { return x * *y; }; - EXPECT_EQ(42, BindLambdaForTesting(f).Run(std::make_unique<int>(7))); -} - -TEST_F(BindTest, Cancellation) { - EXPECT_CALL(no_ref_, VoidMethodWithIntArg(_)).Times(2); - - WeakPtrFactory<NoRef> weak_factory(&no_ref_); - RepeatingCallback<void(int)> cb = - BindRepeating(&NoRef::VoidMethodWithIntArg, weak_factory.GetWeakPtr()); - RepeatingClosure cb2 = BindRepeating(cb, 8); - OnceClosure cb3 = BindOnce(cb, 8); - - OnceCallback<void(int)> cb4 = - BindOnce(&NoRef::VoidMethodWithIntArg, weak_factory.GetWeakPtr()); - EXPECT_FALSE(cb4.IsCancelled()); - - OnceClosure cb5 = BindOnce(std::move(cb4), 8); - - EXPECT_FALSE(cb.IsCancelled()); - EXPECT_FALSE(cb2.IsCancelled()); - EXPECT_FALSE(cb3.IsCancelled()); - EXPECT_FALSE(cb5.IsCancelled()); - - cb.Run(6); - cb2.Run(); - - weak_factory.InvalidateWeakPtrs(); - - EXPECT_TRUE(cb.IsCancelled()); - EXPECT_TRUE(cb2.IsCancelled()); - EXPECT_TRUE(cb3.IsCancelled()); - EXPECT_TRUE(cb5.IsCancelled()); - - cb.Run(6); - cb2.Run(); - std::move(cb3).Run(); - std::move(cb5).Run(); -} - -TEST_F(BindTest, OnceCallback) { - // Check if Callback variants have declarations of conversions as expected. - // Copy constructor and assignment of RepeatingCallback. - static_assert(std::is_constructible< - RepeatingClosure, const RepeatingClosure&>::value, - "RepeatingClosure should be copyable."); - static_assert( - std::is_assignable<RepeatingClosure, const RepeatingClosure&>::value, - "RepeatingClosure should be copy-assignable."); - - // Move constructor and assignment of RepeatingCallback. - static_assert(std::is_constructible< - RepeatingClosure, RepeatingClosure&&>::value, - "RepeatingClosure should be movable."); - static_assert(std::is_assignable<RepeatingClosure, RepeatingClosure&&>::value, - "RepeatingClosure should be move-assignable"); - - // Conversions from OnceCallback to RepeatingCallback. - static_assert(!std::is_constructible< - RepeatingClosure, const OnceClosure&>::value, - "OnceClosure should not be convertible to RepeatingClosure."); - static_assert( - !std::is_assignable<RepeatingClosure, const OnceClosure&>::value, - "OnceClosure should not be convertible to RepeatingClosure."); - - // Destructive conversions from OnceCallback to RepeatingCallback. - static_assert(!std::is_constructible< - RepeatingClosure, OnceClosure&&>::value, - "OnceClosure should not be convertible to RepeatingClosure."); - static_assert(!std::is_assignable<RepeatingClosure, OnceClosure&&>::value, - "OnceClosure should not be convertible to RepeatingClosure."); - - // Copy constructor and assignment of OnceCallback. - static_assert(!std::is_constructible< - OnceClosure, const OnceClosure&>::value, - "OnceClosure should not be copyable."); - static_assert(!std::is_assignable<OnceClosure, const OnceClosure&>::value, - "OnceClosure should not be copy-assignable"); - - // Move constructor and assignment of OnceCallback. - static_assert(std::is_constructible< - OnceClosure, OnceClosure&&>::value, - "OnceClosure should be movable."); - static_assert(std::is_assignable<OnceClosure, OnceClosure&&>::value, - "OnceClosure should be move-assignable."); - - // Conversions from RepeatingCallback to OnceCallback. - static_assert(std::is_constructible< - OnceClosure, const RepeatingClosure&>::value, - "RepeatingClosure should be convertible to OnceClosure."); - static_assert(std::is_assignable<OnceClosure, const RepeatingClosure&>::value, - "RepeatingClosure should be convertible to OnceClosure."); - - // Destructive conversions from RepeatingCallback to OnceCallback. - static_assert(std::is_constructible< - OnceClosure, RepeatingClosure&&>::value, - "RepeatingClosure should be convertible to OnceClosure."); - static_assert(std::is_assignable<OnceClosure, RepeatingClosure&&>::value, - "RepeatingClosure should be covretible to OnceClosure."); - - OnceClosure cb = BindOnce(&VoidPolymorphic<>::Run); - std::move(cb).Run(); - - // RepeatingCallback should be convertible to OnceCallback. - OnceClosure cb2 = BindRepeating(&VoidPolymorphic<>::Run); - std::move(cb2).Run(); - - RepeatingClosure cb3 = BindRepeating(&VoidPolymorphic<>::Run); - cb = cb3; - std::move(cb).Run(); - - cb = std::move(cb2); - - OnceCallback<void(int)> cb4 = - BindOnce(&VoidPolymorphic<std::unique_ptr<int>, int>::Run, - std::make_unique<int>(0)); - BindOnce(std::move(cb4), 1).Run(); -} - -// Callback construction and assignment tests. -// - Construction from an InvokerStorageHolder should not cause ref/deref. -// - Assignment from other callback should only cause one ref -// -// TODO(ajwong): Is there actually a way to test this? - -#if defined(OS_WIN) -int __fastcall FastCallFunc(int n) { - return n; -} - -int __stdcall StdCallFunc(int n) { - return n; -} - -// Windows specific calling convention support. -// - Can bind a __fastcall function. -// - Can bind a __stdcall function. -TEST_F(BindTest, WindowsCallingConventions) { - Callback<int()> fastcall_cb = Bind(&FastCallFunc, 1); - EXPECT_EQ(1, fastcall_cb.Run()); - - Callback<int()> stdcall_cb = Bind(&StdCallFunc, 2); - EXPECT_EQ(2, stdcall_cb.Run()); -} -#endif - -// Test unwrapping the various wrapping functions. - -TEST_F(BindTest, UnwrapUnretained) { - int i = 0; - auto unretained = Unretained(&i); - EXPECT_EQ(&i, internal::Unwrap(unretained)); - EXPECT_EQ(&i, internal::Unwrap(std::move(unretained))); -} - -TEST_F(BindTest, UnwrapConstRef) { - int p = 0; - auto const_ref = ConstRef(p); - EXPECT_EQ(&p, &internal::Unwrap(const_ref)); - EXPECT_EQ(&p, &internal::Unwrap(std::move(const_ref))); -} - -TEST_F(BindTest, UnwrapRetainedRef) { - auto p = MakeRefCounted<RefCountedData<int>>(); - auto retained_ref = RetainedRef(p); - EXPECT_EQ(p.get(), internal::Unwrap(retained_ref)); - EXPECT_EQ(p.get(), internal::Unwrap(std::move(retained_ref))); -} - -TEST_F(BindTest, UnwrapOwned) { - int* p = new int; - auto owned = Owned(p); - EXPECT_EQ(p, internal::Unwrap(owned)); - EXPECT_EQ(p, internal::Unwrap(std::move(owned))); -} - -TEST_F(BindTest, UnwrapPassed) { - int* p = new int; - auto passed = Passed(WrapUnique(p)); - EXPECT_EQ(p, internal::Unwrap(passed).get()); - - p = new int; - EXPECT_EQ(p, internal::Unwrap(Passed(WrapUnique(p))).get()); -} - -TEST_F(BindTest, BindNoexcept) { - EXPECT_EQ(42, base::BindOnce(&Noexcept).Run()); - EXPECT_EQ( - 42, - base::BindOnce(&BindTest::NoexceptMethod, base::Unretained(this)).Run()); - EXPECT_EQ( - 42, base::BindOnce(&BindTest::ConstNoexceptMethod, base::Unretained(this)) - .Run()); -} - -// Test null callbacks cause a DCHECK. -TEST(BindDeathTest, NullCallback) { - base::Callback<void(int)> null_cb; - ASSERT_TRUE(null_cb.is_null()); - EXPECT_DCHECK_DEATH(base::Bind(null_cb, 42)); -} - -} // namespace -} // namespace base
diff --git a/base/bind_unittest.nc b/base/bind_unittest.nc deleted file mode 100644 index d549d2e..0000000 --- a/base/bind_unittest.nc +++ /dev/null
@@ -1,322 +0,0 @@ -// 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. - -// This is a "No Compile Test" suite. -// http://dev.chromium.org/developers/testing/no-compile-tests - -#include <utility> - -#include "base/bind.h" -#include "base/callback.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/test/bind_test_util.h" - -namespace base { - -// Do not put everything inside an anonymous namespace. If you do, many of the -// helper function declarations will generate unused definition warnings. - -static const int kParentValue = 1; -static const int kChildValue = 2; - -class NoRef { - public: - void VoidMethod0() {} - void VoidConstMethod0() const {} - int IntMethod0() { return 1; } -}; - -class HasRef : public NoRef, public base::RefCounted<HasRef> { -}; - -class Parent { - public: - void AddRef() const {} - void Release() const {} - virtual void VirtualSet() { value = kParentValue; } - void NonVirtualSet() { value = kParentValue; } - int value; -}; - -class Child : public Parent { - public: - virtual void VirtualSet() { value = kChildValue; } - void NonVirtualSet() { value = kChildValue; } -}; - -class NoRefParent { - public: - virtual void VirtualSet() { value = kParentValue; } - void NonVirtualSet() { value = kParentValue; } - int value; -}; - -class NoRefChild : public NoRefParent { - virtual void VirtualSet() { value = kChildValue; } - void NonVirtualSet() { value = kChildValue; } -}; - -template <typename T> -T PolymorphicIdentity(T t) { - return t; -} - -int UnwrapParentRef(Parent& p) { - return p.value; -} - -template <typename T> -void VoidPolymorphic1(T t) { -} - -void TakesMoveOnly(std::unique_ptr<int>) { -} - -struct NonEmptyFunctor { - int x; - void operator()() const {} -}; - -// TODO(hans): Remove .* and update the static_assert expectations once we roll -// past Clang r313315. https://crbug.com/765692. - -#if defined(NCTEST_METHOD_ON_CONST_OBJECT) // [r"fatal error: static_assert failed .*\"Bound argument \|i\| of type \|Arg\| cannot be forwarded as \|Unwrapped\| to the bound functor, which declares it as \|Param\|\.\""] - -// Method bound to const-object. -// -// Only const methods should be allowed to work with const objects. -void WontCompile() { - HasRef has_ref; - const HasRef* const_has_ref_ptr_ = &has_ref; - Callback<void()> method_to_const_cb = - Bind(&HasRef::VoidMethod0, const_has_ref_ptr_); - method_to_const_cb.Run(); -} - -#elif defined(NCTEST_METHOD_BIND_NEEDS_REFCOUNTED_OBJECT) // [r"fatal error: static_assert failed \"Receivers may not be raw pointers\."] - - -// Method bound to non-refcounted object. -// -// We require refcounts unless you have Unretained(). -void WontCompile() { - NoRef no_ref; - Callback<void()> no_ref_cb = - Bind(&NoRef::VoidMethod0, &no_ref); - no_ref_cb.Run(); -} - -#elif defined(NCTEST_CONST_METHOD_NEEDS_REFCOUNTED_OBJECT) // [r"fatal error: static_assert failed \"Receivers may not be raw pointers\."] - -// Const Method bound to non-refcounted object. -// -// We require refcounts unless you have Unretained(). -void WontCompile() { - NoRef no_ref; - Callback<void()> no_ref_const_cb = - Bind(&NoRef::VoidConstMethod0, &no_ref); - no_ref_const_cb.Run(); -} - -#elif defined(NCTEST_CONST_POINTER) // [r"fatal error: static_assert failed .*\"Bound argument \|i\| of type \|Arg\| cannot be forwarded as \|Unwrapped\| to the bound functor, which declares it as \|Param\|\.\""] - -// Const argument used with non-const pointer parameter of same type. -// -// This is just a const-correctness check. -void WontCompile() { - const NoRef* const_no_ref_ptr; - Callback<NoRef*()> pointer_same_cb = - Bind(&PolymorphicIdentity<NoRef*>, const_no_ref_ptr); - pointer_same_cb.Run(); -} - -#elif defined(NCTEST_CONST_POINTER_SUBTYPE) // [r"fatal error: static_assert failed .*\"Bound argument \|i\| of type \|Arg\| cannot be forwarded as \|Unwrapped\| to the bound functor, which declares it as \|Param\|\.\""] - -// Const argument used with non-const pointer parameter of super type. -// -// This is just a const-correctness check. -void WontCompile() { - const NoRefChild* const_child_ptr; - Callback<NoRefParent*()> pointer_super_cb = - Bind(&PolymorphicIdentity<NoRefParent*>, const_child_ptr); - pointer_super_cb.Run(); -} - -#elif defined(DISABLED_NCTEST_DISALLOW_NON_CONST_REF_PARAM) // [r"fatal error: no member named 'AddRef' in 'base::NoRef'"] -// TODO(dcheng): I think there's a type safety promotion issue here where we can -// pass a const ref to a non const-ref function, or vice versa accidentally. Or -// we make a copy accidentally. Check. - -// Functions with reference parameters, unsupported. -// -// First, non-const reference parameters are disallowed by the Google -// style guide. Second, since we are doing argument forwarding it becomes -// very tricky to avoid copies, maintain const correctness, and not -// accidentally have the function be modifying a temporary, or a copy. -void WontCompile() { - Parent p; - Callback<int(Parent&)> ref_arg_cb = Bind(&UnwrapParentRef); - ref_arg_cb.Run(p); -} - -#elif defined(NCTEST_DISALLOW_BIND_TO_NON_CONST_REF_PARAM) // [r"fatal error: static_assert failed .*\"Bound argument \|i\| of type \|Arg\| cannot be forwarded as \|Unwrapped\| to the bound functor, which declares it as \|Param\|\.\""] - -// Binding functions with reference parameters, unsupported. -// -// See comment in NCTEST_DISALLOW_NON_CONST_REF_PARAM -void WontCompile() { - Parent p; - Callback<int()> ref_cb = Bind(&UnwrapParentRef, p); - ref_cb.Run(); -} - -#elif defined(NCTEST_NO_IMPLICIT_ARRAY_PTR_CONVERSION) // [r"fatal error: static_assert failed .*\"First bound argument to a method cannot be an array\.\""] - -// A method should not be bindable with an array of objects. -// -// This is likely not wanted behavior. We specifically check for it though -// because it is possible, depending on how you implement prebinding, to -// implicitly convert an array type to a pointer type. -void WontCompile() { - HasRef p[10]; - Callback<void()> method_bound_to_array_cb = - Bind(&HasRef::VoidMethod0, p); - method_bound_to_array_cb.Run(); -} - -#elif defined(NCTEST_NO_RVALUE_RAW_PTR_FOR_REFCOUNTED_TYPES) // [r"fatal error: static_assert failed .*\"A parameter is a refcounted type and needs scoped_refptr\.\""] - -// Refcounted types should not be bound as a raw pointer. -void WontCompile() { - HasRef for_raw_ptr; - int a; - Callback<void()> ref_count_as_raw_ptr_a = - Bind(&VoidPolymorphic1<int*>, &a); - Callback<void()> ref_count_as_raw_ptr = - Bind(&VoidPolymorphic1<HasRef*>, &for_raw_ptr); -} - -#elif defined(NCTEST_NO_LVALUE_RAW_PTR_FOR_REFCOUNTED_TYPES) // [r"fatal error: static_assert failed .*\"A parameter is a refcounted type and needs scoped_refptr\.\""] - -// Refcounted types should not be bound as a raw pointer. -void WontCompile() { - HasRef* for_raw_ptr = nullptr; - Callback<void()> ref_count_as_raw_ptr = - Bind(&VoidPolymorphic1<HasRef*>, for_raw_ptr); -} - -#elif defined(NCTEST_NO_RVALUE_CONST_RAW_PTR_FOR_REFCOUNTED_TYPES) // [r"fatal error: static_assert failed .*\"A parameter is a refcounted type and needs scoped_refptr\.\""] - -// Refcounted types should not be bound as a raw pointer. -void WontCompile() { - const HasRef for_raw_ptr; - Callback<void()> ref_count_as_raw_ptr = - Bind(&VoidPolymorphic1<const HasRef*>, &for_raw_ptr); -} - -#elif defined(NCTEST_NO_LVALUE_CONST_RAW_PTR_FOR_REFCOUNTED_TYPES) // [r"fatal error: static_assert failed .*\"A parameter is a refcounted type and needs scoped_refptr\.\""] - -// Refcounted types should not be bound as a raw pointer. -void WontCompile() { - const HasRef* for_raw_ptr = nullptr; - Callback<void()> ref_count_as_raw_ptr = - Bind(&VoidPolymorphic1<const HasRef*>, for_raw_ptr); -} - -#elif defined(NCTEST_WEAKPTR_BIND_MUST_RETURN_VOID) // [r"fatal error: static_assert failed .*\"weak_ptrs can only bind to methods without return values\""] - -// WeakPtrs cannot be bound to methods with return types. -void WontCompile() { - NoRef no_ref; - WeakPtrFactory<NoRef> weak_factory(&no_ref); - Callback<int()> weak_ptr_with_non_void_return_type = - Bind(&NoRef::IntMethod0, weak_factory.GetWeakPtr()); - weak_ptr_with_non_void_return_type.Run(); -} - -#elif defined(NCTEST_DISALLOW_ASSIGN_DIFFERENT_TYPES) // [r"fatal error: no viable conversion from 'Callback<MakeUnboundRunType<void \(\*\)\(int\)>>' to 'Callback<void \(\)>'"] - -// Bind result cannot be assigned to Callbacks with a mismatching type. -void WontCompile() { - Closure callback_mismatches_bind_type = Bind(&VoidPolymorphic1<int>); -} - -#elif defined(NCTEST_DISALLOW_CAPTURING_LAMBDA) // [r"fatal error: implicit instantiation of undefined template 'base::internal::FunctorTraits<\(lambda at (\.\./)+base/bind_unittest.nc:[0-9]+:[0-9]+\), void>'"] - -void WontCompile() { - int i = 0, j = 0; - Bind([i,&j]() {j = i;}); -} - -#elif defined(NCTEST_DISALLOW_ONCECALLBACK_RUN_ON_LVALUE) // [r"static_assert failed .*\"OnceCallback::Run\(\) may only be invoked on a non-const rvalue, i\.e\. std::move\(callback\)\.Run\(\)\.\""] - -void WontCompile() { - OnceClosure cb = Bind([] {}); - cb.Run(); -} - -#elif defined(NCTEST_DISALLOW_ONCECALLBACK_RUN_ON_CONST_LVALUE) // [r"static_assert failed .*\"OnceCallback::Run\(\) may only be invoked on a non-const rvalue, i\.e\. std::move\(callback\)\.Run\(\)\.\""] - -void WontCompile() { - const OnceClosure cb = Bind([] {}); - cb.Run(); -} - -#elif defined(NCTEST_DISALLOW_ONCECALLBACK_RUN_ON_CONST_RVALUE) // [r"static_assert failed .*\"OnceCallback::Run\(\) may only be invoked on a non-const rvalue, i\.e\. std::move\(callback\)\.Run\(\)\.\""] - -void WontCompile() { - const OnceClosure cb = Bind([] {}); - std::move(cb).Run(); -} - -#elif defined(NCTEST_DISALLOW_BIND_ONCECALLBACK) // [r"fatal error: static_assert failed .*\"BindRepeating cannot bind OnceCallback. Use BindOnce with std::move\(\)\.\""] - -void WontCompile() { - Bind(BindOnce([](int) {}), 42); -} - -#elif defined(NCTEST_DISALLOW_BINDONCE_LVALUE_ONCECALLBACK) // [r"fatal error: static_assert failed .*\"BindOnce requires non-const rvalue for OnceCallback binding\."] -void WontCompile() { - auto cb = BindOnce([](int) {}); - BindOnce(cb, 42); -} - -#elif defined(NCTEST_DISALLOW_BINDONCE_RVALUE_CONST_ONCECALLBACK) // [r"fatal error: static_assert failed .*\"BindOnce requires non-const rvalue for OnceCallback binding\."] - -void WontCompile() { - const auto cb = BindOnce([](int) {}); - BindOnce(std::move(cb), 42); -} - -#elif defined(NCTEST_BINDONCE_MOVEONLY_TYPE_BY_VALUE) // [r"fatal error: static_assert failed .*\"Bound argument \|i\| is move-only but will be bound by copy\. Ensure \|Arg\| is mutable and bound using std::move\(\)\.\""] - -void WontCompile() { - std::unique_ptr<int> x; - BindOnce(&TakesMoveOnly, x); -} - -#elif defined(NCTEST_BIND_MOVEONLY_TYPE_BY_VALUE) // [r"Bound argument \|i\| is move-only but will be forwarded by copy\. Ensure \|Arg\| is bound using base::Passed\(\), not std::move\(\)."] - -void WontCompile() { - std::unique_ptr<int> x; - Bind(&TakesMoveOnly, x); -} - -#elif defined(NCTEST_BIND_MOVEONLY_TYPE_WITH_STDMOVE) // [r"Bound argument \|i\| is move-only but will be forwarded by copy\. Ensure \|Arg\| is bound using base::Passed\(\), not std::move\(\)."] - -void WontCompile() { - std::unique_ptr<int> x; - Bind(&TakesMoveOnly, std::move(x)); -} - -#elif defined(NCTEST_BIND_NON_EMPTY_FUNCTOR) // [r"fatal error: implicit instantiation of undefined template 'base::internal::FunctorTraits<base::NonEmptyFunctor, void>'"] - -void WontCompile() { - Bind(NonEmptyFunctor()); -} - -#endif - -} // namespace base
diff --git a/base/bit_cast_unittest.cc b/base/bit_cast_unittest.cc deleted file mode 100644 index f36d3fe..0000000 --- a/base/bit_cast_unittest.cc +++ /dev/null
@@ -1,31 +0,0 @@ -// Copyright (c) 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/bit_cast.h" - -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -TEST(BitCastTest, FloatIntFloat) { - float f = 3.1415926f; - int i = bit_cast<int32_t>(f); - float f2 = bit_cast<float>(i); - EXPECT_EQ(f, f2); -} - -struct A { - int x; -}; - -TEST(BitCastTest, StructureInt) { - A a = { 1 }; - int b = bit_cast<int>(a); - EXPECT_EQ(1, b); -} - -} // namespace -} // namespace base
diff --git a/base/bits_unittest.cc b/base/bits_unittest.cc deleted file mode 100644 index ceaad3f..0000000 --- a/base/bits_unittest.cc +++ /dev/null
@@ -1,197 +0,0 @@ -// Copyright (c) 2009 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 contains the unit tests for the bit utilities. - -#include "base/bits.h" -#include "build_config.h" - -#include <stddef.h> - -#include <limits> - -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace bits { - -TEST(BitsTest, Log2Floor) { - EXPECT_EQ(-1, Log2Floor(0)); - EXPECT_EQ(0, Log2Floor(1)); - EXPECT_EQ(1, Log2Floor(2)); - EXPECT_EQ(1, Log2Floor(3)); - EXPECT_EQ(2, Log2Floor(4)); - for (int i = 3; i < 31; ++i) { - unsigned int value = 1U << i; - EXPECT_EQ(i, Log2Floor(value)); - EXPECT_EQ(i, Log2Floor(value + 1)); - EXPECT_EQ(i, Log2Floor(value + 2)); - EXPECT_EQ(i - 1, Log2Floor(value - 1)); - EXPECT_EQ(i - 1, Log2Floor(value - 2)); - } - EXPECT_EQ(31, Log2Floor(0xffffffffU)); -} - -TEST(BitsTest, Log2Ceiling) { - EXPECT_EQ(-1, Log2Ceiling(0)); - EXPECT_EQ(0, Log2Ceiling(1)); - EXPECT_EQ(1, Log2Ceiling(2)); - EXPECT_EQ(2, Log2Ceiling(3)); - EXPECT_EQ(2, Log2Ceiling(4)); - for (int i = 3; i < 31; ++i) { - unsigned int value = 1U << i; - EXPECT_EQ(i, Log2Ceiling(value)); - EXPECT_EQ(i + 1, Log2Ceiling(value + 1)); - EXPECT_EQ(i + 1, Log2Ceiling(value + 2)); - EXPECT_EQ(i, Log2Ceiling(value - 1)); - EXPECT_EQ(i, Log2Ceiling(value - 2)); - } - EXPECT_EQ(32, Log2Ceiling(0xffffffffU)); -} - -TEST(BitsTest, Align) { - const size_t kSizeTMax = std::numeric_limits<size_t>::max(); - EXPECT_EQ(0ul, Align(0, 4)); - EXPECT_EQ(4ul, Align(1, 4)); - EXPECT_EQ(4096ul, Align(1, 4096)); - EXPECT_EQ(4096ul, Align(4096, 4096)); - EXPECT_EQ(4096ul, Align(4095, 4096)); - EXPECT_EQ(8192ul, Align(4097, 4096)); - EXPECT_EQ(kSizeTMax - 31, Align(kSizeTMax - 62, 32)); - EXPECT_EQ(kSizeTMax / 2 + 1, Align(1, kSizeTMax / 2 + 1)); -} - -TEST(BitsTest, CountLeadingZeroBits8) { - EXPECT_EQ(8u, CountLeadingZeroBits(uint8_t{0})); - EXPECT_EQ(7u, CountLeadingZeroBits(uint8_t{1})); - for (uint8_t shift = 0; shift <= 7; shift++) { - EXPECT_EQ(7u - shift, - CountLeadingZeroBits(static_cast<uint8_t>(1 << shift))); - } - EXPECT_EQ(4u, CountLeadingZeroBits(uint8_t{0x0f})); -} - -TEST(BitsTest, CountLeadingZeroBits16) { - EXPECT_EQ(16u, CountLeadingZeroBits(uint16_t{0})); - EXPECT_EQ(15u, CountLeadingZeroBits(uint16_t{1})); - for (uint16_t shift = 0; shift <= 15; shift++) { - EXPECT_EQ(15u - shift, - CountLeadingZeroBits(static_cast<uint16_t>(1 << shift))); - } - EXPECT_EQ(4u, CountLeadingZeroBits(uint16_t{0x0f0f})); -} - -TEST(BitsTest, CountLeadingZeroBits32) { - EXPECT_EQ(32u, CountLeadingZeroBits(uint32_t{0})); - EXPECT_EQ(31u, CountLeadingZeroBits(uint32_t{1})); - for (uint32_t shift = 0; shift <= 31; shift++) { - EXPECT_EQ(31u - shift, CountLeadingZeroBits(uint32_t{1} << shift)); - } - EXPECT_EQ(4u, CountLeadingZeroBits(uint32_t{0x0f0f0f0f})); -} - -TEST(BitsTest, CountTrailingeZeroBits8) { - EXPECT_EQ(8u, CountTrailingZeroBits(uint8_t{0})); - EXPECT_EQ(7u, CountTrailingZeroBits(uint8_t{128})); - for (uint8_t shift = 0; shift <= 7; shift++) { - EXPECT_EQ(shift, CountTrailingZeroBits(static_cast<uint8_t>(1 << shift))); - } - EXPECT_EQ(4u, CountTrailingZeroBits(uint8_t{0xf0})); -} - -TEST(BitsTest, CountTrailingeZeroBits16) { - EXPECT_EQ(16u, CountTrailingZeroBits(uint16_t{0})); - EXPECT_EQ(15u, CountTrailingZeroBits(uint16_t{32768})); - for (uint16_t shift = 0; shift <= 15; shift++) { - EXPECT_EQ(shift, CountTrailingZeroBits(static_cast<uint16_t>(1 << shift))); - } - EXPECT_EQ(4u, CountTrailingZeroBits(uint16_t{0xf0f0})); -} - -TEST(BitsTest, CountTrailingeZeroBits32) { - EXPECT_EQ(32u, CountTrailingZeroBits(uint32_t{0})); - EXPECT_EQ(31u, CountTrailingZeroBits(uint32_t{1} << 31)); - for (uint32_t shift = 0; shift <= 31; shift++) { - EXPECT_EQ(shift, CountTrailingZeroBits(uint32_t{1} << shift)); - } - EXPECT_EQ(4u, CountTrailingZeroBits(uint32_t{0xf0f0f0f0})); -} - -#if defined(ARCH_CPU_64_BITS) - -TEST(BitsTest, CountLeadingZeroBits64) { - EXPECT_EQ(64u, CountLeadingZeroBits(uint64_t{0})); - EXPECT_EQ(63u, CountLeadingZeroBits(uint64_t{1})); - for (uint64_t shift = 0; shift <= 63; shift++) { - EXPECT_EQ(63u - shift, CountLeadingZeroBits(uint64_t{1} << shift)); - } - EXPECT_EQ(4u, CountLeadingZeroBits(uint64_t{0x0f0f0f0f0f0f0f0f})); -} - -TEST(BitsTest, CountTrailingeZeroBits64) { - EXPECT_EQ(64u, CountTrailingZeroBits(uint64_t{0})); - EXPECT_EQ(63u, CountTrailingZeroBits(uint64_t{1} << 63)); - for (uint64_t shift = 0; shift <= 31; shift++) { - EXPECT_EQ(shift, CountTrailingZeroBits(uint64_t{1} << shift)); - } - EXPECT_EQ(4u, CountTrailingZeroBits(uint64_t{0xf0f0f0f0f0f0f0f0})); -} - -#endif // ARCH_CPU_64_BITS - -TEST(BitsTest, CountLeadingZeroBitsSizeT) { -#if defined(ARCH_CPU_64_BITS) - EXPECT_EQ(64u, CountLeadingZeroBitsSizeT(size_t{0})); - EXPECT_EQ(63u, CountLeadingZeroBitsSizeT(size_t{1})); - EXPECT_EQ(32u, CountLeadingZeroBitsSizeT(size_t{1} << 31)); - EXPECT_EQ(1u, CountLeadingZeroBitsSizeT(size_t{1} << 62)); - EXPECT_EQ(0u, CountLeadingZeroBitsSizeT(size_t{1} << 63)); -#else - EXPECT_EQ(32u, CountLeadingZeroBitsSizeT(size_t{0})); - EXPECT_EQ(31u, CountLeadingZeroBitsSizeT(size_t{1})); - EXPECT_EQ(1u, CountLeadingZeroBitsSizeT(size_t{1} << 30)); - EXPECT_EQ(0u, CountLeadingZeroBitsSizeT(size_t{1} << 31)); -#endif // ARCH_CPU_64_BITS -} - -TEST(BitsTest, CountTrailingZeroBitsSizeT) { -#if defined(ARCH_CPU_64_BITS) - EXPECT_EQ(64u, CountTrailingZeroBitsSizeT(size_t{0})); - EXPECT_EQ(63u, CountTrailingZeroBitsSizeT(size_t{1} << 63)); - EXPECT_EQ(31u, CountTrailingZeroBitsSizeT(size_t{1} << 31)); - EXPECT_EQ(1u, CountTrailingZeroBitsSizeT(size_t{2})); - EXPECT_EQ(0u, CountTrailingZeroBitsSizeT(size_t{1})); -#else - EXPECT_EQ(32u, CountTrailingZeroBitsSizeT(size_t{0})); - EXPECT_EQ(31u, CountTrailingZeroBitsSizeT(size_t{1} << 31)); - EXPECT_EQ(1u, CountTrailingZeroBitsSizeT(size_t{2})); - EXPECT_EQ(0u, CountTrailingZeroBitsSizeT(size_t{1})); -#endif // ARCH_CPU_64_BITS -} - -TEST(BitsTest, PowerOfTwo) { - EXPECT_FALSE(IsPowerOfTwo(-1)); - EXPECT_FALSE(IsPowerOfTwo(0)); - EXPECT_TRUE(IsPowerOfTwo(1)); - EXPECT_TRUE(IsPowerOfTwo(2)); - // Unsigned 64 bit cases. - for (uint32_t i = 2; i < 64; i++) { - const uint64_t val = uint64_t{1} << i; - EXPECT_FALSE(IsPowerOfTwo(val - 1)); - EXPECT_TRUE(IsPowerOfTwo(val)); - EXPECT_FALSE(IsPowerOfTwo(val + 1)); - } - // Signed 64 bit cases. - for (uint32_t i = 2; i < 63; i++) { - const int64_t val = int64_t{1} << i; - EXPECT_FALSE(IsPowerOfTwo(val - 1)); - EXPECT_TRUE(IsPowerOfTwo(val)); - EXPECT_FALSE(IsPowerOfTwo(val + 1)); - } - // Signed integers with only the last bit set are negative, not powers of two. - EXPECT_FALSE(IsPowerOfTwo(int64_t{1} << 63)); -} - -} // namespace bits -} // namespace base
diff --git a/base/callback_helpers_unittest.cc b/base/callback_helpers_unittest.cc deleted file mode 100644 index 1c1102d..0000000 --- a/base/callback_helpers_unittest.cc +++ /dev/null
@@ -1,127 +0,0 @@ -// 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/callback_helpers.h" - -#include "base/bind.h" -#include "base/callback.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -void Increment(int* value) { - (*value)++; -} - -TEST(CallbackHelpersTest, TestResetAndReturn) { - int run_count = 0; - - base::Closure cb = base::Bind(&Increment, &run_count); - EXPECT_EQ(0, run_count); - base::ResetAndReturn(&cb).Run(); - EXPECT_EQ(1, run_count); - EXPECT_FALSE(cb); - - run_count = 0; - - base::OnceClosure cb2 = base::BindOnce(&Increment, &run_count); - EXPECT_EQ(0, run_count); - base::ResetAndReturn(&cb2).Run(); - EXPECT_EQ(1, run_count); - EXPECT_FALSE(cb2); -} - -TEST(CallbackHelpersTest, TestScopedClosureRunnerExitScope) { - int run_count = 0; - { - base::ScopedClosureRunner runner(base::Bind(&Increment, &run_count)); - EXPECT_EQ(0, run_count); - } - EXPECT_EQ(1, run_count); -} - -TEST(CallbackHelpersTest, TestScopedClosureRunnerRelease) { - int run_count = 0; - base::OnceClosure c; - { - base::ScopedClosureRunner runner(base::Bind(&Increment, &run_count)); - c = runner.Release(); - EXPECT_EQ(0, run_count); - } - EXPECT_EQ(0, run_count); - std::move(c).Run(); - EXPECT_EQ(1, run_count); -} - -TEST(CallbackHelpersTest, TestScopedClosureRunnerReplaceClosure) { - int run_count_1 = 0; - int run_count_2 = 0; - { - base::ScopedClosureRunner runner; - runner.ReplaceClosure(base::Bind(&Increment, &run_count_1)); - runner.ReplaceClosure(base::Bind(&Increment, &run_count_2)); - EXPECT_EQ(0, run_count_1); - EXPECT_EQ(0, run_count_2); - } - EXPECT_EQ(0, run_count_1); - EXPECT_EQ(1, run_count_2); -} - -TEST(CallbackHelpersTest, TestScopedClosureRunnerRunAndReset) { - int run_count_3 = 0; - { - base::ScopedClosureRunner runner(base::Bind(&Increment, &run_count_3)); - EXPECT_EQ(0, run_count_3); - runner.RunAndReset(); - EXPECT_EQ(1, run_count_3); - } - EXPECT_EQ(1, run_count_3); -} - -TEST(CallbackHelpersTest, TestScopedClosureRunnerMoveConstructor) { - int run_count = 0; - { - std::unique_ptr<base::ScopedClosureRunner> runner( - new base::ScopedClosureRunner(base::Bind(&Increment, &run_count))); - base::ScopedClosureRunner runner2(std::move(*runner)); - runner.reset(); - EXPECT_EQ(0, run_count); - } - EXPECT_EQ(1, run_count); -} - -TEST(CallbackHelpersTest, TestScopedClosureRunnerMoveAssignment) { - int run_count_1 = 0; - int run_count_2 = 0; - { - base::ScopedClosureRunner runner(base::Bind(&Increment, &run_count_1)); - { - base::ScopedClosureRunner runner2(base::Bind(&Increment, &run_count_2)); - runner = std::move(runner2); - EXPECT_EQ(0, run_count_1); - EXPECT_EQ(0, run_count_2); - } - EXPECT_EQ(0, run_count_1); - EXPECT_EQ(0, run_count_2); - } - EXPECT_EQ(0, run_count_1); - EXPECT_EQ(1, run_count_2); -} - -TEST(CallbackHelpersTest, TestAdaptCallbackForRepeating) { - int count = 0; - base::OnceCallback<void(int*)> cb = - base::BindOnce([](int* count) { ++*count; }); - - base::RepeatingCallback<void(int*)> wrapped = - base::AdaptCallbackForRepeating(std::move(cb)); - - EXPECT_EQ(0, count); - wrapped.Run(&count); - EXPECT_EQ(1, count); - wrapped.Run(&count); - EXPECT_EQ(1, count); -} - -} // namespace
diff --git a/base/callback_list_unittest.cc b/base/callback_list_unittest.cc deleted file mode 100644 index 6eb5ff7..0000000 --- a/base/callback_list_unittest.cc +++ /dev/null
@@ -1,339 +0,0 @@ -// 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/callback_list.h" - -#include <memory> -#include <utility> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/macros.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -class Listener { - public: - Listener() : total_(0), scaler_(1) {} - explicit Listener(int scaler) : total_(0), scaler_(scaler) {} - void IncrementTotal() { total_++; } - void IncrementByMultipleOfScaler(int x) { total_ += x * scaler_; } - - int total() const { return total_; } - - private: - int total_; - int scaler_; - DISALLOW_COPY_AND_ASSIGN(Listener); -}; - -class Remover { - public: - Remover() : total_(0) {} - void IncrementTotalAndRemove() { - total_++; - removal_subscription_.reset(); - } - void SetSubscriptionToRemove( - std::unique_ptr<CallbackList<void(void)>::Subscription> sub) { - removal_subscription_ = std::move(sub); - } - - int total() const { return total_; } - - private: - int total_; - std::unique_ptr<CallbackList<void(void)>::Subscription> removal_subscription_; - DISALLOW_COPY_AND_ASSIGN(Remover); -}; - -class Adder { - public: - explicit Adder(CallbackList<void(void)>* cb_reg) - : added_(false), - total_(0), - cb_reg_(cb_reg) { - } - void AddCallback() { - if (!added_) { - added_ = true; - subscription_ = - cb_reg_->Add(Bind(&Adder::IncrementTotal, Unretained(this))); - } - } - void IncrementTotal() { total_++; } - - bool added() const { return added_; } - - int total() const { return total_; } - - private: - bool added_; - int total_; - CallbackList<void(void)>* cb_reg_; - std::unique_ptr<CallbackList<void(void)>::Subscription> subscription_; - DISALLOW_COPY_AND_ASSIGN(Adder); -}; - -class Summer { - public: - Summer() : value_(0) {} - - void AddOneParam(int a) { value_ = a; } - void AddTwoParam(int a, int b) { value_ = a + b; } - void AddThreeParam(int a, int b, int c) { value_ = a + b + c; } - void AddFourParam(int a, int b, int c, int d) { value_ = a + b + c + d; } - void AddFiveParam(int a, int b, int c, int d, int e) { - value_ = a + b + c + d + e; - } - void AddSixParam(int a, int b, int c, int d, int e , int f) { - value_ = a + b + c + d + e + f; - } - - int value() const { return value_; } - - private: - int value_; - DISALLOW_COPY_AND_ASSIGN(Summer); -}; - -class Counter { - public: - Counter() : value_(0) {} - - void Increment() { value_++; } - - int value() const { return value_; } - - private: - int value_; - DISALLOW_COPY_AND_ASSIGN(Counter); -}; - -// Sanity check that we can instantiate a CallbackList for each arity. -TEST(CallbackListTest, ArityTest) { - Summer s; - - CallbackList<void(int)> c1; - std::unique_ptr<CallbackList<void(int)>::Subscription> subscription1 = - c1.Add(Bind(&Summer::AddOneParam, Unretained(&s))); - - c1.Notify(1); - EXPECT_EQ(1, s.value()); - - CallbackList<void(int, int)> c2; - std::unique_ptr<CallbackList<void(int, int)>::Subscription> subscription2 = - c2.Add(Bind(&Summer::AddTwoParam, Unretained(&s))); - - c2.Notify(1, 2); - EXPECT_EQ(3, s.value()); - - CallbackList<void(int, int, int)> c3; - std::unique_ptr<CallbackList<void(int, int, int)>::Subscription> - subscription3 = c3.Add(Bind(&Summer::AddThreeParam, Unretained(&s))); - - c3.Notify(1, 2, 3); - EXPECT_EQ(6, s.value()); - - CallbackList<void(int, int, int, int)> c4; - std::unique_ptr<CallbackList<void(int, int, int, int)>::Subscription> - subscription4 = c4.Add(Bind(&Summer::AddFourParam, Unretained(&s))); - - c4.Notify(1, 2, 3, 4); - EXPECT_EQ(10, s.value()); - - CallbackList<void(int, int, int, int, int)> c5; - std::unique_ptr<CallbackList<void(int, int, int, int, int)>::Subscription> - subscription5 = c5.Add(Bind(&Summer::AddFiveParam, Unretained(&s))); - - c5.Notify(1, 2, 3, 4, 5); - EXPECT_EQ(15, s.value()); - - CallbackList<void(int, int, int, int, int, int)> c6; - std::unique_ptr< - CallbackList<void(int, int, int, int, int, int)>::Subscription> - subscription6 = c6.Add(Bind(&Summer::AddSixParam, Unretained(&s))); - - c6.Notify(1, 2, 3, 4, 5, 6); - EXPECT_EQ(21, s.value()); -} - -// Sanity check that closures added to the list will be run, and those removed -// from the list will not be run. -TEST(CallbackListTest, BasicTest) { - CallbackList<void(void)> cb_reg; - Listener a, b, c; - - std::unique_ptr<CallbackList<void(void)>::Subscription> a_subscription = - cb_reg.Add(Bind(&Listener::IncrementTotal, Unretained(&a))); - std::unique_ptr<CallbackList<void(void)>::Subscription> b_subscription = - cb_reg.Add(Bind(&Listener::IncrementTotal, Unretained(&b))); - - EXPECT_TRUE(a_subscription.get()); - EXPECT_TRUE(b_subscription.get()); - - cb_reg.Notify(); - - EXPECT_EQ(1, a.total()); - EXPECT_EQ(1, b.total()); - - b_subscription.reset(); - - std::unique_ptr<CallbackList<void(void)>::Subscription> c_subscription = - cb_reg.Add(Bind(&Listener::IncrementTotal, Unretained(&c))); - - cb_reg.Notify(); - - EXPECT_EQ(2, a.total()); - EXPECT_EQ(1, b.total()); - EXPECT_EQ(1, c.total()); - - a_subscription.reset(); - b_subscription.reset(); - c_subscription.reset(); -} - -// Sanity check that callbacks with details added to the list will be run, with -// the correct details, and those removed from the list will not be run. -TEST(CallbackListTest, BasicTestWithParams) { - CallbackList<void(int)> cb_reg; - Listener a(1), b(-1), c(1); - - std::unique_ptr<CallbackList<void(int)>::Subscription> a_subscription = - cb_reg.Add(Bind(&Listener::IncrementByMultipleOfScaler, Unretained(&a))); - std::unique_ptr<CallbackList<void(int)>::Subscription> b_subscription = - cb_reg.Add(Bind(&Listener::IncrementByMultipleOfScaler, Unretained(&b))); - - EXPECT_TRUE(a_subscription.get()); - EXPECT_TRUE(b_subscription.get()); - - cb_reg.Notify(10); - - EXPECT_EQ(10, a.total()); - EXPECT_EQ(-10, b.total()); - - b_subscription.reset(); - - std::unique_ptr<CallbackList<void(int)>::Subscription> c_subscription = - cb_reg.Add(Bind(&Listener::IncrementByMultipleOfScaler, Unretained(&c))); - - cb_reg.Notify(10); - - EXPECT_EQ(20, a.total()); - EXPECT_EQ(-10, b.total()); - EXPECT_EQ(10, c.total()); - - a_subscription.reset(); - b_subscription.reset(); - c_subscription.reset(); -} - -// Test the a callback can remove itself or a different callback from the list -// during iteration without invalidating the iterator. -TEST(CallbackListTest, RemoveCallbacksDuringIteration) { - CallbackList<void(void)> cb_reg; - Listener a, b; - Remover remover_1, remover_2; - - std::unique_ptr<CallbackList<void(void)>::Subscription> remover_1_sub = - cb_reg.Add( - Bind(&Remover::IncrementTotalAndRemove, Unretained(&remover_1))); - std::unique_ptr<CallbackList<void(void)>::Subscription> remover_2_sub = - cb_reg.Add( - Bind(&Remover::IncrementTotalAndRemove, Unretained(&remover_2))); - std::unique_ptr<CallbackList<void(void)>::Subscription> a_subscription = - cb_reg.Add(Bind(&Listener::IncrementTotal, Unretained(&a))); - std::unique_ptr<CallbackList<void(void)>::Subscription> b_subscription = - cb_reg.Add(Bind(&Listener::IncrementTotal, Unretained(&b))); - - // |remover_1| will remove itself. - remover_1.SetSubscriptionToRemove(std::move(remover_1_sub)); - // |remover_2| will remove a. - remover_2.SetSubscriptionToRemove(std::move(a_subscription)); - - cb_reg.Notify(); - - // |remover_1| runs once (and removes itself), |remover_2| runs once (and - // removes a), |a| never runs, and |b| runs once. - EXPECT_EQ(1, remover_1.total()); - EXPECT_EQ(1, remover_2.total()); - EXPECT_EQ(0, a.total()); - EXPECT_EQ(1, b.total()); - - cb_reg.Notify(); - - // Only |remover_2| and |b| run this time. - EXPECT_EQ(1, remover_1.total()); - EXPECT_EQ(2, remover_2.total()); - EXPECT_EQ(0, a.total()); - EXPECT_EQ(2, b.total()); -} - -// Test that a callback can add another callback to the list durning iteration -// without invalidating the iterator. The newly added callback should be run on -// the current iteration as will all other callbacks in the list. -TEST(CallbackListTest, AddCallbacksDuringIteration) { - CallbackList<void(void)> cb_reg; - Adder a(&cb_reg); - Listener b; - std::unique_ptr<CallbackList<void(void)>::Subscription> a_subscription = - cb_reg.Add(Bind(&Adder::AddCallback, Unretained(&a))); - std::unique_ptr<CallbackList<void(void)>::Subscription> b_subscription = - cb_reg.Add(Bind(&Listener::IncrementTotal, Unretained(&b))); - - cb_reg.Notify(); - - EXPECT_EQ(1, a.total()); - EXPECT_EQ(1, b.total()); - EXPECT_TRUE(a.added()); - - cb_reg.Notify(); - - EXPECT_EQ(2, a.total()); - EXPECT_EQ(2, b.total()); -} - -// Sanity check: notifying an empty list is a no-op. -TEST(CallbackListTest, EmptyList) { - CallbackList<void(void)> cb_reg; - - cb_reg.Notify(); -} - -TEST(CallbackList, RemovalCallback) { - Counter remove_count; - CallbackList<void(void)> cb_reg; - cb_reg.set_removal_callback( - Bind(&Counter::Increment, Unretained(&remove_count))); - - std::unique_ptr<CallbackList<void(void)>::Subscription> subscription = - cb_reg.Add(DoNothing()); - - // Removing a subscription outside of iteration signals the callback. - EXPECT_EQ(0, remove_count.value()); - subscription.reset(); - EXPECT_EQ(1, remove_count.value()); - - // Configure two subscriptions to remove themselves. - Remover remover_1, remover_2; - std::unique_ptr<CallbackList<void(void)>::Subscription> remover_1_sub = - cb_reg.Add( - Bind(&Remover::IncrementTotalAndRemove, Unretained(&remover_1))); - std::unique_ptr<CallbackList<void(void)>::Subscription> remover_2_sub = - cb_reg.Add( - Bind(&Remover::IncrementTotalAndRemove, Unretained(&remover_2))); - remover_1.SetSubscriptionToRemove(std::move(remover_1_sub)); - remover_2.SetSubscriptionToRemove(std::move(remover_2_sub)); - - // The callback should be signaled exactly once. - EXPECT_EQ(1, remove_count.value()); - cb_reg.Notify(); - EXPECT_EQ(2, remove_count.value()); - EXPECT_TRUE(cb_reg.empty()); -} - -} // namespace -} // namespace base
diff --git a/base/callback_list_unittest.nc b/base/callback_list_unittest.nc deleted file mode 100644 index 7347f76..0000000 --- a/base/callback_list_unittest.nc +++ /dev/null
@@ -1,56 +0,0 @@ -// 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. - -// This is a "No Compile Test" suite. -// http://dev.chromium.org/developers/testing/no-compile-tests - -#include "base/callback_list.h" - -#include <memory> -#include <utility> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/macros.h" - -namespace base { - -class Foo { - public: - Foo() {} - ~Foo() {} -}; - -class FooListener { - public: - FooListener() {} - - void GotAScopedFoo(std::unique_ptr<Foo> f) { foo_ = std::move(f); } - - std::unique_ptr<Foo> foo_; - - private: - DISALLOW_COPY_AND_ASSIGN(FooListener); -}; - - -#if defined(NCTEST_MOVE_ONLY_TYPE_PARAMETER) // [r"fatal error: call to (implicitly-)?deleted( copy)? constructor"] - -// Callbacks run with a move-only typed parameter. -// -// CallbackList does not support move-only typed parameters. Notify() is -// designed to take zero or more parameters, and run each registered callback -// with them. With move-only types, the parameter will be set to NULL after the -// first callback has been run. -void WontCompile() { - FooListener f; - CallbackList<void(std::unique_ptr<Foo>)> c1; - std::unique_ptr<CallbackList<void(std::unique_ptr<Foo>)>::Subscription> sub = - c1.Add(Bind(&FooListener::GotAScopedFoo, Unretained(&f))); - c1.Notify(std::unique_ptr<Foo>(new Foo())); -} - -#endif - -} // namespace base
diff --git a/base/callback_unittest.cc b/base/callback_unittest.cc deleted file mode 100644 index c07d3ee..0000000 --- a/base/callback_unittest.cc +++ /dev/null
@@ -1,187 +0,0 @@ -// 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/callback.h" - -#include <memory> - -#include "base/bind.h" -#include "base/callback_helpers.h" -#include "base/callback_internal.h" -#include "base/memory/ref_counted.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -void NopInvokeFunc() {} - -// White-box testpoints to inject into a Callback<> object for checking -// comparators and emptiness APIs. Use a BindState that is specialized -// based on a type we declared in the anonymous namespace above to remove any -// chance of colliding with another instantiation and breaking the -// one-definition-rule. -struct FakeBindState : internal::BindStateBase { - FakeBindState() : BindStateBase(&NopInvokeFunc, &Destroy, &IsCancelled) {} - - private: - ~FakeBindState() = default; - static void Destroy(const internal::BindStateBase* self) { - delete static_cast<const FakeBindState*>(self); - } - static bool IsCancelled(const internal::BindStateBase*) { - return false; - } -}; - -namespace { - -class CallbackTest : public ::testing::Test { - public: - CallbackTest() - : callback_a_(new FakeBindState()), callback_b_(new FakeBindState()) {} - - ~CallbackTest() override = default; - - protected: - Callback<void()> callback_a_; - const Callback<void()> callback_b_; // Ensure APIs work with const. - Callback<void()> null_callback_; -}; - -// Ensure we can create unbound callbacks. We need this to be able to store -// them in class members that can be initialized later. -TEST_F(CallbackTest, DefaultConstruction) { - Callback<void()> c0; - Callback<void(int)> c1; - Callback<void(int,int)> c2; - Callback<void(int,int,int)> c3; - Callback<void(int,int,int,int)> c4; - Callback<void(int,int,int,int,int)> c5; - Callback<void(int,int,int,int,int,int)> c6; - - EXPECT_TRUE(c0.is_null()); - EXPECT_TRUE(c1.is_null()); - EXPECT_TRUE(c2.is_null()); - EXPECT_TRUE(c3.is_null()); - EXPECT_TRUE(c4.is_null()); - EXPECT_TRUE(c5.is_null()); - EXPECT_TRUE(c6.is_null()); -} - -TEST_F(CallbackTest, IsNull) { - EXPECT_TRUE(null_callback_.is_null()); - EXPECT_FALSE(callback_a_.is_null()); - EXPECT_FALSE(callback_b_.is_null()); -} - -TEST_F(CallbackTest, Equals) { - EXPECT_TRUE(callback_a_.Equals(callback_a_)); - EXPECT_FALSE(callback_a_.Equals(callback_b_)); - EXPECT_FALSE(callback_b_.Equals(callback_a_)); - - // We should compare based on instance, not type. - Callback<void()> callback_c(new FakeBindState()); - Callback<void()> callback_a2 = callback_a_; - EXPECT_TRUE(callback_a_.Equals(callback_a2)); - EXPECT_FALSE(callback_a_.Equals(callback_c)); - - // Empty, however, is always equal to empty. - Callback<void()> empty2; - EXPECT_TRUE(null_callback_.Equals(empty2)); -} - -TEST_F(CallbackTest, Reset) { - // Resetting should bring us back to empty. - ASSERT_FALSE(callback_a_.is_null()); - ASSERT_FALSE(callback_a_.Equals(null_callback_)); - - callback_a_.Reset(); - - EXPECT_TRUE(callback_a_.is_null()); - EXPECT_TRUE(callback_a_.Equals(null_callback_)); -} - -TEST_F(CallbackTest, Move) { - // Moving should reset the callback. - ASSERT_FALSE(callback_a_.is_null()); - ASSERT_FALSE(callback_a_.Equals(null_callback_)); - - auto tmp = std::move(callback_a_); - - EXPECT_TRUE(callback_a_.is_null()); - EXPECT_TRUE(callback_a_.Equals(null_callback_)); -} - -struct TestForReentrancy { - TestForReentrancy() - : cb_already_run(false), - cb(Bind(&TestForReentrancy::AssertCBIsNull, Unretained(this))) { - } - void AssertCBIsNull() { - ASSERT_TRUE(cb.is_null()); - cb_already_run = true; - } - bool cb_already_run; - Closure cb; -}; - -TEST_F(CallbackTest, ResetAndReturn) { - TestForReentrancy tfr; - ASSERT_FALSE(tfr.cb.is_null()); - ASSERT_FALSE(tfr.cb_already_run); - ResetAndReturn(&tfr.cb).Run(); - ASSERT_TRUE(tfr.cb.is_null()); - ASSERT_TRUE(tfr.cb_already_run); -} - -TEST_F(CallbackTest, NullAfterMoveRun) { - Closure cb = Bind([] {}); - ASSERT_TRUE(cb); - std::move(cb).Run(); - ASSERT_FALSE(cb); - - const Closure cb2 = Bind([] {}); - ASSERT_TRUE(cb2); - std::move(cb2).Run(); - ASSERT_TRUE(cb2); - - OnceClosure cb3 = BindOnce([] {}); - ASSERT_TRUE(cb3); - std::move(cb3).Run(); - ASSERT_FALSE(cb3); -} - -class CallbackOwner : public base::RefCounted<CallbackOwner> { - public: - explicit CallbackOwner(bool* deleted) { - callback_ = Bind(&CallbackOwner::Unused, this); - deleted_ = deleted; - } - void Reset() { - callback_.Reset(); - // We are deleted here if no-one else had a ref to us. - } - - private: - friend class base::RefCounted<CallbackOwner>; - virtual ~CallbackOwner() { - *deleted_ = true; - } - void Unused() { - FAIL() << "Should never be called"; - } - - Closure callback_; - bool* deleted_; -}; - -TEST_F(CallbackTest, CallbackHasLastRefOnContainingObject) { - bool deleted = false; - CallbackOwner* owner = new CallbackOwner(&deleted); - owner->Reset(); - ASSERT_TRUE(deleted); -} - -} // namespace -} // namespace base
diff --git a/base/callback_unittest.nc b/base/callback_unittest.nc deleted file mode 100644 index 3261529..0000000 --- a/base/callback_unittest.nc +++ /dev/null
@@ -1,53 +0,0 @@ -// 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. - -// This is a "No Compile Test" suite. -// http://dev.chromium.org/developers/testing/no-compile-tests - -#include "base/callback.h" - -namespace base { - -class Parent { -}; - -class Child : Parent { -}; - -#if defined(NCTEST_EQUALS_REQUIRES_SAMETYPE) // [r"fatal error: no viable conversion from 'RepeatingCallback<int \(\)>' to 'const RepeatingCallback<void \(\)>'"] - -// Attempting to call comparison function on two callbacks of different type. -// -// This should be a compile time failure because each callback type should be -// considered distinct. -void WontCompile() { - Closure c1; - Callback<int()> c2; - c1.Equals(c2); -} - -#elif defined(NCTEST_CONSTRUCTION_FROM_SUBTYPE) // [r"fatal error: no viable conversion from 'Callback<base::Parent \(\)>' to 'Callback<base::Child \(\)>'"] - -// Construction of Callback<A> from Callback<B> if A is supertype of B. -// -// While this is technically safe, most people aren't used to it when coding -// C++ so if this is happening, it is almost certainly an error. -void WontCompile() { - Callback<Parent()> cb_a; - Callback<Child()> cb_b = cb_a; -} - -#elif defined(NCTEST_ASSIGNMENT_FROM_SUBTYPE) // [r"fatal error: no viable overloaded '='"] - -// Assignment of Callback<A> from Callback<B> if A is supertype of B. -// See explanation for NCTEST_CONSTRUCTION_FROM_SUBTYPE -void WontCompile() { - Callback<Parent()> cb_a; - Callback<Child()> cb_b; - cb_a = cb_b; -} - -#endif - -} // namespace base
diff --git a/base/cancelable_callback_unittest.cc b/base/cancelable_callback_unittest.cc deleted file mode 100644 index 373498c..0000000 --- a/base/cancelable_callback_unittest.cc +++ /dev/null
@@ -1,207 +0,0 @@ -// 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/cancelable_callback.h" - -#include <memory> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/location.h" -#include "base/memory/ptr_util.h" -#include "base/memory/ref_counted.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "base/single_thread_task_runner.h" -#include "base/threading/thread_task_runner_handle.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -class TestRefCounted : public RefCountedThreadSafe<TestRefCounted> { - private: - friend class RefCountedThreadSafe<TestRefCounted>; - ~TestRefCounted() = default; - ; -}; - -void Increment(int* count) { (*count)++; } -void IncrementBy(int* count, int n) { (*count) += n; } -void RefCountedParam(const scoped_refptr<TestRefCounted>& ref_counted) {} - -void OnMoveOnlyReceived(int* value, std::unique_ptr<int> result) { - *value = *result; -} - -// Cancel(). -// - Callback can be run multiple times. -// - After Cancel(), Run() completes but has no effect. -TEST(CancelableCallbackTest, Cancel) { - int count = 0; - CancelableClosure cancelable( - base::Bind(&Increment, base::Unretained(&count))); - - base::Closure callback = cancelable.callback(); - callback.Run(); - EXPECT_EQ(1, count); - - callback.Run(); - EXPECT_EQ(2, count); - - cancelable.Cancel(); - callback.Run(); - EXPECT_EQ(2, count); -} - -// Cancel() called multiple times. -// - Cancel() cancels all copies of the wrapped callback. -// - Calling Cancel() more than once has no effect. -// - After Cancel(), callback() returns a null callback. -TEST(CancelableCallbackTest, MultipleCancel) { - int count = 0; - CancelableClosure cancelable( - base::Bind(&Increment, base::Unretained(&count))); - - base::Closure callback1 = cancelable.callback(); - base::Closure callback2 = cancelable.callback(); - cancelable.Cancel(); - - callback1.Run(); - EXPECT_EQ(0, count); - - callback2.Run(); - EXPECT_EQ(0, count); - - // Calling Cancel() again has no effect. - cancelable.Cancel(); - - // callback() of a cancelled callback is null. - base::Closure callback3 = cancelable.callback(); - EXPECT_TRUE(callback3.is_null()); -} - -// CancelableCallback destroyed before callback is run. -// - Destruction of CancelableCallback cancels outstanding callbacks. -TEST(CancelableCallbackTest, CallbackCanceledOnDestruction) { - int count = 0; - base::Closure callback; - - { - CancelableClosure cancelable( - base::Bind(&Increment, base::Unretained(&count))); - - callback = cancelable.callback(); - callback.Run(); - EXPECT_EQ(1, count); - } - - callback.Run(); - EXPECT_EQ(1, count); -} - -// Cancel() called on bound closure with a RefCounted parameter. -// - Cancel drops wrapped callback (and, implicitly, its bound arguments). -TEST(CancelableCallbackTest, CancelDropsCallback) { - scoped_refptr<TestRefCounted> ref_counted = new TestRefCounted; - EXPECT_TRUE(ref_counted->HasOneRef()); - - CancelableClosure cancelable(base::Bind(RefCountedParam, ref_counted)); - EXPECT_FALSE(cancelable.IsCancelled()); - EXPECT_TRUE(ref_counted.get()); - EXPECT_FALSE(ref_counted->HasOneRef()); - - // There is only one reference to |ref_counted| after the Cancel(). - cancelable.Cancel(); - EXPECT_TRUE(cancelable.IsCancelled()); - EXPECT_TRUE(ref_counted.get()); - EXPECT_TRUE(ref_counted->HasOneRef()); -} - -// Reset(). -// - Reset() replaces the existing wrapped callback with a new callback. -// - Reset() deactivates outstanding callbacks. -TEST(CancelableCallbackTest, Reset) { - int count = 0; - CancelableClosure cancelable( - base::Bind(&Increment, base::Unretained(&count))); - - base::Closure callback = cancelable.callback(); - callback.Run(); - EXPECT_EQ(1, count); - - callback.Run(); - EXPECT_EQ(2, count); - - cancelable.Reset( - base::Bind(&IncrementBy, base::Unretained(&count), 3)); - EXPECT_FALSE(cancelable.IsCancelled()); - - // The stale copy of the cancelable callback is non-null. - ASSERT_FALSE(callback.is_null()); - - // The stale copy of the cancelable callback is no longer active. - callback.Run(); - EXPECT_EQ(2, count); - - base::Closure callback2 = cancelable.callback(); - ASSERT_FALSE(callback2.is_null()); - - callback2.Run(); - EXPECT_EQ(5, count); -} - -// IsCanceled(). -// - Cancel() transforms the CancelableCallback into a cancelled state. -TEST(CancelableCallbackTest, IsNull) { - CancelableClosure cancelable; - EXPECT_TRUE(cancelable.IsCancelled()); - - int count = 0; - cancelable.Reset(base::Bind(&Increment, - base::Unretained(&count))); - EXPECT_FALSE(cancelable.IsCancelled()); - - cancelable.Cancel(); - EXPECT_TRUE(cancelable.IsCancelled()); -} - -// CancelableCallback posted to a MessageLoop with PostTask. -// - Callbacks posted to a MessageLoop can be cancelled. -TEST(CancelableCallbackTest, PostTask) { - MessageLoop loop; - - int count = 0; - CancelableClosure cancelable(base::Bind(&Increment, - base::Unretained(&count))); - - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, cancelable.callback()); - RunLoop().RunUntilIdle(); - - EXPECT_EQ(1, count); - - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, cancelable.callback()); - - // Cancel before running the message loop. - cancelable.Cancel(); - RunLoop().RunUntilIdle(); - - // Callback never ran due to cancellation; count is the same. - EXPECT_EQ(1, count); -} - -// CancelableCallback can be used with move-only types. -TEST(CancelableCallbackTest, MoveOnlyType) { - const int kExpectedResult = 42; - - int result = 0; - CancelableCallback<void(std::unique_ptr<int>)> cb( - base::Bind(&OnMoveOnlyReceived, base::Unretained(&result))); - cb.callback().Run(base::WrapUnique(new int(kExpectedResult))); - - EXPECT_EQ(kExpectedResult, result); -} - -} // namespace -} // namespace base
diff --git a/base/command_line_unittest.cc b/base/command_line_unittest.cc deleted file mode 100644 index 2396830..0000000 --- a/base/command_line_unittest.cc +++ /dev/null
@@ -1,440 +0,0 @@ -// 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/command_line.h" - -#include <memory> -#include <string> -#include <vector> - -#include "base/files/file_path.h" -#include "base/macros.h" -#include "base/strings/utf_string_conversions.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -// To test Windows quoting behavior, we use a string that has some backslashes -// and quotes. -// Consider the command-line argument: q\"bs1\bs2\\bs3q\\\" -// Here it is with C-style escapes. -static const CommandLine::StringType kTrickyQuoted = - FILE_PATH_LITERAL("q\\\"bs1\\bs2\\\\bs3q\\\\\\\""); -// It should be parsed by Windows as: q"bs1\bs2\\bs3q\" -// Here that is with C-style escapes. -static const CommandLine::StringType kTricky = - FILE_PATH_LITERAL("q\"bs1\\bs2\\\\bs3q\\\""); - -TEST(CommandLineTest, CommandLineConstructor) { - const CommandLine::CharType* argv[] = { - FILE_PATH_LITERAL("program"), - FILE_PATH_LITERAL("--foo="), - FILE_PATH_LITERAL("-bAr"), - FILE_PATH_LITERAL("-spaetzel=pierogi"), - FILE_PATH_LITERAL("-baz"), - FILE_PATH_LITERAL("flim"), - FILE_PATH_LITERAL("--other-switches=--dog=canine --cat=feline"), - FILE_PATH_LITERAL("-spaetzle=Crepe"), - FILE_PATH_LITERAL("-=loosevalue"), - FILE_PATH_LITERAL("-"), - FILE_PATH_LITERAL("FLAN"), - FILE_PATH_LITERAL("a"), - FILE_PATH_LITERAL("--input-translation=45--output-rotation"), - FILE_PATH_LITERAL("--"), - FILE_PATH_LITERAL("--"), - FILE_PATH_LITERAL("--not-a-switch"), - FILE_PATH_LITERAL("\"in the time of submarines...\""), - FILE_PATH_LITERAL("unquoted arg-with-space")}; - CommandLine cl(arraysize(argv), argv); - - EXPECT_FALSE(cl.GetCommandLineString().empty()); - EXPECT_FALSE(cl.HasSwitch("cruller")); - EXPECT_FALSE(cl.HasSwitch("flim")); - EXPECT_FALSE(cl.HasSwitch("program")); - EXPECT_FALSE(cl.HasSwitch("dog")); - EXPECT_FALSE(cl.HasSwitch("cat")); - EXPECT_FALSE(cl.HasSwitch("output-rotation")); - EXPECT_FALSE(cl.HasSwitch("not-a-switch")); - EXPECT_FALSE(cl.HasSwitch("--")); - - EXPECT_EQ(FilePath(FILE_PATH_LITERAL("program")).value(), - cl.GetProgram().value()); - - EXPECT_TRUE(cl.HasSwitch("foo")); -#if defined(OS_WIN) - EXPECT_TRUE(cl.HasSwitch("bar")); -#else - EXPECT_FALSE(cl.HasSwitch("bar")); -#endif - EXPECT_TRUE(cl.HasSwitch("baz")); - EXPECT_TRUE(cl.HasSwitch("spaetzle")); - EXPECT_TRUE(cl.HasSwitch("other-switches")); - EXPECT_TRUE(cl.HasSwitch("input-translation")); - - EXPECT_EQ("Crepe", cl.GetSwitchValueASCII("spaetzle")); - EXPECT_EQ("", cl.GetSwitchValueASCII("foo")); - EXPECT_EQ("", cl.GetSwitchValueASCII("bar")); - EXPECT_EQ("", cl.GetSwitchValueASCII("cruller")); - EXPECT_EQ("--dog=canine --cat=feline", cl.GetSwitchValueASCII( - "other-switches")); - EXPECT_EQ("45--output-rotation", cl.GetSwitchValueASCII("input-translation")); - - const CommandLine::StringVector& args = cl.GetArgs(); - ASSERT_EQ(8U, args.size()); - - std::vector<CommandLine::StringType>::const_iterator iter = args.begin(); - EXPECT_EQ(FILE_PATH_LITERAL("flim"), *iter); - ++iter; - EXPECT_EQ(FILE_PATH_LITERAL("-"), *iter); - ++iter; - EXPECT_EQ(FILE_PATH_LITERAL("FLAN"), *iter); - ++iter; - EXPECT_EQ(FILE_PATH_LITERAL("a"), *iter); - ++iter; - EXPECT_EQ(FILE_PATH_LITERAL("--"), *iter); - ++iter; - EXPECT_EQ(FILE_PATH_LITERAL("--not-a-switch"), *iter); - ++iter; - EXPECT_EQ(FILE_PATH_LITERAL("\"in the time of submarines...\""), *iter); - ++iter; - EXPECT_EQ(FILE_PATH_LITERAL("unquoted arg-with-space"), *iter); - ++iter; - EXPECT_TRUE(iter == args.end()); -} - -TEST(CommandLineTest, CommandLineFromString) { -#if defined(OS_WIN) - CommandLine cl = CommandLine::FromString( - L"program --foo= -bAr /Spaetzel=pierogi /Baz flim " - L"--other-switches=\"--dog=canine --cat=feline\" " - L"-spaetzle=Crepe -=loosevalue FLAN " - L"--input-translation=\"45\"--output-rotation " - L"--quotes=" + kTrickyQuoted + L" " - L"-- -- --not-a-switch " - L"\"in the time of submarines...\""); - - EXPECT_FALSE(cl.GetCommandLineString().empty()); - EXPECT_FALSE(cl.HasSwitch("cruller")); - EXPECT_FALSE(cl.HasSwitch("flim")); - EXPECT_FALSE(cl.HasSwitch("program")); - EXPECT_FALSE(cl.HasSwitch("dog")); - EXPECT_FALSE(cl.HasSwitch("cat")); - EXPECT_FALSE(cl.HasSwitch("output-rotation")); - EXPECT_FALSE(cl.HasSwitch("not-a-switch")); - EXPECT_FALSE(cl.HasSwitch("--")); - - EXPECT_EQ(FilePath(FILE_PATH_LITERAL("program")).value(), - cl.GetProgram().value()); - - EXPECT_TRUE(cl.HasSwitch("foo")); - EXPECT_TRUE(cl.HasSwitch("bar")); - EXPECT_TRUE(cl.HasSwitch("baz")); - EXPECT_TRUE(cl.HasSwitch("spaetzle")); - EXPECT_TRUE(cl.HasSwitch("other-switches")); - EXPECT_TRUE(cl.HasSwitch("input-translation")); - EXPECT_TRUE(cl.HasSwitch("quotes")); - - EXPECT_EQ("Crepe", cl.GetSwitchValueASCII("spaetzle")); - EXPECT_EQ("", cl.GetSwitchValueASCII("foo")); - EXPECT_EQ("", cl.GetSwitchValueASCII("bar")); - EXPECT_EQ("", cl.GetSwitchValueASCII("cruller")); - EXPECT_EQ("--dog=canine --cat=feline", cl.GetSwitchValueASCII( - "other-switches")); - EXPECT_EQ("45--output-rotation", cl.GetSwitchValueASCII("input-translation")); - EXPECT_EQ(kTricky, cl.GetSwitchValueNative("quotes")); - - const CommandLine::StringVector& args = cl.GetArgs(); - ASSERT_EQ(5U, args.size()); - - std::vector<CommandLine::StringType>::const_iterator iter = args.begin(); - EXPECT_EQ(FILE_PATH_LITERAL("flim"), *iter); - ++iter; - EXPECT_EQ(FILE_PATH_LITERAL("FLAN"), *iter); - ++iter; - EXPECT_EQ(FILE_PATH_LITERAL("--"), *iter); - ++iter; - EXPECT_EQ(FILE_PATH_LITERAL("--not-a-switch"), *iter); - ++iter; - EXPECT_EQ(FILE_PATH_LITERAL("in the time of submarines..."), *iter); - ++iter; - EXPECT_TRUE(iter == args.end()); - - // Check that a generated string produces an equivalent command line. - CommandLine cl_duplicate = CommandLine::FromString(cl.GetCommandLineString()); - EXPECT_EQ(cl.GetCommandLineString(), cl_duplicate.GetCommandLineString()); -#endif -} - -// Tests behavior with an empty input string. -TEST(CommandLineTest, EmptyString) { -#if defined(OS_WIN) - CommandLine cl_from_string = CommandLine::FromString(L""); - EXPECT_TRUE(cl_from_string.GetCommandLineString().empty()); - EXPECT_TRUE(cl_from_string.GetProgram().empty()); - EXPECT_EQ(1U, cl_from_string.argv().size()); - EXPECT_TRUE(cl_from_string.GetArgs().empty()); -#endif - CommandLine cl_from_argv(0, nullptr); - EXPECT_TRUE(cl_from_argv.GetCommandLineString().empty()); - EXPECT_TRUE(cl_from_argv.GetProgram().empty()); - EXPECT_EQ(1U, cl_from_argv.argv().size()); - EXPECT_TRUE(cl_from_argv.GetArgs().empty()); -} - -TEST(CommandLineTest, GetArgumentsString) { - static const FilePath::CharType kPath1[] = - FILE_PATH_LITERAL("C:\\Some File\\With Spaces.ggg"); - static const FilePath::CharType kPath2[] = - FILE_PATH_LITERAL("C:\\no\\spaces.ggg"); - - static const char kFirstArgName[] = "first-arg"; - static const char kSecondArgName[] = "arg2"; - static const char kThirdArgName[] = "arg with space"; - static const char kFourthArgName[] = "nospace"; - static const char kFifthArgName[] = "%1"; - - CommandLine cl(CommandLine::NO_PROGRAM); - cl.AppendSwitchPath(kFirstArgName, FilePath(kPath1)); - cl.AppendSwitchPath(kSecondArgName, FilePath(kPath2)); - cl.AppendArg(kThirdArgName); - cl.AppendArg(kFourthArgName); - cl.AppendArg(kFifthArgName); - -#if defined(OS_WIN) - CommandLine::StringType expected_first_arg(UTF8ToUTF16(kFirstArgName)); - CommandLine::StringType expected_second_arg(UTF8ToUTF16(kSecondArgName)); - CommandLine::StringType expected_third_arg(UTF8ToUTF16(kThirdArgName)); - CommandLine::StringType expected_fourth_arg(UTF8ToUTF16(kFourthArgName)); - CommandLine::StringType expected_fifth_arg(UTF8ToUTF16(kFifthArgName)); -#elif defined(OS_POSIX) || defined(OS_FUCHSIA) - CommandLine::StringType expected_first_arg(kFirstArgName); - CommandLine::StringType expected_second_arg(kSecondArgName); - CommandLine::StringType expected_third_arg(kThirdArgName); - CommandLine::StringType expected_fourth_arg(kFourthArgName); - CommandLine::StringType expected_fifth_arg(kFifthArgName); -#endif - -#if defined(OS_WIN) -#define QUOTE_ON_WIN FILE_PATH_LITERAL("\"") -#else -#define QUOTE_ON_WIN FILE_PATH_LITERAL("") -#endif // OS_WIN - - CommandLine::StringType expected_str; - expected_str.append(FILE_PATH_LITERAL("--")) - .append(expected_first_arg) - .append(FILE_PATH_LITERAL("=")) - .append(QUOTE_ON_WIN) - .append(kPath1) - .append(QUOTE_ON_WIN) - .append(FILE_PATH_LITERAL(" ")) - .append(FILE_PATH_LITERAL("--")) - .append(expected_second_arg) - .append(FILE_PATH_LITERAL("=")) - .append(QUOTE_ON_WIN) - .append(kPath2) - .append(QUOTE_ON_WIN) - .append(FILE_PATH_LITERAL(" ")) - .append(QUOTE_ON_WIN) - .append(expected_third_arg) - .append(QUOTE_ON_WIN) - .append(FILE_PATH_LITERAL(" ")) - .append(expected_fourth_arg) - .append(FILE_PATH_LITERAL(" ")); - - CommandLine::StringType expected_str_no_quote_placeholders(expected_str); - expected_str_no_quote_placeholders.append(expected_fifth_arg); - EXPECT_EQ(expected_str_no_quote_placeholders, cl.GetArgumentsString()); - -#if defined(OS_WIN) - CommandLine::StringType expected_str_quote_placeholders(expected_str); - expected_str_quote_placeholders.append(QUOTE_ON_WIN) - .append(expected_fifth_arg) - .append(QUOTE_ON_WIN); - EXPECT_EQ(expected_str_quote_placeholders, - cl.GetArgumentsStringWithPlaceholders()); -#endif -} - -// Test methods for appending switches to a command line. -TEST(CommandLineTest, AppendSwitches) { - std::string switch1 = "switch1"; - std::string switch2 = "switch2"; - std::string value2 = "value"; - std::string switch3 = "switch3"; - std::string value3 = "a value with spaces"; - std::string switch4 = "switch4"; - std::string value4 = "\"a value with quotes\""; - std::string switch5 = "quotes"; - CommandLine::StringType value5 = kTricky; - - CommandLine cl(FilePath(FILE_PATH_LITERAL("Program"))); - - cl.AppendSwitch(switch1); - cl.AppendSwitchASCII(switch2, value2); - cl.AppendSwitchASCII(switch3, value3); - cl.AppendSwitchASCII(switch4, value4); - cl.AppendSwitchASCII(switch5, value4); - cl.AppendSwitchNative(switch5, value5); - - EXPECT_TRUE(cl.HasSwitch(switch1)); - EXPECT_TRUE(cl.HasSwitch(switch2)); - EXPECT_EQ(value2, cl.GetSwitchValueASCII(switch2)); - EXPECT_TRUE(cl.HasSwitch(switch3)); - EXPECT_EQ(value3, cl.GetSwitchValueASCII(switch3)); - EXPECT_TRUE(cl.HasSwitch(switch4)); - EXPECT_EQ(value4, cl.GetSwitchValueASCII(switch4)); - EXPECT_TRUE(cl.HasSwitch(switch5)); - EXPECT_EQ(value5, cl.GetSwitchValueNative(switch5)); - -#if defined(OS_WIN) - EXPECT_EQ(L"Program " - L"--switch1 " - L"--switch2=value " - L"--switch3=\"a value with spaces\" " - L"--switch4=\"\\\"a value with quotes\\\"\" " - // Even though the switches are unique, appending can add repeat - // switches to argv. - L"--quotes=\"\\\"a value with quotes\\\"\" " - L"--quotes=\"" + kTrickyQuoted + L"\"", - cl.GetCommandLineString()); -#endif -} - -TEST(CommandLineTest, AppendSwitchesDashDash) { - const CommandLine::CharType* raw_argv[] = { FILE_PATH_LITERAL("prog"), - FILE_PATH_LITERAL("--"), - FILE_PATH_LITERAL("--arg1") }; - CommandLine cl(arraysize(raw_argv), raw_argv); - - cl.AppendSwitch("switch1"); - cl.AppendSwitchASCII("switch2", "foo"); - - cl.AppendArg("--arg2"); - - EXPECT_EQ(FILE_PATH_LITERAL("prog --switch1 --switch2=foo -- --arg1 --arg2"), - cl.GetCommandLineString()); - CommandLine::StringVector cl_argv = cl.argv(); - EXPECT_EQ(FILE_PATH_LITERAL("prog"), cl_argv[0]); - EXPECT_EQ(FILE_PATH_LITERAL("--switch1"), cl_argv[1]); - EXPECT_EQ(FILE_PATH_LITERAL("--switch2=foo"), cl_argv[2]); - EXPECT_EQ(FILE_PATH_LITERAL("--"), cl_argv[3]); - EXPECT_EQ(FILE_PATH_LITERAL("--arg1"), cl_argv[4]); - EXPECT_EQ(FILE_PATH_LITERAL("--arg2"), cl_argv[5]); -} - -// Tests that when AppendArguments is called that the program is set correctly -// on the target CommandLine object and the switches from the source -// CommandLine are added to the target. -TEST(CommandLineTest, AppendArguments) { - CommandLine cl1(FilePath(FILE_PATH_LITERAL("Program"))); - cl1.AppendSwitch("switch1"); - cl1.AppendSwitchASCII("switch2", "foo"); - - CommandLine cl2(CommandLine::NO_PROGRAM); - cl2.AppendArguments(cl1, true); - EXPECT_EQ(cl1.GetProgram().value(), cl2.GetProgram().value()); - EXPECT_EQ(cl1.GetCommandLineString(), cl2.GetCommandLineString()); - - CommandLine c1(FilePath(FILE_PATH_LITERAL("Program1"))); - c1.AppendSwitch("switch1"); - CommandLine c2(FilePath(FILE_PATH_LITERAL("Program2"))); - c2.AppendSwitch("switch2"); - - c1.AppendArguments(c2, true); - EXPECT_EQ(c1.GetProgram().value(), c2.GetProgram().value()); - EXPECT_TRUE(c1.HasSwitch("switch1")); - EXPECT_TRUE(c1.HasSwitch("switch2")); -} - -#if defined(OS_WIN) -// Make sure that the command line string program paths are quoted as necessary. -// This only makes sense on Windows and the test is basically here to guard -// against regressions. -TEST(CommandLineTest, ProgramQuotes) { - // Check that quotes are not added for paths without spaces. - const FilePath kProgram(L"Program"); - CommandLine cl_program(kProgram); - EXPECT_EQ(kProgram.value(), cl_program.GetProgram().value()); - EXPECT_EQ(kProgram.value(), cl_program.GetCommandLineString()); - - const FilePath kProgramPath(L"Program Path"); - - // Check that quotes are not returned from GetProgram(). - CommandLine cl_program_path(kProgramPath); - EXPECT_EQ(kProgramPath.value(), cl_program_path.GetProgram().value()); - - // Check that quotes are added to command line string paths containing spaces. - CommandLine::StringType cmd_string(cl_program_path.GetCommandLineString()); - EXPECT_EQ(L"\"Program Path\"", cmd_string); - - // Check the optional quoting of placeholders in programs. - CommandLine cl_quote_placeholder(FilePath(L"%1")); - EXPECT_EQ(L"%1", cl_quote_placeholder.GetCommandLineString()); - EXPECT_EQ(L"\"%1\"", - cl_quote_placeholder.GetCommandLineStringWithPlaceholders()); -} -#endif - -// Calling Init multiple times should not modify the previous CommandLine. -TEST(CommandLineTest, Init) { - // Call Init without checking output once so we know it's been called - // whether or not the test runner does so. - CommandLine::Init(0, nullptr); - CommandLine* initial = CommandLine::ForCurrentProcess(); - EXPECT_FALSE(CommandLine::Init(0, nullptr)); - CommandLine* current = CommandLine::ForCurrentProcess(); - EXPECT_EQ(initial, current); -} - -// Test that copies of CommandLine have a valid StringPiece map. -TEST(CommandLineTest, Copy) { - std::unique_ptr<CommandLine> initial( - new CommandLine(CommandLine::NO_PROGRAM)); - initial->AppendSwitch("a"); - initial->AppendSwitch("bbbbbbbbbbbbbbb"); - initial->AppendSwitch("c"); - CommandLine copy_constructed(*initial); - CommandLine assigned = *initial; - CommandLine::SwitchMap switch_map = initial->GetSwitches(); - initial.reset(); - for (const auto& pair : switch_map) - EXPECT_TRUE(copy_constructed.HasSwitch(pair.first)); - for (const auto& pair : switch_map) - EXPECT_TRUE(assigned.HasSwitch(pair.first)); -} - -TEST(CommandLineTest, PrependSimpleWrapper) { - CommandLine cl(FilePath(FILE_PATH_LITERAL("Program"))); - cl.AppendSwitch("a"); - cl.AppendSwitch("b"); - cl.PrependWrapper(FILE_PATH_LITERAL("wrapper --foo --bar")); - - EXPECT_EQ(6u, cl.argv().size()); - EXPECT_EQ(FILE_PATH_LITERAL("wrapper"), cl.argv()[0]); - EXPECT_EQ(FILE_PATH_LITERAL("--foo"), cl.argv()[1]); - EXPECT_EQ(FILE_PATH_LITERAL("--bar"), cl.argv()[2]); - EXPECT_EQ(FILE_PATH_LITERAL("Program"), cl.argv()[3]); - EXPECT_EQ(FILE_PATH_LITERAL("--a"), cl.argv()[4]); - EXPECT_EQ(FILE_PATH_LITERAL("--b"), cl.argv()[5]); -} - -TEST(CommandLineTest, PrependComplexWrapper) { - CommandLine cl(FilePath(FILE_PATH_LITERAL("Program"))); - cl.AppendSwitch("a"); - cl.AppendSwitch("b"); - cl.PrependWrapper( - FILE_PATH_LITERAL("wrapper --foo='hello world' --bar=\"let's go\"")); - - EXPECT_EQ(6u, cl.argv().size()); - EXPECT_EQ(FILE_PATH_LITERAL("wrapper"), cl.argv()[0]); - EXPECT_EQ(FILE_PATH_LITERAL("--foo='hello world'"), cl.argv()[1]); - EXPECT_EQ(FILE_PATH_LITERAL("--bar=\"let's go\""), cl.argv()[2]); - EXPECT_EQ(FILE_PATH_LITERAL("Program"), cl.argv()[3]); - EXPECT_EQ(FILE_PATH_LITERAL("--a"), cl.argv()[4]); - EXPECT_EQ(FILE_PATH_LITERAL("--b"), cl.argv()[5]); -} - -} // namespace base
diff --git a/base/component_export_unittest.cc b/base/component_export_unittest.cc deleted file mode 100644 index e994353..0000000 --- a/base/component_export_unittest.cc +++ /dev/null
@@ -1,82 +0,0 @@ -// 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/component_export.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -using ComponentExportTest = testing::Test; - -#define IS_TEST_COMPONENT_A_IMPL 1 -#define IS_TEST_COMPONENT_B_IMPL -#define IS_TEST_COMPONENT_C_IMPL 0 -#define IS_TEST_COMPONENT_D_IMPL 2 -#define IS_TEST_COMPONENT_E_IMPL xyz - -TEST(ComponentExportTest, ImportExport) { - // Defined as 1. Treat as export. - EXPECT_EQ(1, INSIDE_COMPONENT_IMPL(TEST_COMPONENT_A)); - - // Defined, but empty. Treat as import. - EXPECT_EQ(0, INSIDE_COMPONENT_IMPL(TEST_COMPONENT_B)); - - // Defined, but 0. Treat as import. - EXPECT_EQ(0, INSIDE_COMPONENT_IMPL(TEST_COMPONENT_C)); - - // Defined, but some other arbitrary thing that isn't 1. Treat as import. - EXPECT_EQ(0, INSIDE_COMPONENT_IMPL(TEST_COMPONENT_D)); - EXPECT_EQ(0, INSIDE_COMPONENT_IMPL(TEST_COMPONENT_E)); - - // Undefined. Treat as import. - EXPECT_EQ(0, INSIDE_COMPONENT_IMPL(TEST_COMPONENT_F)); - - // And just for good measure, ensure that the macros evaluate properly in the - // context of preprocessor #if blocks. -#if INSIDE_COMPONENT_IMPL(TEST_COMPONENT_A) - EXPECT_TRUE(true); -#else - EXPECT_TRUE(false); -#endif - -#if !INSIDE_COMPONENT_IMPL(TEST_COMPONENT_B) - EXPECT_TRUE(true); -#else - EXPECT_TRUE(false); -#endif - -#if !INSIDE_COMPONENT_IMPL(TEST_COMPONENT_C) - EXPECT_TRUE(true); -#else - EXPECT_TRUE(false); -#endif - -#if !INSIDE_COMPONENT_IMPL(TEST_COMPONENT_D) - EXPECT_TRUE(true); -#else - EXPECT_TRUE(false); -#endif - -#if !INSIDE_COMPONENT_IMPL(TEST_COMPONENT_E) - EXPECT_TRUE(true); -#else - EXPECT_TRUE(false); -#endif - -#if !INSIDE_COMPONENT_IMPL(TEST_COMPONENT_F) - EXPECT_TRUE(true); -#else - EXPECT_TRUE(false); -#endif -} - -#undef IS_TEST_COMPONENT_A_IMPL -#undef IS_TEST_COMPONENT_B_IMPL -#undef IS_TEST_COMPONENT_C_IMPL -#undef IS_TEST_COMPONENT_D_IMPL -#undef IS_TEST_COMPONENT_E_IMPL - -} // namespace -} // namespace base
diff --git a/base/containers/adapters_unittest.cc b/base/containers/adapters_unittest.cc deleted file mode 100644 index 92554b7..0000000 --- a/base/containers/adapters_unittest.cc +++ /dev/null
@@ -1,52 +0,0 @@ -// 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/containers/adapters.h" - -#include <vector> - -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -TEST(AdaptersTest, Reversed) { - std::vector<int> v; - v.push_back(3); - v.push_back(2); - v.push_back(1); - int j = 0; - for (int& i : base::Reversed(v)) { - EXPECT_EQ(++j, i); - i += 100; - } - EXPECT_EQ(103, v[0]); - EXPECT_EQ(102, v[1]); - EXPECT_EQ(101, v[2]); -} - -TEST(AdaptersTest, ReversedArray) { - int v[3] = {3, 2, 1}; - int j = 0; - for (int& i : base::Reversed(v)) { - EXPECT_EQ(++j, i); - i += 100; - } - EXPECT_EQ(103, v[0]); - EXPECT_EQ(102, v[1]); - EXPECT_EQ(101, v[2]); -} - -TEST(AdaptersTest, ReversedConst) { - std::vector<int> v; - v.push_back(3); - v.push_back(2); - v.push_back(1); - const std::vector<int>& cv = v; - int j = 0; - for (int i : base::Reversed(cv)) { - EXPECT_EQ(++j, i); - } -} - -} // namespace
diff --git a/base/containers/circular_deque_unittest.cc b/base/containers/circular_deque_unittest.cc deleted file mode 100644 index 0c168e0..0000000 --- a/base/containers/circular_deque_unittest.cc +++ /dev/null
@@ -1,881 +0,0 @@ -// 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/containers/circular_deque.h" - -#include "base/test/copy_only_int.h" -#include "base/test/move_only_int.h" -#include "testing/gtest/include/gtest/gtest.h" - -using base::internal::VectorBuffer; - -namespace base { - -namespace { - -circular_deque<int> MakeSequence(size_t max) { - circular_deque<int> ret; - for (size_t i = 0; i < max; i++) - ret.push_back(i); - return ret; -} - -// Cycles through the queue, popping items from the back and pushing items -// at the front to validate behavior across different configurations of the -// queue in relation to the underlying buffer. The tester closure is run for -// each cycle. -template <class QueueT, class Tester> -void CycleTest(circular_deque<QueueT>& queue, const Tester& tester) { - size_t steps = queue.size() * 2; - for (size_t i = 0; i < steps; i++) { - tester(queue, i); - queue.pop_back(); - queue.push_front(QueueT()); - } -} - -class DestructorCounter { - public: - DestructorCounter(int* counter) : counter_(counter) {} - ~DestructorCounter() { ++(*counter_); } - - private: - int* counter_; -}; - -} // namespace - -TEST(CircularDeque, FillConstructor) { - constexpr size_t num_elts = 9; - - std::vector<int> foo(15); - EXPECT_EQ(15u, foo.size()); - - // Fill with default constructor. - { - circular_deque<int> buf(num_elts); - - EXPECT_EQ(num_elts, buf.size()); - EXPECT_EQ(num_elts, static_cast<size_t>(buf.end() - buf.begin())); - - for (size_t i = 0; i < num_elts; i++) - EXPECT_EQ(0, buf[i]); - } - - // Fill with explicit value. - { - int value = 199; - circular_deque<int> buf(num_elts, value); - - EXPECT_EQ(num_elts, buf.size()); - EXPECT_EQ(num_elts, static_cast<size_t>(buf.end() - buf.begin())); - - for (size_t i = 0; i < num_elts; i++) - EXPECT_EQ(value, buf[i]); - } -} - -TEST(CircularDeque, CopyAndRangeConstructor) { - int values[] = {1, 2, 3, 4, 5, 6}; - circular_deque<CopyOnlyInt> first(std::begin(values), std::end(values)); - - circular_deque<CopyOnlyInt> second(first); - EXPECT_EQ(6u, second.size()); - for (int i = 0; i < 6; i++) - EXPECT_EQ(i + 1, second[i].data()); -} - -TEST(CircularDeque, MoveConstructor) { - int values[] = {1, 2, 3, 4, 5, 6}; - circular_deque<MoveOnlyInt> first(std::begin(values), std::end(values)); - - circular_deque<MoveOnlyInt> second(std::move(first)); - EXPECT_TRUE(first.empty()); - EXPECT_EQ(6u, second.size()); - for (int i = 0; i < 6; i++) - EXPECT_EQ(i + 1, second[i].data()); -} - -TEST(CircularDeque, InitializerListConstructor) { - circular_deque<int> empty({}); - ASSERT_TRUE(empty.empty()); - - circular_deque<int> first({1, 2, 3, 4, 5, 6}); - EXPECT_EQ(6u, first.size()); - for (int i = 0; i < 6; i++) - EXPECT_EQ(i + 1, first[i]); -} - -TEST(CircularDeque, Destructor) { - int destruct_count = 0; - - // Contiguous buffer. - { - circular_deque<DestructorCounter> q; - q.resize(5, DestructorCounter(&destruct_count)); - - EXPECT_EQ(1, destruct_count); // The temporary in the call to resize(). - destruct_count = 0; - } - EXPECT_EQ(5, destruct_count); // One call for each. - - // Force a wraparound buffer. - { - circular_deque<DestructorCounter> q; - q.reserve(7); - q.resize(5, DestructorCounter(&destruct_count)); - - // Cycle throught some elements in our buffer to force a wraparound. - destruct_count = 0; - for (int i = 0; i < 4; i++) { - q.emplace_back(&destruct_count); - q.pop_front(); - } - EXPECT_EQ(4, destruct_count); // One for each cycle. - destruct_count = 0; - } - EXPECT_EQ(5, destruct_count); // One call for each. -} - -TEST(CircularDeque, EqualsCopy) { - circular_deque<int> first = {1, 2, 3, 4, 5, 6}; - circular_deque<int> copy; - EXPECT_TRUE(copy.empty()); - copy = first; - EXPECT_EQ(6u, copy.size()); - for (int i = 0; i < 6; i++) { - EXPECT_EQ(i + 1, first[i]); - EXPECT_EQ(i + 1, copy[i]); - EXPECT_NE(&first[i], ©[i]); - } -} - -TEST(CircularDeque, EqualsMove) { - circular_deque<int> first = {1, 2, 3, 4, 5, 6}; - circular_deque<int> move; - EXPECT_TRUE(move.empty()); - move = std::move(first); - EXPECT_TRUE(first.empty()); - EXPECT_EQ(6u, move.size()); - for (int i = 0; i < 6; i++) - EXPECT_EQ(i + 1, move[i]); -} - -// Tests that self-assignment is a no-op. -TEST(CircularDeque, EqualsSelf) { - circular_deque<int> q = {1, 2, 3, 4, 5, 6}; - q = *&q; // The *& defeats Clang's -Wself-assign warning. - EXPECT_EQ(6u, q.size()); - for (int i = 0; i < 6; i++) - EXPECT_EQ(i + 1, q[i]); -} - -TEST(CircularDeque, EqualsInitializerList) { - circular_deque<int> q; - EXPECT_TRUE(q.empty()); - q = {1, 2, 3, 4, 5, 6}; - EXPECT_EQ(6u, q.size()); - for (int i = 0; i < 6; i++) - EXPECT_EQ(i + 1, q[i]); -} - -TEST(CircularDeque, AssignCountValue) { - circular_deque<int> empty; - empty.assign(0, 52); - EXPECT_EQ(0u, empty.size()); - - circular_deque<int> full; - size_t count = 13; - int value = 12345; - full.assign(count, value); - EXPECT_EQ(count, full.size()); - - for (size_t i = 0; i < count; i++) - EXPECT_EQ(value, full[i]); -} - -TEST(CircularDeque, AssignIterator) { - int range[8] = {11, 12, 13, 14, 15, 16, 17, 18}; - - circular_deque<int> empty; - empty.assign(std::begin(range), std::begin(range)); - EXPECT_TRUE(empty.empty()); - - circular_deque<int> full; - full.assign(std::begin(range), std::end(range)); - EXPECT_EQ(8u, full.size()); - for (size_t i = 0; i < 8; i++) - EXPECT_EQ(range[i], full[i]); -} - -TEST(CircularDeque, AssignInitializerList) { - circular_deque<int> empty; - empty.assign({}); - EXPECT_TRUE(empty.empty()); - - circular_deque<int> full; - full.assign({11, 12, 13, 14, 15, 16, 17, 18}); - EXPECT_EQ(8u, full.size()); - for (int i = 0; i < 8; i++) - EXPECT_EQ(11 + i, full[i]); -} - -// Tests [] and .at(). -TEST(CircularDeque, At) { - circular_deque<int> q = MakeSequence(10); - CycleTest(q, [](const circular_deque<int>& q, size_t cycle) { - size_t expected_size = 10; - EXPECT_EQ(expected_size, q.size()); - - // A sequence of 0's. - size_t index = 0; - size_t num_zeros = std::min(expected_size, cycle); - for (size_t i = 0; i < num_zeros; i++, index++) { - EXPECT_EQ(0, q[index]); - EXPECT_EQ(0, q.at(index)); - } - - // Followed by a sequence of increasing ints. - size_t num_ints = expected_size - num_zeros; - for (int i = 0; i < static_cast<int>(num_ints); i++, index++) { - EXPECT_EQ(i, q[index]); - EXPECT_EQ(i, q.at(index)); - } - }); -} - -// This also tests the copy constructor with lots of different types of -// input configurations. -TEST(CircularDeque, FrontBackPushPop) { - circular_deque<int> q = MakeSequence(10); - - int expected_front = 0; - int expected_back = 9; - - // Go in one direction. - for (int i = 0; i < 100; i++) { - const circular_deque<int> const_q(q); - - EXPECT_EQ(expected_front, q.front()); - EXPECT_EQ(expected_back, q.back()); - EXPECT_EQ(expected_front, const_q.front()); - EXPECT_EQ(expected_back, const_q.back()); - - expected_front++; - expected_back++; - - q.pop_front(); - q.push_back(expected_back); - } - - // Go back in reverse. - for (int i = 0; i < 100; i++) { - const circular_deque<int> const_q(q); - - EXPECT_EQ(expected_front, q.front()); - EXPECT_EQ(expected_back, q.back()); - EXPECT_EQ(expected_front, const_q.front()); - EXPECT_EQ(expected_back, const_q.back()); - - expected_front--; - expected_back--; - - q.pop_back(); - q.push_front(expected_front); - } -} - -TEST(CircularDeque, ReallocateWithSplitBuffer) { - // Tests reallocating a deque with an internal buffer that looks like this: - // 4 5 x x 0 1 2 3 - // end-^ ^-begin - circular_deque<int> q; - q.reserve(7); // Internal buffer is always 1 larger than requested. - q.push_back(-1); - q.push_back(-1); - q.push_back(-1); - q.push_back(-1); - q.push_back(0); - q.pop_front(); - q.pop_front(); - q.pop_front(); - q.pop_front(); - q.push_back(1); - q.push_back(2); - q.push_back(3); - q.push_back(4); - q.push_back(5); - - q.shrink_to_fit(); - EXPECT_EQ(6u, q.size()); - - EXPECT_EQ(0, q[0]); - EXPECT_EQ(1, q[1]); - EXPECT_EQ(2, q[2]); - EXPECT_EQ(3, q[3]); - EXPECT_EQ(4, q[4]); - EXPECT_EQ(5, q[5]); -} - -TEST(CircularDeque, Swap) { - circular_deque<int> a = MakeSequence(10); - circular_deque<int> b = MakeSequence(100); - - a.swap(b); - EXPECT_EQ(100u, a.size()); - for (int i = 0; i < 100; i++) - EXPECT_EQ(i, a[i]); - - EXPECT_EQ(10u, b.size()); - for (int i = 0; i < 10; i++) - EXPECT_EQ(i, b[i]); -} - -TEST(CircularDeque, Iteration) { - circular_deque<int> q = MakeSequence(10); - - int expected_front = 0; - int expected_back = 9; - - // This loop causes various combinations of begin and end to be tested. - for (int i = 0; i < 30; i++) { - // Range-based for loop going forward. - int current_expected = expected_front; - for (int cur : q) { - EXPECT_EQ(current_expected, cur); - current_expected++; - } - - // Manually test reverse iterators. - current_expected = expected_back; - for (auto cur = q.crbegin(); cur < q.crend(); cur++) { - EXPECT_EQ(current_expected, *cur); - current_expected--; - } - - expected_front++; - expected_back++; - - q.pop_front(); - q.push_back(expected_back); - } - - // Go back in reverse. - for (int i = 0; i < 100; i++) { - const circular_deque<int> const_q(q); - - EXPECT_EQ(expected_front, q.front()); - EXPECT_EQ(expected_back, q.back()); - EXPECT_EQ(expected_front, const_q.front()); - EXPECT_EQ(expected_back, const_q.back()); - - expected_front--; - expected_back--; - - q.pop_back(); - q.push_front(expected_front); - } -} - -TEST(CircularDeque, IteratorComparisons) { - circular_deque<int> q = MakeSequence(10); - - // This loop causes various combinations of begin and end to be tested. - for (int i = 0; i < 30; i++) { - EXPECT_LT(q.begin(), q.end()); - EXPECT_LE(q.begin(), q.end()); - EXPECT_LE(q.begin(), q.begin()); - - EXPECT_GT(q.end(), q.begin()); - EXPECT_GE(q.end(), q.begin()); - EXPECT_GE(q.end(), q.end()); - - EXPECT_EQ(q.begin(), q.begin()); - EXPECT_NE(q.begin(), q.end()); - - q.push_front(10); - q.pop_back(); - } -} - -TEST(CircularDeque, IteratorIncDec) { - circular_deque<int> q; - - // No-op offset computations with no capacity. - EXPECT_EQ(q.end(), q.end() + 0); - EXPECT_EQ(q.end(), q.end() - 0); - - q = MakeSequence(10); - - // Mutable preincrement, predecrement. - { - circular_deque<int>::iterator it = q.begin(); - circular_deque<int>::iterator op_result = ++it; - EXPECT_EQ(1, *op_result); - EXPECT_EQ(1, *it); - - op_result = --it; - EXPECT_EQ(0, *op_result); - EXPECT_EQ(0, *it); - } - - // Const preincrement, predecrement. - { - circular_deque<int>::const_iterator it = q.begin(); - circular_deque<int>::const_iterator op_result = ++it; - EXPECT_EQ(1, *op_result); - EXPECT_EQ(1, *it); - - op_result = --it; - EXPECT_EQ(0, *op_result); - EXPECT_EQ(0, *it); - } - - // Mutable postincrement, postdecrement. - { - circular_deque<int>::iterator it = q.begin(); - circular_deque<int>::iterator op_result = it++; - EXPECT_EQ(0, *op_result); - EXPECT_EQ(1, *it); - - op_result = it--; - EXPECT_EQ(1, *op_result); - EXPECT_EQ(0, *it); - } - - // Const postincrement, postdecrement. - { - circular_deque<int>::const_iterator it = q.begin(); - circular_deque<int>::const_iterator op_result = it++; - EXPECT_EQ(0, *op_result); - EXPECT_EQ(1, *it); - - op_result = it--; - EXPECT_EQ(1, *op_result); - EXPECT_EQ(0, *it); - } -} - -TEST(CircularDeque, IteratorIntegerOps) { - circular_deque<int> q = MakeSequence(10); - - int expected_front = 0; - int expected_back = 9; - - for (int i = 0; i < 30; i++) { - EXPECT_EQ(0, q.begin() - q.begin()); - EXPECT_EQ(0, q.end() - q.end()); - EXPECT_EQ(q.size(), static_cast<size_t>(q.end() - q.begin())); - - // += - circular_deque<int>::iterator eight = q.begin(); - eight += 8; - EXPECT_EQ(8, eight - q.begin()); - EXPECT_EQ(expected_front + 8, *eight); - - // -= - eight -= 8; - EXPECT_EQ(q.begin(), eight); - - // + - eight = eight + 8; - EXPECT_EQ(8, eight - q.begin()); - - // - - eight = eight - 8; - EXPECT_EQ(q.begin(), eight); - - expected_front++; - expected_back++; - - q.pop_front(); - q.push_back(expected_back); - } -} - -TEST(CircularDeque, IteratorArrayAccess) { - circular_deque<int> q = MakeSequence(10); - - circular_deque<int>::iterator begin = q.begin(); - EXPECT_EQ(0, begin[0]); - EXPECT_EQ(9, begin[9]); - - circular_deque<int>::iterator end = q.end(); - EXPECT_EQ(0, end[-10]); - EXPECT_EQ(9, end[-1]); - - begin[0] = 100; - EXPECT_EQ(100, end[-10]); -} - -TEST(CircularDeque, ReverseIterator) { - circular_deque<int> q; - q.push_back(4); - q.push_back(3); - q.push_back(2); - q.push_back(1); - - circular_deque<int>::reverse_iterator iter = q.rbegin(); - EXPECT_EQ(1, *iter); - iter++; - EXPECT_EQ(2, *iter); - ++iter; - EXPECT_EQ(3, *iter); - iter++; - EXPECT_EQ(4, *iter); - ++iter; - EXPECT_EQ(q.rend(), iter); -} - -TEST(CircularDeque, CapacityReserveShrink) { - circular_deque<int> q; - - // A default constructed queue should have no capacity since it should waste - // no space. - EXPECT_TRUE(q.empty()); - EXPECT_EQ(0u, q.size()); - EXPECT_EQ(0u, q.capacity()); - - size_t new_capacity = 100; - q.reserve(new_capacity); - EXPECT_EQ(new_capacity, q.capacity()); - - // Adding that many items should not cause a resize. - for (size_t i = 0; i < new_capacity; i++) - q.push_back(i); - EXPECT_EQ(new_capacity, q.size()); - EXPECT_EQ(new_capacity, q.capacity()); - - // Shrink to fit to a smaller size. - size_t capacity_2 = new_capacity / 2; - q.resize(capacity_2); - q.shrink_to_fit(); - EXPECT_EQ(capacity_2, q.size()); - EXPECT_EQ(capacity_2, q.capacity()); -} - -TEST(CircularDeque, CapacityAutoShrink) { - size_t big_size = 1000u; - circular_deque<int> q; - q.resize(big_size); - - size_t big_capacity = q.capacity(); - - // Delete 3/4 of the items. - for (size_t i = 0; i < big_size / 4 * 3; i++) - q.pop_back(); - - // The capacity should have shrunk by deleting that many items. - size_t medium_capacity = q.capacity(); - EXPECT_GT(big_capacity, medium_capacity); - - // Using resize to shrink should keep some extra capacity. - q.resize(1); - EXPECT_LT(1u, q.capacity()); - - q.resize(0); - EXPECT_LT(0u, q.capacity()); - - // Using clear() should delete everything. - q.clear(); - EXPECT_EQ(0u, q.capacity()); -} - -TEST(CircularDeque, ClearAndEmpty) { - circular_deque<int> q; - EXPECT_TRUE(q.empty()); - - q.resize(10); - EXPECT_EQ(10u, q.size()); - EXPECT_FALSE(q.empty()); - - q.clear(); - EXPECT_EQ(0u, q.size()); - EXPECT_TRUE(q.empty()); - - // clear() also should reset the capacity. - EXPECT_EQ(0u, q.capacity()); -} - -TEST(CircularDeque, Resize) { - circular_deque<int> q; - - // Resize with default constructor. - size_t first_size = 10; - q.resize(first_size); - EXPECT_EQ(first_size, q.size()); - for (size_t i = 0; i < first_size; i++) - EXPECT_EQ(0, q[i]); - - // Resize with different value. - size_t second_expand = 10; - q.resize(first_size + second_expand, 3); - EXPECT_EQ(first_size + second_expand, q.size()); - for (size_t i = 0; i < first_size; i++) - EXPECT_EQ(0, q[i]); - for (size_t i = 0; i < second_expand; i++) - EXPECT_EQ(3, q[i + first_size]); - - // Erase from the end and add to the beginning so resize is forced to cross - // a circular buffer wrap boundary. - q.shrink_to_fit(); - for (int i = 0; i < 5; i++) { - q.pop_back(); - q.push_front(6); - } - q.resize(10); - - EXPECT_EQ(6, q[0]); - EXPECT_EQ(6, q[1]); - EXPECT_EQ(6, q[2]); - EXPECT_EQ(6, q[3]); - EXPECT_EQ(6, q[4]); - EXPECT_EQ(0, q[5]); - EXPECT_EQ(0, q[6]); - EXPECT_EQ(0, q[7]); - EXPECT_EQ(0, q[8]); - EXPECT_EQ(0, q[9]); -} - -// Tests destructor behavior of resize. -TEST(CircularDeque, ResizeDelete) { - int counter = 0; - circular_deque<DestructorCounter> q; - q.resize(10, DestructorCounter(&counter)); - // The one temporary when calling resize() should be deleted, that's it. - EXPECT_EQ(1, counter); - - // The loops below assume the capacity will be set by resize(). - EXPECT_EQ(10u, q.capacity()); - - // Delete some via resize(). This is done so that the wasted items are - // still greater than the size() so that auto-shrinking is not triggered - // (which will mess up our destructor counting). - counter = 0; - q.resize(8, DestructorCounter(&counter)); - // 2 deleted ones + the one temporary in the resize() call. - EXPECT_EQ(3, counter); - - // Cycle through some items so two items will cross the boundary in the - // 11-item buffer (one more than the capacity). - // Before: x x x x x x x x . . . - // After: x . . . x x x x x x x - counter = 0; - for (int i = 0; i < 4; i++) { - q.emplace_back(&counter); - q.pop_front(); - } - EXPECT_EQ(4, counter); // Loop should have deleted 7 items. - - // Delete two items with resize, these should be on either side of the - // buffer wrap point. - counter = 0; - q.resize(6, DestructorCounter(&counter)); - // 2 deleted ones + the one temporary in the resize() call. - EXPECT_EQ(3, counter); -} - -TEST(CircularDeque, InsertEraseSingle) { - circular_deque<int> q; - q.push_back(1); - q.push_back(2); - - // Insert at the beginning. - auto result = q.insert(q.begin(), 0); - EXPECT_EQ(q.begin(), result); - EXPECT_EQ(3u, q.size()); - EXPECT_EQ(0, q[0]); - EXPECT_EQ(1, q[1]); - EXPECT_EQ(2, q[2]); - - // Erase at the beginning. - result = q.erase(q.begin()); - EXPECT_EQ(q.begin(), result); - EXPECT_EQ(2u, q.size()); - EXPECT_EQ(1, q[0]); - EXPECT_EQ(2, q[1]); - - // Insert at the end. - result = q.insert(q.end(), 3); - EXPECT_EQ(q.end() - 1, result); - EXPECT_EQ(1, q[0]); - EXPECT_EQ(2, q[1]); - EXPECT_EQ(3, q[2]); - - // Erase at the end. - result = q.erase(q.end() - 1); - EXPECT_EQ(q.end(), result); - EXPECT_EQ(1, q[0]); - EXPECT_EQ(2, q[1]); - - // Insert in the middle. - result = q.insert(q.begin() + 1, 10); - EXPECT_EQ(q.begin() + 1, result); - EXPECT_EQ(1, q[0]); - EXPECT_EQ(10, q[1]); - EXPECT_EQ(2, q[2]); - - // Erase in the middle. - result = q.erase(q.begin() + 1); - EXPECT_EQ(q.begin() + 1, result); - EXPECT_EQ(1, q[0]); - EXPECT_EQ(2, q[1]); -} - -TEST(CircularDeque, InsertFill) { - circular_deque<int> q; - - // Fill when empty. - q.insert(q.begin(), 2, 1); - - // 0's at the beginning. - q.insert(q.begin(), 2, 0); - - // 50's in the middle (now at offset 3). - q.insert(q.begin() + 3, 2, 50); - - // 200's at the end. - q.insert(q.end(), 2, 200); - - ASSERT_EQ(8u, q.size()); - EXPECT_EQ(0, q[0]); - EXPECT_EQ(0, q[1]); - EXPECT_EQ(1, q[2]); - EXPECT_EQ(50, q[3]); - EXPECT_EQ(50, q[4]); - EXPECT_EQ(1, q[5]); - EXPECT_EQ(200, q[6]); - EXPECT_EQ(200, q[7]); -} - -TEST(CircularDeque, InsertEraseRange) { - circular_deque<int> q; - - // Erase nothing from an empty deque should work. - q.erase(q.begin(), q.end()); - - // Loop index used below to shift the used items in the buffer. - for (int i = 0; i < 10; i++) { - circular_deque<int> source; - - // Fill empty range. - q.insert(q.begin(), source.begin(), source.end()); - - // Have some stuff to insert. - source.push_back(1); - source.push_back(2); - - q.insert(q.begin(), source.begin(), source.end()); - - // Shift the used items in the buffer by i which will place the two used - // elements in different places in the buffer each time through this loop. - for (int shift_i = 0; shift_i < i; shift_i++) { - q.push_back(0); - q.pop_front(); - } - - // Set the two items to notable values so we can check for them later. - ASSERT_EQ(2u, q.size()); - q[0] = 100; - q[1] = 101; - - // Insert at the beginning, middle (now at offset 3), and end. - q.insert(q.begin(), source.begin(), source.end()); - q.insert(q.begin() + 3, source.begin(), source.end()); - q.insert(q.end(), source.begin(), source.end()); - - ASSERT_EQ(8u, q.size()); - EXPECT_EQ(1, q[0]); - EXPECT_EQ(2, q[1]); - EXPECT_EQ(100, q[2]); // First inserted one. - EXPECT_EQ(1, q[3]); - EXPECT_EQ(2, q[4]); - EXPECT_EQ(101, q[5]); // First inserted second one. - EXPECT_EQ(1, q[6]); - EXPECT_EQ(2, q[7]); - - // Now erase the inserted ranges. Try each subsection also with no items - // being erased, which should be a no-op. - auto result = q.erase(q.begin(), q.begin()); // No-op. - EXPECT_EQ(q.begin(), result); - result = q.erase(q.begin(), q.begin() + 2); - EXPECT_EQ(q.begin(), result); - - result = q.erase(q.begin() + 1, q.begin() + 1); // No-op. - EXPECT_EQ(q.begin() + 1, result); - result = q.erase(q.begin() + 1, q.begin() + 3); - EXPECT_EQ(q.begin() + 1, result); - - result = q.erase(q.end() - 2, q.end() - 2); // No-op. - EXPECT_EQ(q.end() - 2, result); - result = q.erase(q.end() - 2, q.end()); - EXPECT_EQ(q.end(), result); - - ASSERT_EQ(2u, q.size()); - EXPECT_EQ(100, q[0]); - EXPECT_EQ(101, q[1]); - - // Erase everything. - result = q.erase(q.begin(), q.end()); - EXPECT_EQ(q.end(), result); - EXPECT_TRUE(q.empty()); - } -} - -TEST(CircularDeque, EmplaceMoveOnly) { - int values[] = {1, 3}; - circular_deque<MoveOnlyInt> q(std::begin(values), std::end(values)); - - q.emplace(q.begin(), MoveOnlyInt(0)); - q.emplace(q.begin() + 2, MoveOnlyInt(2)); - q.emplace(q.end(), MoveOnlyInt(4)); - - ASSERT_EQ(5u, q.size()); - EXPECT_EQ(0, q[0].data()); - EXPECT_EQ(1, q[1].data()); - EXPECT_EQ(2, q[2].data()); - EXPECT_EQ(3, q[3].data()); - EXPECT_EQ(4, q[4].data()); -} - -TEST(CircularDeque, EmplaceFrontBackReturnsReference) { - circular_deque<int> q; - q.reserve(2); - - int& front = q.emplace_front(1); - int& back = q.emplace_back(2); - ASSERT_EQ(2u, q.size()); - EXPECT_EQ(1, q[0]); - EXPECT_EQ(2, q[1]); - - EXPECT_EQ(&front, &q.front()); - EXPECT_EQ(&back, &q.back()); - - front = 3; - back = 4; - - ASSERT_EQ(2u, q.size()); - EXPECT_EQ(3, q[0]); - EXPECT_EQ(4, q[1]); - - EXPECT_EQ(&front, &q.front()); - EXPECT_EQ(&back, &q.back()); -} - -/* -This test should assert in a debug build. It tries to dereference an iterator -after mutating the container. Uncomment to double-check that this works. -TEST(CircularDeque, UseIteratorAfterMutate) { - circular_deque<int> q; - q.push_back(0); - - auto old_begin = q.begin(); - EXPECT_EQ(0, *old_begin); - - q.push_back(1); - EXPECT_EQ(0, *old_begin); // Should DCHECK. -} -*/ - -} // namespace base
diff --git a/base/containers/flat_map_unittest.cc b/base/containers/flat_map_unittest.cc deleted file mode 100644 index 87958bd..0000000 --- a/base/containers/flat_map_unittest.cc +++ /dev/null
@@ -1,369 +0,0 @@ -// 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/containers/flat_map.h" - -#include <string> -#include <vector> - -#include "base/macros.h" -#include "base/test/move_only_int.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -// A flat_map is basically a interface to flat_tree. So several basic -// operations are tested to make sure things are set up properly, but the bulk -// of the tests are in flat_tree_unittests.cc. - -using ::testing::ElementsAre; - -namespace base { - -TEST(FlatMap, IncompleteType) { - struct A { - using Map = flat_map<A, A>; - int data; - Map set_with_incomplete_type; - Map::iterator it; - Map::const_iterator cit; - - // We do not declare operator< because clang complains that it's unused. - }; - - A a; -} - -TEST(FlatMap, RangeConstructor) { - flat_map<int, int>::value_type input_vals[] = { - {1, 1}, {1, 2}, {1, 3}, {2, 1}, {2, 2}, {2, 3}, {3, 1}, {3, 2}, {3, 3}}; - - flat_map<int, int> first(std::begin(input_vals), std::end(input_vals)); - EXPECT_THAT(first, ElementsAre(std::make_pair(1, 1), std::make_pair(2, 1), - std::make_pair(3, 1))); - - flat_map<int, int> last(std::begin(input_vals), std::end(input_vals), - KEEP_LAST_OF_DUPES); - EXPECT_THAT(last, ElementsAre(std::make_pair(1, 3), std::make_pair(2, 3), - std::make_pair(3, 3))); -} - -TEST(FlatMap, MoveConstructor) { - using pair = std::pair<MoveOnlyInt, MoveOnlyInt>; - - flat_map<MoveOnlyInt, MoveOnlyInt> original; - original.insert(pair(MoveOnlyInt(1), MoveOnlyInt(1))); - original.insert(pair(MoveOnlyInt(2), MoveOnlyInt(2))); - original.insert(pair(MoveOnlyInt(3), MoveOnlyInt(3))); - original.insert(pair(MoveOnlyInt(4), MoveOnlyInt(4))); - - flat_map<MoveOnlyInt, MoveOnlyInt> moved(std::move(original)); - - EXPECT_EQ(1U, moved.count(MoveOnlyInt(1))); - EXPECT_EQ(1U, moved.count(MoveOnlyInt(2))); - EXPECT_EQ(1U, moved.count(MoveOnlyInt(3))); - EXPECT_EQ(1U, moved.count(MoveOnlyInt(4))); -} - -TEST(FlatMap, VectorConstructor) { - using IntPair = std::pair<int, int>; - using IntMap = flat_map<int, int>; - { - std::vector<IntPair> vect{{1, 1}, {1, 2}, {2, 1}}; - IntMap map(std::move(vect)); - EXPECT_THAT(map, ElementsAre(IntPair(1, 1), IntPair(2, 1))); - } - { - std::vector<IntPair> vect{{1, 1}, {1, 2}, {2, 1}}; - IntMap map(std::move(vect), KEEP_LAST_OF_DUPES); - EXPECT_THAT(map, ElementsAre(IntPair(1, 2), IntPair(2, 1))); - } -} - -TEST(FlatMap, InitializerListConstructor) { - { - flat_map<int, int> cont( - {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}, {1, 2}, {10, 10}, {8, 8}}); - EXPECT_THAT(cont, ElementsAre(std::make_pair(1, 1), std::make_pair(2, 2), - std::make_pair(3, 3), std::make_pair(4, 4), - std::make_pair(5, 5), std::make_pair(8, 8), - std::make_pair(10, 10))); - } - { - flat_map<int, int> cont( - {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}, {1, 2}, {10, 10}, {8, 8}}, - KEEP_LAST_OF_DUPES); - EXPECT_THAT(cont, ElementsAre(std::make_pair(1, 2), std::make_pair(2, 2), - std::make_pair(3, 3), std::make_pair(4, 4), - std::make_pair(5, 5), std::make_pair(8, 8), - std::make_pair(10, 10))); - } -} - -TEST(FlatMap, InitializerListAssignment) { - flat_map<int, int> cont; - cont = {{1, 1}, {2, 2}}; - EXPECT_THAT(cont, ElementsAre(std::make_pair(1, 1), std::make_pair(2, 2))); -} - -TEST(FlatMap, InsertFindSize) { - base::flat_map<int, int> s; - s.insert(std::make_pair(1, 1)); - s.insert(std::make_pair(1, 1)); - s.insert(std::make_pair(2, 2)); - - EXPECT_EQ(2u, s.size()); - EXPECT_EQ(std::make_pair(1, 1), *s.find(1)); - EXPECT_EQ(std::make_pair(2, 2), *s.find(2)); - EXPECT_EQ(s.end(), s.find(7)); -} - -TEST(FlatMap, CopySwap) { - base::flat_map<int, int> original; - original.insert({1, 1}); - original.insert({2, 2}); - EXPECT_THAT(original, - ElementsAre(std::make_pair(1, 1), std::make_pair(2, 2))); - - base::flat_map<int, int> copy(original); - EXPECT_THAT(copy, ElementsAre(std::make_pair(1, 1), std::make_pair(2, 2))); - - copy.erase(copy.begin()); - copy.insert({10, 10}); - EXPECT_THAT(copy, ElementsAre(std::make_pair(2, 2), std::make_pair(10, 10))); - - original.swap(copy); - EXPECT_THAT(original, - ElementsAre(std::make_pair(2, 2), std::make_pair(10, 10))); - EXPECT_THAT(copy, ElementsAre(std::make_pair(1, 1), std::make_pair(2, 2))); -} - -// operator[](const Key&) -TEST(FlatMap, SubscriptConstKey) { - base::flat_map<std::string, int> m; - - // Default construct elements that don't exist yet. - int& s = m["a"]; - EXPECT_EQ(0, s); - EXPECT_EQ(1u, m.size()); - - // The returned mapped reference should refer into the map. - s = 22; - EXPECT_EQ(22, m["a"]); - - // Overwrite existing elements. - m["a"] = 44; - EXPECT_EQ(44, m["a"]); -} - -// operator[](Key&&) -TEST(FlatMap, SubscriptMoveOnlyKey) { - base::flat_map<MoveOnlyInt, int> m; - - // Default construct elements that don't exist yet. - int& s = m[MoveOnlyInt(1)]; - EXPECT_EQ(0, s); - EXPECT_EQ(1u, m.size()); - - // The returned mapped reference should refer into the map. - s = 22; - EXPECT_EQ(22, m[MoveOnlyInt(1)]); - - // Overwrite existing elements. - m[MoveOnlyInt(1)] = 44; - EXPECT_EQ(44, m[MoveOnlyInt(1)]); -} - -// insert_or_assign(K&&, M&&) -TEST(FlatMap, InsertOrAssignMoveOnlyKey) { - base::flat_map<MoveOnlyInt, MoveOnlyInt> m; - - // Initial insertion should return an iterator to the element and set the - // second pair member to |true|. The inserted key and value should be moved - // from. - MoveOnlyInt key(1); - MoveOnlyInt val(22); - auto result = m.insert_or_assign(std::move(key), std::move(val)); - EXPECT_EQ(1, result.first->first.data()); - EXPECT_EQ(22, result.first->second.data()); - EXPECT_TRUE(result.second); - EXPECT_EQ(1u, m.size()); - EXPECT_EQ(0, key.data()); // moved from - EXPECT_EQ(0, val.data()); // moved from - - // Second call with same key should result in an assignment, overwriting the - // old value. Assignment should be indicated by setting the second pair member - // to |false|. Only the inserted value should be moved from, the key should be - // left intact. - key = MoveOnlyInt(1); - val = MoveOnlyInt(44); - result = m.insert_or_assign(std::move(key), std::move(val)); - EXPECT_EQ(1, result.first->first.data()); - EXPECT_EQ(44, result.first->second.data()); - EXPECT_FALSE(result.second); - EXPECT_EQ(1u, m.size()); - EXPECT_EQ(1, key.data()); // not moved from - EXPECT_EQ(0, val.data()); // moved from - - // Check that random insertion results in sorted range. - base::flat_map<MoveOnlyInt, int> map; - for (int i : {3, 1, 5, 6, 8, 7, 0, 9, 4, 2}) { - map.insert_or_assign(MoveOnlyInt(i), i); - EXPECT_TRUE(std::is_sorted(map.begin(), map.end())); - } -} - -// insert_or_assign(const_iterator hint, K&&, M&&) -TEST(FlatMap, InsertOrAssignMoveOnlyKeyWithHint) { - base::flat_map<MoveOnlyInt, MoveOnlyInt> m; - - // Initial insertion should return an iterator to the element. The inserted - // key and value should be moved from. - MoveOnlyInt key(1); - MoveOnlyInt val(22); - auto result = m.insert_or_assign(m.end(), std::move(key), std::move(val)); - EXPECT_EQ(1, result->first.data()); - EXPECT_EQ(22, result->second.data()); - EXPECT_EQ(1u, m.size()); - EXPECT_EQ(0, key.data()); // moved from - EXPECT_EQ(0, val.data()); // moved from - - // Second call with same key should result in an assignment, overwriting the - // old value. Only the inserted value should be moved from, the key should be - // left intact. - key = MoveOnlyInt(1); - val = MoveOnlyInt(44); - result = m.insert_or_assign(m.end(), std::move(key), std::move(val)); - EXPECT_EQ(1, result->first.data()); - EXPECT_EQ(44, result->second.data()); - EXPECT_EQ(1u, m.size()); - EXPECT_EQ(1, key.data()); // not moved from - EXPECT_EQ(0, val.data()); // moved from - - // Check that random insertion results in sorted range. - base::flat_map<MoveOnlyInt, int> map; - for (int i : {3, 1, 5, 6, 8, 7, 0, 9, 4, 2}) { - map.insert_or_assign(map.end(), MoveOnlyInt(i), i); - EXPECT_TRUE(std::is_sorted(map.begin(), map.end())); - } -} - -// try_emplace(K&&, Args&&...) -TEST(FlatMap, TryEmplaceMoveOnlyKey) { - base::flat_map<MoveOnlyInt, std::pair<MoveOnlyInt, MoveOnlyInt>> m; - - // Trying to emplace into an empty map should succeed. Insertion should return - // an iterator to the element and set the second pair member to |true|. The - // inserted key and value should be moved from. - MoveOnlyInt key(1); - MoveOnlyInt val1(22); - MoveOnlyInt val2(44); - // Test piecewise construction of mapped_type. - auto result = m.try_emplace(std::move(key), std::move(val1), std::move(val2)); - EXPECT_EQ(1, result.first->first.data()); - EXPECT_EQ(22, result.first->second.first.data()); - EXPECT_EQ(44, result.first->second.second.data()); - EXPECT_TRUE(result.second); - EXPECT_EQ(1u, m.size()); - EXPECT_EQ(0, key.data()); // moved from - EXPECT_EQ(0, val1.data()); // moved from - EXPECT_EQ(0, val2.data()); // moved from - - // Second call with same key should result in a no-op, returning an iterator - // to the existing element and returning false as the second pair member. - // Key and values that were attempted to be inserted should be left intact. - key = MoveOnlyInt(1); - auto paired_val = std::make_pair(MoveOnlyInt(33), MoveOnlyInt(55)); - // Test construction of mapped_type from pair. - result = m.try_emplace(std::move(key), std::move(paired_val)); - EXPECT_EQ(1, result.first->first.data()); - EXPECT_EQ(22, result.first->second.first.data()); - EXPECT_EQ(44, result.first->second.second.data()); - EXPECT_FALSE(result.second); - EXPECT_EQ(1u, m.size()); - EXPECT_EQ(1, key.data()); // not moved from - EXPECT_EQ(33, paired_val.first.data()); // not moved from - EXPECT_EQ(55, paired_val.second.data()); // not moved from - - // Check that random insertion results in sorted range. - base::flat_map<MoveOnlyInt, int> map; - for (int i : {3, 1, 5, 6, 8, 7, 0, 9, 4, 2}) { - map.try_emplace(MoveOnlyInt(i), i); - EXPECT_TRUE(std::is_sorted(map.begin(), map.end())); - } -} - -// try_emplace(const_iterator hint, K&&, Args&&...) -TEST(FlatMap, TryEmplaceMoveOnlyKeyWithHint) { - base::flat_map<MoveOnlyInt, std::pair<MoveOnlyInt, MoveOnlyInt>> m; - - // Trying to emplace into an empty map should succeed. Insertion should return - // an iterator to the element. The inserted key and value should be moved - // from. - MoveOnlyInt key(1); - MoveOnlyInt val1(22); - MoveOnlyInt val2(44); - // Test piecewise construction of mapped_type. - auto result = - m.try_emplace(m.end(), std::move(key), std::move(val1), std::move(val2)); - EXPECT_EQ(1, result->first.data()); - EXPECT_EQ(22, result->second.first.data()); - EXPECT_EQ(44, result->second.second.data()); - EXPECT_EQ(1u, m.size()); - EXPECT_EQ(0, key.data()); // moved from - EXPECT_EQ(0, val1.data()); // moved from - EXPECT_EQ(0, val2.data()); // moved from - - // Second call with same key should result in a no-op, returning an iterator - // to the existing element. Key and values that were attempted to be inserted - // should be left intact. - key = MoveOnlyInt(1); - val1 = MoveOnlyInt(33); - val2 = MoveOnlyInt(55); - auto paired_val = std::make_pair(MoveOnlyInt(33), MoveOnlyInt(55)); - // Test construction of mapped_type from pair. - result = m.try_emplace(m.end(), std::move(key), std::move(paired_val)); - EXPECT_EQ(1, result->first.data()); - EXPECT_EQ(22, result->second.first.data()); - EXPECT_EQ(44, result->second.second.data()); - EXPECT_EQ(1u, m.size()); - EXPECT_EQ(1, key.data()); // not moved from - EXPECT_EQ(33, paired_val.first.data()); // not moved from - EXPECT_EQ(55, paired_val.second.data()); // not moved from - - // Check that random insertion results in sorted range. - base::flat_map<MoveOnlyInt, int> map; - for (int i : {3, 1, 5, 6, 8, 7, 0, 9, 4, 2}) { - map.try_emplace(map.end(), MoveOnlyInt(i), i); - EXPECT_TRUE(std::is_sorted(map.begin(), map.end())); - } -} - -TEST(FlatMap, UsingTransparentCompare) { - using ExplicitInt = base::MoveOnlyInt; - base::flat_map<ExplicitInt, int> m; - const auto& m1 = m; - int x = 0; - - // Check if we can use lookup functions without converting to key_type. - // Correctness is checked in flat_tree tests. - m.count(x); - m1.count(x); - m.find(x); - m1.find(x); - m.equal_range(x); - m1.equal_range(x); - m.lower_bound(x); - m1.lower_bound(x); - m.upper_bound(x); - m1.upper_bound(x); - m.erase(x); - - // Check if we broke overload resolution. - m.emplace(ExplicitInt(0), 0); - m.emplace(ExplicitInt(1), 0); - m.erase(m.begin()); - m.erase(m.cbegin()); -} - -} // namespace base
diff --git a/base/containers/flat_set_unittest.cc b/base/containers/flat_set_unittest.cc deleted file mode 100644 index 4596975..0000000 --- a/base/containers/flat_set_unittest.cc +++ /dev/null
@@ -1,121 +0,0 @@ -// 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/containers/flat_set.h" - -#include <string> -#include <vector> - -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/test/move_only_int.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -// A flat_set is basically a interface to flat_tree. So several basic -// operations are tested to make sure things are set up properly, but the bulk -// of the tests are in flat_tree_unittests.cc. - -using ::testing::ElementsAre; - -namespace base { - -TEST(FlatSet, IncompleteType) { - struct A { - using Set = flat_set<A>; - int data; - Set set_with_incomplete_type; - Set::iterator it; - Set::const_iterator cit; - - // We do not declare operator< because clang complains that it's unused. - }; - - A a; -} - -TEST(FlatSet, RangeConstructor) { - flat_set<int>::value_type input_vals[] = {1, 1, 1, 2, 2, 2, 3, 3, 3}; - - flat_set<int> cont(std::begin(input_vals), std::end(input_vals), - base::KEEP_FIRST_OF_DUPES); - EXPECT_THAT(cont, ElementsAre(1, 2, 3)); -} - -TEST(FlatSet, MoveConstructor) { - int input_range[] = {1, 2, 3, 4}; - - flat_set<MoveOnlyInt> original(std::begin(input_range), std::end(input_range), - base::KEEP_FIRST_OF_DUPES); - flat_set<MoveOnlyInt> moved(std::move(original)); - - EXPECT_EQ(1U, moved.count(MoveOnlyInt(1))); - EXPECT_EQ(1U, moved.count(MoveOnlyInt(2))); - EXPECT_EQ(1U, moved.count(MoveOnlyInt(3))); - EXPECT_EQ(1U, moved.count(MoveOnlyInt(4))); -} - -TEST(FlatSet, InitializerListConstructor) { - flat_set<int> cont({1, 2, 3, 4, 5, 6, 10, 8}, KEEP_FIRST_OF_DUPES); - EXPECT_THAT(cont, ElementsAre(1, 2, 3, 4, 5, 6, 8, 10)); -} - -TEST(FlatSet, InsertFindSize) { - base::flat_set<int> s; - s.insert(1); - s.insert(1); - s.insert(2); - - EXPECT_EQ(2u, s.size()); - EXPECT_EQ(1, *s.find(1)); - EXPECT_EQ(2, *s.find(2)); - EXPECT_EQ(s.end(), s.find(7)); -} - -TEST(FlatSet, CopySwap) { - base::flat_set<int> original; - original.insert(1); - original.insert(2); - EXPECT_THAT(original, ElementsAre(1, 2)); - - base::flat_set<int> copy(original); - EXPECT_THAT(copy, ElementsAre(1, 2)); - - copy.erase(copy.begin()); - copy.insert(10); - EXPECT_THAT(copy, ElementsAre(2, 10)); - - original.swap(copy); - EXPECT_THAT(original, ElementsAre(2, 10)); - EXPECT_THAT(copy, ElementsAre(1, 2)); -} - -TEST(FlatSet, UsingTransparentCompare) { - using ExplicitInt = base::MoveOnlyInt; - base::flat_set<ExplicitInt> s; - const auto& s1 = s; - int x = 0; - - // Check if we can use lookup functions without converting to key_type. - // Correctness is checked in flat_tree tests. - s.count(x); - s1.count(x); - s.find(x); - s1.find(x); - s.equal_range(x); - s1.equal_range(x); - s.lower_bound(x); - s1.lower_bound(x); - s.upper_bound(x); - s1.upper_bound(x); - s.erase(x); - - // Check if we broke overload resolution. - s.emplace(0); - s.emplace(1); - s.erase(s.begin()); - s.erase(s.cbegin()); -} - -} // namespace base
diff --git a/base/containers/flat_tree_unittest.cc b/base/containers/flat_tree_unittest.cc deleted file mode 100644 index 5b788d5..0000000 --- a/base/containers/flat_tree_unittest.cc +++ /dev/null
@@ -1,1385 +0,0 @@ -// 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/containers/flat_tree.h" - -// Following tests are ported and extended tests from libcpp for std::set. -// They can be found here: -// https://github.com/llvm-mirror/libcxx/tree/master/test/std/containers/associative/set -// -// Not ported tests: -// * No tests with PrivateConstructor and std::less<> changed to std::less<T> -// These tests have to do with C++14 std::less<> -// http://en.cppreference.com/w/cpp/utility/functional/less_void -// and add support for templated versions of lookup functions. -// Because we use same implementation, we figured that it's OK just to check -// compilation and this is what we do in flat_set_unittest/flat_map_unittest. -// * No tests for max_size() -// Has to do with allocator support. -// * No tests with DefaultOnly. -// Standard containers allocate each element in the separate node on the heap -// and then manipulate these nodes. Flat containers store their elements in -// contiguous memory and move them around, type is required to be movable. -// * No tests for N3644. -// This proposal suggests that all default constructed iterators compare -// equal. Currently we use std::vector iterators and they don't implement -// this. -// * No tests with min_allocator and no tests counting allocations. -// Flat sets currently don't support allocators. - -#include <forward_list> -#include <functional> -#include <iterator> -#include <list> -#include <string> -#include <vector> - -#include "base/macros.h" -#include "base/template_util.h" -#include "base/test/move_only_int.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace internal { - -namespace { - -template <class It> -class InputIterator { - public: - using iterator_category = std::input_iterator_tag; - using value_type = typename std::iterator_traits<It>::value_type; - using difference_type = typename std::iterator_traits<It>::difference_type; - using pointer = It; - using reference = typename std::iterator_traits<It>::reference; - - InputIterator() : it_() {} - explicit InputIterator(It it) : it_(it) {} - - reference operator*() const { return *it_; } - pointer operator->() const { return it_; } - - InputIterator& operator++() { - ++it_; - return *this; - } - InputIterator operator++(int) { - InputIterator tmp(*this); - ++(*this); - return tmp; - } - - friend bool operator==(const InputIterator& lhs, const InputIterator& rhs) { - return lhs.it_ == rhs.it_; - } - friend bool operator!=(const InputIterator& lhs, const InputIterator& rhs) { - return !(lhs == rhs); - } - - private: - It it_; -}; - -template <typename It> -InputIterator<It> MakeInputIterator(It it) { - return InputIterator<It>(it); -} - -class Emplaceable { - public: - Emplaceable() : Emplaceable(0, 0.0) {} - Emplaceable(int i, double d) : int_(i), double_(d) {} - Emplaceable(Emplaceable&& other) : int_(other.int_), double_(other.double_) { - other.int_ = 0; - other.double_ = 0.0; - } - - Emplaceable& operator=(Emplaceable&& other) { - int_ = other.int_; - other.int_ = 0; - double_ = other.double_; - other.double_ = 0.0; - return *this; - } - - friend bool operator==(const Emplaceable& lhs, const Emplaceable& rhs) { - return std::tie(lhs.int_, lhs.double_) == std::tie(rhs.int_, rhs.double_); - } - - friend bool operator<(const Emplaceable& lhs, const Emplaceable& rhs) { - return std::tie(lhs.int_, lhs.double_) < std::tie(rhs.int_, rhs.double_); - } - - private: - int int_; - double double_; - - DISALLOW_COPY_AND_ASSIGN(Emplaceable); -}; - -struct TemplateConstructor { - template <typename T> - TemplateConstructor(const T&) {} - - friend bool operator<(const TemplateConstructor&, - const TemplateConstructor&) { - return false; - } -}; - -class NonDefaultConstructibleCompare { - public: - explicit NonDefaultConstructibleCompare(int) {} - - template <typename T> - bool operator()(const T& lhs, const T& rhs) const { - return std::less<T>()(lhs, rhs); - } -}; - -template <class PairType> -struct LessByFirst { - bool operator()(const PairType& lhs, const PairType& rhs) const { - return lhs.first < rhs.first; - } -}; - -// Common test trees. -using IntTree = - flat_tree<int, int, GetKeyFromValueIdentity<int>, std::less<int>>; -using IntPair = std::pair<int, int>; -using IntPairTree = flat_tree<IntPair, - IntPair, - GetKeyFromValueIdentity<IntPair>, - LessByFirst<IntPair>>; -using MoveOnlyTree = flat_tree<MoveOnlyInt, - MoveOnlyInt, - GetKeyFromValueIdentity<MoveOnlyInt>, - std::less<MoveOnlyInt>>; -using EmplaceableTree = flat_tree<Emplaceable, - Emplaceable, - GetKeyFromValueIdentity<Emplaceable>, - std::less<Emplaceable>>; -using ReversedTree = - flat_tree<int, int, GetKeyFromValueIdentity<int>, std::greater<int>>; - -using TreeWithStrangeCompare = flat_tree<int, - int, - GetKeyFromValueIdentity<int>, - NonDefaultConstructibleCompare>; - -using ::testing::ElementsAre; - -} // namespace - -TEST(FlatTree, IsMultipass) { - static_assert(!is_multipass<std::istream_iterator<int>>(), - "InputIterator is not multipass"); - static_assert(!is_multipass<std::ostream_iterator<int>>(), - "OutputIterator is not multipass"); - - static_assert(is_multipass<std::forward_list<int>::iterator>(), - "ForwardIterator is multipass"); - static_assert(is_multipass<std::list<int>::iterator>(), - "BidirectionalIterator is multipass"); - static_assert(is_multipass<std::vector<int>::iterator>(), - "RandomAccessIterator is multipass"); -} - -TEST(FlatTree, LastUnique) { - using Pair = std::pair<int, int>; - using Vect = std::vector<Pair>; - - auto cmp = [](const Pair& lhs, const Pair& rhs) { - return lhs.first == rhs.first; - }; - - // Empty case. - Vect empty; - EXPECT_EQ(empty.end(), LastUnique(empty.begin(), empty.end(), cmp)); - - // Single element. - Vect one; - one.push_back(Pair(1, 1)); - EXPECT_EQ(one.end(), LastUnique(one.begin(), one.end(), cmp)); - ASSERT_EQ(1u, one.size()); - EXPECT_THAT(one, ElementsAre(Pair(1, 1))); - - // Two elements, already unique. - Vect two_u; - two_u.push_back(Pair(1, 1)); - two_u.push_back(Pair(2, 2)); - EXPECT_EQ(two_u.end(), LastUnique(two_u.begin(), two_u.end(), cmp)); - EXPECT_THAT(two_u, ElementsAre(Pair(1, 1), Pair(2, 2))); - - // Two elements, dupes. - Vect two_d; - two_d.push_back(Pair(1, 1)); - two_d.push_back(Pair(1, 2)); - auto last = LastUnique(two_d.begin(), two_d.end(), cmp); - EXPECT_EQ(two_d.begin() + 1, last); - two_d.erase(last, two_d.end()); - EXPECT_THAT(two_d, ElementsAre(Pair(1, 2))); - - // Non-dupes, dupes, non-dupes. - Vect ndn; - ndn.push_back(Pair(1, 1)); - ndn.push_back(Pair(2, 1)); - ndn.push_back(Pair(2, 2)); - ndn.push_back(Pair(2, 3)); - ndn.push_back(Pair(3, 1)); - last = LastUnique(ndn.begin(), ndn.end(), cmp); - EXPECT_EQ(ndn.begin() + 3, last); - ndn.erase(last, ndn.end()); - EXPECT_THAT(ndn, ElementsAre(Pair(1, 1), Pair(2, 3), Pair(3, 1))); - - // Dupes, non-dupes, dupes. - Vect dnd; - dnd.push_back(Pair(1, 1)); - dnd.push_back(Pair(1, 2)); - dnd.push_back(Pair(1, 3)); - dnd.push_back(Pair(2, 1)); - dnd.push_back(Pair(3, 1)); - dnd.push_back(Pair(3, 2)); - dnd.push_back(Pair(3, 3)); - last = LastUnique(dnd.begin(), dnd.end(), cmp); - EXPECT_EQ(dnd.begin() + 3, last); - dnd.erase(last, dnd.end()); - EXPECT_THAT(dnd, ElementsAre(Pair(1, 3), Pair(2, 1), Pair(3, 3))); -} - -// ---------------------------------------------------------------------------- -// Class. - -// Check that flat_tree and its iterators can be instantiated with an -// incomplete type. - -TEST(FlatTree, IncompleteType) { - struct A { - using Tree = flat_tree<A, A, GetKeyFromValueIdentity<A>, std::less<A>>; - int data; - Tree set_with_incomplete_type; - Tree::iterator it; - Tree::const_iterator cit; - - // We do not declare operator< because clang complains that it's unused. - }; - - A a; -} - -TEST(FlatTree, Stability) { - using Pair = std::pair<int, int>; - - using Tree = - flat_tree<Pair, Pair, GetKeyFromValueIdentity<Pair>, LessByFirst<Pair>>; - - // Constructors are stable. - Tree cont({{0, 0}, {1, 0}, {0, 1}, {2, 0}, {0, 2}, {1, 1}}); - - auto AllOfSecondsAreZero = [&cont] { - return std::all_of(cont.begin(), cont.end(), - [](const Pair& elem) { return elem.second == 0; }); - }; - - EXPECT_TRUE(AllOfSecondsAreZero()) << "constructor should be stable"; - - // Should not replace existing. - cont.insert(Pair(0, 2)); - cont.insert(Pair(1, 2)); - cont.insert(Pair(2, 2)); - - EXPECT_TRUE(AllOfSecondsAreZero()) << "insert should be stable"; - - cont.insert(Pair(3, 0)); - cont.insert(Pair(3, 2)); - - EXPECT_TRUE(AllOfSecondsAreZero()) << "insert should be stable"; -} - -// ---------------------------------------------------------------------------- -// Types. - -// key_type -// key_compare -// value_type -// value_compare -// pointer -// const_pointer -// reference -// const_reference -// size_type -// difference_type -// iterator -// const_iterator -// reverse_iterator -// const_reverse_iterator - -TEST(FlatTree, Types) { - // These are guaranteed to be portable. - static_assert((std::is_same<int, IntTree::key_type>::value), ""); - static_assert((std::is_same<int, IntTree::value_type>::value), ""); - static_assert((std::is_same<std::less<int>, IntTree::key_compare>::value), - ""); - static_assert((std::is_same<int&, IntTree::reference>::value), ""); - static_assert((std::is_same<const int&, IntTree::const_reference>::value), - ""); - static_assert((std::is_same<int*, IntTree::pointer>::value), ""); - static_assert((std::is_same<const int*, IntTree::const_pointer>::value), ""); -} - -// ---------------------------------------------------------------------------- -// Lifetime. - -// flat_tree() -// flat_tree(const Compare& comp) - -TEST(FlatTree, DefaultConstructor) { - { - IntTree cont; - EXPECT_THAT(cont, ElementsAre()); - } - - { - TreeWithStrangeCompare cont(NonDefaultConstructibleCompare(0)); - EXPECT_THAT(cont, ElementsAre()); - } -} - -// flat_tree(InputIterator first, -// InputIterator last, -// FlatContainerDupes dupe_handling, -// const Compare& comp = Compare()) - -TEST(FlatTree, RangeConstructor) { - { - IntPair input_vals[] = {{1, 1}, {1, 2}, {2, 1}, {2, 2}, {1, 3}, - {2, 3}, {3, 1}, {3, 2}, {3, 3}}; - - IntPairTree first_of(MakeInputIterator(std::begin(input_vals)), - MakeInputIterator(std::end(input_vals))); - EXPECT_THAT(first_of, - ElementsAre(IntPair(1, 1), IntPair(2, 1), IntPair(3, 1))); - - IntPairTree last_of(MakeInputIterator(std::begin(input_vals)), - MakeInputIterator(std::end(input_vals)), - KEEP_LAST_OF_DUPES); - EXPECT_THAT(last_of, - ElementsAre(IntPair(1, 3), IntPair(2, 3), IntPair(3, 3))); - } - { - TreeWithStrangeCompare::value_type input_vals[] = {1, 1, 1, 2, 2, - 2, 3, 3, 3}; - - TreeWithStrangeCompare cont(MakeInputIterator(std::begin(input_vals)), - MakeInputIterator(std::end(input_vals)), - KEEP_FIRST_OF_DUPES, - NonDefaultConstructibleCompare(0)); - EXPECT_THAT(cont, ElementsAre(1, 2, 3)); - } -} - -// flat_tree(const flat_tree& x) - -TEST(FlatTree, CopyConstructor) { - IntTree original({1, 2, 3, 4}); - IntTree copied(original); - - EXPECT_THAT(copied, ElementsAre(1, 2, 3, 4)); - - EXPECT_THAT(copied, ElementsAre(1, 2, 3, 4)); - EXPECT_THAT(original, ElementsAre(1, 2, 3, 4)); - EXPECT_EQ(original, copied); -} - -// flat_tree(flat_tree&& x) - -TEST(FlatTree, MoveConstructor) { - int input_range[] = {1, 2, 3, 4}; - - MoveOnlyTree original(std::begin(input_range), std::end(input_range)); - MoveOnlyTree moved(std::move(original)); - - EXPECT_EQ(1U, moved.count(MoveOnlyInt(1))); - EXPECT_EQ(1U, moved.count(MoveOnlyInt(2))); - EXPECT_EQ(1U, moved.count(MoveOnlyInt(3))); - EXPECT_EQ(1U, moved.count(MoveOnlyInt(4))); -} - -// flat_tree(std::vector<value_type>, FlatContainerDupes dupe_handling) - -TEST(FlatTree, VectorConstructor) { - using Pair = std::pair<int, MoveOnlyInt>; - - // Construct an unsorted vector with a duplicate item in it. Sorted by the - // first item, the second allows us to test for stability. Using a move - // only type to ensure the vector is not copied. - std::vector<Pair> storage; - storage.push_back(Pair(2, MoveOnlyInt(0))); - storage.push_back(Pair(1, MoveOnlyInt(0))); - storage.push_back(Pair(2, MoveOnlyInt(1))); - - using Tree = - flat_tree<Pair, Pair, GetKeyFromValueIdentity<Pair>, LessByFirst<Pair>>; - Tree tree(std::move(storage)); - - // The list should be two items long, with only the first "2" saved. - ASSERT_EQ(2u, tree.size()); - const Pair& zeroth = *tree.begin(); - ASSERT_EQ(1, zeroth.first); - ASSERT_EQ(0, zeroth.second.data()); - - const Pair& first = *(tree.begin() + 1); - ASSERT_EQ(2, first.first); - ASSERT_EQ(0, first.second.data()); - - // Test KEEP_LAST_OF_DUPES with a simple vector constructor. - std::vector<IntPair> int_storage{{1, 1}, {1, 2}, {2, 1}}; - IntPairTree int_tree(std::move(int_storage), KEEP_LAST_OF_DUPES); - EXPECT_THAT(int_tree, ElementsAre(IntPair(1, 2), IntPair(2, 1))); -} - -// flat_tree(std::initializer_list<value_type> ilist, -// FlatContainerDupes dupe_handling, -// const Compare& comp = Compare()) - -TEST(FlatTree, InitializerListConstructor) { - { - IntTree cont({1, 2, 3, 4, 5, 6, 10, 8}); - EXPECT_THAT(cont, ElementsAre(1, 2, 3, 4, 5, 6, 8, 10)); - } - { - IntTree cont({1, 2, 3, 4, 5, 6, 10, 8}); - EXPECT_THAT(cont, ElementsAre(1, 2, 3, 4, 5, 6, 8, 10)); - } - { - TreeWithStrangeCompare cont({1, 2, 3, 4, 5, 6, 10, 8}, KEEP_FIRST_OF_DUPES, - NonDefaultConstructibleCompare(0)); - EXPECT_THAT(cont, ElementsAre(1, 2, 3, 4, 5, 6, 8, 10)); - } - { - IntPairTree first_of({{1, 1}, {2, 1}, {1, 2}}); - EXPECT_THAT(first_of, ElementsAre(IntPair(1, 1), IntPair(2, 1))); - } - { - IntPairTree last_of({{1, 1}, {2, 1}, {1, 2}}, KEEP_LAST_OF_DUPES); - EXPECT_THAT(last_of, ElementsAre(IntPair(1, 2), IntPair(2, 1))); - } -} - -// ---------------------------------------------------------------------------- -// Assignments. - -// flat_tree& operator=(const flat_tree&) - -TEST(FlatTree, CopyAssignable) { - IntTree original({1, 2, 3, 4}); - IntTree copied; - copied = original; - - EXPECT_THAT(copied, ElementsAre(1, 2, 3, 4)); - EXPECT_THAT(original, ElementsAre(1, 2, 3, 4)); - EXPECT_EQ(original, copied); -} - -// flat_tree& operator=(flat_tree&&) - -TEST(FlatTree, MoveAssignable) { - int input_range[] = {1, 2, 3, 4}; - - MoveOnlyTree original(std::begin(input_range), std::end(input_range)); - MoveOnlyTree moved; - moved = std::move(original); - - EXPECT_EQ(1U, moved.count(MoveOnlyInt(1))); - EXPECT_EQ(1U, moved.count(MoveOnlyInt(2))); - EXPECT_EQ(1U, moved.count(MoveOnlyInt(3))); - EXPECT_EQ(1U, moved.count(MoveOnlyInt(4))); -} - -// flat_tree& operator=(std::initializer_list<value_type> ilist) - -TEST(FlatTree, InitializerListAssignable) { - IntTree cont({0}); - cont = {1, 2, 3, 4, 5, 6, 10, 8}; - - EXPECT_EQ(0U, cont.count(0)); - EXPECT_THAT(cont, ElementsAre(1, 2, 3, 4, 5, 6, 8, 10)); -} - -// -------------------------------------------------------------------------- -// Memory management. - -// void reserve(size_type new_capacity) - -TEST(FlatTree, Reserve) { - IntTree cont({1, 2, 3}); - - cont.reserve(5); - EXPECT_LE(5U, cont.capacity()); -} - -// size_type capacity() const - -TEST(FlatTree, Capacity) { - IntTree cont({1, 2, 3}); - - EXPECT_LE(cont.size(), cont.capacity()); - cont.reserve(5); - EXPECT_LE(cont.size(), cont.capacity()); -} - -// void shrink_to_fit() - -TEST(FlatTree, ShrinkToFit) { - IntTree cont({1, 2, 3}); - - IntTree::size_type capacity_before = cont.capacity(); - cont.shrink_to_fit(); - EXPECT_GE(capacity_before, cont.capacity()); -} - -// ---------------------------------------------------------------------------- -// Size management. - -// void clear() - -TEST(FlatTree, Clear) { - IntTree cont({1, 2, 3, 4, 5, 6, 7, 8}); - cont.clear(); - EXPECT_THAT(cont, ElementsAre()); -} - -// size_type size() const - -TEST(FlatTree, Size) { - IntTree cont; - - EXPECT_EQ(0U, cont.size()); - cont.insert(2); - EXPECT_EQ(1U, cont.size()); - cont.insert(1); - EXPECT_EQ(2U, cont.size()); - cont.insert(3); - EXPECT_EQ(3U, cont.size()); - cont.erase(cont.begin()); - EXPECT_EQ(2U, cont.size()); - cont.erase(cont.begin()); - EXPECT_EQ(1U, cont.size()); - cont.erase(cont.begin()); - EXPECT_EQ(0U, cont.size()); -} - -// bool empty() const - -TEST(FlatTree, Empty) { - IntTree cont; - - EXPECT_TRUE(cont.empty()); - cont.insert(1); - EXPECT_FALSE(cont.empty()); - cont.clear(); - EXPECT_TRUE(cont.empty()); -} - -// ---------------------------------------------------------------------------- -// Iterators. - -// iterator begin() -// const_iterator begin() const -// iterator end() -// const_iterator end() const -// -// reverse_iterator rbegin() -// const_reverse_iterator rbegin() const -// reverse_iterator rend() -// const_reverse_iterator rend() const -// -// const_iterator cbegin() const -// const_iterator cend() const -// const_reverse_iterator crbegin() const -// const_reverse_iterator crend() const - -TEST(FlatTree, Iterators) { - IntTree cont({1, 2, 3, 4, 5, 6, 7, 8}); - - auto size = static_cast<IntTree::difference_type>(cont.size()); - - EXPECT_EQ(size, std::distance(cont.begin(), cont.end())); - EXPECT_EQ(size, std::distance(cont.cbegin(), cont.cend())); - EXPECT_EQ(size, std::distance(cont.rbegin(), cont.rend())); - EXPECT_EQ(size, std::distance(cont.crbegin(), cont.crend())); - - { - IntTree::iterator it = cont.begin(); - IntTree::const_iterator c_it = cont.cbegin(); - EXPECT_EQ(it, c_it); - for (int j = 1; it != cont.end(); ++it, ++c_it, ++j) { - EXPECT_EQ(j, *it); - EXPECT_EQ(j, *c_it); - } - } - { - IntTree::reverse_iterator rit = cont.rbegin(); - IntTree::const_reverse_iterator c_rit = cont.crbegin(); - EXPECT_EQ(rit, c_rit); - for (int j = static_cast<int>(size); rit != cont.rend(); - ++rit, ++c_rit, --j) { - EXPECT_EQ(j, *rit); - EXPECT_EQ(j, *c_rit); - } - } -} - -// ---------------------------------------------------------------------------- -// Insert operations. - -// pair<iterator, bool> insert(const value_type& val) - -TEST(FlatTree, InsertLValue) { - IntTree cont; - - int value = 2; - std::pair<IntTree::iterator, bool> result = cont.insert(value); - EXPECT_TRUE(result.second); - EXPECT_EQ(cont.begin(), result.first); - EXPECT_EQ(1U, cont.size()); - EXPECT_EQ(2, *result.first); - - value = 1; - result = cont.insert(value); - EXPECT_TRUE(result.second); - EXPECT_EQ(cont.begin(), result.first); - EXPECT_EQ(2U, cont.size()); - EXPECT_EQ(1, *result.first); - - value = 3; - result = cont.insert(value); - EXPECT_TRUE(result.second); - EXPECT_EQ(std::prev(cont.end()), result.first); - EXPECT_EQ(3U, cont.size()); - EXPECT_EQ(3, *result.first); - - value = 3; - result = cont.insert(value); - EXPECT_FALSE(result.second); - EXPECT_EQ(std::prev(cont.end()), result.first); - EXPECT_EQ(3U, cont.size()); - EXPECT_EQ(3, *result.first); -} - -// pair<iterator, bool> insert(value_type&& val) - -TEST(FlatTree, InsertRValue) { - MoveOnlyTree cont; - - std::pair<MoveOnlyTree::iterator, bool> result = cont.insert(MoveOnlyInt(2)); - EXPECT_TRUE(result.second); - EXPECT_EQ(cont.begin(), result.first); - EXPECT_EQ(1U, cont.size()); - EXPECT_EQ(2, result.first->data()); - - result = cont.insert(MoveOnlyInt(1)); - EXPECT_TRUE(result.second); - EXPECT_EQ(cont.begin(), result.first); - EXPECT_EQ(2U, cont.size()); - EXPECT_EQ(1, result.first->data()); - - result = cont.insert(MoveOnlyInt(3)); - EXPECT_TRUE(result.second); - EXPECT_EQ(std::prev(cont.end()), result.first); - EXPECT_EQ(3U, cont.size()); - EXPECT_EQ(3, result.first->data()); - - result = cont.insert(MoveOnlyInt(3)); - EXPECT_FALSE(result.second); - EXPECT_EQ(std::prev(cont.end()), result.first); - EXPECT_EQ(3U, cont.size()); - EXPECT_EQ(3, result.first->data()); -} - -// iterator insert(const_iterator position_hint, const value_type& val) - -TEST(FlatTree, InsertPositionLValue) { - IntTree cont; - - IntTree::iterator result = cont.insert(cont.cend(), 2); - EXPECT_EQ(cont.begin(), result); - EXPECT_EQ(1U, cont.size()); - EXPECT_EQ(2, *result); - - result = cont.insert(cont.cend(), 1); - EXPECT_EQ(cont.begin(), result); - EXPECT_EQ(2U, cont.size()); - EXPECT_EQ(1, *result); - - result = cont.insert(cont.cend(), 3); - EXPECT_EQ(std::prev(cont.end()), result); - EXPECT_EQ(3U, cont.size()); - EXPECT_EQ(3, *result); - - result = cont.insert(cont.cend(), 3); - EXPECT_EQ(std::prev(cont.end()), result); - EXPECT_EQ(3U, cont.size()); - EXPECT_EQ(3, *result); -} - -// iterator insert(const_iterator position_hint, value_type&& val) - -TEST(FlatTree, InsertPositionRValue) { - MoveOnlyTree cont; - - MoveOnlyTree::iterator result = cont.insert(cont.cend(), MoveOnlyInt(2)); - EXPECT_EQ(cont.begin(), result); - EXPECT_EQ(1U, cont.size()); - EXPECT_EQ(2, result->data()); - - result = cont.insert(cont.cend(), MoveOnlyInt(1)); - EXPECT_EQ(cont.begin(), result); - EXPECT_EQ(2U, cont.size()); - EXPECT_EQ(1, result->data()); - - result = cont.insert(cont.cend(), MoveOnlyInt(3)); - EXPECT_EQ(std::prev(cont.end()), result); - EXPECT_EQ(3U, cont.size()); - EXPECT_EQ(3, result->data()); - - result = cont.insert(cont.cend(), MoveOnlyInt(3)); - EXPECT_EQ(std::prev(cont.end()), result); - EXPECT_EQ(3U, cont.size()); - EXPECT_EQ(3, result->data()); -} - -// template <class InputIterator> -// void insert(InputIterator first, InputIterator last); - -TEST(FlatTree, InsertIterIter) { - struct GetKeyFromIntIntPair { - const int& operator()(const std::pair<int, int>& p) const { - return p.first; - } - }; - - using IntIntMap = - flat_tree<int, IntPair, GetKeyFromIntIntPair, std::less<int>>; - - { - IntIntMap cont; - IntPair int_pairs[] = {{3, 1}, {1, 1}, {4, 1}, {2, 1}}; - cont.insert(std::begin(int_pairs), std::end(int_pairs)); - EXPECT_THAT(cont, ElementsAre(IntPair(1, 1), IntPair(2, 1), IntPair(3, 1), - IntPair(4, 1))); - } - - { - IntIntMap cont({{1, 1}, {2, 1}, {3, 1}, {4, 1}}); - std::vector<IntPair> int_pairs; - cont.insert(std::begin(int_pairs), std::end(int_pairs)); - EXPECT_THAT(cont, ElementsAre(IntPair(1, 1), IntPair(2, 1), IntPair(3, 1), - IntPair(4, 1))); - } - - { - IntIntMap cont({{1, 1}, {2, 1}, {3, 1}, {4, 1}}); - IntPair int_pairs[] = {{1, 1}}; - cont.insert(std::begin(int_pairs), std::end(int_pairs)); - EXPECT_THAT(cont, ElementsAre(IntPair(1, 1), IntPair(2, 1), IntPair(3, 1), - IntPair(4, 1))); - } - - { - IntIntMap cont({{1, 1}, {2, 1}, {3, 1}, {4, 1}}); - IntPair int_pairs[] = {{1, 2}}; - cont.insert(std::begin(int_pairs), std::end(int_pairs), KEEP_LAST_OF_DUPES); - EXPECT_THAT(cont, ElementsAre(IntPair(1, 2), IntPair(2, 1), IntPair(3, 1), - IntPair(4, 1))); - } - - { - IntIntMap cont({{1, 1}, {2, 1}, {3, 1}, {4, 1}}); - IntPair int_pairs[] = {{5, 1}}; - cont.insert(std::begin(int_pairs), std::end(int_pairs)); - EXPECT_THAT(cont, ElementsAre(IntPair(1, 1), IntPair(2, 1), IntPair(3, 1), - IntPair(4, 1), IntPair(5, 1))); - } - - { - IntIntMap cont({{1, 1}, {2, 1}, {3, 1}, {4, 1}}); - IntPair int_pairs[] = {{5, 1}}; - cont.insert(std::begin(int_pairs), std::end(int_pairs), KEEP_LAST_OF_DUPES); - EXPECT_THAT(cont, ElementsAre(IntPair(1, 1), IntPair(2, 1), IntPair(3, 1), - IntPair(4, 1), IntPair(5, 1))); - } - - { - IntIntMap cont({{1, 1}, {2, 1}, {3, 1}, {4, 1}}); - IntPair int_pairs[] = {{3, 2}, {1, 2}, {4, 2}, {2, 2}}; - cont.insert(std::begin(int_pairs), std::end(int_pairs)); - EXPECT_THAT(cont, ElementsAre(IntPair(1, 1), IntPair(2, 1), IntPair(3, 1), - IntPair(4, 1))); - } - - { - IntIntMap cont({{1, 1}, {2, 1}, {3, 1}, {4, 1}}); - IntPair int_pairs[] = {{3, 2}, {1, 2}, {4, 2}, {2, 2}}; - cont.insert(std::begin(int_pairs), std::end(int_pairs), KEEP_LAST_OF_DUPES); - EXPECT_THAT(cont, ElementsAre(IntPair(1, 2), IntPair(2, 2), IntPair(3, 2), - IntPair(4, 2))); - } - - { - IntIntMap cont({{1, 1}, {2, 1}, {3, 1}, {4, 1}}); - IntPair int_pairs[] = {{3, 2}, {1, 2}, {4, 2}, {2, 2}, {7, 2}, {6, 2}, - {8, 2}, {5, 2}, {5, 3}, {6, 3}, {7, 3}, {8, 3}}; - cont.insert(std::begin(int_pairs), std::end(int_pairs)); - EXPECT_THAT(cont, ElementsAre(IntPair(1, 1), IntPair(2, 1), IntPair(3, 1), - IntPair(4, 1), IntPair(5, 2), IntPair(6, 2), - IntPair(7, 2), IntPair(8, 2))); - } - - { - IntIntMap cont({{1, 1}, {2, 1}, {3, 1}, {4, 1}}); - IntPair int_pairs[] = {{3, 2}, {1, 2}, {4, 2}, {2, 2}, {7, 2}, {6, 2}, - {8, 2}, {5, 2}, {5, 3}, {6, 3}, {7, 3}, {8, 3}}; - cont.insert(std::begin(int_pairs), std::end(int_pairs), KEEP_LAST_OF_DUPES); - EXPECT_THAT(cont, ElementsAre(IntPair(1, 2), IntPair(2, 2), IntPair(3, 2), - IntPair(4, 2), IntPair(5, 3), IntPair(6, 3), - IntPair(7, 3), IntPair(8, 3))); - } -} - -// template <class... Args> -// pair<iterator, bool> emplace(Args&&... args) - -TEST(FlatTree, Emplace) { - { - EmplaceableTree cont; - - std::pair<EmplaceableTree::iterator, bool> result = cont.emplace(); - EXPECT_TRUE(result.second); - EXPECT_EQ(cont.begin(), result.first); - EXPECT_EQ(1U, cont.size()); - EXPECT_EQ(Emplaceable(), *cont.begin()); - - result = cont.emplace(2, 3.5); - EXPECT_TRUE(result.second); - EXPECT_EQ(std::next(cont.begin()), result.first); - EXPECT_EQ(2U, cont.size()); - EXPECT_EQ(Emplaceable(2, 3.5), *result.first); - - result = cont.emplace(2, 3.5); - EXPECT_FALSE(result.second); - EXPECT_EQ(std::next(cont.begin()), result.first); - EXPECT_EQ(2U, cont.size()); - EXPECT_EQ(Emplaceable(2, 3.5), *result.first); - } - { - IntTree cont; - - std::pair<IntTree::iterator, bool> result = cont.emplace(2); - EXPECT_TRUE(result.second); - EXPECT_EQ(cont.begin(), result.first); - EXPECT_EQ(1U, cont.size()); - EXPECT_EQ(2, *result.first); - } -} - -// template <class... Args> -// iterator emplace_hint(const_iterator position_hint, Args&&... args) - -TEST(FlatTree, EmplacePosition) { - { - EmplaceableTree cont; - - EmplaceableTree::iterator result = cont.emplace_hint(cont.cend()); - EXPECT_EQ(cont.begin(), result); - EXPECT_EQ(1U, cont.size()); - EXPECT_EQ(Emplaceable(), *cont.begin()); - - result = cont.emplace_hint(cont.cend(), 2, 3.5); - EXPECT_EQ(std::next(cont.begin()), result); - EXPECT_EQ(2U, cont.size()); - EXPECT_EQ(Emplaceable(2, 3.5), *result); - - result = cont.emplace_hint(cont.cbegin(), 2, 3.5); - EXPECT_EQ(std::next(cont.begin()), result); - EXPECT_EQ(2U, cont.size()); - EXPECT_EQ(Emplaceable(2, 3.5), *result); - } - { - IntTree cont; - - IntTree::iterator result = cont.emplace_hint(cont.cend(), 2); - EXPECT_EQ(cont.begin(), result); - EXPECT_EQ(1U, cont.size()); - EXPECT_EQ(2, *result); - } -} - -// ---------------------------------------------------------------------------- -// Erase operations. - -// iterator erase(const_iterator position_hint) - -TEST(FlatTree, ErasePosition) { - { - IntTree cont({1, 2, 3, 4, 5, 6, 7, 8}); - - IntTree::iterator it = cont.erase(std::next(cont.cbegin(), 3)); - EXPECT_EQ(std::next(cont.begin(), 3), it); - EXPECT_THAT(cont, ElementsAre(1, 2, 3, 5, 6, 7, 8)); - - it = cont.erase(std::next(cont.cbegin(), 0)); - EXPECT_EQ(cont.begin(), it); - EXPECT_THAT(cont, ElementsAre(2, 3, 5, 6, 7, 8)); - - it = cont.erase(std::next(cont.cbegin(), 5)); - EXPECT_EQ(cont.end(), it); - EXPECT_THAT(cont, ElementsAre(2, 3, 5, 6, 7)); - - it = cont.erase(std::next(cont.cbegin(), 1)); - EXPECT_EQ(std::next(cont.begin()), it); - EXPECT_THAT(cont, ElementsAre(2, 5, 6, 7)); - - it = cont.erase(std::next(cont.cbegin(), 2)); - EXPECT_EQ(std::next(cont.begin(), 2), it); - EXPECT_THAT(cont, ElementsAre(2, 5, 7)); - - it = cont.erase(std::next(cont.cbegin(), 2)); - EXPECT_EQ(std::next(cont.begin(), 2), it); - EXPECT_THAT(cont, ElementsAre(2, 5)); - - it = cont.erase(std::next(cont.cbegin(), 0)); - EXPECT_EQ(std::next(cont.begin(), 0), it); - EXPECT_THAT(cont, ElementsAre(5)); - - it = cont.erase(cont.cbegin()); - EXPECT_EQ(cont.begin(), it); - EXPECT_EQ(cont.end(), it); - } - // This is LWG #2059. - // There is a potential ambiguity between erase with an iterator and erase - // with a key, if key has a templated constructor. - { - using T = TemplateConstructor; - - flat_tree<T, T, GetKeyFromValueIdentity<T>, std::less<>> cont; - T v(0); - - auto it = cont.find(v); - if (it != cont.end()) - cont.erase(it); - } -} - -// iterator erase(const_iterator first, const_iterator last) - -TEST(FlatTree, EraseRange) { - IntTree cont({1, 2, 3, 4, 5, 6, 7, 8}); - - IntTree::iterator it = - cont.erase(std::next(cont.cbegin(), 5), std::next(cont.cbegin(), 5)); - EXPECT_EQ(std::next(cont.begin(), 5), it); - EXPECT_THAT(cont, ElementsAre(1, 2, 3, 4, 5, 6, 7, 8)); - - it = cont.erase(std::next(cont.cbegin(), 3), std::next(cont.cbegin(), 4)); - EXPECT_EQ(std::next(cont.begin(), 3), it); - EXPECT_THAT(cont, ElementsAre(1, 2, 3, 5, 6, 7, 8)); - - it = cont.erase(std::next(cont.cbegin(), 2), std::next(cont.cbegin(), 5)); - EXPECT_EQ(std::next(cont.begin(), 2), it); - EXPECT_THAT(cont, ElementsAre(1, 2, 7, 8)); - - it = cont.erase(std::next(cont.cbegin(), 0), std::next(cont.cbegin(), 2)); - EXPECT_EQ(std::next(cont.begin(), 0), it); - EXPECT_THAT(cont, ElementsAre(7, 8)); - - it = cont.erase(cont.cbegin(), cont.cend()); - EXPECT_EQ(cont.begin(), it); - EXPECT_EQ(cont.end(), it); -} - -// size_type erase(const key_type& key) - -TEST(FlatTree, EraseKey) { - IntTree cont({1, 2, 3, 4, 5, 6, 7, 8}); - - EXPECT_EQ(0U, cont.erase(9)); - EXPECT_THAT(cont, ElementsAre(1, 2, 3, 4, 5, 6, 7, 8)); - - EXPECT_EQ(1U, cont.erase(4)); - EXPECT_THAT(cont, ElementsAre(1, 2, 3, 5, 6, 7, 8)); - - EXPECT_EQ(1U, cont.erase(1)); - EXPECT_THAT(cont, ElementsAre(2, 3, 5, 6, 7, 8)); - - EXPECT_EQ(1U, cont.erase(8)); - EXPECT_THAT(cont, ElementsAre(2, 3, 5, 6, 7)); - - EXPECT_EQ(1U, cont.erase(3)); - EXPECT_THAT(cont, ElementsAre(2, 5, 6, 7)); - - EXPECT_EQ(1U, cont.erase(6)); - EXPECT_THAT(cont, ElementsAre(2, 5, 7)); - - EXPECT_EQ(1U, cont.erase(7)); - EXPECT_THAT(cont, ElementsAre(2, 5)); - - EXPECT_EQ(1U, cont.erase(2)); - EXPECT_THAT(cont, ElementsAre(5)); - - EXPECT_EQ(1U, cont.erase(5)); - EXPECT_THAT(cont, ElementsAre()); -} - -// ---------------------------------------------------------------------------- -// Comparators. - -// key_compare key_comp() const - -TEST(FlatTree, KeyComp) { - ReversedTree cont({1, 2, 3, 4, 5}); - - EXPECT_TRUE(std::is_sorted(cont.begin(), cont.end(), cont.key_comp())); - int new_elements[] = {6, 7, 8, 9, 10}; - std::copy(std::begin(new_elements), std::end(new_elements), - std::inserter(cont, cont.end())); - EXPECT_TRUE(std::is_sorted(cont.begin(), cont.end(), cont.key_comp())); -} - -// value_compare value_comp() const - -TEST(FlatTree, ValueComp) { - ReversedTree cont({1, 2, 3, 4, 5}); - - EXPECT_TRUE(std::is_sorted(cont.begin(), cont.end(), cont.value_comp())); - int new_elements[] = {6, 7, 8, 9, 10}; - std::copy(std::begin(new_elements), std::end(new_elements), - std::inserter(cont, cont.end())); - EXPECT_TRUE(std::is_sorted(cont.begin(), cont.end(), cont.value_comp())); -} - -// ---------------------------------------------------------------------------- -// Search operations. - -// size_type count(const key_type& key) const - -TEST(FlatTree, Count) { - const IntTree cont({5, 6, 7, 8, 9, 10, 11, 12}); - - EXPECT_EQ(1U, cont.count(5)); - EXPECT_EQ(1U, cont.count(6)); - EXPECT_EQ(1U, cont.count(7)); - EXPECT_EQ(1U, cont.count(8)); - EXPECT_EQ(1U, cont.count(9)); - EXPECT_EQ(1U, cont.count(10)); - EXPECT_EQ(1U, cont.count(11)); - EXPECT_EQ(1U, cont.count(12)); - EXPECT_EQ(0U, cont.count(4)); -} - -// iterator find(const key_type& key) -// const_iterator find(const key_type& key) const - -TEST(FlatTree, Find) { - { - IntTree cont({5, 6, 7, 8, 9, 10, 11, 12}); - - EXPECT_EQ(cont.begin(), cont.find(5)); - EXPECT_EQ(std::next(cont.begin()), cont.find(6)); - EXPECT_EQ(std::next(cont.begin(), 2), cont.find(7)); - EXPECT_EQ(std::next(cont.begin(), 3), cont.find(8)); - EXPECT_EQ(std::next(cont.begin(), 4), cont.find(9)); - EXPECT_EQ(std::next(cont.begin(), 5), cont.find(10)); - EXPECT_EQ(std::next(cont.begin(), 6), cont.find(11)); - EXPECT_EQ(std::next(cont.begin(), 7), cont.find(12)); - EXPECT_EQ(std::next(cont.begin(), 8), cont.find(4)); - } - { - const IntTree cont({5, 6, 7, 8, 9, 10, 11, 12}); - - EXPECT_EQ(cont.begin(), cont.find(5)); - EXPECT_EQ(std::next(cont.begin()), cont.find(6)); - EXPECT_EQ(std::next(cont.begin(), 2), cont.find(7)); - EXPECT_EQ(std::next(cont.begin(), 3), cont.find(8)); - EXPECT_EQ(std::next(cont.begin(), 4), cont.find(9)); - EXPECT_EQ(std::next(cont.begin(), 5), cont.find(10)); - EXPECT_EQ(std::next(cont.begin(), 6), cont.find(11)); - EXPECT_EQ(std::next(cont.begin(), 7), cont.find(12)); - EXPECT_EQ(std::next(cont.begin(), 8), cont.find(4)); - } -} - -// pair<iterator, iterator> equal_range(const key_type& key) -// pair<const_iterator, const_iterator> equal_range(const key_type& key) const - -TEST(FlatTree, EqualRange) { - { - IntTree cont({5, 7, 9, 11, 13, 15, 17, 19}); - - std::pair<IntTree::iterator, IntTree::iterator> result = - cont.equal_range(5); - EXPECT_EQ(std::next(cont.begin(), 0), result.first); - EXPECT_EQ(std::next(cont.begin(), 1), result.second); - result = cont.equal_range(7); - EXPECT_EQ(std::next(cont.begin(), 1), result.first); - EXPECT_EQ(std::next(cont.begin(), 2), result.second); - result = cont.equal_range(9); - EXPECT_EQ(std::next(cont.begin(), 2), result.first); - EXPECT_EQ(std::next(cont.begin(), 3), result.second); - result = cont.equal_range(11); - EXPECT_EQ(std::next(cont.begin(), 3), result.first); - EXPECT_EQ(std::next(cont.begin(), 4), result.second); - result = cont.equal_range(13); - EXPECT_EQ(std::next(cont.begin(), 4), result.first); - EXPECT_EQ(std::next(cont.begin(), 5), result.second); - result = cont.equal_range(15); - EXPECT_EQ(std::next(cont.begin(), 5), result.first); - EXPECT_EQ(std::next(cont.begin(), 6), result.second); - result = cont.equal_range(17); - EXPECT_EQ(std::next(cont.begin(), 6), result.first); - EXPECT_EQ(std::next(cont.begin(), 7), result.second); - result = cont.equal_range(19); - EXPECT_EQ(std::next(cont.begin(), 7), result.first); - EXPECT_EQ(std::next(cont.begin(), 8), result.second); - result = cont.equal_range(4); - EXPECT_EQ(std::next(cont.begin(), 0), result.first); - EXPECT_EQ(std::next(cont.begin(), 0), result.second); - result = cont.equal_range(6); - EXPECT_EQ(std::next(cont.begin(), 1), result.first); - EXPECT_EQ(std::next(cont.begin(), 1), result.second); - result = cont.equal_range(8); - EXPECT_EQ(std::next(cont.begin(), 2), result.first); - EXPECT_EQ(std::next(cont.begin(), 2), result.second); - result = cont.equal_range(10); - EXPECT_EQ(std::next(cont.begin(), 3), result.first); - EXPECT_EQ(std::next(cont.begin(), 3), result.second); - result = cont.equal_range(12); - EXPECT_EQ(std::next(cont.begin(), 4), result.first); - EXPECT_EQ(std::next(cont.begin(), 4), result.second); - result = cont.equal_range(14); - EXPECT_EQ(std::next(cont.begin(), 5), result.first); - EXPECT_EQ(std::next(cont.begin(), 5), result.second); - result = cont.equal_range(16); - EXPECT_EQ(std::next(cont.begin(), 6), result.first); - EXPECT_EQ(std::next(cont.begin(), 6), result.second); - result = cont.equal_range(18); - EXPECT_EQ(std::next(cont.begin(), 7), result.first); - EXPECT_EQ(std::next(cont.begin(), 7), result.second); - result = cont.equal_range(20); - EXPECT_EQ(std::next(cont.begin(), 8), result.first); - EXPECT_EQ(std::next(cont.begin(), 8), result.second); - } - { - const IntTree cont({5, 7, 9, 11, 13, 15, 17, 19}); - - std::pair<IntTree::const_iterator, IntTree::const_iterator> result = - cont.equal_range(5); - EXPECT_EQ(std::next(cont.begin(), 0), result.first); - EXPECT_EQ(std::next(cont.begin(), 1), result.second); - result = cont.equal_range(7); - EXPECT_EQ(std::next(cont.begin(), 1), result.first); - EXPECT_EQ(std::next(cont.begin(), 2), result.second); - result = cont.equal_range(9); - EXPECT_EQ(std::next(cont.begin(), 2), result.first); - EXPECT_EQ(std::next(cont.begin(), 3), result.second); - result = cont.equal_range(11); - EXPECT_EQ(std::next(cont.begin(), 3), result.first); - EXPECT_EQ(std::next(cont.begin(), 4), result.second); - result = cont.equal_range(13); - EXPECT_EQ(std::next(cont.begin(), 4), result.first); - EXPECT_EQ(std::next(cont.begin(), 5), result.second); - result = cont.equal_range(15); - EXPECT_EQ(std::next(cont.begin(), 5), result.first); - EXPECT_EQ(std::next(cont.begin(), 6), result.second); - result = cont.equal_range(17); - EXPECT_EQ(std::next(cont.begin(), 6), result.first); - EXPECT_EQ(std::next(cont.begin(), 7), result.second); - result = cont.equal_range(19); - EXPECT_EQ(std::next(cont.begin(), 7), result.first); - EXPECT_EQ(std::next(cont.begin(), 8), result.second); - result = cont.equal_range(4); - EXPECT_EQ(std::next(cont.begin(), 0), result.first); - EXPECT_EQ(std::next(cont.begin(), 0), result.second); - result = cont.equal_range(6); - EXPECT_EQ(std::next(cont.begin(), 1), result.first); - EXPECT_EQ(std::next(cont.begin(), 1), result.second); - result = cont.equal_range(8); - EXPECT_EQ(std::next(cont.begin(), 2), result.first); - EXPECT_EQ(std::next(cont.begin(), 2), result.second); - result = cont.equal_range(10); - EXPECT_EQ(std::next(cont.begin(), 3), result.first); - EXPECT_EQ(std::next(cont.begin(), 3), result.second); - result = cont.equal_range(12); - EXPECT_EQ(std::next(cont.begin(), 4), result.first); - EXPECT_EQ(std::next(cont.begin(), 4), result.second); - result = cont.equal_range(14); - EXPECT_EQ(std::next(cont.begin(), 5), result.first); - EXPECT_EQ(std::next(cont.begin(), 5), result.second); - result = cont.equal_range(16); - EXPECT_EQ(std::next(cont.begin(), 6), result.first); - EXPECT_EQ(std::next(cont.begin(), 6), result.second); - result = cont.equal_range(18); - EXPECT_EQ(std::next(cont.begin(), 7), result.first); - EXPECT_EQ(std::next(cont.begin(), 7), result.second); - result = cont.equal_range(20); - EXPECT_EQ(std::next(cont.begin(), 8), result.first); - EXPECT_EQ(std::next(cont.begin(), 8), result.second); - } -} - -// iterator lower_bound(const key_type& key); -// const_iterator lower_bound(const key_type& key) const; - -TEST(FlatTree, LowerBound) { - { - IntTree cont({5, 7, 9, 11, 13, 15, 17, 19}); - - EXPECT_EQ(cont.begin(), cont.lower_bound(5)); - EXPECT_EQ(std::next(cont.begin()), cont.lower_bound(7)); - EXPECT_EQ(std::next(cont.begin(), 2), cont.lower_bound(9)); - EXPECT_EQ(std::next(cont.begin(), 3), cont.lower_bound(11)); - EXPECT_EQ(std::next(cont.begin(), 4), cont.lower_bound(13)); - EXPECT_EQ(std::next(cont.begin(), 5), cont.lower_bound(15)); - EXPECT_EQ(std::next(cont.begin(), 6), cont.lower_bound(17)); - EXPECT_EQ(std::next(cont.begin(), 7), cont.lower_bound(19)); - EXPECT_EQ(std::next(cont.begin(), 0), cont.lower_bound(4)); - EXPECT_EQ(std::next(cont.begin(), 1), cont.lower_bound(6)); - EXPECT_EQ(std::next(cont.begin(), 2), cont.lower_bound(8)); - EXPECT_EQ(std::next(cont.begin(), 3), cont.lower_bound(10)); - EXPECT_EQ(std::next(cont.begin(), 4), cont.lower_bound(12)); - EXPECT_EQ(std::next(cont.begin(), 5), cont.lower_bound(14)); - EXPECT_EQ(std::next(cont.begin(), 6), cont.lower_bound(16)); - EXPECT_EQ(std::next(cont.begin(), 7), cont.lower_bound(18)); - EXPECT_EQ(std::next(cont.begin(), 8), cont.lower_bound(20)); - } - { - const IntTree cont({5, 7, 9, 11, 13, 15, 17, 19}); - - EXPECT_EQ(cont.begin(), cont.lower_bound(5)); - EXPECT_EQ(std::next(cont.begin()), cont.lower_bound(7)); - EXPECT_EQ(std::next(cont.begin(), 2), cont.lower_bound(9)); - EXPECT_EQ(std::next(cont.begin(), 3), cont.lower_bound(11)); - EXPECT_EQ(std::next(cont.begin(), 4), cont.lower_bound(13)); - EXPECT_EQ(std::next(cont.begin(), 5), cont.lower_bound(15)); - EXPECT_EQ(std::next(cont.begin(), 6), cont.lower_bound(17)); - EXPECT_EQ(std::next(cont.begin(), 7), cont.lower_bound(19)); - EXPECT_EQ(std::next(cont.begin(), 0), cont.lower_bound(4)); - EXPECT_EQ(std::next(cont.begin(), 1), cont.lower_bound(6)); - EXPECT_EQ(std::next(cont.begin(), 2), cont.lower_bound(8)); - EXPECT_EQ(std::next(cont.begin(), 3), cont.lower_bound(10)); - EXPECT_EQ(std::next(cont.begin(), 4), cont.lower_bound(12)); - EXPECT_EQ(std::next(cont.begin(), 5), cont.lower_bound(14)); - EXPECT_EQ(std::next(cont.begin(), 6), cont.lower_bound(16)); - EXPECT_EQ(std::next(cont.begin(), 7), cont.lower_bound(18)); - EXPECT_EQ(std::next(cont.begin(), 8), cont.lower_bound(20)); - } -} - -// iterator upper_bound(const key_type& key) -// const_iterator upper_bound(const key_type& key) const - -TEST(FlatTree, UpperBound) { - { - IntTree cont({5, 7, 9, 11, 13, 15, 17, 19}); - - EXPECT_EQ(std::next(cont.begin(), 1), cont.upper_bound(5)); - EXPECT_EQ(std::next(cont.begin(), 2), cont.upper_bound(7)); - EXPECT_EQ(std::next(cont.begin(), 3), cont.upper_bound(9)); - EXPECT_EQ(std::next(cont.begin(), 4), cont.upper_bound(11)); - EXPECT_EQ(std::next(cont.begin(), 5), cont.upper_bound(13)); - EXPECT_EQ(std::next(cont.begin(), 6), cont.upper_bound(15)); - EXPECT_EQ(std::next(cont.begin(), 7), cont.upper_bound(17)); - EXPECT_EQ(std::next(cont.begin(), 8), cont.upper_bound(19)); - EXPECT_EQ(std::next(cont.begin(), 0), cont.upper_bound(4)); - EXPECT_EQ(std::next(cont.begin(), 1), cont.upper_bound(6)); - EXPECT_EQ(std::next(cont.begin(), 2), cont.upper_bound(8)); - EXPECT_EQ(std::next(cont.begin(), 3), cont.upper_bound(10)); - EXPECT_EQ(std::next(cont.begin(), 4), cont.upper_bound(12)); - EXPECT_EQ(std::next(cont.begin(), 5), cont.upper_bound(14)); - EXPECT_EQ(std::next(cont.begin(), 6), cont.upper_bound(16)); - EXPECT_EQ(std::next(cont.begin(), 7), cont.upper_bound(18)); - EXPECT_EQ(std::next(cont.begin(), 8), cont.upper_bound(20)); - } - { - const IntTree cont({5, 7, 9, 11, 13, 15, 17, 19}); - - EXPECT_EQ(std::next(cont.begin(), 1), cont.upper_bound(5)); - EXPECT_EQ(std::next(cont.begin(), 2), cont.upper_bound(7)); - EXPECT_EQ(std::next(cont.begin(), 3), cont.upper_bound(9)); - EXPECT_EQ(std::next(cont.begin(), 4), cont.upper_bound(11)); - EXPECT_EQ(std::next(cont.begin(), 5), cont.upper_bound(13)); - EXPECT_EQ(std::next(cont.begin(), 6), cont.upper_bound(15)); - EXPECT_EQ(std::next(cont.begin(), 7), cont.upper_bound(17)); - EXPECT_EQ(std::next(cont.begin(), 8), cont.upper_bound(19)); - EXPECT_EQ(std::next(cont.begin(), 0), cont.upper_bound(4)); - EXPECT_EQ(std::next(cont.begin(), 1), cont.upper_bound(6)); - EXPECT_EQ(std::next(cont.begin(), 2), cont.upper_bound(8)); - EXPECT_EQ(std::next(cont.begin(), 3), cont.upper_bound(10)); - EXPECT_EQ(std::next(cont.begin(), 4), cont.upper_bound(12)); - EXPECT_EQ(std::next(cont.begin(), 5), cont.upper_bound(14)); - EXPECT_EQ(std::next(cont.begin(), 6), cont.upper_bound(16)); - EXPECT_EQ(std::next(cont.begin(), 7), cont.upper_bound(18)); - EXPECT_EQ(std::next(cont.begin(), 8), cont.upper_bound(20)); - } -} - -// ---------------------------------------------------------------------------- -// General operations. - -// void swap(flat_tree& other) -// void swap(flat_tree& lhs, flat_tree& rhs) - -TEST(FlatTreeOurs, Swap) { - IntTree x({1, 2, 3}); - IntTree y({4}); - swap(x, y); - EXPECT_THAT(x, ElementsAre(4)); - EXPECT_THAT(y, ElementsAre(1, 2, 3)); - - y.swap(x); - EXPECT_THAT(x, ElementsAre(1, 2, 3)); - EXPECT_THAT(y, ElementsAre(4)); -} - -// bool operator==(const flat_tree& lhs, const flat_tree& rhs) -// bool operator!=(const flat_tree& lhs, const flat_tree& rhs) -// bool operator<(const flat_tree& lhs, const flat_tree& rhs) -// bool operator>(const flat_tree& lhs, const flat_tree& rhs) -// bool operator<=(const flat_tree& lhs, const flat_tree& rhs) -// bool operator>=(const flat_tree& lhs, const flat_tree& rhs) - -TEST(FlatTree, Comparison) { - // Provided comparator does not participate in comparison. - ReversedTree biggest({3}); - ReversedTree smallest({1}); - ReversedTree middle({1, 2}); - - EXPECT_EQ(biggest, biggest); - EXPECT_NE(biggest, smallest); - EXPECT_LT(smallest, middle); - EXPECT_LE(smallest, middle); - EXPECT_LE(middle, middle); - EXPECT_GT(biggest, middle); - EXPECT_GE(biggest, middle); - EXPECT_GE(biggest, biggest); -} - -TEST(FlatSet, EraseIf) { - IntTree x; - EraseIf(x, [](int) { return false; }); - EXPECT_THAT(x, ElementsAre()); - - x = {1, 2, 3}; - EraseIf(x, [](int elem) { return !(elem & 1); }); - EXPECT_THAT(x, ElementsAre(1, 3)); - - x = {1, 2, 3, 4}; - EraseIf(x, [](int elem) { return elem & 1; }); - EXPECT_THAT(x, ElementsAre(2, 4)); -} - -} // namespace internal -} // namespace base
diff --git a/base/containers/hash_tables_unittest.cc b/base/containers/hash_tables_unittest.cc deleted file mode 100644 index 6072e5d..0000000 --- a/base/containers/hash_tables_unittest.cc +++ /dev/null
@@ -1,67 +0,0 @@ -// 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/containers/hash_tables.h" - -#include <stdint.h> -#include <string> - -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -class HashPairTest : public testing::Test { -}; - -#define INSERT_PAIR_TEST(Type, value1, value2) \ - { \ - Type pair(value1, value2); \ - base::hash_map<Type, int> map; \ - map[pair] = 1; \ - } - -// Verify that a hash_map can be constructed for pairs of integers of various -// sizes. -TEST_F(HashPairTest, IntegerPairs) { - typedef std::pair<int16_t, int16_t> Int16Int16Pair; - typedef std::pair<int16_t, int32_t> Int16Int32Pair; - typedef std::pair<int16_t, int64_t> Int16Int64Pair; - - INSERT_PAIR_TEST(Int16Int16Pair, 4, 6); - INSERT_PAIR_TEST(Int16Int32Pair, 9, (1 << 29) + 378128932); - INSERT_PAIR_TEST(Int16Int64Pair, 10, - (INT64_C(1) << 60) + INT64_C(78931732321)); - - typedef std::pair<int32_t, int16_t> Int32Int16Pair; - typedef std::pair<int32_t, int32_t> Int32Int32Pair; - typedef std::pair<int32_t, int64_t> Int32Int64Pair; - - INSERT_PAIR_TEST(Int32Int16Pair, 4, 6); - INSERT_PAIR_TEST(Int32Int32Pair, 9, (1 << 29) + 378128932); - INSERT_PAIR_TEST(Int32Int64Pair, 10, - (INT64_C(1) << 60) + INT64_C(78931732321)); - - typedef std::pair<int64_t, int16_t> Int64Int16Pair; - typedef std::pair<int64_t, int32_t> Int64Int32Pair; - typedef std::pair<int64_t, int64_t> Int64Int64Pair; - - INSERT_PAIR_TEST(Int64Int16Pair, 4, 6); - INSERT_PAIR_TEST(Int64Int32Pair, 9, (1 << 29) + 378128932); - INSERT_PAIR_TEST(Int64Int64Pair, 10, - (INT64_C(1) << 60) + INT64_C(78931732321)); -} - -// Verify that base::hash_set<const char*> compares by pointer value, not as C -// strings. -TEST(HashTableTest, CharPointers) { - std::string str1("hello"); - std::string str2("hello"); - base::hash_set<const char*> set; - - set.insert(str1.c_str()); - EXPECT_EQ(1u, set.count(str1.c_str())); - EXPECT_EQ(0u, set.count(str2.c_str())); -} - -} // namespace
diff --git a/base/containers/id_map_unittest.cc b/base/containers/id_map_unittest.cc deleted file mode 100644 index 346b69f..0000000 --- a/base/containers/id_map_unittest.cc +++ /dev/null
@@ -1,399 +0,0 @@ -// 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/containers/id_map.h" - -#include <stdint.h> - -#include <memory> - -#include "base/test/gtest_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -class TestObject { -}; - -class DestructorCounter { - public: - explicit DestructorCounter(int* counter) : counter_(counter) {} - ~DestructorCounter() { ++(*counter_); } - - private: - int* counter_; -}; - -} // namespace - -TEST(IDMapTest, Basic) { - IDMap<TestObject*> map; - EXPECT_TRUE(map.IsEmpty()); - EXPECT_EQ(0U, map.size()); - - TestObject obj1; - TestObject obj2; - - int32_t id1 = map.Add(&obj1); - EXPECT_FALSE(map.IsEmpty()); - EXPECT_EQ(1U, map.size()); - EXPECT_EQ(&obj1, map.Lookup(id1)); - - int32_t id2 = map.Add(&obj2); - EXPECT_FALSE(map.IsEmpty()); - EXPECT_EQ(2U, map.size()); - - EXPECT_EQ(&obj1, map.Lookup(id1)); - EXPECT_EQ(&obj2, map.Lookup(id2)); - - map.Remove(id1); - EXPECT_FALSE(map.IsEmpty()); - EXPECT_EQ(1U, map.size()); - - map.Remove(id2); - EXPECT_TRUE(map.IsEmpty()); - EXPECT_EQ(0U, map.size()); - - map.AddWithID(&obj1, 1); - map.AddWithID(&obj2, 2); - EXPECT_EQ(&obj1, map.Lookup(1)); - EXPECT_EQ(&obj2, map.Lookup(2)); - - EXPECT_EQ(&obj2, map.Replace(2, &obj1)); - EXPECT_EQ(&obj1, map.Lookup(2)); - - EXPECT_EQ(0, map.iteration_depth()); -} - -TEST(IDMapTest, IteratorRemainsValidWhenRemovingCurrentElement) { - IDMap<TestObject*> map; - - TestObject obj1; - TestObject obj2; - TestObject obj3; - - map.Add(&obj1); - map.Add(&obj2); - map.Add(&obj3); - - { - IDMap<TestObject*>::const_iterator iter(&map); - - EXPECT_EQ(1, map.iteration_depth()); - - while (!iter.IsAtEnd()) { - map.Remove(iter.GetCurrentKey()); - iter.Advance(); - } - - // Test that while an iterator is still in scope, we get the map emptiness - // right (http://crbug.com/35571). - EXPECT_TRUE(map.IsEmpty()); - EXPECT_EQ(0U, map.size()); - } - - EXPECT_TRUE(map.IsEmpty()); - EXPECT_EQ(0U, map.size()); - - EXPECT_EQ(0, map.iteration_depth()); -} - -TEST(IDMapTest, IteratorRemainsValidWhenRemovingOtherElements) { - IDMap<TestObject*> map; - - const int kCount = 5; - TestObject obj[kCount]; - - for (int i = 0; i < kCount; i++) - map.Add(&obj[i]); - - // IDMap has no predictable iteration order. - int32_t ids_in_iteration_order[kCount]; - const TestObject* objs_in_iteration_order[kCount]; - int counter = 0; - for (IDMap<TestObject*>::const_iterator iter(&map); !iter.IsAtEnd(); - iter.Advance()) { - ids_in_iteration_order[counter] = iter.GetCurrentKey(); - objs_in_iteration_order[counter] = iter.GetCurrentValue(); - counter++; - } - - counter = 0; - for (IDMap<TestObject*>::const_iterator iter(&map); !iter.IsAtEnd(); - iter.Advance()) { - EXPECT_EQ(1, map.iteration_depth()); - - switch (counter) { - case 0: - EXPECT_EQ(ids_in_iteration_order[0], iter.GetCurrentKey()); - EXPECT_EQ(objs_in_iteration_order[0], iter.GetCurrentValue()); - map.Remove(ids_in_iteration_order[1]); - break; - case 1: - EXPECT_EQ(ids_in_iteration_order[2], iter.GetCurrentKey()); - EXPECT_EQ(objs_in_iteration_order[2], iter.GetCurrentValue()); - map.Remove(ids_in_iteration_order[3]); - break; - case 2: - EXPECT_EQ(ids_in_iteration_order[4], iter.GetCurrentKey()); - EXPECT_EQ(objs_in_iteration_order[4], iter.GetCurrentValue()); - map.Remove(ids_in_iteration_order[0]); - break; - default: - FAIL() << "should not have that many elements"; - break; - } - - counter++; - } - - EXPECT_EQ(0, map.iteration_depth()); -} - -TEST(IDMapTest, CopyIterator) { - IDMap<TestObject*> map; - - TestObject obj1; - TestObject obj2; - TestObject obj3; - - map.Add(&obj1); - map.Add(&obj2); - map.Add(&obj3); - - EXPECT_EQ(0, map.iteration_depth()); - - { - IDMap<TestObject*>::const_iterator iter1(&map); - EXPECT_EQ(1, map.iteration_depth()); - - // Make sure that copying the iterator correctly increments - // map's iteration depth. - IDMap<TestObject*>::const_iterator iter2(iter1); - EXPECT_EQ(2, map.iteration_depth()); - } - - // Make sure after destroying all iterators the map's iteration depth - // returns to initial state. - EXPECT_EQ(0, map.iteration_depth()); -} - -TEST(IDMapTest, AssignIterator) { - IDMap<TestObject*> map; - - TestObject obj1; - TestObject obj2; - TestObject obj3; - - map.Add(&obj1); - map.Add(&obj2); - map.Add(&obj3); - - EXPECT_EQ(0, map.iteration_depth()); - - { - IDMap<TestObject*>::const_iterator iter1(&map); - EXPECT_EQ(1, map.iteration_depth()); - - IDMap<TestObject*>::const_iterator iter2(&map); - EXPECT_EQ(2, map.iteration_depth()); - - // Make sure that assigning the iterator correctly updates - // map's iteration depth (-1 for destruction, +1 for assignment). - EXPECT_EQ(2, map.iteration_depth()); - } - - // Make sure after destroying all iterators the map's iteration depth - // returns to initial state. - EXPECT_EQ(0, map.iteration_depth()); -} - -TEST(IDMapTest, IteratorRemainsValidWhenClearing) { - IDMap<TestObject*> map; - - const int kCount = 5; - TestObject obj[kCount]; - - for (int i = 0; i < kCount; i++) - map.Add(&obj[i]); - - // IDMap has no predictable iteration order. - int32_t ids_in_iteration_order[kCount]; - const TestObject* objs_in_iteration_order[kCount]; - int counter = 0; - for (IDMap<TestObject*>::const_iterator iter(&map); !iter.IsAtEnd(); - iter.Advance()) { - ids_in_iteration_order[counter] = iter.GetCurrentKey(); - objs_in_iteration_order[counter] = iter.GetCurrentValue(); - counter++; - } - - counter = 0; - for (IDMap<TestObject*>::const_iterator iter(&map); !iter.IsAtEnd(); - iter.Advance()) { - switch (counter) { - case 0: - EXPECT_EQ(ids_in_iteration_order[0], iter.GetCurrentKey()); - EXPECT_EQ(objs_in_iteration_order[0], iter.GetCurrentValue()); - break; - case 1: - EXPECT_EQ(ids_in_iteration_order[1], iter.GetCurrentKey()); - EXPECT_EQ(objs_in_iteration_order[1], iter.GetCurrentValue()); - map.Clear(); - EXPECT_TRUE(map.IsEmpty()); - EXPECT_EQ(0U, map.size()); - break; - default: - FAIL() << "should not have that many elements"; - break; - } - counter++; - } - - EXPECT_TRUE(map.IsEmpty()); - EXPECT_EQ(0U, map.size()); -} - -TEST(IDMapTest, OwningPointersDeletesThemOnRemove) { - const int kCount = 3; - - int external_del_count = 0; - DestructorCounter* external_obj[kCount]; - int map_external_ids[kCount]; - - int owned_del_count = 0; - int map_owned_ids[kCount]; - - IDMap<DestructorCounter*> map_external; - IDMap<std::unique_ptr<DestructorCounter>> map_owned; - - for (int i = 0; i < kCount; ++i) { - external_obj[i] = new DestructorCounter(&external_del_count); - map_external_ids[i] = map_external.Add(external_obj[i]); - - map_owned_ids[i] = - map_owned.Add(std::make_unique<DestructorCounter>(&owned_del_count)); - } - - for (int i = 0; i < kCount; ++i) { - EXPECT_EQ(external_del_count, 0); - EXPECT_EQ(owned_del_count, i); - - map_external.Remove(map_external_ids[i]); - map_owned.Remove(map_owned_ids[i]); - } - - for (int i = 0; i < kCount; ++i) { - delete external_obj[i]; - } - - EXPECT_EQ(external_del_count, kCount); - EXPECT_EQ(owned_del_count, kCount); -} - -TEST(IDMapTest, OwningPointersDeletesThemOnClear) { - const int kCount = 3; - - int external_del_count = 0; - DestructorCounter* external_obj[kCount]; - - int owned_del_count = 0; - - IDMap<DestructorCounter*> map_external; - IDMap<std::unique_ptr<DestructorCounter>> map_owned; - - for (int i = 0; i < kCount; ++i) { - external_obj[i] = new DestructorCounter(&external_del_count); - map_external.Add(external_obj[i]); - - map_owned.Add(std::make_unique<DestructorCounter>(&owned_del_count)); - } - - EXPECT_EQ(external_del_count, 0); - EXPECT_EQ(owned_del_count, 0); - - map_external.Clear(); - map_owned.Clear(); - - EXPECT_EQ(external_del_count, 0); - EXPECT_EQ(owned_del_count, kCount); - - for (int i = 0; i < kCount; ++i) { - delete external_obj[i]; - } - - EXPECT_EQ(external_del_count, kCount); - EXPECT_EQ(owned_del_count, kCount); -} - -TEST(IDMapTest, OwningPointersDeletesThemOnDestruct) { - const int kCount = 3; - - int external_del_count = 0; - DestructorCounter* external_obj[kCount]; - - int owned_del_count = 0; - - { - IDMap<DestructorCounter*> map_external; - IDMap<std::unique_ptr<DestructorCounter>> map_owned; - - for (int i = 0; i < kCount; ++i) { - external_obj[i] = new DestructorCounter(&external_del_count); - map_external.Add(external_obj[i]); - - map_owned.Add(std::make_unique<DestructorCounter>(&owned_del_count)); - } - } - - EXPECT_EQ(external_del_count, 0); - - for (int i = 0; i < kCount; ++i) { - delete external_obj[i]; - } - - EXPECT_EQ(external_del_count, kCount); - EXPECT_EQ(owned_del_count, kCount); -} - -TEST(IDMapTest, Int64KeyType) { - IDMap<TestObject*, int64_t> map; - TestObject obj1; - const int64_t kId1 = 999999999999999999; - - map.AddWithID(&obj1, kId1); - EXPECT_EQ(&obj1, map.Lookup(kId1)); - - IDMap<TestObject*, int64_t>::const_iterator iter(&map); - ASSERT_FALSE(iter.IsAtEnd()); - EXPECT_EQ(kId1, iter.GetCurrentKey()); - EXPECT_EQ(&obj1, iter.GetCurrentValue()); - iter.Advance(); - ASSERT_TRUE(iter.IsAtEnd()); - - map.Remove(kId1); - EXPECT_TRUE(map.IsEmpty()); -} - -TEST(IDMapTest, RemovedValueHandling) { - TestObject obj; - IDMap<TestObject*> map; - int key = map.Add(&obj); - - IDMap<TestObject*>::iterator itr(&map); - map.Clear(); - EXPECT_DCHECK_DEATH(map.Remove(key)); - EXPECT_DCHECK_DEATH(map.Replace(key, &obj)); - EXPECT_FALSE(map.Lookup(key)); - EXPECT_FALSE(itr.IsAtEnd()); - EXPECT_FALSE(itr.GetCurrentValue()); - - EXPECT_TRUE(map.IsEmpty()); - map.AddWithID(&obj, key); - EXPECT_EQ(1u, map.size()); -} - -} // namespace base
diff --git a/base/containers/linked_list_unittest.cc b/base/containers/linked_list_unittest.cc deleted file mode 100644 index 8e547ba..0000000 --- a/base/containers/linked_list_unittest.cc +++ /dev/null
@@ -1,349 +0,0 @@ -// Copyright (c) 2009 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/containers/linked_list.h" -#include "base/macros.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -class Node : public LinkNode<Node> { - public: - explicit Node(int id) : id_(id) {} - - int id() const { return id_; } - - private: - int id_; -}; - -class MultipleInheritanceNodeBase { - public: - MultipleInheritanceNodeBase() : field_taking_up_space_(0) {} - int field_taking_up_space_; -}; - -class MultipleInheritanceNode : public MultipleInheritanceNodeBase, - public LinkNode<MultipleInheritanceNode> { - public: - MultipleInheritanceNode() = default; -}; - -class MovableNode : public LinkNode<MovableNode> { - public: - explicit MovableNode(int id) : id_(id) {} - - MovableNode(MovableNode&&) = default; - - int id() const { return id_; } - - private: - int id_; -}; - -// Checks that when iterating |list| (either from head to tail, or from -// tail to head, as determined by |forward|), we get back |node_ids|, -// which is an array of size |num_nodes|. -void ExpectListContentsForDirection(const LinkedList<Node>& list, - int num_nodes, const int* node_ids, bool forward) { - int i = 0; - for (const LinkNode<Node>* node = (forward ? list.head() : list.tail()); - node != list.end(); - node = (forward ? node->next() : node->previous())) { - ASSERT_LT(i, num_nodes); - int index_of_id = forward ? i : num_nodes - i - 1; - EXPECT_EQ(node_ids[index_of_id], node->value()->id()); - ++i; - } - EXPECT_EQ(num_nodes, i); -} - -void ExpectListContents(const LinkedList<Node>& list, - int num_nodes, - const int* node_ids) { - { - SCOPED_TRACE("Iterating forward (from head to tail)"); - ExpectListContentsForDirection(list, num_nodes, node_ids, true); - } - { - SCOPED_TRACE("Iterating backward (from tail to head)"); - ExpectListContentsForDirection(list, num_nodes, node_ids, false); - } -} - -TEST(LinkedList, Empty) { - LinkedList<Node> list; - EXPECT_EQ(list.end(), list.head()); - EXPECT_EQ(list.end(), list.tail()); - ExpectListContents(list, 0, nullptr); -} - -TEST(LinkedList, Append) { - LinkedList<Node> list; - ExpectListContents(list, 0, nullptr); - - Node n1(1); - list.Append(&n1); - - EXPECT_EQ(&n1, list.head()); - EXPECT_EQ(&n1, list.tail()); - { - const int expected[] = {1}; - ExpectListContents(list, arraysize(expected), expected); - } - - Node n2(2); - list.Append(&n2); - - EXPECT_EQ(&n1, list.head()); - EXPECT_EQ(&n2, list.tail()); - { - const int expected[] = {1, 2}; - ExpectListContents(list, arraysize(expected), expected); - } - - Node n3(3); - list.Append(&n3); - - EXPECT_EQ(&n1, list.head()); - EXPECT_EQ(&n3, list.tail()); - { - const int expected[] = {1, 2, 3}; - ExpectListContents(list, arraysize(expected), expected); - } -} - -TEST(LinkedList, RemoveFromList) { - LinkedList<Node> list; - - Node n1(1); - Node n2(2); - Node n3(3); - Node n4(4); - Node n5(5); - - list.Append(&n1); - list.Append(&n2); - list.Append(&n3); - list.Append(&n4); - list.Append(&n5); - - EXPECT_EQ(&n1, list.head()); - EXPECT_EQ(&n5, list.tail()); - { - const int expected[] = {1, 2, 3, 4, 5}; - ExpectListContents(list, arraysize(expected), expected); - } - - // Remove from the middle. - n3.RemoveFromList(); - - EXPECT_EQ(&n1, list.head()); - EXPECT_EQ(&n5, list.tail()); - { - const int expected[] = {1, 2, 4, 5}; - ExpectListContents(list, arraysize(expected), expected); - } - - // Remove from the tail. - n5.RemoveFromList(); - - EXPECT_EQ(&n1, list.head()); - EXPECT_EQ(&n4, list.tail()); - { - const int expected[] = {1, 2, 4}; - ExpectListContents(list, arraysize(expected), expected); - } - - // Remove from the head. - n1.RemoveFromList(); - - EXPECT_EQ(&n2, list.head()); - EXPECT_EQ(&n4, list.tail()); - { - const int expected[] = {2, 4}; - ExpectListContents(list, arraysize(expected), expected); - } - - // Empty the list. - n2.RemoveFromList(); - n4.RemoveFromList(); - - ExpectListContents(list, 0, nullptr); - EXPECT_EQ(list.end(), list.head()); - EXPECT_EQ(list.end(), list.tail()); - - // Fill the list once again. - list.Append(&n1); - list.Append(&n2); - list.Append(&n3); - list.Append(&n4); - list.Append(&n5); - - EXPECT_EQ(&n1, list.head()); - EXPECT_EQ(&n5, list.tail()); - { - const int expected[] = {1, 2, 3, 4, 5}; - ExpectListContents(list, arraysize(expected), expected); - } -} - -TEST(LinkedList, InsertBefore) { - LinkedList<Node> list; - - Node n1(1); - Node n2(2); - Node n3(3); - Node n4(4); - - list.Append(&n1); - list.Append(&n2); - - EXPECT_EQ(&n1, list.head()); - EXPECT_EQ(&n2, list.tail()); - { - const int expected[] = {1, 2}; - ExpectListContents(list, arraysize(expected), expected); - } - - n3.InsertBefore(&n2); - - EXPECT_EQ(&n1, list.head()); - EXPECT_EQ(&n2, list.tail()); - { - const int expected[] = {1, 3, 2}; - ExpectListContents(list, arraysize(expected), expected); - } - - n4.InsertBefore(&n1); - - EXPECT_EQ(&n4, list.head()); - EXPECT_EQ(&n2, list.tail()); - { - const int expected[] = {4, 1, 3, 2}; - ExpectListContents(list, arraysize(expected), expected); - } -} - -TEST(LinkedList, InsertAfter) { - LinkedList<Node> list; - - Node n1(1); - Node n2(2); - Node n3(3); - Node n4(4); - - list.Append(&n1); - list.Append(&n2); - - EXPECT_EQ(&n1, list.head()); - EXPECT_EQ(&n2, list.tail()); - { - const int expected[] = {1, 2}; - ExpectListContents(list, arraysize(expected), expected); - } - - n3.InsertAfter(&n2); - - EXPECT_EQ(&n1, list.head()); - EXPECT_EQ(&n3, list.tail()); - { - const int expected[] = {1, 2, 3}; - ExpectListContents(list, arraysize(expected), expected); - } - - n4.InsertAfter(&n1); - - EXPECT_EQ(&n1, list.head()); - EXPECT_EQ(&n3, list.tail()); - { - const int expected[] = {1, 4, 2, 3}; - ExpectListContents(list, arraysize(expected), expected); - } -} - -TEST(LinkedList, MultipleInheritanceNode) { - MultipleInheritanceNode node; - EXPECT_EQ(&node, node.value()); -} - -TEST(LinkedList, EmptyListIsEmpty) { - LinkedList<Node> list; - EXPECT_TRUE(list.empty()); -} - -TEST(LinkedList, NonEmptyListIsNotEmpty) { - LinkedList<Node> list; - - Node n(1); - list.Append(&n); - - EXPECT_FALSE(list.empty()); -} - -TEST(LinkedList, EmptiedListIsEmptyAgain) { - LinkedList<Node> list; - - Node n(1); - list.Append(&n); - n.RemoveFromList(); - - EXPECT_TRUE(list.empty()); -} - -TEST(LinkedList, NodesCanBeReused) { - LinkedList<Node> list1; - LinkedList<Node> list2; - - Node n(1); - list1.Append(&n); - n.RemoveFromList(); - list2.Append(&n); - - EXPECT_EQ(list2.head()->value(), &n); -} - -TEST(LinkedList, RemovedNodeHasNullNextPrevious) { - LinkedList<Node> list; - - Node n(1); - list.Append(&n); - n.RemoveFromList(); - - EXPECT_EQ(nullptr, n.next()); - EXPECT_EQ(nullptr, n.previous()); -} - -TEST(LinkedList, NodeMoveConstructor) { - LinkedList<MovableNode> list; - - MovableNode n1(1); - MovableNode n2(2); - MovableNode n3(3); - - list.Append(&n1); - list.Append(&n2); - list.Append(&n3); - - EXPECT_EQ(&n1, n2.previous()); - EXPECT_EQ(&n2, n1.next()); - EXPECT_EQ(&n3, n2.next()); - EXPECT_EQ(&n2, n3.previous()); - EXPECT_EQ(2, n2.id()); - - MovableNode n2_new(std::move(n2)); - - EXPECT_EQ(nullptr, n2.next()); - EXPECT_EQ(nullptr, n2.previous()); - - EXPECT_EQ(&n1, n2_new.previous()); - EXPECT_EQ(&n2_new, n1.next()); - EXPECT_EQ(&n3, n2_new.next()); - EXPECT_EQ(&n2_new, n3.previous()); - EXPECT_EQ(2, n2_new.id()); -} - -} // namespace -} // namespace base
diff --git a/base/containers/mru_cache_unittest.cc b/base/containers/mru_cache_unittest.cc deleted file mode 100644 index 28e6f0d..0000000 --- a/base/containers/mru_cache_unittest.cc +++ /dev/null
@@ -1,394 +0,0 @@ -// 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/containers/mru_cache.h" - -#include <cstddef> -#include <memory> - -#include "base/memory/ptr_util.h" -#include "base/trace_event/memory_usage_estimator.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -int cached_item_live_count = 0; - -struct CachedItem { - CachedItem() : value(0) { - cached_item_live_count++; - } - - explicit CachedItem(int new_value) : value(new_value) { - cached_item_live_count++; - } - - explicit CachedItem(const CachedItem& other) : value(other.value) { - cached_item_live_count++; - } - - ~CachedItem() { - cached_item_live_count--; - } - - int value; -}; - -} // namespace - -TEST(MRUCacheTest, Basic) { - typedef base::MRUCache<int, CachedItem> Cache; - Cache cache(Cache::NO_AUTO_EVICT); - - // Check failure conditions - { - CachedItem test_item; - EXPECT_TRUE(cache.Get(0) == cache.end()); - EXPECT_TRUE(cache.Peek(0) == cache.end()); - } - - static const int kItem1Key = 5; - CachedItem item1(10); - Cache::iterator inserted_item = cache.Put(kItem1Key, item1); - EXPECT_EQ(1U, cache.size()); - - // Check that item1 was properly inserted. - { - Cache::iterator found = cache.Get(kItem1Key); - EXPECT_TRUE(inserted_item == cache.begin()); - EXPECT_TRUE(found != cache.end()); - - found = cache.Peek(kItem1Key); - EXPECT_TRUE(found != cache.end()); - - EXPECT_EQ(kItem1Key, found->first); - EXPECT_EQ(item1.value, found->second.value); - } - - static const int kItem2Key = 7; - CachedItem item2(12); - cache.Put(kItem2Key, item2); - EXPECT_EQ(2U, cache.size()); - - // Check that item1 is the oldest since item2 was added afterwards. - { - Cache::reverse_iterator oldest = cache.rbegin(); - ASSERT_TRUE(oldest != cache.rend()); - EXPECT_EQ(kItem1Key, oldest->first); - EXPECT_EQ(item1.value, oldest->second.value); - } - - // Check that item1 is still accessible by key. - { - Cache::iterator test_item = cache.Get(kItem1Key); - ASSERT_TRUE(test_item != cache.end()); - EXPECT_EQ(kItem1Key, test_item->first); - EXPECT_EQ(item1.value, test_item->second.value); - } - - // Check that retrieving item1 pushed item2 to oldest. - { - Cache::reverse_iterator oldest = cache.rbegin(); - ASSERT_TRUE(oldest != cache.rend()); - EXPECT_EQ(kItem2Key, oldest->first); - EXPECT_EQ(item2.value, oldest->second.value); - } - - // Remove the oldest item and check that item1 is now the only member. - { - Cache::reverse_iterator next = cache.Erase(cache.rbegin()); - - EXPECT_EQ(1U, cache.size()); - - EXPECT_TRUE(next == cache.rbegin()); - EXPECT_EQ(kItem1Key, next->first); - EXPECT_EQ(item1.value, next->second.value); - - cache.Erase(cache.begin()); - EXPECT_EQ(0U, cache.size()); - } - - // Check that Clear() works properly. - cache.Put(kItem1Key, item1); - cache.Put(kItem2Key, item2); - EXPECT_EQ(2U, cache.size()); - cache.Clear(); - EXPECT_EQ(0U, cache.size()); -} - -TEST(MRUCacheTest, GetVsPeek) { - typedef base::MRUCache<int, CachedItem> Cache; - Cache cache(Cache::NO_AUTO_EVICT); - - static const int kItem1Key = 1; - CachedItem item1(10); - cache.Put(kItem1Key, item1); - - static const int kItem2Key = 2; - CachedItem item2(20); - cache.Put(kItem2Key, item2); - - // This should do nothing since the size is bigger than the number of items. - cache.ShrinkToSize(100); - - // Check that item1 starts out as oldest - { - Cache::reverse_iterator iter = cache.rbegin(); - ASSERT_TRUE(iter != cache.rend()); - EXPECT_EQ(kItem1Key, iter->first); - EXPECT_EQ(item1.value, iter->second.value); - } - - // Check that Peek doesn't change ordering - { - Cache::iterator peekiter = cache.Peek(kItem1Key); - ASSERT_TRUE(peekiter != cache.end()); - - Cache::reverse_iterator iter = cache.rbegin(); - ASSERT_TRUE(iter != cache.rend()); - EXPECT_EQ(kItem1Key, iter->first); - EXPECT_EQ(item1.value, iter->second.value); - } -} - -TEST(MRUCacheTest, KeyReplacement) { - typedef base::MRUCache<int, CachedItem> Cache; - Cache cache(Cache::NO_AUTO_EVICT); - - static const int kItem1Key = 1; - CachedItem item1(10); - cache.Put(kItem1Key, item1); - - static const int kItem2Key = 2; - CachedItem item2(20); - cache.Put(kItem2Key, item2); - - static const int kItem3Key = 3; - CachedItem item3(30); - cache.Put(kItem3Key, item3); - - static const int kItem4Key = 4; - CachedItem item4(40); - cache.Put(kItem4Key, item4); - - CachedItem item5(50); - cache.Put(kItem3Key, item5); - - EXPECT_EQ(4U, cache.size()); - for (int i = 0; i < 3; ++i) { - Cache::reverse_iterator iter = cache.rbegin(); - ASSERT_TRUE(iter != cache.rend()); - } - - // Make it so only the most important element is there. - cache.ShrinkToSize(1); - - Cache::iterator iter = cache.begin(); - EXPECT_EQ(kItem3Key, iter->first); - EXPECT_EQ(item5.value, iter->second.value); -} - -// Make sure that the owning version release its pointers properly. -TEST(MRUCacheTest, Owning) { - using Cache = base::MRUCache<int, std::unique_ptr<CachedItem>>; - Cache cache(Cache::NO_AUTO_EVICT); - - int initial_count = cached_item_live_count; - - // First insert and item and then overwrite it. - static const int kItem1Key = 1; - cache.Put(kItem1Key, WrapUnique(new CachedItem(20))); - cache.Put(kItem1Key, WrapUnique(new CachedItem(22))); - - // There should still be one item, and one extra live item. - Cache::iterator iter = cache.Get(kItem1Key); - EXPECT_EQ(1U, cache.size()); - EXPECT_TRUE(iter != cache.end()); - EXPECT_EQ(initial_count + 1, cached_item_live_count); - - // Now remove it. - cache.Erase(cache.begin()); - EXPECT_EQ(initial_count, cached_item_live_count); - - // Now try another cache that goes out of scope to make sure its pointers - // go away. - { - Cache cache2(Cache::NO_AUTO_EVICT); - cache2.Put(1, WrapUnique(new CachedItem(20))); - cache2.Put(2, WrapUnique(new CachedItem(20))); - } - - // There should be no objects leaked. - EXPECT_EQ(initial_count, cached_item_live_count); - - // Check that Clear() also frees things correctly. - { - Cache cache2(Cache::NO_AUTO_EVICT); - cache2.Put(1, WrapUnique(new CachedItem(20))); - cache2.Put(2, WrapUnique(new CachedItem(20))); - EXPECT_EQ(initial_count + 2, cached_item_live_count); - cache2.Clear(); - EXPECT_EQ(initial_count, cached_item_live_count); - } -} - -TEST(MRUCacheTest, AutoEvict) { - using Cache = base::MRUCache<int, std::unique_ptr<CachedItem>>; - static const Cache::size_type kMaxSize = 3; - - int initial_count = cached_item_live_count; - - { - Cache cache(kMaxSize); - - static const int kItem1Key = 1, kItem2Key = 2, kItem3Key = 3, kItem4Key = 4; - cache.Put(kItem1Key, std::make_unique<CachedItem>(20)); - cache.Put(kItem2Key, std::make_unique<CachedItem>(21)); - cache.Put(kItem3Key, std::make_unique<CachedItem>(22)); - cache.Put(kItem4Key, std::make_unique<CachedItem>(23)); - - // The cache should only have kMaxSize items in it even though we inserted - // more. - EXPECT_EQ(kMaxSize, cache.size()); - } - - // There should be no objects leaked. - EXPECT_EQ(initial_count, cached_item_live_count); -} - -TEST(MRUCacheTest, HashingMRUCache) { - // Very simple test to make sure that the hashing cache works correctly. - typedef base::HashingMRUCache<std::string, CachedItem> Cache; - Cache cache(Cache::NO_AUTO_EVICT); - - CachedItem one(1); - cache.Put("First", one); - - CachedItem two(2); - cache.Put("Second", two); - - EXPECT_EQ(one.value, cache.Get("First")->second.value); - EXPECT_EQ(two.value, cache.Get("Second")->second.value); - cache.ShrinkToSize(1); - EXPECT_EQ(two.value, cache.Get("Second")->second.value); - EXPECT_TRUE(cache.Get("First") == cache.end()); -} - -TEST(MRUCacheTest, Swap) { - typedef base::MRUCache<int, CachedItem> Cache; - Cache cache1(Cache::NO_AUTO_EVICT); - - // Insert two items into cache1. - static const int kItem1Key = 1; - CachedItem item1(2); - Cache::iterator inserted_item = cache1.Put(kItem1Key, item1); - EXPECT_EQ(1U, cache1.size()); - - static const int kItem2Key = 3; - CachedItem item2(4); - cache1.Put(kItem2Key, item2); - EXPECT_EQ(2U, cache1.size()); - - // Verify cache1's elements. - { - Cache::iterator iter = cache1.begin(); - ASSERT_TRUE(iter != cache1.end()); - EXPECT_EQ(kItem2Key, iter->first); - EXPECT_EQ(item2.value, iter->second.value); - - ++iter; - ASSERT_TRUE(iter != cache1.end()); - EXPECT_EQ(kItem1Key, iter->first); - EXPECT_EQ(item1.value, iter->second.value); - } - - // Create another cache2. - Cache cache2(Cache::NO_AUTO_EVICT); - - // Insert three items into cache2. - static const int kItem3Key = 5; - CachedItem item3(6); - inserted_item = cache2.Put(kItem3Key, item3); - EXPECT_EQ(1U, cache2.size()); - - static const int kItem4Key = 7; - CachedItem item4(8); - cache2.Put(kItem4Key, item4); - EXPECT_EQ(2U, cache2.size()); - - static const int kItem5Key = 9; - CachedItem item5(10); - cache2.Put(kItem5Key, item5); - EXPECT_EQ(3U, cache2.size()); - - // Verify cache2's elements. - { - Cache::iterator iter = cache2.begin(); - ASSERT_TRUE(iter != cache2.end()); - EXPECT_EQ(kItem5Key, iter->first); - EXPECT_EQ(item5.value, iter->second.value); - - ++iter; - ASSERT_TRUE(iter != cache2.end()); - EXPECT_EQ(kItem4Key, iter->first); - EXPECT_EQ(item4.value, iter->second.value); - - ++iter; - ASSERT_TRUE(iter != cache2.end()); - EXPECT_EQ(kItem3Key, iter->first); - EXPECT_EQ(item3.value, iter->second.value); - } - - // Swap cache1 and cache2 and verify cache2 has cache1's elements and cache1 - // has cache2's elements. - cache2.Swap(cache1); - - EXPECT_EQ(3U, cache1.size()); - EXPECT_EQ(2U, cache2.size()); - - // Verify cache1's elements. - { - Cache::iterator iter = cache1.begin(); - ASSERT_TRUE(iter != cache1.end()); - EXPECT_EQ(kItem5Key, iter->first); - EXPECT_EQ(item5.value, iter->second.value); - - ++iter; - ASSERT_TRUE(iter != cache1.end()); - EXPECT_EQ(kItem4Key, iter->first); - EXPECT_EQ(item4.value, iter->second.value); - - ++iter; - ASSERT_TRUE(iter != cache1.end()); - EXPECT_EQ(kItem3Key, iter->first); - EXPECT_EQ(item3.value, iter->second.value); - } - - // Verify cache2's elements. - { - Cache::iterator iter = cache2.begin(); - ASSERT_TRUE(iter != cache2.end()); - EXPECT_EQ(kItem2Key, iter->first); - EXPECT_EQ(item2.value, iter->second.value); - - ++iter; - ASSERT_TRUE(iter != cache2.end()); - EXPECT_EQ(kItem1Key, iter->first); - EXPECT_EQ(item1.value, iter->second.value); - } -} - -TEST(MRUCacheTest, EstimateMemory) { - base::MRUCache<std::string, int> cache(10); - - const std::string key(100u, 'a'); - cache.Put(key, 1); - - EXPECT_GT(trace_event::EstimateMemoryUsage(cache), - trace_event::EstimateMemoryUsage(key)); -} - -} // namespace base
diff --git a/base/containers/small_map_unittest.cc b/base/containers/small_map_unittest.cc deleted file mode 100644 index 6561851..0000000 --- a/base/containers/small_map_unittest.cc +++ /dev/null
@@ -1,603 +0,0 @@ -// 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/containers/small_map.h" - -#include <stddef.h> - -#include <algorithm> -#include <functional> -#include <map> -#include <unordered_map> - -#include "base/logging.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(SmallMap, General) { - small_map<std::unordered_map<int, int>> m; - - EXPECT_TRUE(m.empty()); - - m[0] = 5; - - EXPECT_FALSE(m.empty()); - EXPECT_EQ(m.size(), 1u); - - m[9] = 2; - - EXPECT_FALSE(m.empty()); - EXPECT_EQ(m.size(), 2u); - - EXPECT_EQ(m[9], 2); - EXPECT_EQ(m[0], 5); - EXPECT_FALSE(m.UsingFullMap()); - - small_map<std::unordered_map<int, int>>::iterator iter(m.begin()); - ASSERT_TRUE(iter != m.end()); - EXPECT_EQ(iter->first, 0); - EXPECT_EQ(iter->second, 5); - ++iter; - ASSERT_TRUE(iter != m.end()); - EXPECT_EQ((*iter).first, 9); - EXPECT_EQ((*iter).second, 2); - ++iter; - EXPECT_TRUE(iter == m.end()); - - m[8] = 23; - m[1234] = 90; - m[-5] = 6; - - EXPECT_EQ(m[ 9], 2); - EXPECT_EQ(m[ 0], 5); - EXPECT_EQ(m[1234], 90); - EXPECT_EQ(m[ 8], 23); - EXPECT_EQ(m[ -5], 6); - EXPECT_EQ(m.size(), 5u); - EXPECT_FALSE(m.empty()); - EXPECT_TRUE(m.UsingFullMap()); - - iter = m.begin(); - for (int i = 0; i < 5; i++) { - EXPECT_TRUE(iter != m.end()); - ++iter; - } - EXPECT_TRUE(iter == m.end()); - - const small_map<std::unordered_map<int, int>>& ref = m; - EXPECT_TRUE(ref.find(1234) != m.end()); - EXPECT_TRUE(ref.find(5678) == m.end()); -} - -TEST(SmallMap, PostFixIteratorIncrement) { - small_map<std::unordered_map<int, int>> m; - m[0] = 5; - m[2] = 3; - - { - small_map<std::unordered_map<int, int>>::iterator iter(m.begin()); - small_map<std::unordered_map<int, int>>::iterator last(iter++); - ++last; - EXPECT_TRUE(last == iter); - } - - { - small_map<std::unordered_map<int, int>>::const_iterator iter(m.begin()); - small_map<std::unordered_map<int, int>>::const_iterator last(iter++); - ++last; - EXPECT_TRUE(last == iter); - } -} - -// Based on the General testcase. -TEST(SmallMap, CopyConstructor) { - small_map<std::unordered_map<int, int>> src; - - { - small_map<std::unordered_map<int, int>> m(src); - EXPECT_TRUE(m.empty()); - } - - src[0] = 5; - - { - small_map<std::unordered_map<int, int>> m(src); - EXPECT_FALSE(m.empty()); - EXPECT_EQ(m.size(), 1u); - } - - src[9] = 2; - - { - small_map<std::unordered_map<int, int>> m(src); - EXPECT_FALSE(m.empty()); - EXPECT_EQ(m.size(), 2u); - - EXPECT_EQ(m[9], 2); - EXPECT_EQ(m[0], 5); - EXPECT_FALSE(m.UsingFullMap()); - } - - src[8] = 23; - src[1234] = 90; - src[-5] = 6; - - { - small_map<std::unordered_map<int, int>> m(src); - EXPECT_EQ(m[ 9], 2); - EXPECT_EQ(m[ 0], 5); - EXPECT_EQ(m[1234], 90); - EXPECT_EQ(m[ 8], 23); - EXPECT_EQ(m[ -5], 6); - EXPECT_EQ(m.size(), 5u); - EXPECT_FALSE(m.empty()); - EXPECT_TRUE(m.UsingFullMap()); - } -} - -template <class inner> -static bool SmallMapIsSubset(small_map<inner> const& a, - small_map<inner> const& b) { - typename small_map<inner>::const_iterator it; - for (it = a.begin(); it != a.end(); ++it) { - typename small_map<inner>::const_iterator it_in_b = b.find(it->first); - if (it_in_b == b.end() || it_in_b->second != it->second) - return false; - } - return true; -} - -template <class inner> -static bool SmallMapEqual(small_map<inner> const& a, - small_map<inner> const& b) { - return SmallMapIsSubset(a, b) && SmallMapIsSubset(b, a); -} - -TEST(SmallMap, AssignmentOperator) { - small_map<std::unordered_map<int, int>> src_small; - small_map<std::unordered_map<int, int>> src_large; - - src_small[1] = 20; - src_small[2] = 21; - src_small[3] = 22; - EXPECT_FALSE(src_small.UsingFullMap()); - - src_large[1] = 20; - src_large[2] = 21; - src_large[3] = 22; - src_large[5] = 23; - src_large[6] = 24; - src_large[7] = 25; - EXPECT_TRUE(src_large.UsingFullMap()); - - // Assignments to empty. - small_map<std::unordered_map<int, int>> dest_small; - dest_small = src_small; - EXPECT_TRUE(SmallMapEqual(dest_small, src_small)); - EXPECT_EQ(dest_small.UsingFullMap(), - src_small.UsingFullMap()); - - small_map<std::unordered_map<int, int>> dest_large; - dest_large = src_large; - EXPECT_TRUE(SmallMapEqual(dest_large, src_large)); - EXPECT_EQ(dest_large.UsingFullMap(), - src_large.UsingFullMap()); - - // Assignments which assign from full to small, and vice versa. - dest_small = src_large; - EXPECT_TRUE(SmallMapEqual(dest_small, src_large)); - EXPECT_EQ(dest_small.UsingFullMap(), - src_large.UsingFullMap()); - - dest_large = src_small; - EXPECT_TRUE(SmallMapEqual(dest_large, src_small)); - EXPECT_EQ(dest_large.UsingFullMap(), - src_small.UsingFullMap()); - - // Double check that SmallMapEqual works: - dest_large[42] = 666; - EXPECT_FALSE(SmallMapEqual(dest_large, src_small)); -} - -TEST(SmallMap, Insert) { - small_map<std::unordered_map<int, int>> sm; - - // loop through the transition from small map to map. - for (int i = 1; i <= 10; ++i) { - VLOG(1) << "Iteration " << i; - // insert an element - std::pair<small_map<std::unordered_map<int, int>>::iterator, bool> ret; - ret = sm.insert(std::make_pair(i, 100*i)); - EXPECT_TRUE(ret.second); - EXPECT_TRUE(ret.first == sm.find(i)); - EXPECT_EQ(ret.first->first, i); - EXPECT_EQ(ret.first->second, 100*i); - - // try to insert it again with different value, fails, but we still get an - // iterator back with the original value. - ret = sm.insert(std::make_pair(i, -i)); - EXPECT_FALSE(ret.second); - EXPECT_TRUE(ret.first == sm.find(i)); - EXPECT_EQ(ret.first->first, i); - EXPECT_EQ(ret.first->second, 100*i); - - // check the state of the map. - for (int j = 1; j <= i; ++j) { - small_map<std::unordered_map<int, int>>::iterator it = sm.find(j); - EXPECT_TRUE(it != sm.end()); - EXPECT_EQ(it->first, j); - EXPECT_EQ(it->second, j * 100); - } - EXPECT_EQ(sm.size(), static_cast<size_t>(i)); - EXPECT_FALSE(sm.empty()); - } -} - -TEST(SmallMap, InsertRange) { - // loop through the transition from small map to map. - for (int elements = 0; elements <= 10; ++elements) { - VLOG(1) << "Elements " << elements; - std::unordered_map<int, int> normal_map; - for (int i = 1; i <= elements; ++i) { - normal_map.insert(std::make_pair(i, 100*i)); - } - - small_map<std::unordered_map<int, int>> sm; - sm.insert(normal_map.begin(), normal_map.end()); - EXPECT_EQ(normal_map.size(), sm.size()); - for (int i = 1; i <= elements; ++i) { - VLOG(1) << "Iteration " << i; - EXPECT_TRUE(sm.find(i) != sm.end()); - EXPECT_EQ(sm.find(i)->first, i); - EXPECT_EQ(sm.find(i)->second, 100*i); - } - } -} - -TEST(SmallMap, Erase) { - small_map<std::unordered_map<std::string, int>> m; - small_map<std::unordered_map<std::string, int>>::iterator iter; - - m["monday"] = 1; - m["tuesday"] = 2; - m["wednesday"] = 3; - - EXPECT_EQ(m["monday" ], 1); - EXPECT_EQ(m["tuesday" ], 2); - EXPECT_EQ(m["wednesday"], 3); - EXPECT_EQ(m.count("tuesday"), 1u); - EXPECT_FALSE(m.UsingFullMap()); - - iter = m.begin(); - ASSERT_TRUE(iter != m.end()); - EXPECT_EQ(iter->first, "monday"); - EXPECT_EQ(iter->second, 1); - ++iter; - ASSERT_TRUE(iter != m.end()); - EXPECT_EQ(iter->first, "tuesday"); - EXPECT_EQ(iter->second, 2); - ++iter; - ASSERT_TRUE(iter != m.end()); - EXPECT_EQ(iter->first, "wednesday"); - EXPECT_EQ(iter->second, 3); - ++iter; - EXPECT_TRUE(iter == m.end()); - - EXPECT_EQ(m.erase("tuesday"), 1u); - - EXPECT_EQ(m["monday" ], 1); - EXPECT_EQ(m["wednesday"], 3); - EXPECT_EQ(m.count("tuesday"), 0u); - EXPECT_EQ(m.erase("tuesday"), 0u); - - iter = m.begin(); - ASSERT_TRUE(iter != m.end()); - EXPECT_EQ(iter->first, "monday"); - EXPECT_EQ(iter->second, 1); - ++iter; - ASSERT_TRUE(iter != m.end()); - EXPECT_EQ(iter->first, "wednesday"); - EXPECT_EQ(iter->second, 3); - ++iter; - EXPECT_TRUE(iter == m.end()); - - m["thursday"] = 4; - m["friday"] = 5; - EXPECT_EQ(m.size(), 4u); - EXPECT_FALSE(m.empty()); - EXPECT_FALSE(m.UsingFullMap()); - - m["saturday"] = 6; - EXPECT_TRUE(m.UsingFullMap()); - - EXPECT_EQ(m.count("friday"), 1u); - EXPECT_EQ(m.erase("friday"), 1u); - EXPECT_TRUE(m.UsingFullMap()); - EXPECT_EQ(m.count("friday"), 0u); - EXPECT_EQ(m.erase("friday"), 0u); - - EXPECT_EQ(m.size(), 4u); - EXPECT_FALSE(m.empty()); - EXPECT_EQ(m.erase("monday"), 1u); - EXPECT_EQ(m.size(), 3u); - EXPECT_FALSE(m.empty()); - - m.clear(); - EXPECT_FALSE(m.UsingFullMap()); - EXPECT_EQ(m.size(), 0u); - EXPECT_TRUE(m.empty()); -} - -TEST(SmallMap, EraseReturnsIteratorFollowingRemovedElement) { - small_map<std::unordered_map<std::string, int>> m; - small_map<std::unordered_map<std::string, int>>::iterator iter; - - m["a"] = 0; - m["b"] = 1; - m["c"] = 2; - - // Erase first item. - auto following_iter = m.erase(m.begin()); - EXPECT_EQ(m.begin(), following_iter); - EXPECT_EQ(2u, m.size()); - EXPECT_EQ(m.count("a"), 0u); - EXPECT_EQ(m.count("b"), 1u); - EXPECT_EQ(m.count("c"), 1u); - - // Iterate to last item and erase it. - ++following_iter; - following_iter = m.erase(following_iter); - ASSERT_EQ(1u, m.size()); - EXPECT_EQ(m.end(), following_iter); - EXPECT_EQ(m.count("b"), 0u); - EXPECT_EQ(m.count("c"), 1u); - - // Erase remaining item. - following_iter = m.erase(m.begin()); - EXPECT_TRUE(m.empty()); - EXPECT_EQ(m.end(), following_iter); -} - -TEST(SmallMap, NonHashMap) { - small_map<std::map<int, int>, 4, std::equal_to<int>> m; - EXPECT_TRUE(m.empty()); - - m[9] = 2; - m[0] = 5; - - EXPECT_EQ(m[9], 2); - EXPECT_EQ(m[0], 5); - EXPECT_EQ(m.size(), 2u); - EXPECT_FALSE(m.empty()); - EXPECT_FALSE(m.UsingFullMap()); - - small_map<std::map<int, int>, 4, std::equal_to<int>>::iterator iter( - m.begin()); - ASSERT_TRUE(iter != m.end()); - EXPECT_EQ(iter->first, 9); - EXPECT_EQ(iter->second, 2); - ++iter; - ASSERT_TRUE(iter != m.end()); - EXPECT_EQ(iter->first, 0); - EXPECT_EQ(iter->second, 5); - ++iter; - EXPECT_TRUE(iter == m.end()); - --iter; - ASSERT_TRUE(iter != m.end()); - EXPECT_EQ(iter->first, 0); - EXPECT_EQ(iter->second, 5); - - m[8] = 23; - m[1234] = 90; - m[-5] = 6; - - EXPECT_EQ(m[ 9], 2); - EXPECT_EQ(m[ 0], 5); - EXPECT_EQ(m[1234], 90); - EXPECT_EQ(m[ 8], 23); - EXPECT_EQ(m[ -5], 6); - EXPECT_EQ(m.size(), 5u); - EXPECT_FALSE(m.empty()); - EXPECT_TRUE(m.UsingFullMap()); - - iter = m.begin(); - ASSERT_TRUE(iter != m.end()); - EXPECT_EQ(iter->first, -5); - EXPECT_EQ(iter->second, 6); - ++iter; - ASSERT_TRUE(iter != m.end()); - EXPECT_EQ(iter->first, 0); - EXPECT_EQ(iter->second, 5); - ++iter; - ASSERT_TRUE(iter != m.end()); - EXPECT_EQ(iter->first, 8); - EXPECT_EQ(iter->second, 23); - ++iter; - ASSERT_TRUE(iter != m.end()); - EXPECT_EQ(iter->first, 9); - EXPECT_EQ(iter->second, 2); - ++iter; - ASSERT_TRUE(iter != m.end()); - EXPECT_EQ(iter->first, 1234); - EXPECT_EQ(iter->second, 90); - ++iter; - EXPECT_TRUE(iter == m.end()); - --iter; - ASSERT_TRUE(iter != m.end()); - EXPECT_EQ(iter->first, 1234); - EXPECT_EQ(iter->second, 90); -} - -TEST(SmallMap, DefaultEqualKeyWorks) { - // If these tests compile, they pass. The EXPECT calls are only there to avoid - // unused variable warnings. - small_map<std::unordered_map<int, int>> hm; - EXPECT_EQ(0u, hm.size()); - small_map<std::map<int, int>> m; - EXPECT_EQ(0u, m.size()); -} - -namespace { - -class unordered_map_add_item : public std::unordered_map<int, int> { - public: - unordered_map_add_item() = default; - explicit unordered_map_add_item(const std::pair<int, int>& item) { - insert(item); - } -}; - -void InitMap(unordered_map_add_item* map_ctor) { - new (map_ctor) unordered_map_add_item(std::make_pair(0, 0)); -} - -class unordered_map_add_item_initializer { - public: - explicit unordered_map_add_item_initializer(int item_to_add) - : item_(item_to_add) {} - unordered_map_add_item_initializer() : item_(0) {} - void operator()(unordered_map_add_item* map_ctor) const { - new (map_ctor) unordered_map_add_item(std::make_pair(item_, item_)); - } - - int item_; -}; - -} // anonymous namespace - -TEST(SmallMap, SubclassInitializationWithFunctionPointer) { - small_map<unordered_map_add_item, 4, std::equal_to<int>, - void (&)(unordered_map_add_item*)> - m(InitMap); - - EXPECT_TRUE(m.empty()); - - m[1] = 1; - m[2] = 2; - m[3] = 3; - m[4] = 4; - - EXPECT_EQ(4u, m.size()); - EXPECT_EQ(0u, m.count(0)); - - m[5] = 5; - EXPECT_EQ(6u, m.size()); - // Our function adds an extra item when we convert to a map. - EXPECT_EQ(1u, m.count(0)); -} - -TEST(SmallMap, SubclassInitializationWithFunctionObject) { - small_map<unordered_map_add_item, 4, std::equal_to<int>, - unordered_map_add_item_initializer> - m(unordered_map_add_item_initializer(-1)); - - EXPECT_TRUE(m.empty()); - - m[1] = 1; - m[2] = 2; - m[3] = 3; - m[4] = 4; - - EXPECT_EQ(4u, m.size()); - EXPECT_EQ(0u, m.count(-1)); - - m[5] = 5; - EXPECT_EQ(6u, m.size()); - // Our functor adds an extra item when we convert to a map. - EXPECT_EQ(1u, m.count(-1)); -} - -namespace { - -// This class acts as a basic implementation of a move-only type. The canonical -// example of such a type is scoped_ptr/unique_ptr. -template <typename V> -class MoveOnlyType { - public: - MoveOnlyType() : value_(0) {} - explicit MoveOnlyType(V value) : value_(value) {} - - MoveOnlyType(MoveOnlyType&& other) { - *this = std::move(other); - } - - MoveOnlyType& operator=(MoveOnlyType&& other) { - value_ = other.value_; - other.value_ = 0; - return *this; - } - - MoveOnlyType(const MoveOnlyType&) = delete; - MoveOnlyType& operator=(const MoveOnlyType&) = delete; - - V value() const { return value_; } - - private: - V value_; -}; - -} // namespace - -TEST(SmallMap, MoveOnlyValueType) { - small_map<std::map<int, MoveOnlyType<int>>, 2> m; - - m[0] = MoveOnlyType<int>(1); - m[1] = MoveOnlyType<int>(2); - m.erase(m.begin()); - - // small_map will move m[1] to an earlier index in the internal array. - EXPECT_EQ(m.size(), 1u); - EXPECT_EQ(m[1].value(), 2); - - m[0] = MoveOnlyType<int>(1); - // small_map must move the values from the array into the internal std::map. - m[2] = MoveOnlyType<int>(3); - - EXPECT_EQ(m.size(), 3u); - EXPECT_EQ(m[0].value(), 1); - EXPECT_EQ(m[1].value(), 2); - EXPECT_EQ(m[2].value(), 3); - - m.erase(m.begin()); - - // small_map should also let internal std::map erase with a move-only type. - EXPECT_EQ(m.size(), 2u); - EXPECT_EQ(m[1].value(), 2); - EXPECT_EQ(m[2].value(), 3); -} - -TEST(SmallMap, Emplace) { - small_map<std::map<size_t, MoveOnlyType<size_t>>> sm; - - // loop through the transition from small map to map. - for (size_t i = 1; i <= 10; ++i) { - // insert an element - auto ret = sm.emplace(i, MoveOnlyType<size_t>(100 * i)); - EXPECT_TRUE(ret.second); - EXPECT_TRUE(ret.first == sm.find(i)); - EXPECT_EQ(ret.first->first, i); - EXPECT_EQ(ret.first->second.value(), 100 * i); - - // try to insert it again with different value, fails, but we still get an - // iterator back with the original value. - ret = sm.emplace(i, MoveOnlyType<size_t>(i)); - EXPECT_FALSE(ret.second); - EXPECT_TRUE(ret.first == sm.find(i)); - EXPECT_EQ(ret.first->first, i); - EXPECT_EQ(ret.first->second.value(), 100 * i); - - // check the state of the map. - for (size_t j = 1; j <= i; ++j) { - const auto it = sm.find(j); - EXPECT_TRUE(it != sm.end()); - EXPECT_EQ(it->first, j); - EXPECT_EQ(it->second.value(), j * 100); - } - EXPECT_EQ(sm.size(), i); - EXPECT_FALSE(sm.empty()); - } -} - -} // namespace base
diff --git a/base/containers/span_unittest.cc b/base/containers/span_unittest.cc deleted file mode 100644 index de5e401..0000000 --- a/base/containers/span_unittest.cc +++ /dev/null
@@ -1,1170 +0,0 @@ -// 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/containers/span.h" - -#include <stdint.h> - -#include <algorithm> -#include <memory> -#include <string> -#include <vector> - -#include "base/macros.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using ::testing::ElementsAre; -using ::testing::Eq; -using ::testing::Pointwise; - -namespace base { - -TEST(SpanTest, DefaultConstructor) { - span<int> dynamic_span; - EXPECT_EQ(nullptr, dynamic_span.data()); - EXPECT_EQ(0u, dynamic_span.size()); - - constexpr span<int, 0> static_span; - static_assert(nullptr == static_span.data(), ""); - static_assert(0u == static_span.size(), ""); -} - -TEST(SpanTest, ConstructFromDataAndSize) { - constexpr span<int> empty_span(nullptr, 0); - EXPECT_TRUE(empty_span.empty()); - EXPECT_EQ(nullptr, empty_span.data()); - - std::vector<int> vector = {1, 1, 2, 3, 5, 8}; - - span<int> dynamic_span(vector.data(), vector.size()); - EXPECT_EQ(vector.data(), dynamic_span.data()); - EXPECT_EQ(vector.size(), dynamic_span.size()); - - for (size_t i = 0; i < dynamic_span.size(); ++i) - EXPECT_EQ(vector[i], dynamic_span[i]); - - span<int, 6> static_span(vector.data(), vector.size()); - EXPECT_EQ(vector.data(), static_span.data()); - EXPECT_EQ(vector.size(), static_span.size()); - - for (size_t i = 0; i < static_span.size(); ++i) - EXPECT_EQ(vector[i], static_span[i]); -} - -TEST(SpanTest, ConstructFromPointerPair) { - constexpr span<int> empty_span(nullptr, nullptr); - EXPECT_TRUE(empty_span.empty()); - EXPECT_EQ(nullptr, empty_span.data()); - - std::vector<int> vector = {1, 1, 2, 3, 5, 8}; - - span<int> dynamic_span(vector.data(), vector.data() + vector.size() / 2); - EXPECT_EQ(vector.data(), dynamic_span.data()); - EXPECT_EQ(vector.size() / 2, dynamic_span.size()); - - for (size_t i = 0; i < dynamic_span.size(); ++i) - EXPECT_EQ(vector[i], dynamic_span[i]); - - span<int, 3> static_span(vector.data(), vector.data() + vector.size() / 2); - EXPECT_EQ(vector.data(), static_span.data()); - EXPECT_EQ(vector.size() / 2, static_span.size()); - - for (size_t i = 0; i < static_span.size(); ++i) - EXPECT_EQ(vector[i], static_span[i]); -} - -TEST(SpanTest, ConstructFromConstexprArray) { - static constexpr int kArray[] = {5, 4, 3, 2, 1}; - - constexpr span<const int> dynamic_span(kArray); - static_assert(kArray == dynamic_span.data(), ""); - static_assert(base::size(kArray) == dynamic_span.size(), ""); - - static_assert(kArray[0] == dynamic_span[0], ""); - static_assert(kArray[1] == dynamic_span[1], ""); - static_assert(kArray[2] == dynamic_span[2], ""); - static_assert(kArray[3] == dynamic_span[3], ""); - static_assert(kArray[4] == dynamic_span[4], ""); - - constexpr span<const int, base::size(kArray)> static_span(kArray); - static_assert(kArray == static_span.data(), ""); - static_assert(base::size(kArray) == static_span.size(), ""); - - static_assert(kArray[0] == static_span[0], ""); - static_assert(kArray[1] == static_span[1], ""); - static_assert(kArray[2] == static_span[2], ""); - static_assert(kArray[3] == static_span[3], ""); - static_assert(kArray[4] == static_span[4], ""); -} - -TEST(SpanTest, ConstructFromArray) { - int array[] = {5, 4, 3, 2, 1}; - - span<const int> const_span(array); - EXPECT_EQ(array, const_span.data()); - EXPECT_EQ(arraysize(array), const_span.size()); - for (size_t i = 0; i < const_span.size(); ++i) - EXPECT_EQ(array[i], const_span[i]); - - span<int> dynamic_span(array); - EXPECT_EQ(array, dynamic_span.data()); - EXPECT_EQ(base::size(array), dynamic_span.size()); - for (size_t i = 0; i < dynamic_span.size(); ++i) - EXPECT_EQ(array[i], dynamic_span[i]); - - span<int, base::size(array)> static_span(array); - EXPECT_EQ(array, static_span.data()); - EXPECT_EQ(base::size(array), static_span.size()); - for (size_t i = 0; i < static_span.size(); ++i) - EXPECT_EQ(array[i], static_span[i]); -} - -TEST(SpanTest, ConstructFromStdArray) { - // Note: Constructing a constexpr span from a constexpr std::array does not - // work prior to C++17 due to non-constexpr std::array::data. - std::array<int, 5> array = {{5, 4, 3, 2, 1}}; - - span<const int> const_span(array); - EXPECT_EQ(array.data(), const_span.data()); - EXPECT_EQ(array.size(), const_span.size()); - for (size_t i = 0; i < const_span.size(); ++i) - EXPECT_EQ(array[i], const_span[i]); - - span<int> dynamic_span(array); - EXPECT_EQ(array.data(), dynamic_span.data()); - EXPECT_EQ(array.size(), dynamic_span.size()); - for (size_t i = 0; i < dynamic_span.size(); ++i) - EXPECT_EQ(array[i], dynamic_span[i]); - - span<int, base::size(array)> static_span(array); - EXPECT_EQ(array.data(), static_span.data()); - EXPECT_EQ(array.size(), static_span.size()); - for (size_t i = 0; i < static_span.size(); ++i) - EXPECT_EQ(array[i], static_span[i]); -} - -TEST(SpanTest, ConstructFromInitializerList) { - std::initializer_list<int> il = {1, 1, 2, 3, 5, 8}; - - span<const int> const_span(il); - EXPECT_EQ(il.begin(), const_span.data()); - EXPECT_EQ(il.size(), const_span.size()); - - for (size_t i = 0; i < const_span.size(); ++i) - EXPECT_EQ(il.begin()[i], const_span[i]); - - span<const int, 6> static_span(il); - EXPECT_EQ(il.begin(), static_span.data()); - EXPECT_EQ(il.size(), static_span.size()); - - for (size_t i = 0; i < static_span.size(); ++i) - EXPECT_EQ(il.begin()[i], static_span[i]); -} - -TEST(SpanTest, ConstructFromStdString) { - std::string str = "foobar"; - - span<const char> const_span(str); - EXPECT_EQ(str.data(), const_span.data()); - EXPECT_EQ(str.size(), const_span.size()); - - for (size_t i = 0; i < const_span.size(); ++i) - EXPECT_EQ(str[i], const_span[i]); - - span<char> dynamic_span(str); - EXPECT_EQ(str.data(), dynamic_span.data()); - EXPECT_EQ(str.size(), dynamic_span.size()); - - for (size_t i = 0; i < dynamic_span.size(); ++i) - EXPECT_EQ(str[i], dynamic_span[i]); - - span<char, 6> static_span(str); - EXPECT_EQ(str.data(), static_span.data()); - EXPECT_EQ(str.size(), static_span.size()); - - for (size_t i = 0; i < static_span.size(); ++i) - EXPECT_EQ(str[i], static_span[i]); -} - -TEST(SpanTest, ConstructFromConstContainer) { - const std::vector<int> vector = {1, 1, 2, 3, 5, 8}; - - span<const int> const_span(vector); - EXPECT_EQ(vector.data(), const_span.data()); - EXPECT_EQ(vector.size(), const_span.size()); - - for (size_t i = 0; i < const_span.size(); ++i) - EXPECT_EQ(vector[i], const_span[i]); - - span<const int, 6> static_span(vector); - EXPECT_EQ(vector.data(), static_span.data()); - EXPECT_EQ(vector.size(), static_span.size()); - - for (size_t i = 0; i < static_span.size(); ++i) - EXPECT_EQ(vector[i], static_span[i]); -} - -TEST(SpanTest, ConstructFromContainer) { - std::vector<int> vector = {1, 1, 2, 3, 5, 8}; - - span<const int> const_span(vector); - EXPECT_EQ(vector.data(), const_span.data()); - EXPECT_EQ(vector.size(), const_span.size()); - - for (size_t i = 0; i < const_span.size(); ++i) - EXPECT_EQ(vector[i], const_span[i]); - - span<int> dynamic_span(vector); - EXPECT_EQ(vector.data(), dynamic_span.data()); - EXPECT_EQ(vector.size(), dynamic_span.size()); - - for (size_t i = 0; i < dynamic_span.size(); ++i) - EXPECT_EQ(vector[i], dynamic_span[i]); - - span<int, 6> static_span(vector); - EXPECT_EQ(vector.data(), static_span.data()); - EXPECT_EQ(vector.size(), static_span.size()); - - for (size_t i = 0; i < static_span.size(); ++i) - EXPECT_EQ(vector[i], static_span[i]); -} - -TEST(SpanTest, ConvertNonConstIntegralToConst) { - std::vector<int> vector = {1, 1, 2, 3, 5, 8}; - - span<int> int_span(vector.data(), vector.size()); - span<const int> const_span(int_span); - EXPECT_THAT(const_span, Pointwise(Eq(), int_span)); - - span<int, 6> static_int_span(vector.data(), vector.size()); - span<const int, 6> static_const_span(static_int_span); - EXPECT_THAT(static_const_span, Pointwise(Eq(), static_int_span)); -} - -TEST(SpanTest, ConvertNonConstPointerToConst) { - auto a = std::make_unique<int>(11); - auto b = std::make_unique<int>(22); - auto c = std::make_unique<int>(33); - std::vector<int*> vector = {a.get(), b.get(), c.get()}; - - span<int*> non_const_pointer_span(vector); - EXPECT_THAT(non_const_pointer_span, Pointwise(Eq(), vector)); - span<int* const> const_pointer_span(non_const_pointer_span); - EXPECT_THAT(const_pointer_span, Pointwise(Eq(), non_const_pointer_span)); - // Note: no test for conversion from span<int> to span<const int*>, since that - // would imply a conversion from int** to const int**, which is unsafe. - // - // Note: no test for conversion from span<int*> to span<const int* const>, - // due to CWG Defect 330: - // http://open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#330 - - span<int*, 3> static_non_const_pointer_span(vector); - EXPECT_THAT(static_non_const_pointer_span, Pointwise(Eq(), vector)); - span<int* const, 3> static_const_pointer_span(static_non_const_pointer_span); - EXPECT_THAT(static_const_pointer_span, - Pointwise(Eq(), static_non_const_pointer_span)); -} - -TEST(SpanTest, ConvertBetweenEquivalentTypes) { - std::vector<int32_t> vector = {2, 4, 8, 16, 32}; - - span<int32_t> int32_t_span(vector); - span<int> converted_span(int32_t_span); - EXPECT_EQ(int32_t_span, converted_span); - - span<int32_t, 5> static_int32_t_span(vector); - span<int, 5> static_converted_span(static_int32_t_span); - EXPECT_EQ(static_int32_t_span, static_converted_span); -} - -TEST(SpanTest, TemplatedFirst) { - static constexpr int array[] = {1, 2, 3}; - constexpr span<const int, 3> span(array); - - { - constexpr auto subspan = span.first<0>(); - static_assert(span.data() == subspan.data(), ""); - static_assert(0u == subspan.size(), ""); - static_assert(0u == decltype(subspan)::extent, ""); - } - - { - constexpr auto subspan = span.first<1>(); - static_assert(span.data() == subspan.data(), ""); - static_assert(1u == subspan.size(), ""); - static_assert(1u == decltype(subspan)::extent, ""); - static_assert(1 == subspan[0], ""); - } - - { - constexpr auto subspan = span.first<2>(); - static_assert(span.data() == subspan.data(), ""); - static_assert(2u == subspan.size(), ""); - static_assert(2u == decltype(subspan)::extent, ""); - static_assert(1 == subspan[0], ""); - static_assert(2 == subspan[1], ""); - } - - { - constexpr auto subspan = span.first<3>(); - static_assert(span.data() == subspan.data(), ""); - static_assert(3u == subspan.size(), ""); - static_assert(3u == decltype(subspan)::extent, ""); - static_assert(1 == subspan[0], ""); - static_assert(2 == subspan[1], ""); - static_assert(3 == subspan[2], ""); - } -} - -TEST(SpanTest, TemplatedLast) { - static constexpr int array[] = {1, 2, 3}; - constexpr span<const int, 3> span(array); - - { - constexpr auto subspan = span.last<0>(); - static_assert(span.data() + 3 == subspan.data(), ""); - static_assert(0u == subspan.size(), ""); - static_assert(0u == decltype(subspan)::extent, ""); - } - - { - constexpr auto subspan = span.last<1>(); - static_assert(span.data() + 2 == subspan.data(), ""); - static_assert(1u == subspan.size(), ""); - static_assert(1u == decltype(subspan)::extent, ""); - static_assert(3 == subspan[0], ""); - } - - { - constexpr auto subspan = span.last<2>(); - static_assert(span.data() + 1 == subspan.data(), ""); - static_assert(2u == subspan.size(), ""); - static_assert(2u == decltype(subspan)::extent, ""); - static_assert(2 == subspan[0], ""); - static_assert(3 == subspan[1], ""); - } - - { - constexpr auto subspan = span.last<3>(); - static_assert(span.data() == subspan.data(), ""); - static_assert(3u == subspan.size(), ""); - static_assert(3u == decltype(subspan)::extent, ""); - static_assert(1 == subspan[0], ""); - static_assert(2 == subspan[1], ""); - static_assert(3 == subspan[2], ""); - } -} - -TEST(SpanTest, TemplatedSubspan) { - static constexpr int array[] = {1, 2, 3}; - constexpr span<const int, 3> span(array); - - { - constexpr auto subspan = span.subspan<0>(); - static_assert(span.data() == subspan.data(), ""); - static_assert(3u == subspan.size(), ""); - static_assert(3u == decltype(subspan)::extent, ""); - static_assert(1 == subspan[0], ""); - static_assert(2 == subspan[1], ""); - static_assert(3 == subspan[2], ""); - } - - { - constexpr auto subspan = span.subspan<1>(); - static_assert(span.data() + 1 == subspan.data(), ""); - static_assert(2u == subspan.size(), ""); - static_assert(2u == decltype(subspan)::extent, ""); - static_assert(2 == subspan[0], ""); - static_assert(3 == subspan[1], ""); - } - - { - constexpr auto subspan = span.subspan<2>(); - static_assert(span.data() + 2 == subspan.data(), ""); - static_assert(1u == subspan.size(), ""); - static_assert(1u == decltype(subspan)::extent, ""); - static_assert(3 == subspan[0], ""); - } - - { - constexpr auto subspan = span.subspan<3>(); - static_assert(span.data() + 3 == subspan.data(), ""); - static_assert(0u == subspan.size(), ""); - static_assert(0u == decltype(subspan)::extent, ""); - } - - { - constexpr auto subspan = span.subspan<0, 0>(); - static_assert(span.data() == subspan.data(), ""); - static_assert(0u == subspan.size(), ""); - static_assert(0u == decltype(subspan)::extent, ""); - } - - { - constexpr auto subspan = span.subspan<1, 0>(); - static_assert(span.data() + 1 == subspan.data(), ""); - static_assert(0u == subspan.size(), ""); - static_assert(0u == decltype(subspan)::extent, ""); - } - - { - constexpr auto subspan = span.subspan<2, 0>(); - static_assert(span.data() + 2 == subspan.data(), ""); - static_assert(0u == subspan.size(), ""); - static_assert(0u == decltype(subspan)::extent, ""); - } - - { - constexpr auto subspan = span.subspan<0, 1>(); - static_assert(span.data() == subspan.data(), ""); - static_assert(1u == subspan.size(), ""); - static_assert(1u == decltype(subspan)::extent, ""); - static_assert(1 == subspan[0], ""); - } - - { - constexpr auto subspan = span.subspan<1, 1>(); - static_assert(span.data() + 1 == subspan.data(), ""); - static_assert(1u == subspan.size(), ""); - static_assert(1u == decltype(subspan)::extent, ""); - static_assert(2 == subspan[0], ""); - } - - { - constexpr auto subspan = span.subspan<2, 1>(); - static_assert(span.data() + 2 == subspan.data(), ""); - static_assert(1u == subspan.size(), ""); - static_assert(1u == decltype(subspan)::extent, ""); - static_assert(3 == subspan[0], ""); - } - - { - constexpr auto subspan = span.subspan<0, 2>(); - static_assert(span.data() == subspan.data(), ""); - static_assert(2u == subspan.size(), ""); - static_assert(2u == decltype(subspan)::extent, ""); - static_assert(1 == subspan[0], ""); - static_assert(2 == subspan[1], ""); - } - - { - constexpr auto subspan = span.subspan<1, 2>(); - static_assert(span.data() + 1 == subspan.data(), ""); - static_assert(2u == subspan.size(), ""); - static_assert(2u == decltype(subspan)::extent, ""); - static_assert(2 == subspan[0], ""); - static_assert(3 == subspan[1], ""); - } - - { - constexpr auto subspan = span.subspan<0, 3>(); - static_assert(span.data() == subspan.data(), ""); - static_assert(3u == subspan.size(), ""); - static_assert(3u == decltype(subspan)::extent, ""); - static_assert(1 == subspan[0], ""); - static_assert(2 == subspan[1], ""); - static_assert(3 == subspan[2], ""); - } -} - -TEST(SpanTest, TemplatedFirstOnDynamicSpan) { - int array[] = {1, 2, 3}; - span<const int> span(array); - - { - auto subspan = span.first<0>(); - EXPECT_EQ(span.data(), subspan.data()); - EXPECT_EQ(0u, subspan.size()); - static_assert(0u == decltype(subspan)::extent, ""); - } - - { - auto subspan = span.first<1>(); - EXPECT_EQ(span.data(), subspan.data()); - EXPECT_EQ(1u, subspan.size()); - static_assert(1u == decltype(subspan)::extent, ""); - EXPECT_EQ(1, subspan[0]); - } - - { - auto subspan = span.first<2>(); - EXPECT_EQ(span.data(), subspan.data()); - EXPECT_EQ(2u, subspan.size()); - static_assert(2u == decltype(subspan)::extent, ""); - EXPECT_EQ(1, subspan[0]); - EXPECT_EQ(2, subspan[1]); - } - - { - auto subspan = span.first<3>(); - EXPECT_EQ(span.data(), subspan.data()); - EXPECT_EQ(3u, subspan.size()); - static_assert(3u == decltype(subspan)::extent, ""); - EXPECT_EQ(1, subspan[0]); - EXPECT_EQ(2, subspan[1]); - EXPECT_EQ(3, subspan[2]); - } -} - -TEST(SpanTest, TemplatedLastOnDynamicSpan) { - int array[] = {1, 2, 3}; - span<int> span(array); - - { - auto subspan = span.last<0>(); - EXPECT_EQ(span.data() + 3, subspan.data()); - EXPECT_EQ(0u, subspan.size()); - static_assert(0u == decltype(subspan)::extent, ""); - } - - { - auto subspan = span.last<1>(); - EXPECT_EQ(span.data() + 2, subspan.data()); - EXPECT_EQ(1u, subspan.size()); - static_assert(1u == decltype(subspan)::extent, ""); - EXPECT_EQ(3, subspan[0]); - } - - { - auto subspan = span.last<2>(); - EXPECT_EQ(span.data() + 1, subspan.data()); - EXPECT_EQ(2u, subspan.size()); - static_assert(2u == decltype(subspan)::extent, ""); - EXPECT_EQ(2, subspan[0]); - EXPECT_EQ(3, subspan[1]); - } - - { - auto subspan = span.last<3>(); - EXPECT_EQ(span.data(), subspan.data()); - EXPECT_EQ(3u, subspan.size()); - static_assert(3u == decltype(subspan)::extent, ""); - EXPECT_EQ(1, subspan[0]); - EXPECT_EQ(2, subspan[1]); - EXPECT_EQ(3, subspan[2]); - } -} - -TEST(SpanTest, TemplatedSubspanFromDynamicSpan) { - int array[] = {1, 2, 3}; - span<int, 3> span(array); - - { - auto subspan = span.subspan<0>(); - EXPECT_EQ(span.data(), subspan.data()); - static_assert(3u == decltype(subspan)::extent, ""); - EXPECT_EQ(3u, subspan.size()); - EXPECT_EQ(1, subspan[0]); - EXPECT_EQ(2, subspan[1]); - EXPECT_EQ(3, subspan[2]); - } - - { - auto subspan = span.subspan<1>(); - EXPECT_EQ(span.data() + 1, subspan.data()); - EXPECT_EQ(2u, subspan.size()); - static_assert(2u == decltype(subspan)::extent, ""); - EXPECT_EQ(2, subspan[0]); - EXPECT_EQ(3, subspan[1]); - } - - { - auto subspan = span.subspan<2>(); - EXPECT_EQ(span.data() + 2, subspan.data()); - EXPECT_EQ(1u, subspan.size()); - static_assert(1u == decltype(subspan)::extent, ""); - EXPECT_EQ(3, subspan[0]); - } - - { - auto subspan = span.subspan<3>(); - EXPECT_EQ(span.data() + 3, subspan.data()); - EXPECT_EQ(0u, subspan.size()); - static_assert(0u == decltype(subspan)::extent, ""); - } - - { - auto subspan = span.subspan<0, 0>(); - EXPECT_EQ(span.data(), subspan.data()); - EXPECT_EQ(0u, subspan.size()); - static_assert(0u == decltype(subspan)::extent, ""); - } - - { - auto subspan = span.subspan<1, 0>(); - EXPECT_EQ(span.data() + 1, subspan.data()); - EXPECT_EQ(0u, subspan.size()); - static_assert(0u == decltype(subspan)::extent, ""); - } - - { - auto subspan = span.subspan<2, 0>(); - EXPECT_EQ(span.data() + 2, subspan.data()); - EXPECT_EQ(0u, subspan.size()); - static_assert(0u == decltype(subspan)::extent, ""); - } - - { - auto subspan = span.subspan<0, 1>(); - EXPECT_EQ(span.data(), subspan.data()); - EXPECT_EQ(1u, subspan.size()); - static_assert(1u == decltype(subspan)::extent, ""); - EXPECT_EQ(1, subspan[0]); - } - - { - auto subspan = span.subspan<1, 1>(); - EXPECT_EQ(span.data() + 1, subspan.data()); - EXPECT_EQ(1u, subspan.size()); - static_assert(1u == decltype(subspan)::extent, ""); - EXPECT_EQ(2, subspan[0]); - } - - { - auto subspan = span.subspan<2, 1>(); - EXPECT_EQ(span.data() + 2, subspan.data()); - EXPECT_EQ(1u, subspan.size()); - static_assert(1u == decltype(subspan)::extent, ""); - EXPECT_EQ(3, subspan[0]); - } - - { - auto subspan = span.subspan<0, 2>(); - EXPECT_EQ(span.data(), subspan.data()); - EXPECT_EQ(2u, subspan.size()); - static_assert(2u == decltype(subspan)::extent, ""); - EXPECT_EQ(1, subspan[0]); - EXPECT_EQ(2, subspan[1]); - } - - { - auto subspan = span.subspan<1, 2>(); - EXPECT_EQ(span.data() + 1, subspan.data()); - EXPECT_EQ(2u, subspan.size()); - static_assert(2u == decltype(subspan)::extent, ""); - EXPECT_EQ(2, subspan[0]); - EXPECT_EQ(3, subspan[1]); - } - - { - auto subspan = span.subspan<0, 3>(); - EXPECT_EQ(span.data(), subspan.data()); - EXPECT_EQ(3u, subspan.size()); - static_assert(3u == decltype(subspan)::extent, ""); - EXPECT_EQ(1, subspan[0]); - EXPECT_EQ(2, subspan[1]); - EXPECT_EQ(3, subspan[2]); - } -} - -TEST(SpanTest, First) { - int array[] = {1, 2, 3}; - span<int> span(array); - - { - auto subspan = span.first(0); - EXPECT_EQ(span.data(), subspan.data()); - EXPECT_EQ(0u, subspan.size()); - } - - { - auto subspan = span.first(1); - EXPECT_EQ(span.data(), subspan.data()); - EXPECT_EQ(1u, subspan.size()); - EXPECT_EQ(1, subspan[0]); - } - - { - auto subspan = span.first(2); - EXPECT_EQ(span.data(), subspan.data()); - EXPECT_EQ(2u, subspan.size()); - EXPECT_EQ(1, subspan[0]); - EXPECT_EQ(2, subspan[1]); - } - - { - auto subspan = span.first(3); - EXPECT_EQ(span.data(), subspan.data()); - EXPECT_EQ(3u, subspan.size()); - EXPECT_EQ(1, subspan[0]); - EXPECT_EQ(2, subspan[1]); - EXPECT_EQ(3, subspan[2]); - } -} - -TEST(SpanTest, Last) { - int array[] = {1, 2, 3}; - span<int> span(array); - - { - auto subspan = span.last(0); - EXPECT_EQ(span.data() + 3, subspan.data()); - EXPECT_EQ(0u, subspan.size()); - } - - { - auto subspan = span.last(1); - EXPECT_EQ(span.data() + 2, subspan.data()); - EXPECT_EQ(1u, subspan.size()); - EXPECT_EQ(3, subspan[0]); - } - - { - auto subspan = span.last(2); - EXPECT_EQ(span.data() + 1, subspan.data()); - EXPECT_EQ(2u, subspan.size()); - EXPECT_EQ(2, subspan[0]); - EXPECT_EQ(3, subspan[1]); - } - - { - auto subspan = span.last(3); - EXPECT_EQ(span.data(), subspan.data()); - EXPECT_EQ(3u, subspan.size()); - EXPECT_EQ(1, subspan[0]); - EXPECT_EQ(2, subspan[1]); - EXPECT_EQ(3, subspan[2]); - } -} - -TEST(SpanTest, Subspan) { - int array[] = {1, 2, 3}; - span<int> span(array); - - { - auto subspan = span.subspan(0); - EXPECT_EQ(span.data(), subspan.data()); - EXPECT_EQ(3u, subspan.size()); - EXPECT_EQ(1, subspan[0]); - EXPECT_EQ(2, subspan[1]); - EXPECT_EQ(3, subspan[2]); - } - - { - auto subspan = span.subspan(1); - EXPECT_EQ(span.data() + 1, subspan.data()); - EXPECT_EQ(2u, subspan.size()); - EXPECT_EQ(2, subspan[0]); - EXPECT_EQ(3, subspan[1]); - } - - { - auto subspan = span.subspan(2); - EXPECT_EQ(span.data() + 2, subspan.data()); - EXPECT_EQ(1u, subspan.size()); - EXPECT_EQ(3, subspan[0]); - } - - { - auto subspan = span.subspan(3); - EXPECT_EQ(span.data() + 3, subspan.data()); - EXPECT_EQ(0u, subspan.size()); - } - - { - auto subspan = span.subspan(0, 0); - EXPECT_EQ(span.data(), subspan.data()); - EXPECT_EQ(0u, subspan.size()); - } - - { - auto subspan = span.subspan(1, 0); - EXPECT_EQ(span.data() + 1, subspan.data()); - EXPECT_EQ(0u, subspan.size()); - } - - { - auto subspan = span.subspan(2, 0); - EXPECT_EQ(span.data() + 2, subspan.data()); - EXPECT_EQ(0u, subspan.size()); - } - - { - auto subspan = span.subspan(0, 1); - EXPECT_EQ(span.data(), subspan.data()); - EXPECT_EQ(1u, subspan.size()); - EXPECT_EQ(1, subspan[0]); - } - - { - auto subspan = span.subspan(1, 1); - EXPECT_EQ(span.data() + 1, subspan.data()); - EXPECT_EQ(1u, subspan.size()); - EXPECT_EQ(2, subspan[0]); - } - - { - auto subspan = span.subspan(2, 1); - EXPECT_EQ(span.data() + 2, subspan.data()); - EXPECT_EQ(1u, subspan.size()); - EXPECT_EQ(3, subspan[0]); - } - - { - auto subspan = span.subspan(0, 2); - EXPECT_EQ(span.data(), subspan.data()); - EXPECT_EQ(2u, subspan.size()); - EXPECT_EQ(1, subspan[0]); - EXPECT_EQ(2, subspan[1]); - } - - { - auto subspan = span.subspan(1, 2); - EXPECT_EQ(span.data() + 1, subspan.data()); - EXPECT_EQ(2u, subspan.size()); - EXPECT_EQ(2, subspan[0]); - EXPECT_EQ(3, subspan[1]); - } - - { - auto subspan = span.subspan(0, 3); - EXPECT_EQ(span.data(), subspan.data()); - EXPECT_EQ(span.size(), subspan.size()); - EXPECT_EQ(1, subspan[0]); - EXPECT_EQ(2, subspan[1]); - EXPECT_EQ(3, subspan[2]); - } -} - -TEST(SpanTest, Size) { - { - span<int> span; - EXPECT_EQ(0u, span.size()); - } - - { - int array[] = {1, 2, 3}; - span<int> span(array); - EXPECT_EQ(3u, span.size()); - } -} - -TEST(SpanTest, SizeBytes) { - { - span<int> span; - EXPECT_EQ(0u, span.size_bytes()); - } - - { - int array[] = {1, 2, 3}; - span<int> span(array); - EXPECT_EQ(3u * sizeof(int), span.size_bytes()); - } -} - -TEST(SpanTest, Empty) { - { - span<int> span; - EXPECT_TRUE(span.empty()); - } - - { - int array[] = {1, 2, 3}; - span<int> span(array); - EXPECT_FALSE(span.empty()); - } -} - -TEST(SpanTest, OperatorAt) { - static constexpr int kArray[] = {1, 6, 1, 8, 0}; - constexpr span<const int> span(kArray); - - static_assert(kArray[0] == span[0], "span[0] does not equal kArray[0]"); - static_assert(kArray[1] == span[1], "span[1] does not equal kArray[1]"); - static_assert(kArray[2] == span[2], "span[2] does not equal kArray[2]"); - static_assert(kArray[3] == span[3], "span[3] does not equal kArray[3]"); - static_assert(kArray[4] == span[4], "span[4] does not equal kArray[4]"); - - static_assert(kArray[0] == span(0), "span(0) does not equal kArray[0]"); - static_assert(kArray[1] == span(1), "span(1) does not equal kArray[1]"); - static_assert(kArray[2] == span(2), "span(2) does not equal kArray[2]"); - static_assert(kArray[3] == span(3), "span(3) does not equal kArray[3]"); - static_assert(kArray[4] == span(4), "span(4) does not equal kArray[4]"); -} - -TEST(SpanTest, Iterator) { - static constexpr int kArray[] = {1, 6, 1, 8, 0}; - constexpr span<const int> span(kArray); - - std::vector<int> results; - for (int i : span) - results.emplace_back(i); - EXPECT_THAT(results, ElementsAre(1, 6, 1, 8, 0)); -} - -TEST(SpanTest, ReverseIterator) { - static constexpr int kArray[] = {1, 6, 1, 8, 0}; - constexpr span<const int> span(kArray); - - EXPECT_TRUE(std::equal(std::rbegin(kArray), std::rend(kArray), span.rbegin(), - span.rend())); - EXPECT_TRUE(std::equal(std::crbegin(kArray), std::crend(kArray), - span.crbegin(), span.crend())); -} - -TEST(SpanTest, Equality) { - static constexpr int kArray1[] = {3, 1, 4, 1, 5}; - static constexpr int kArray2[] = {3, 1, 4, 1, 5}; - constexpr span<const int> span1(kArray1); - constexpr span<const int, 5> span2(kArray2); - - EXPECT_EQ(span1, span2); - - static constexpr int kArray3[] = {2, 7, 1, 8, 3}; - constexpr span<const int> span3(kArray3); - - EXPECT_FALSE(span1 == span3); - - static double kArray4[] = {2.0, 7.0, 1.0, 8.0, 3.0}; - span<double, 5> span4(kArray4); - - EXPECT_EQ(span3, span4); -} - -TEST(SpanTest, Inequality) { - static constexpr int kArray1[] = {2, 3, 5, 7, 11}; - static constexpr int kArray2[] = {1, 4, 6, 8, 9}; - constexpr span<const int> span1(kArray1); - constexpr span<const int, 5> span2(kArray2); - - EXPECT_NE(span1, span2); - - static constexpr int kArray3[] = {2, 3, 5, 7, 11}; - constexpr span<const int> span3(kArray3); - - EXPECT_FALSE(span1 != span3); - - static double kArray4[] = {1.0, 4.0, 6.0, 8.0, 9.0}; - span<double, 5> span4(kArray4); - - EXPECT_NE(span3, span4); -} - -TEST(SpanTest, LessThan) { - static constexpr int kArray1[] = {2, 3, 5, 7, 11}; - static constexpr int kArray2[] = {2, 3, 5, 7, 11, 13}; - constexpr span<const int> span1(kArray1); - constexpr span<const int, 6> span2(kArray2); - - EXPECT_LT(span1, span2); - - static constexpr int kArray3[] = {2, 3, 5, 7, 11}; - constexpr span<const int> span3(kArray3); - - EXPECT_FALSE(span1 < span3); - - static double kArray4[] = {2.0, 3.0, 5.0, 7.0, 11.0, 13.0}; - span<double, 6> span4(kArray4); - - EXPECT_LT(span3, span4); -} - -TEST(SpanTest, LessEqual) { - static constexpr int kArray1[] = {2, 3, 5, 7, 11}; - static constexpr int kArray2[] = {2, 3, 5, 7, 11, 13}; - constexpr span<const int> span1(kArray1); - constexpr span<const int, 6> span2(kArray2); - - EXPECT_LE(span1, span1); - EXPECT_LE(span1, span2); - - static constexpr int kArray3[] = {2, 3, 5, 7, 10}; - constexpr span<const int> span3(kArray3); - - EXPECT_FALSE(span1 <= span3); - - static double kArray4[] = {2.0, 3.0, 5.0, 7.0, 11.0, 13.0}; - span<double, 6> span4(kArray4); - - EXPECT_LE(span3, span4); -} - -TEST(SpanTest, GreaterThan) { - static constexpr int kArray1[] = {2, 3, 5, 7, 11, 13}; - static constexpr int kArray2[] = {2, 3, 5, 7, 11}; - constexpr span<const int> span1(kArray1); - constexpr span<const int, 5> span2(kArray2); - - EXPECT_GT(span1, span2); - - static constexpr int kArray3[] = {2, 3, 5, 7, 11, 13}; - constexpr span<const int> span3(kArray3); - - EXPECT_FALSE(span1 > span3); - - static double kArray4[] = {2.0, 3.0, 5.0, 7.0, 11.0}; - span<double, 5> span4(kArray4); - - EXPECT_GT(span3, span4); -} - -TEST(SpanTest, GreaterEqual) { - static constexpr int kArray1[] = {2, 3, 5, 7, 11, 13}; - static constexpr int kArray2[] = {2, 3, 5, 7, 11}; - constexpr span<const int> span1(kArray1); - constexpr span<const int, 5> span2(kArray2); - - EXPECT_GE(span1, span1); - EXPECT_GE(span1, span2); - - static constexpr int kArray3[] = {2, 3, 5, 7, 12}; - constexpr span<const int> span3(kArray3); - - EXPECT_FALSE(span1 >= span3); - - static double kArray4[] = {2.0, 3.0, 5.0, 7.0, 11.0}; - span<double, 5> span4(kArray4); - - EXPECT_GE(span3, span4); -} - -TEST(SpanTest, AsBytes) { - { - constexpr int kArray[] = {2, 3, 5, 7, 11, 13}; - span<const uint8_t, sizeof(kArray)> bytes_span = - as_bytes(make_span(kArray)); - EXPECT_EQ(reinterpret_cast<const uint8_t*>(kArray), bytes_span.data()); - EXPECT_EQ(sizeof(kArray), bytes_span.size()); - EXPECT_EQ(bytes_span.size(), bytes_span.size_bytes()); - } - - { - std::vector<int> vec = {1, 1, 2, 3, 5, 8}; - span<int> mutable_span(vec); - span<const uint8_t> bytes_span = as_bytes(mutable_span); - EXPECT_EQ(reinterpret_cast<const uint8_t*>(vec.data()), bytes_span.data()); - EXPECT_EQ(sizeof(int) * vec.size(), bytes_span.size()); - EXPECT_EQ(bytes_span.size(), bytes_span.size_bytes()); - } -} - -TEST(SpanTest, AsWritableBytes) { - std::vector<int> vec = {1, 1, 2, 3, 5, 8}; - span<int> mutable_span(vec); - span<uint8_t> writable_bytes_span = as_writable_bytes(mutable_span); - EXPECT_EQ(reinterpret_cast<uint8_t*>(vec.data()), writable_bytes_span.data()); - EXPECT_EQ(sizeof(int) * vec.size(), writable_bytes_span.size()); - EXPECT_EQ(writable_bytes_span.size(), writable_bytes_span.size_bytes()); - - // Set the first entry of vec to zero while writing through the span. - std::fill(writable_bytes_span.data(), - writable_bytes_span.data() + sizeof(int), 0); - EXPECT_EQ(0, vec[0]); -} - -TEST(SpanTest, MakeSpanFromDataAndSize) { - int* nullint = nullptr; - auto empty_span = make_span(nullint, 0); - EXPECT_TRUE(empty_span.empty()); - EXPECT_EQ(nullptr, empty_span.data()); - - std::vector<int> vector = {1, 1, 2, 3, 5, 8}; - span<int> span(vector.data(), vector.size()); - auto made_span = make_span(vector.data(), vector.size()); - EXPECT_EQ(span, made_span); - static_assert(decltype(made_span)::extent == dynamic_extent, ""); -} - -TEST(SpanTest, MakeSpanFromPointerPair) { - int* nullint = nullptr; - auto empty_span = make_span(nullint, nullint); - EXPECT_TRUE(empty_span.empty()); - EXPECT_EQ(nullptr, empty_span.data()); - - std::vector<int> vector = {1, 1, 2, 3, 5, 8}; - span<int> span(vector.data(), vector.size()); - auto made_span = make_span(vector.data(), vector.data() + vector.size()); - EXPECT_EQ(span, made_span); - static_assert(decltype(made_span)::extent == dynamic_extent, ""); -} - -TEST(SpanTest, MakeSpanFromConstexprArray) { - static constexpr int kArray[] = {1, 2, 3, 4, 5}; - constexpr span<const int> span(kArray); - EXPECT_EQ(span, make_span(kArray)); - static_assert(decltype(make_span(kArray))::extent == 5, ""); -} - -TEST(SpanTest, MakeSpanFromStdArray) { - const std::array<int, 5> kArray = {{1, 2, 3, 4, 5}}; - span<const int> span(kArray); - EXPECT_EQ(span, make_span(kArray)); - static_assert(decltype(make_span(kArray))::extent == 5, ""); -} - -TEST(SpanTest, MakeSpanFromConstContainer) { - const std::vector<int> vector = {-1, -2, -3, -4, -5}; - span<const int> span(vector); - EXPECT_EQ(span, make_span(vector)); - static_assert(decltype(make_span(vector))::extent == dynamic_extent, ""); -} - -TEST(SpanTest, MakeSpanFromContainer) { - std::vector<int> vector = {-1, -2, -3, -4, -5}; - span<int> span(vector); - EXPECT_EQ(span, make_span(vector)); - static_assert(decltype(make_span(vector))::extent == dynamic_extent, ""); -} - -TEST(SpanTest, MakeSpanFromDynamicSpan) { - static constexpr int kArray[] = {1, 2, 3, 4, 5}; - constexpr span<const int> span(kArray); - static_assert(std::is_same<decltype(span)::element_type, - decltype(make_span(span))::element_type>::value, - "make_span(span) should have the same element_type as span"); - - static_assert(span.data() == make_span(span).data(), - "make_span(span) should have the same data() as span"); - - static_assert(span.size() == make_span(span).size(), - "make_span(span) should have the same size() as span"); - - static_assert(decltype(make_span(span))::extent == decltype(span)::extent, - "make_span(span) should have the same extent as span"); -} - -TEST(SpanTest, MakeSpanFromStaticSpan) { - static constexpr int kArray[] = {1, 2, 3, 4, 5}; - constexpr span<const int, 5> span(kArray); - static_assert(std::is_same<decltype(span)::element_type, - decltype(make_span(span))::element_type>::value, - "make_span(span) should have the same element_type as span"); - - static_assert(span.data() == make_span(span).data(), - "make_span(span) should have the same data() as span"); - - static_assert(span.size() == make_span(span).size(), - "make_span(span) should have the same size() as span"); - - static_assert(decltype(make_span(span))::extent == decltype(span)::extent, - "make_span(span) should have the same extent as span"); -} - -TEST(SpanTest, EnsureConstexprGoodness) { - static constexpr int kArray[] = {5, 4, 3, 2, 1}; - constexpr span<const int> constexpr_span(kArray); - const size_t size = 2; - - const size_t start = 1; - constexpr span<const int> subspan = - constexpr_span.subspan(start, start + size); - for (size_t i = 0; i < subspan.size(); ++i) - EXPECT_EQ(kArray[start + i], subspan[i]); - - constexpr span<const int> firsts = constexpr_span.first(size); - for (size_t i = 0; i < firsts.size(); ++i) - EXPECT_EQ(kArray[i], firsts[i]); - - constexpr span<const int> lasts = constexpr_span.last(size); - for (size_t i = 0; i < lasts.size(); ++i) { - const size_t j = (arraysize(kArray) - size) + i; - EXPECT_EQ(kArray[j], lasts[i]); - } - - constexpr int item = constexpr_span[size]; - EXPECT_EQ(kArray[size], item); -} - -} // namespace base
diff --git a/base/containers/span_unittest.nc b/base/containers/span_unittest.nc deleted file mode 100644 index 0d2af89..0000000 --- a/base/containers/span_unittest.nc +++ /dev/null
@@ -1,167 +0,0 @@ -// 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. - -// This is a "No Compile Test" suite. -// http://dev.chromium.org/developers/testing/no-compile-tests - -#include "base/containers/span.h" - -#include <array> -#include <set> -#include <vector> - -namespace base { - -class Base { -}; - -class Derived : Base { -}; - -#if defined(NCTEST_DEFAULT_SPAN_WITH_NON_ZERO_STATIC_EXTENT_DISALLOWED) // [r"fatal error: static_assert failed \"Invalid Extent\""] - -// A default constructed span must have an extent of 0 or dynamic_extent. -void WontCompile() { - span<int, 1> span; -} - -#elif defined(NCTEST_SPAN_FROM_ARRAY_WITH_NON_MATCHING_STATIC_EXTENT_DISALLOWED) // [r"fatal error: no matching constructor for initialization of 'span<int, 1>'"] - -// A span with static extent constructed from an array must match the size of -// the array. -void WontCompile() { - int array[] = {1, 2, 3}; - span<int, 1> span(array); -} - -#elif defined(NCTEST_SPAN_FROM_STD_ARRAY_WITH_NON_MATCHING_STATIC_EXTENT_DISALLOWED) // [r"fatal error: no matching constructor for initialization of 'span<int, 2>'"] - -// A span with static extent constructed from std::array must match the size of -// the array. -void WontCompile() { - std::array<int, 3> array = {1, 2, 3}; - span<int, 2> span(array); -} - -#elif defined(NCTEST_SPAN_FROM_CONST_STD_ARRAY_WITH_NON_MATCHING_STATIC_EXTENT_DISALLOWED) // [r"fatal error: no matching constructor for initialization of 'span<const int, 2>'"] - -// A span with static extent constructed from std::array must match the size of -// the array. -void WontCompile() { - const std::array<int, 3> array = {1, 2, 3}; - span<const int, 2> span(array); -} - -#elif defined(NCTEST_SPAN_FROM_OTHER_SPAN_WITH_MISMATCHING_EXTENT_DISALLOWED) // [r"fatal error: no matching constructor for initialization of 'span<int, 4>'"] - -// A span with static extent constructed from another span must match the -// extent. -void WontCompile() { - std::array<int, 3> array = {1, 2, 3}; - span<int, 3> span3(array); - span<int, 4> span4(span3); -} - -#elif defined(NCTEST_DYNAMIC_SPAN_TO_STATIC_SPAN_DISALLOWED) // [r"fatal error: no matching constructor for initialization of 'span<int, 3>'"] - -// Converting a dynamic span to a static span should not be allowed. -void WontCompile() { - span<int> dynamic_span; - span<int, 3> static_span(dynamic_span); -} - -#elif defined(NCTEST_DERIVED_TO_BASE_CONVERSION_DISALLOWED) // [r"fatal error: no matching constructor for initialization of 'span<base::Base \*>'"] - -// Internally, this is represented as a pointer to pointers to Derived. An -// implicit conversion to a pointer to pointers to Base must not be allowed. -// If it were allowed, then something like this would be possible. -// Cat** cats = GetCats(); -// Animals** animals = cats; -// animals[0] = new Dog(); // Uhoh! -void WontCompile() { - span<Derived*> derived_span; - span<Base*> base_span(derived_span); -} - -#elif defined(NCTEST_PTR_TO_CONSTPTR_CONVERSION_DISALLOWED) // [r"fatal error: no matching constructor for initialization of 'span<const int \*>'"] - -// Similarly, converting a span<int*> to span<const int*> requires internally -// converting T** to const T**. This is also disallowed, as it would allow code -// to violate the contract of const. -void WontCompile() { - span<int*> non_const_span; - span<const int*> const_span(non_const_span); -} - -#elif defined(NCTEST_CONST_CONTAINER_TO_MUTABLE_CONVERSION_DISALLOWED) // [r"fatal error: no matching constructor for initialization of 'span<int>'"] - -// A const container should not be convertible to a mutable span. -void WontCompile() { - const std::vector<int> v = {1, 2, 3}; - span<int> span(v); -} - -#elif defined(NCTEST_STD_SET_CONVERSION_DISALLOWED) // [r"fatal error: no matching constructor for initialization of 'span<int>'"] - -// A std::set() should not satisfy the requirements for conversion to a span. -void WontCompile() { - std::set<int> set; - span<int> span(set); -} - -#elif defined(NCTEST_STATIC_FRONT_WITH_EXCEEDING_COUNT_DISALLOWED) // [r"fatal error: static_assert failed \"Count must not exceed Extent\""] - -// Static first called on a span with static extent must not exceed the size. -void WontCompile() { - std::array<int, 3> array = {1, 2, 3}; - span<int, 3> span(array); - auto first = span.first<4>(); -} - -#elif defined(NCTEST_STATIC_LAST_WITH_EXCEEDING_COUNT_DISALLOWED) // [r"fatal error: static_assert failed \"Count must not exceed Extent\""] - -// Static last called on a span with static extent must not exceed the size. -void WontCompile() { - std::array<int, 3> array = {1, 2, 3}; - span<int, 3> span(array); - auto last = span.last<4>(); -} - -#elif defined(NCTEST_STATIC_SUBSPAN_WITH_EXCEEDING_OFFSET_DISALLOWED) // [r"fatal error: static_assert failed \"Offset must not exceed Extent\""] - -// Static subspan called on a span with static extent must not exceed the size. -void WontCompile() { - std::array<int, 3> array = {1, 2, 3}; - span<int, 3> span(array); - auto subspan = span.subspan<4>(); -} - -#elif defined(NCTEST_STATIC_SUBSPAN_WITH_EXCEEDING_COUNT_DISALLOWED) // [r"fatal error: static_assert failed \"Count must not exceed Extent - Offset\""] - -// Static subspan called on a span with static extent must not exceed the size. -void WontCompile() { - std::array<int, 3> array = {1, 2, 3}; - span<int, 3> span(array); - auto subspan = span.subspan<0, 4>(); -} - -#elif defined(NCTEST_AS_WRITABLE_BYTES_WITH_CONST_CONTAINER_DISALLOWED) // [r"fatal error: no matching function for call to 'as_writable_bytes'"] - -// as_writable_bytes should not be possible for a const container. -void WontCompile() { - const std::vector<int> v = {1, 2, 3}; - span<uint8_t> bytes = as_writable_bytes(make_span(v)); -} - -#elif defined(NCTEST_MAKE_SPAN_FROM_SET_CONVERSION_DISALLOWED) // [r"fatal error: no matching function for call to 'make_span'"] - -// A std::set() should not satisfy the requirements for conversion to a span. -void WontCompile() { - std::set<int> set; - auto span = make_span(set); -} - -#endif - -} // namespace base
diff --git a/base/containers/stack_container_unittest.cc b/base/containers/stack_container_unittest.cc deleted file mode 100644 index 8c039ad..0000000 --- a/base/containers/stack_container_unittest.cc +++ /dev/null
@@ -1,145 +0,0 @@ -// 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/containers/stack_container.h" - -#include <stddef.h> - -#include <algorithm> - -#include "base/memory/ref_counted.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -class Dummy : public base::RefCounted<Dummy> { - public: - explicit Dummy(int* alive) : alive_(alive) { - ++*alive_; - } - - private: - friend class base::RefCounted<Dummy>; - - ~Dummy() { - --*alive_; - } - - int* const alive_; -}; - -} // namespace - -TEST(StackContainer, Vector) { - const int stack_size = 3; - StackVector<int, stack_size> vect; - const int* stack_buffer = &vect.stack_data().stack_buffer()[0]; - - // The initial |stack_size| elements should appear in the stack buffer. - EXPECT_EQ(static_cast<size_t>(stack_size), vect.container().capacity()); - for (int i = 0; i < stack_size; i++) { - vect.container().push_back(i); - EXPECT_EQ(stack_buffer, &vect.container()[0]); - EXPECT_TRUE(vect.stack_data().used_stack_buffer_); - } - - // Adding more elements should push the array onto the heap. - for (int i = 0; i < stack_size; i++) { - vect.container().push_back(i + stack_size); - EXPECT_NE(stack_buffer, &vect.container()[0]); - EXPECT_FALSE(vect.stack_data().used_stack_buffer_); - } - - // The array should still be in order. - for (int i = 0; i < stack_size * 2; i++) - EXPECT_EQ(i, vect.container()[i]); - - // Resize to smaller. Our STL implementation won't reallocate in this case, - // otherwise it might use our stack buffer. We reserve right after the resize - // to guarantee it isn't using the stack buffer, even though it doesn't have - // much data. - vect.container().resize(stack_size); - vect.container().reserve(stack_size * 2); - EXPECT_FALSE(vect.stack_data().used_stack_buffer_); - - // Copying the small vector to another should use the same allocator and use - // the now-unused stack buffer. GENERALLY CALLERS SHOULD NOT DO THIS since - // they have to get the template types just right and it can cause errors. - std::vector<int, StackAllocator<int, stack_size> > other(vect.container()); - EXPECT_EQ(stack_buffer, &other.front()); - EXPECT_TRUE(vect.stack_data().used_stack_buffer_); - for (int i = 0; i < stack_size; i++) - EXPECT_EQ(i, other[i]); -} - -TEST(StackContainer, VectorDoubleDelete) { - // Regression testing for double-delete. - typedef StackVector<scoped_refptr<Dummy>, 2> Vector; - typedef Vector::ContainerType Container; - Vector vect; - - int alive = 0; - scoped_refptr<Dummy> dummy(new Dummy(&alive)); - EXPECT_EQ(alive, 1); - - vect->push_back(dummy); - EXPECT_EQ(alive, 1); - - Dummy* dummy_unref = dummy.get(); - dummy = nullptr; - EXPECT_EQ(alive, 1); - - Container::iterator itr = std::find(vect->begin(), vect->end(), dummy_unref); - EXPECT_EQ(itr->get(), dummy_unref); - vect->erase(itr); - EXPECT_EQ(alive, 0); - - // Shouldn't crash at exit. -} - -namespace { - -template <size_t alignment> -class AlignedData { - public: - AlignedData() { memset(data_, 0, alignment); } - ~AlignedData() = default; - alignas(alignment) char data_[alignment]; -}; - -} // anonymous namespace - -#define EXPECT_ALIGNED(ptr, align) \ - EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1)) - -TEST(StackContainer, BufferAlignment) { - StackVector<wchar_t, 16> text; - text->push_back(L'A'); - EXPECT_ALIGNED(&text[0], alignof(wchar_t)); - - StackVector<double, 1> doubles; - doubles->push_back(0.0); - EXPECT_ALIGNED(&doubles[0], alignof(double)); - - StackVector<AlignedData<16>, 1> aligned16; - aligned16->push_back(AlignedData<16>()); - EXPECT_ALIGNED(&aligned16[0], 16); - -#if !defined(__GNUC__) || defined(ARCH_CPU_X86_FAMILY) - // It seems that non-X86 gcc doesn't respect greater than 16 byte alignment. - // See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=33721 for details. - // TODO(sbc):re-enable this if GCC starts respecting higher alignments. - StackVector<AlignedData<256>, 1> aligned256; - aligned256->push_back(AlignedData<256>()); - EXPECT_ALIGNED(&aligned256[0], 256); -#endif -} - -template class StackVector<int, 2>; -template class StackVector<scoped_refptr<Dummy>, 2>; - -} // namespace base
diff --git a/base/containers/unique_ptr_adapters_unittest.cc b/base/containers/unique_ptr_adapters_unittest.cc deleted file mode 100644 index 5b8f1fc..0000000 --- a/base/containers/unique_ptr_adapters_unittest.cc +++ /dev/null
@@ -1,134 +0,0 @@ -// 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/containers/unique_ptr_adapters.h" - -#include <memory> -#include <vector> - -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -class Foo { - public: - Foo() { instance_count++; } - ~Foo() { instance_count--; } - static int instance_count; -}; - -int Foo::instance_count = 0; - -TEST(UniquePtrComparatorTest, Basic) { - std::set<std::unique_ptr<Foo>, UniquePtrComparator> set; - Foo* foo1 = new Foo(); - Foo* foo2 = new Foo(); - Foo* foo3 = new Foo(); - EXPECT_EQ(3, Foo::instance_count); - - set.emplace(foo1); - set.emplace(foo2); - - auto it1 = set.find(foo1); - EXPECT_TRUE(it1 != set.end()); - EXPECT_EQ(foo1, it1->get()); - - { - auto it2 = set.find(foo2); - EXPECT_TRUE(it2 != set.end()); - EXPECT_EQ(foo2, it2->get()); - } - - EXPECT_TRUE(set.find(foo3) == set.end()); - - set.erase(it1); - EXPECT_EQ(2, Foo::instance_count); - - EXPECT_TRUE(set.find(foo1) == set.end()); - - { - auto it2 = set.find(foo2); - EXPECT_TRUE(it2 != set.end()); - EXPECT_EQ(foo2, it2->get()); - } - - set.clear(); - EXPECT_EQ(1, Foo::instance_count); - - EXPECT_TRUE(set.find(foo1) == set.end()); - EXPECT_TRUE(set.find(foo2) == set.end()); - EXPECT_TRUE(set.find(foo3) == set.end()); - - delete foo3; - EXPECT_EQ(0, Foo::instance_count); -} - -TEST(UniquePtrMatcherTest, Basic) { - std::vector<std::unique_ptr<Foo>> v; - auto foo_ptr1 = std::make_unique<Foo>(); - Foo* foo1 = foo_ptr1.get(); - v.push_back(std::move(foo_ptr1)); - auto foo_ptr2 = std::make_unique<Foo>(); - Foo* foo2 = foo_ptr2.get(); - v.push_back(std::move(foo_ptr2)); - - { - auto iter = std::find_if(v.begin(), v.end(), UniquePtrMatcher<Foo>(foo1)); - ASSERT_TRUE(iter != v.end()); - EXPECT_EQ(foo1, iter->get()); - } - - { - auto iter = std::find_if(v.begin(), v.end(), UniquePtrMatcher<Foo>(foo2)); - ASSERT_TRUE(iter != v.end()); - EXPECT_EQ(foo2, iter->get()); - } - - { - auto iter = std::find_if(v.begin(), v.end(), MatchesUniquePtr(foo2)); - ASSERT_TRUE(iter != v.end()); - EXPECT_EQ(foo2, iter->get()); - } -} - -class TestDeleter { - public: - void operator()(Foo* foo) { delete foo; } -}; - -TEST(UniquePtrMatcherTest, Deleter) { - using UniqueFoo = std::unique_ptr<Foo, TestDeleter>; - std::vector<UniqueFoo> v; - UniqueFoo foo_ptr1(new Foo); - Foo* foo1 = foo_ptr1.get(); - v.push_back(std::move(foo_ptr1)); - UniqueFoo foo_ptr2(new Foo); - Foo* foo2 = foo_ptr2.get(); - v.push_back(std::move(foo_ptr2)); - - { - auto iter = std::find_if(v.begin(), v.end(), - UniquePtrMatcher<Foo, TestDeleter>(foo1)); - ASSERT_TRUE(iter != v.end()); - EXPECT_EQ(foo1, iter->get()); - } - - { - auto iter = std::find_if(v.begin(), v.end(), - UniquePtrMatcher<Foo, TestDeleter>(foo2)); - ASSERT_TRUE(iter != v.end()); - EXPECT_EQ(foo2, iter->get()); - } - - { - auto iter = std::find_if(v.begin(), v.end(), - MatchesUniquePtr<Foo, TestDeleter>(foo2)); - ASSERT_TRUE(iter != v.end()); - EXPECT_EQ(foo2, iter->get()); - } -} - -} // namespace -} // namespace base
diff --git a/base/containers/vector_buffer_unittest.cc b/base/containers/vector_buffer_unittest.cc deleted file mode 100644 index 6d49505..0000000 --- a/base/containers/vector_buffer_unittest.cc +++ /dev/null
@@ -1,89 +0,0 @@ -// 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/containers/vector_buffer.h" - -#include "base/test/copy_only_int.h" -#include "base/test/move_only_int.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace internal { - -TEST(VectorBuffer, DeletePOD) { - constexpr int size = 10; - VectorBuffer<int> buffer(size); - for (int i = 0; i < size; i++) - buffer.begin()[i] = i + 1; - - buffer.DestructRange(buffer.begin(), buffer.end()); - - // Delete should do nothing. - for (int i = 0; i < size; i++) - EXPECT_EQ(i + 1, buffer.begin()[i]); -} - -TEST(VectorBuffer, DeleteMoveOnly) { - constexpr int size = 10; - VectorBuffer<MoveOnlyInt> buffer(size); - for (int i = 0; i < size; i++) - new (buffer.begin() + i) MoveOnlyInt(i + 1); - - buffer.DestructRange(buffer.begin(), buffer.end()); - - // Delete should have reset all of the values to 0. - for (int i = 0; i < size; i++) - EXPECT_EQ(0, buffer.begin()[i].data()); -} - -TEST(VectorBuffer, PODMove) { - constexpr int size = 10; - VectorBuffer<int> dest(size); - - VectorBuffer<int> original(size); - for (int i = 0; i < size; i++) - original.begin()[i] = i + 1; - - original.MoveRange(original.begin(), original.end(), dest.begin()); - for (int i = 0; i < size; i++) - EXPECT_EQ(i + 1, dest.begin()[i]); -} - -TEST(VectorBuffer, MovableMove) { - constexpr int size = 10; - VectorBuffer<MoveOnlyInt> dest(size); - - VectorBuffer<MoveOnlyInt> original(size); - for (int i = 0; i < size; i++) - new (original.begin() + i) MoveOnlyInt(i + 1); - - original.MoveRange(original.begin(), original.end(), dest.begin()); - - // Moving from a MoveOnlyInt resets to 0. - for (int i = 0; i < size; i++) { - EXPECT_EQ(0, original.begin()[i].data()); - EXPECT_EQ(i + 1, dest.begin()[i].data()); - } -} - -TEST(VectorBuffer, CopyToMove) { - constexpr int size = 10; - VectorBuffer<CopyOnlyInt> dest(size); - - VectorBuffer<CopyOnlyInt> original(size); - for (int i = 0; i < size; i++) - new (original.begin() + i) CopyOnlyInt(i + 1); - - original.MoveRange(original.begin(), original.end(), dest.begin()); - - // The original should have been destructed, which should reset the value to - // 0. Technically this dereferences the destructed object. - for (int i = 0; i < size; i++) { - EXPECT_EQ(0, original.begin()[i].data()); - EXPECT_EQ(i + 1, dest.begin()[i].data()); - } -} - -} // namespace internal -} // namespace base
diff --git a/base/cpu_unittest.cc b/base/cpu_unittest.cc deleted file mode 100644 index bfdb1cd..0000000 --- a/base/cpu_unittest.cc +++ /dev/null
@@ -1,134 +0,0 @@ -// 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/cpu.h" -#include "base/stl_util.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if _MSC_VER >= 1700 -// C4752: found Intel(R) Advanced Vector Extensions; consider using /arch:AVX. -#pragma warning(disable: 4752) -#endif - -// Tests whether we can run extended instructions represented by the CPU -// information. This test actually executes some extended instructions (such as -// MMX, SSE, etc.) supported by the CPU and sees we can run them without -// "undefined instruction" exceptions. That is, this test succeeds when this -// test finishes without a crash. -TEST(CPU, RunExtendedInstructions) { -#if defined(ARCH_CPU_X86_FAMILY) - // Retrieve the CPU information. - base::CPU cpu; - - ASSERT_TRUE(cpu.has_mmx()); - ASSERT_TRUE(cpu.has_sse()); - ASSERT_TRUE(cpu.has_sse2()); - -// GCC and clang instruction test. -#if defined(COMPILER_GCC) - // Execute an MMX instruction. - __asm__ __volatile__("emms\n" : : : "mm0"); - - // Execute an SSE instruction. - __asm__ __volatile__("xorps %%xmm0, %%xmm0\n" : : : "xmm0"); - - // Execute an SSE 2 instruction. - __asm__ __volatile__("psrldq $0, %%xmm0\n" : : : "xmm0"); - - if (cpu.has_sse3()) { - // Execute an SSE 3 instruction. - __asm__ __volatile__("addsubpd %%xmm0, %%xmm0\n" : : : "xmm0"); - } - - if (cpu.has_ssse3()) { - // Execute a Supplimental SSE 3 instruction. - __asm__ __volatile__("psignb %%xmm0, %%xmm0\n" : : : "xmm0"); - } - - if (cpu.has_sse41()) { - // Execute an SSE 4.1 instruction. - __asm__ __volatile__("pmuldq %%xmm0, %%xmm0\n" : : : "xmm0"); - } - - if (cpu.has_sse42()) { - // Execute an SSE 4.2 instruction. - __asm__ __volatile__("crc32 %%eax, %%eax\n" : : : "eax"); - } - - if (cpu.has_popcnt()) { - // Execute a POPCNT instruction. - __asm__ __volatile__("popcnt %%eax, %%eax\n" : : : "eax"); - } - - if (cpu.has_avx()) { - // Execute an AVX instruction. - __asm__ __volatile__("vzeroupper\n" : : : "xmm0"); - } - - if (cpu.has_avx2()) { - // Execute an AVX 2 instruction. - __asm__ __volatile__("vpunpcklbw %%ymm0, %%ymm0, %%ymm0\n" : : : "xmm0"); - } - -// Visual C 32 bit and ClangCL 32/64 bit test. -#elif defined(COMPILER_MSVC) && (defined(ARCH_CPU_32_BITS) || \ - (defined(ARCH_CPU_64_BITS) && defined(__clang__))) - - // Execute an MMX instruction. - __asm emms; - - // Execute an SSE instruction. - __asm xorps xmm0, xmm0; - - // Execute an SSE 2 instruction. - __asm psrldq xmm0, 0; - - if (cpu.has_sse3()) { - // Execute an SSE 3 instruction. - __asm addsubpd xmm0, xmm0; - } - - if (cpu.has_ssse3()) { - // Execute a Supplimental SSE 3 instruction. - __asm psignb xmm0, xmm0; - } - - if (cpu.has_sse41()) { - // Execute an SSE 4.1 instruction. - __asm pmuldq xmm0, xmm0; - } - - if (cpu.has_sse42()) { - // Execute an SSE 4.2 instruction. - __asm crc32 eax, eax; - } - - if (cpu.has_popcnt()) { - // Execute a POPCNT instruction. - __asm popcnt eax, eax; - } - -// Visual C 2012 required for AVX. -#if _MSC_VER >= 1700 - if (cpu.has_avx()) { - // Execute an AVX instruction. - __asm vzeroupper; - } - - if (cpu.has_avx2()) { - // Execute an AVX 2 instruction. - __asm vpunpcklbw ymm0, ymm0, ymm0 - } -#endif // _MSC_VER >= 1700 -#endif // defined(COMPILER_GCC) -#endif // defined(ARCH_CPU_X86_FAMILY) -} - -// For https://crbug.com/249713 -TEST(CPU, BrandAndVendorContainsNoNUL) { - base::CPU cpu; - EXPECT_FALSE(base::ContainsValue(cpu.cpu_brand(), '\0')); - EXPECT_FALSE(base::ContainsValue(cpu.vendor_name(), '\0')); -}
diff --git a/base/debug/activity_analyzer_unittest.cc b/base/debug/activity_analyzer_unittest.cc deleted file mode 100644 index e08b43a..0000000 --- a/base/debug/activity_analyzer_unittest.cc +++ /dev/null
@@ -1,546 +0,0 @@ -// 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/debug/activity_analyzer.h" - -#include <atomic> -#include <memory> - -#include "base/auto_reset.h" -#include "base/bind.h" -#include "base/debug/activity_tracker.h" -#include "base/files/file.h" -#include "base/files/file_util.h" -#include "base/files/memory_mapped_file.h" -#include "base/files/scoped_temp_dir.h" -#include "base/memory/ptr_util.h" -#include "base/pending_task.h" -#include "base/process/process.h" -#include "base/stl_util.h" -#include "base/synchronization/condition_variable.h" -#include "base/synchronization/lock.h" -#include "base/synchronization/spin_wait.h" -#include "base/threading/platform_thread.h" -#include "base/threading/simple_thread.h" -#include "base/time/time.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace debug { - -namespace { - -class TestActivityTracker : public ThreadActivityTracker { - public: - TestActivityTracker(std::unique_ptr<char[]> memory, size_t mem_size) - : ThreadActivityTracker(memset(memory.get(), 0, mem_size), mem_size), - mem_segment_(std::move(memory)) {} - - ~TestActivityTracker() override = default; - - private: - std::unique_ptr<char[]> mem_segment_; -}; - -} // namespace - - -class ActivityAnalyzerTest : public testing::Test { - public: - const int kMemorySize = 1 << 20; // 1MiB - const int kStackSize = 1 << 10; // 1KiB - - ActivityAnalyzerTest() = default; - - ~ActivityAnalyzerTest() override { - GlobalActivityTracker* global_tracker = GlobalActivityTracker::Get(); - if (global_tracker) { - global_tracker->ReleaseTrackerForCurrentThreadForTesting(); - delete global_tracker; - } - } - - std::unique_ptr<ThreadActivityTracker> CreateActivityTracker() { - std::unique_ptr<char[]> memory(new char[kStackSize]); - return std::make_unique<TestActivityTracker>(std::move(memory), kStackSize); - } - - template <typename Function> - void AsOtherProcess(int64_t pid, Function function) { - std::unique_ptr<GlobalActivityTracker> old_global = - GlobalActivityTracker::ReleaseForTesting(); - ASSERT_TRUE(old_global); - - PersistentMemoryAllocator* old_allocator = old_global->allocator(); - std::unique_ptr<PersistentMemoryAllocator> new_allocator( - std::make_unique<PersistentMemoryAllocator>( - const_cast<void*>(old_allocator->data()), old_allocator->size(), 0, - 0, "", false)); - GlobalActivityTracker::CreateWithAllocator(std::move(new_allocator), 3, - pid); - - function(); - - GlobalActivityTracker::ReleaseForTesting(); - GlobalActivityTracker::SetForTesting(std::move(old_global)); - } - - static void DoNothing() {} -}; - -TEST_F(ActivityAnalyzerTest, ThreadAnalyzerConstruction) { - std::unique_ptr<ThreadActivityTracker> tracker = CreateActivityTracker(); - { - ThreadActivityAnalyzer analyzer(*tracker); - EXPECT_TRUE(analyzer.IsValid()); - EXPECT_EQ(PlatformThread::GetName(), analyzer.GetThreadName()); - } - - // TODO(bcwhite): More tests once Analyzer does more. -} - - -// GlobalActivityAnalyzer tests below. - -namespace { - -class SimpleActivityThread : public SimpleThread { - public: - SimpleActivityThread(const std::string& name, - const void* source, - Activity::Type activity, - const ActivityData& data) - : SimpleThread(name, Options()), - source_(source), - activity_(activity), - data_(data), - ready_(false), - exit_(false), - exit_condition_(&lock_) {} - - ~SimpleActivityThread() override = default; - - void Run() override { - ThreadActivityTracker::ActivityId id = - GlobalActivityTracker::Get() - ->GetOrCreateTrackerForCurrentThread() - ->PushActivity(source_, activity_, data_); - - { - AutoLock auto_lock(lock_); - ready_.store(true, std::memory_order_release); - while (!exit_.load(std::memory_order_relaxed)) - exit_condition_.Wait(); - } - - GlobalActivityTracker::Get()->GetTrackerForCurrentThread()->PopActivity(id); - } - - void Exit() { - AutoLock auto_lock(lock_); - exit_.store(true, std::memory_order_relaxed); - exit_condition_.Signal(); - } - - void WaitReady() { - SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(ready_.load(std::memory_order_acquire)); - } - - private: - const void* source_; - Activity::Type activity_; - ActivityData data_; - - std::atomic<bool> ready_; - std::atomic<bool> exit_; - Lock lock_; - ConditionVariable exit_condition_; - - DISALLOW_COPY_AND_ASSIGN(SimpleActivityThread); -}; - -} // namespace - -TEST_F(ActivityAnalyzerTest, GlobalAnalyzerConstruction) { - GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0); - GlobalActivityTracker::Get()->process_data().SetString("foo", "bar"); - - PersistentMemoryAllocator* allocator = - GlobalActivityTracker::Get()->allocator(); - GlobalActivityAnalyzer analyzer(std::make_unique<PersistentMemoryAllocator>( - const_cast<void*>(allocator->data()), allocator->size(), 0, 0, "", true)); - - // The only thread at this point is the test thread of this process. - const int64_t pid = analyzer.GetFirstProcess(); - ASSERT_NE(0, pid); - ThreadActivityAnalyzer* ta1 = analyzer.GetFirstAnalyzer(pid); - ASSERT_TRUE(ta1); - EXPECT_FALSE(analyzer.GetNextAnalyzer()); - ThreadActivityAnalyzer::ThreadKey tk1 = ta1->GetThreadKey(); - EXPECT_EQ(ta1, analyzer.GetAnalyzerForThread(tk1)); - EXPECT_EQ(0, analyzer.GetNextProcess()); - - // Create a second thread that will do something. - SimpleActivityThread t2("t2", nullptr, Activity::ACT_TASK, - ActivityData::ForTask(11)); - t2.Start(); - t2.WaitReady(); - - // Now there should be two. Calling GetFirstProcess invalidates any - // previously returned analyzer pointers. - ASSERT_EQ(pid, analyzer.GetFirstProcess()); - EXPECT_TRUE(analyzer.GetFirstAnalyzer(pid)); - EXPECT_TRUE(analyzer.GetNextAnalyzer()); - EXPECT_FALSE(analyzer.GetNextAnalyzer()); - EXPECT_EQ(0, analyzer.GetNextProcess()); - - // Let thread exit. - t2.Exit(); - t2.Join(); - - // Now there should be only one again. - ASSERT_EQ(pid, analyzer.GetFirstProcess()); - ThreadActivityAnalyzer* ta2 = analyzer.GetFirstAnalyzer(pid); - ASSERT_TRUE(ta2); - EXPECT_FALSE(analyzer.GetNextAnalyzer()); - ThreadActivityAnalyzer::ThreadKey tk2 = ta2->GetThreadKey(); - EXPECT_EQ(ta2, analyzer.GetAnalyzerForThread(tk2)); - EXPECT_EQ(tk1, tk2); - EXPECT_EQ(0, analyzer.GetNextProcess()); - - // Verify that there is process data. - const ActivityUserData::Snapshot& data_snapshot = - analyzer.GetProcessDataSnapshot(pid); - ASSERT_LE(1U, data_snapshot.size()); - EXPECT_EQ("bar", data_snapshot.at("foo").GetString()); -} - -TEST_F(ActivityAnalyzerTest, GlobalAnalyzerFromSharedMemory) { - SharedMemoryHandle handle1; - SharedMemoryHandle handle2; - - { - std::unique_ptr<SharedMemory> shmem(new SharedMemory()); - ASSERT_TRUE(shmem->CreateAndMapAnonymous(kMemorySize)); - handle1 = shmem->handle().Duplicate(); - ASSERT_TRUE(handle1.IsValid()); - handle2 = shmem->handle().Duplicate(); - ASSERT_TRUE(handle2.IsValid()); - } - - GlobalActivityTracker::CreateWithSharedMemoryHandle(handle1, kMemorySize, 0, - "", 3); - GlobalActivityTracker::Get()->process_data().SetString("foo", "bar"); - - std::unique_ptr<GlobalActivityAnalyzer> analyzer = - GlobalActivityAnalyzer::CreateWithSharedMemoryHandle(handle2, - kMemorySize); - - const int64_t pid = analyzer->GetFirstProcess(); - ASSERT_NE(0, pid); - const ActivityUserData::Snapshot& data_snapshot = - analyzer->GetProcessDataSnapshot(pid); - ASSERT_LE(1U, data_snapshot.size()); - EXPECT_EQ("bar", data_snapshot.at("foo").GetString()); -} - -TEST_F(ActivityAnalyzerTest, UserDataSnapshotTest) { - GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0); - ThreadActivityAnalyzer::Snapshot tracker_snapshot; - - const char string1a[] = "string1a"; - const char string1b[] = "string1b"; - const char string2a[] = "string2a"; - const char string2b[] = "string2b"; - - PersistentMemoryAllocator* allocator = - GlobalActivityTracker::Get()->allocator(); - GlobalActivityAnalyzer global_analyzer( - std::make_unique<PersistentMemoryAllocator>( - const_cast<void*>(allocator->data()), allocator->size(), 0, 0, "", - true)); - - ThreadActivityTracker* tracker = - GlobalActivityTracker::Get()->GetOrCreateTrackerForCurrentThread(); - - { - ScopedActivity activity1(1, 11, 111); - ActivityUserData& user_data1 = activity1.user_data(); - user_data1.Set("raw1", "foo1", 4); - user_data1.SetString("string1", "bar1"); - user_data1.SetChar("char1", '1'); - user_data1.SetInt("int1", -1111); - user_data1.SetUint("uint1", 1111); - user_data1.SetBool("bool1", true); - user_data1.SetReference("ref1", string1a, sizeof(string1a)); - user_data1.SetStringReference("sref1", string1b); - - { - ScopedActivity activity2(2, 22, 222); - ActivityUserData& user_data2 = activity2.user_data(); - user_data2.Set("raw2", "foo2", 4); - user_data2.SetString("string2", "bar2"); - user_data2.SetChar("char2", '2'); - user_data2.SetInt("int2", -2222); - user_data2.SetUint("uint2", 2222); - user_data2.SetBool("bool2", false); - user_data2.SetReference("ref2", string2a, sizeof(string2a)); - user_data2.SetStringReference("sref2", string2b); - - ASSERT_TRUE(tracker->CreateSnapshot(&tracker_snapshot)); - ASSERT_EQ(2U, tracker_snapshot.activity_stack.size()); - - ThreadActivityAnalyzer analyzer(*tracker); - analyzer.AddGlobalInformation(&global_analyzer); - const ThreadActivityAnalyzer::Snapshot& analyzer_snapshot = - analyzer.activity_snapshot(); - ASSERT_EQ(2U, analyzer_snapshot.user_data_stack.size()); - const ActivityUserData::Snapshot& user_data = - analyzer_snapshot.user_data_stack.at(1); - EXPECT_EQ(8U, user_data.size()); - ASSERT_TRUE(ContainsKey(user_data, "raw2")); - EXPECT_EQ("foo2", user_data.at("raw2").Get().as_string()); - ASSERT_TRUE(ContainsKey(user_data, "string2")); - EXPECT_EQ("bar2", user_data.at("string2").GetString().as_string()); - ASSERT_TRUE(ContainsKey(user_data, "char2")); - EXPECT_EQ('2', user_data.at("char2").GetChar()); - ASSERT_TRUE(ContainsKey(user_data, "int2")); - EXPECT_EQ(-2222, user_data.at("int2").GetInt()); - ASSERT_TRUE(ContainsKey(user_data, "uint2")); - EXPECT_EQ(2222U, user_data.at("uint2").GetUint()); - ASSERT_TRUE(ContainsKey(user_data, "bool2")); - EXPECT_FALSE(user_data.at("bool2").GetBool()); - ASSERT_TRUE(ContainsKey(user_data, "ref2")); - EXPECT_EQ(string2a, user_data.at("ref2").GetReference().data()); - EXPECT_EQ(sizeof(string2a), user_data.at("ref2").GetReference().size()); - ASSERT_TRUE(ContainsKey(user_data, "sref2")); - EXPECT_EQ(string2b, user_data.at("sref2").GetStringReference().data()); - EXPECT_EQ(strlen(string2b), - user_data.at("sref2").GetStringReference().size()); - } - - ASSERT_TRUE(tracker->CreateSnapshot(&tracker_snapshot)); - ASSERT_EQ(1U, tracker_snapshot.activity_stack.size()); - - ThreadActivityAnalyzer analyzer(*tracker); - analyzer.AddGlobalInformation(&global_analyzer); - const ThreadActivityAnalyzer::Snapshot& analyzer_snapshot = - analyzer.activity_snapshot(); - ASSERT_EQ(1U, analyzer_snapshot.user_data_stack.size()); - const ActivityUserData::Snapshot& user_data = - analyzer_snapshot.user_data_stack.at(0); - EXPECT_EQ(8U, user_data.size()); - EXPECT_EQ("foo1", user_data.at("raw1").Get().as_string()); - EXPECT_EQ("bar1", user_data.at("string1").GetString().as_string()); - EXPECT_EQ('1', user_data.at("char1").GetChar()); - EXPECT_EQ(-1111, user_data.at("int1").GetInt()); - EXPECT_EQ(1111U, user_data.at("uint1").GetUint()); - EXPECT_TRUE(user_data.at("bool1").GetBool()); - EXPECT_EQ(string1a, user_data.at("ref1").GetReference().data()); - EXPECT_EQ(sizeof(string1a), user_data.at("ref1").GetReference().size()); - EXPECT_EQ(string1b, user_data.at("sref1").GetStringReference().data()); - EXPECT_EQ(strlen(string1b), - user_data.at("sref1").GetStringReference().size()); - } - - ASSERT_TRUE(tracker->CreateSnapshot(&tracker_snapshot)); - ASSERT_EQ(0U, tracker_snapshot.activity_stack.size()); -} - -TEST_F(ActivityAnalyzerTest, GlobalUserDataTest) { - const int64_t pid = GetCurrentProcId(); - GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0); - - const char string1[] = "foo"; - const char string2[] = "bar"; - - PersistentMemoryAllocator* allocator = - GlobalActivityTracker::Get()->allocator(); - GlobalActivityAnalyzer global_analyzer( - std::make_unique<PersistentMemoryAllocator>( - const_cast<void*>(allocator->data()), allocator->size(), 0, 0, "", - true)); - - ActivityUserData& process_data = GlobalActivityTracker::Get()->process_data(); - ASSERT_NE(0U, process_data.id()); - process_data.Set("raw", "foo", 3); - process_data.SetString("string", "bar"); - process_data.SetChar("char", '9'); - process_data.SetInt("int", -9999); - process_data.SetUint("uint", 9999); - process_data.SetBool("bool", true); - process_data.SetReference("ref", string1, sizeof(string1)); - process_data.SetStringReference("sref", string2); - - int64_t first_pid = global_analyzer.GetFirstProcess(); - DCHECK_EQ(pid, first_pid); - const ActivityUserData::Snapshot& snapshot = - global_analyzer.GetProcessDataSnapshot(pid); - ASSERT_TRUE(ContainsKey(snapshot, "raw")); - EXPECT_EQ("foo", snapshot.at("raw").Get().as_string()); - ASSERT_TRUE(ContainsKey(snapshot, "string")); - EXPECT_EQ("bar", snapshot.at("string").GetString().as_string()); - ASSERT_TRUE(ContainsKey(snapshot, "char")); - EXPECT_EQ('9', snapshot.at("char").GetChar()); - ASSERT_TRUE(ContainsKey(snapshot, "int")); - EXPECT_EQ(-9999, snapshot.at("int").GetInt()); - ASSERT_TRUE(ContainsKey(snapshot, "uint")); - EXPECT_EQ(9999U, snapshot.at("uint").GetUint()); - ASSERT_TRUE(ContainsKey(snapshot, "bool")); - EXPECT_TRUE(snapshot.at("bool").GetBool()); - ASSERT_TRUE(ContainsKey(snapshot, "ref")); - EXPECT_EQ(string1, snapshot.at("ref").GetReference().data()); - EXPECT_EQ(sizeof(string1), snapshot.at("ref").GetReference().size()); - ASSERT_TRUE(ContainsKey(snapshot, "sref")); - EXPECT_EQ(string2, snapshot.at("sref").GetStringReference().data()); - EXPECT_EQ(strlen(string2), snapshot.at("sref").GetStringReference().size()); -} - -TEST_F(ActivityAnalyzerTest, GlobalModulesTest) { - GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0); - GlobalActivityTracker* global = GlobalActivityTracker::Get(); - - PersistentMemoryAllocator* allocator = global->allocator(); - GlobalActivityAnalyzer global_analyzer( - std::make_unique<PersistentMemoryAllocator>( - const_cast<void*>(allocator->data()), allocator->size(), 0, 0, "", - true)); - - GlobalActivityTracker::ModuleInfo info1; - info1.is_loaded = true; - info1.address = 0x12345678; - info1.load_time = 1111; - info1.size = 0xABCDEF; - info1.timestamp = 111; - info1.age = 11; - info1.identifier[0] = 1; - info1.file = "anything"; - info1.debug_file = "elsewhere"; - - global->RecordModuleInfo(info1); - std::vector<GlobalActivityTracker::ModuleInfo> modules1; - modules1 = global_analyzer.GetModules(global_analyzer.GetFirstProcess()); - ASSERT_EQ(1U, modules1.size()); - GlobalActivityTracker::ModuleInfo& stored1a = modules1[0]; - EXPECT_EQ(info1.is_loaded, stored1a.is_loaded); - EXPECT_EQ(info1.address, stored1a.address); - EXPECT_NE(info1.load_time, stored1a.load_time); - EXPECT_EQ(info1.size, stored1a.size); - EXPECT_EQ(info1.timestamp, stored1a.timestamp); - EXPECT_EQ(info1.age, stored1a.age); - EXPECT_EQ(info1.identifier[0], stored1a.identifier[0]); - EXPECT_EQ(info1.file, stored1a.file); - EXPECT_EQ(info1.debug_file, stored1a.debug_file); - - info1.is_loaded = false; - global->RecordModuleInfo(info1); - modules1 = global_analyzer.GetModules(global_analyzer.GetFirstProcess()); - ASSERT_EQ(1U, modules1.size()); - GlobalActivityTracker::ModuleInfo& stored1b = modules1[0]; - EXPECT_EQ(info1.is_loaded, stored1b.is_loaded); - EXPECT_EQ(info1.address, stored1b.address); - EXPECT_NE(info1.load_time, stored1b.load_time); - EXPECT_EQ(info1.size, stored1b.size); - EXPECT_EQ(info1.timestamp, stored1b.timestamp); - EXPECT_EQ(info1.age, stored1b.age); - EXPECT_EQ(info1.identifier[0], stored1b.identifier[0]); - EXPECT_EQ(info1.file, stored1b.file); - EXPECT_EQ(info1.debug_file, stored1b.debug_file); - - GlobalActivityTracker::ModuleInfo info2; - info2.is_loaded = true; - info2.address = 0x87654321; - info2.load_time = 2222; - info2.size = 0xFEDCBA; - info2.timestamp = 222; - info2.age = 22; - info2.identifier[0] = 2; - info2.file = "nothing"; - info2.debug_file = "farewell"; - - global->RecordModuleInfo(info2); - std::vector<GlobalActivityTracker::ModuleInfo> modules2; - modules2 = global_analyzer.GetModules(global_analyzer.GetFirstProcess()); - ASSERT_EQ(2U, modules2.size()); - GlobalActivityTracker::ModuleInfo& stored2 = modules2[1]; - EXPECT_EQ(info2.is_loaded, stored2.is_loaded); - EXPECT_EQ(info2.address, stored2.address); - EXPECT_NE(info2.load_time, stored2.load_time); - EXPECT_EQ(info2.size, stored2.size); - EXPECT_EQ(info2.timestamp, stored2.timestamp); - EXPECT_EQ(info2.age, stored2.age); - EXPECT_EQ(info2.identifier[0], stored2.identifier[0]); - EXPECT_EQ(info2.file, stored2.file); - EXPECT_EQ(info2.debug_file, stored2.debug_file); -} - -TEST_F(ActivityAnalyzerTest, GlobalLogMessages) { - GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0); - - PersistentMemoryAllocator* allocator = - GlobalActivityTracker::Get()->allocator(); - GlobalActivityAnalyzer analyzer(std::make_unique<PersistentMemoryAllocator>( - const_cast<void*>(allocator->data()), allocator->size(), 0, 0, "", true)); - - GlobalActivityTracker::Get()->RecordLogMessage("hello world"); - GlobalActivityTracker::Get()->RecordLogMessage("foo bar"); - - std::vector<std::string> messages = analyzer.GetLogMessages(); - ASSERT_EQ(2U, messages.size()); - EXPECT_EQ("hello world", messages[0]); - EXPECT_EQ("foo bar", messages[1]); -} - -TEST_F(ActivityAnalyzerTest, GlobalMultiProcess) { - GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 1001); - GlobalActivityTracker* global = GlobalActivityTracker::Get(); - PersistentMemoryAllocator* allocator = global->allocator(); - EXPECT_EQ(1001, global->process_id()); - - int64_t process_id; - int64_t create_stamp; - ActivityUserData::GetOwningProcessId( - GlobalActivityTracker::Get()->process_data().GetBaseAddress(), - &process_id, &create_stamp); - ASSERT_EQ(1001, process_id); - - GlobalActivityTracker::Get()->process_data().SetInt("pid", - global->process_id()); - - GlobalActivityAnalyzer analyzer(std::make_unique<PersistentMemoryAllocator>( - const_cast<void*>(allocator->data()), allocator->size(), 0, 0, "", true)); - - AsOtherProcess(2002, [&global]() { - ASSERT_NE(global, GlobalActivityTracker::Get()); - EXPECT_EQ(2002, GlobalActivityTracker::Get()->process_id()); - - int64_t process_id; - int64_t create_stamp; - ActivityUserData::GetOwningProcessId( - GlobalActivityTracker::Get()->process_data().GetBaseAddress(), - &process_id, &create_stamp); - ASSERT_EQ(2002, process_id); - - GlobalActivityTracker::Get()->process_data().SetInt( - "pid", GlobalActivityTracker::Get()->process_id()); - }); - ASSERT_EQ(global, GlobalActivityTracker::Get()); - EXPECT_EQ(1001, GlobalActivityTracker::Get()->process_id()); - - const int64_t pid1 = analyzer.GetFirstProcess(); - ASSERT_EQ(1001, pid1); - const int64_t pid2 = analyzer.GetNextProcess(); - ASSERT_EQ(2002, pid2); - EXPECT_EQ(0, analyzer.GetNextProcess()); - - const ActivityUserData::Snapshot& pdata1 = - analyzer.GetProcessDataSnapshot(pid1); - const ActivityUserData::Snapshot& pdata2 = - analyzer.GetProcessDataSnapshot(pid2); - EXPECT_EQ(1001, pdata1.at("pid").GetInt()); - EXPECT_EQ(2002, pdata2.at("pid").GetInt()); -} - -} // namespace debug -} // namespace base
diff --git a/base/debug/activity_tracker_unittest.cc b/base/debug/activity_tracker_unittest.cc deleted file mode 100644 index e2b61a9..0000000 --- a/base/debug/activity_tracker_unittest.cc +++ /dev/null
@@ -1,585 +0,0 @@ -// 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/debug/activity_tracker.h" - -#include <memory> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/files/file.h" -#include "base/files/file_util.h" -#include "base/files/memory_mapped_file.h" -#include "base/files/scoped_temp_dir.h" -#include "base/memory/ptr_util.h" -#include "base/pending_task.h" -#include "base/rand_util.h" -#include "base/synchronization/condition_variable.h" -#include "base/synchronization/lock.h" -#include "base/synchronization/spin_wait.h" -#include "base/threading/platform_thread.h" -#include "base/threading/simple_thread.h" -#include "base/time/time.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace debug { - -namespace { - -class TestActivityTracker : public ThreadActivityTracker { - public: - TestActivityTracker(std::unique_ptr<char[]> memory, size_t mem_size) - : ThreadActivityTracker(memset(memory.get(), 0, mem_size), mem_size), - mem_segment_(std::move(memory)) {} - - ~TestActivityTracker() override = default; - - private: - std::unique_ptr<char[]> mem_segment_; -}; - -} // namespace - - -class ActivityTrackerTest : public testing::Test { - public: - const int kMemorySize = 1 << 20; // 1MiB - const int kStackSize = 1 << 10; // 1KiB - - using ActivityId = ThreadActivityTracker::ActivityId; - - ActivityTrackerTest() = default; - - ~ActivityTrackerTest() override { - GlobalActivityTracker* global_tracker = GlobalActivityTracker::Get(); - if (global_tracker) { - global_tracker->ReleaseTrackerForCurrentThreadForTesting(); - delete global_tracker; - } - } - - std::unique_ptr<ThreadActivityTracker> CreateActivityTracker() { - std::unique_ptr<char[]> memory(new char[kStackSize]); - return std::make_unique<TestActivityTracker>(std::move(memory), kStackSize); - } - - size_t GetGlobalActiveTrackerCount() { - GlobalActivityTracker* global_tracker = GlobalActivityTracker::Get(); - if (!global_tracker) - return 0; - return global_tracker->thread_tracker_count_.load( - std::memory_order_relaxed); - } - - size_t GetGlobalInactiveTrackerCount() { - GlobalActivityTracker* global_tracker = GlobalActivityTracker::Get(); - if (!global_tracker) - return 0; - AutoLock autolock(global_tracker->thread_tracker_allocator_lock_); - return global_tracker->thread_tracker_allocator_.cache_used(); - } - - size_t GetGlobalUserDataMemoryCacheUsed() { - return GlobalActivityTracker::Get()->user_data_allocator_.cache_used(); - } - - void HandleProcessExit(int64_t id, - int64_t stamp, - int code, - GlobalActivityTracker::ProcessPhase phase, - std::string&& command, - ActivityUserData::Snapshot&& data) { - exit_id_ = id; - exit_stamp_ = stamp; - exit_code_ = code; - exit_phase_ = phase; - exit_command_ = std::move(command); - exit_data_ = std::move(data); - } - - int64_t exit_id_ = 0; - int64_t exit_stamp_; - int exit_code_; - GlobalActivityTracker::ProcessPhase exit_phase_; - std::string exit_command_; - ActivityUserData::Snapshot exit_data_; -}; - -TEST_F(ActivityTrackerTest, UserDataTest) { - char buffer[256]; - memset(buffer, 0, sizeof(buffer)); - ActivityUserData data(buffer, sizeof(buffer)); - size_t space = sizeof(buffer) - sizeof(ActivityUserData::MemoryHeader); - ASSERT_EQ(space, data.available_); - - data.SetInt("foo", 1); - space -= 24; - ASSERT_EQ(space, data.available_); - - data.SetUint("b", 1U); // Small names fit beside header in a word. - space -= 16; - ASSERT_EQ(space, data.available_); - - data.Set("c", buffer, 10); - space -= 24; - ASSERT_EQ(space, data.available_); - - data.SetString("dear john", "it's been fun"); - space -= 32; - ASSERT_EQ(space, data.available_); - - data.Set("c", buffer, 20); - ASSERT_EQ(space, data.available_); - - data.SetString("dear john", "but we're done together"); - ASSERT_EQ(space, data.available_); - - data.SetString("dear john", "bye"); - ASSERT_EQ(space, data.available_); - - data.SetChar("d", 'x'); - space -= 8; - ASSERT_EQ(space, data.available_); - - data.SetBool("ee", true); - space -= 16; - ASSERT_EQ(space, data.available_); - - data.SetString("f", ""); - space -= 8; - ASSERT_EQ(space, data.available_); -} - -TEST_F(ActivityTrackerTest, PushPopTest) { - std::unique_ptr<ThreadActivityTracker> tracker = CreateActivityTracker(); - ThreadActivityTracker::Snapshot snapshot; - - ASSERT_TRUE(tracker->CreateSnapshot(&snapshot)); - ASSERT_EQ(0U, snapshot.activity_stack_depth); - ASSERT_EQ(0U, snapshot.activity_stack.size()); - - char origin1; - ActivityId id1 = tracker->PushActivity(&origin1, Activity::ACT_TASK, - ActivityData::ForTask(11)); - ASSERT_TRUE(tracker->CreateSnapshot(&snapshot)); - ASSERT_EQ(1U, snapshot.activity_stack_depth); - ASSERT_EQ(1U, snapshot.activity_stack.size()); - EXPECT_NE(0, snapshot.activity_stack[0].time_internal); - EXPECT_EQ(Activity::ACT_TASK, snapshot.activity_stack[0].activity_type); - EXPECT_EQ(reinterpret_cast<uintptr_t>(&origin1), - snapshot.activity_stack[0].origin_address); - EXPECT_EQ(11U, snapshot.activity_stack[0].data.task.sequence_id); - - char origin2; - char lock2; - ActivityId id2 = tracker->PushActivity(&origin2, Activity::ACT_LOCK, - ActivityData::ForLock(&lock2)); - ASSERT_TRUE(tracker->CreateSnapshot(&snapshot)); - ASSERT_EQ(2U, snapshot.activity_stack_depth); - ASSERT_EQ(2U, snapshot.activity_stack.size()); - EXPECT_LE(snapshot.activity_stack[0].time_internal, - snapshot.activity_stack[1].time_internal); - EXPECT_EQ(Activity::ACT_LOCK, snapshot.activity_stack[1].activity_type); - EXPECT_EQ(reinterpret_cast<uintptr_t>(&origin2), - snapshot.activity_stack[1].origin_address); - EXPECT_EQ(reinterpret_cast<uintptr_t>(&lock2), - snapshot.activity_stack[1].data.lock.lock_address); - - tracker->PopActivity(id2); - ASSERT_TRUE(tracker->CreateSnapshot(&snapshot)); - ASSERT_EQ(1U, snapshot.activity_stack_depth); - ASSERT_EQ(1U, snapshot.activity_stack.size()); - EXPECT_EQ(Activity::ACT_TASK, snapshot.activity_stack[0].activity_type); - EXPECT_EQ(reinterpret_cast<uintptr_t>(&origin1), - snapshot.activity_stack[0].origin_address); - EXPECT_EQ(11U, snapshot.activity_stack[0].data.task.sequence_id); - - tracker->PopActivity(id1); - ASSERT_TRUE(tracker->CreateSnapshot(&snapshot)); - ASSERT_EQ(0U, snapshot.activity_stack_depth); - ASSERT_EQ(0U, snapshot.activity_stack.size()); -} - -TEST_F(ActivityTrackerTest, ScopedTaskTest) { - GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0); - - ThreadActivityTracker* tracker = - GlobalActivityTracker::Get()->GetOrCreateTrackerForCurrentThread(); - ThreadActivityTracker::Snapshot snapshot; - ASSERT_EQ(0U, GetGlobalUserDataMemoryCacheUsed()); - - ASSERT_TRUE(tracker->CreateSnapshot(&snapshot)); - ASSERT_EQ(0U, snapshot.activity_stack_depth); - ASSERT_EQ(0U, snapshot.activity_stack.size()); - - { - PendingTask task1(FROM_HERE, DoNothing()); - ScopedTaskRunActivity activity1(task1); - ActivityUserData& user_data1 = activity1.user_data(); - (void)user_data1; // Tell compiler it's been used. - - ASSERT_TRUE(tracker->CreateSnapshot(&snapshot)); - ASSERT_EQ(1U, snapshot.activity_stack_depth); - ASSERT_EQ(1U, snapshot.activity_stack.size()); - EXPECT_EQ(Activity::ACT_TASK, snapshot.activity_stack[0].activity_type); - - { - PendingTask task2(FROM_HERE, DoNothing()); - ScopedTaskRunActivity activity2(task2); - ActivityUserData& user_data2 = activity2.user_data(); - (void)user_data2; // Tell compiler it's been used. - - ASSERT_TRUE(tracker->CreateSnapshot(&snapshot)); - ASSERT_EQ(2U, snapshot.activity_stack_depth); - ASSERT_EQ(2U, snapshot.activity_stack.size()); - EXPECT_EQ(Activity::ACT_TASK, snapshot.activity_stack[1].activity_type); - } - - ASSERT_TRUE(tracker->CreateSnapshot(&snapshot)); - ASSERT_EQ(1U, snapshot.activity_stack_depth); - ASSERT_EQ(1U, snapshot.activity_stack.size()); - EXPECT_EQ(Activity::ACT_TASK, snapshot.activity_stack[0].activity_type); - } - - ASSERT_TRUE(tracker->CreateSnapshot(&snapshot)); - ASSERT_EQ(0U, snapshot.activity_stack_depth); - ASSERT_EQ(0U, snapshot.activity_stack.size()); - ASSERT_EQ(2U, GetGlobalUserDataMemoryCacheUsed()); -} - -namespace { - -class SimpleLockThread : public SimpleThread { - public: - SimpleLockThread(const std::string& name, Lock* lock) - : SimpleThread(name, Options()), - lock_(lock), - data_changed_(false), - is_running_(false) {} - - ~SimpleLockThread() override = default; - - void Run() override { - ThreadActivityTracker* tracker = - GlobalActivityTracker::Get()->GetOrCreateTrackerForCurrentThread(); - uint32_t pre_version = tracker->GetDataVersionForTesting(); - - is_running_.store(true, std::memory_order_relaxed); - lock_->Acquire(); - data_changed_ = tracker->GetDataVersionForTesting() != pre_version; - lock_->Release(); - is_running_.store(false, std::memory_order_relaxed); - } - - bool IsRunning() { return is_running_.load(std::memory_order_relaxed); } - - bool WasDataChanged() { return data_changed_; }; - - private: - Lock* lock_; - bool data_changed_; - std::atomic<bool> is_running_; - - DISALLOW_COPY_AND_ASSIGN(SimpleLockThread); -}; - -} // namespace - -TEST_F(ActivityTrackerTest, LockTest) { - GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0); - - ThreadActivityTracker* tracker = - GlobalActivityTracker::Get()->GetOrCreateTrackerForCurrentThread(); - ThreadActivityTracker::Snapshot snapshot; - ASSERT_EQ(0U, GetGlobalUserDataMemoryCacheUsed()); - - Lock lock; - uint32_t pre_version = tracker->GetDataVersionForTesting(); - - // Check no activity when only "trying" a lock. - EXPECT_TRUE(lock.Try()); - EXPECT_EQ(pre_version, tracker->GetDataVersionForTesting()); - lock.Release(); - EXPECT_EQ(pre_version, tracker->GetDataVersionForTesting()); - - // Check no activity when acquiring a free lock. - SimpleLockThread t1("locker1", &lock); - t1.Start(); - t1.Join(); - EXPECT_FALSE(t1.WasDataChanged()); - - // Check that activity is recorded when acquring a busy lock. - SimpleLockThread t2("locker2", &lock); - lock.Acquire(); - t2.Start(); - while (!t2.IsRunning()) - PlatformThread::Sleep(TimeDelta::FromMilliseconds(10)); - // t2 can't join until the lock is released but have to give time for t2 to - // actually block on the lock before releasing it or the results will not - // be correct. - PlatformThread::Sleep(TimeDelta::FromMilliseconds(200)); - lock.Release(); - // Now the results will be valid. - t2.Join(); - EXPECT_TRUE(t2.WasDataChanged()); -} - -TEST_F(ActivityTrackerTest, ExceptionTest) { - GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0); - GlobalActivityTracker* global = GlobalActivityTracker::Get(); - - ThreadActivityTracker* tracker = - GlobalActivityTracker::Get()->GetOrCreateTrackerForCurrentThread(); - ThreadActivityTracker::Snapshot snapshot; - ASSERT_EQ(0U, GetGlobalUserDataMemoryCacheUsed()); - - ASSERT_TRUE(tracker->CreateSnapshot(&snapshot)); - ASSERT_EQ(0U, snapshot.last_exception.activity_type); - - char origin; - global->RecordException(&origin, 42); - - ASSERT_TRUE(tracker->CreateSnapshot(&snapshot)); - EXPECT_EQ(Activity::ACT_EXCEPTION, snapshot.last_exception.activity_type); - EXPECT_EQ(reinterpret_cast<uintptr_t>(&origin), - snapshot.last_exception.origin_address); - EXPECT_EQ(42U, snapshot.last_exception.data.exception.code); -} - -TEST_F(ActivityTrackerTest, CreateWithFileTest) { - const char temp_name[] = "CreateWithFileTest"; - ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - FilePath temp_file = temp_dir.GetPath().AppendASCII(temp_name); - const size_t temp_size = 64 << 10; // 64 KiB - - // Create a global tracker on a new file. - ASSERT_FALSE(PathExists(temp_file)); - GlobalActivityTracker::CreateWithFile(temp_file, temp_size, 0, "foo", 3); - GlobalActivityTracker* global = GlobalActivityTracker::Get(); - EXPECT_EQ(std::string("foo"), global->allocator()->Name()); - global->ReleaseTrackerForCurrentThreadForTesting(); - delete global; - - // Create a global tracker over an existing file, replacing it. If the - // replacement doesn't work, the name will remain as it was first created. - ASSERT_TRUE(PathExists(temp_file)); - GlobalActivityTracker::CreateWithFile(temp_file, temp_size, 0, "bar", 3); - global = GlobalActivityTracker::Get(); - EXPECT_EQ(std::string("bar"), global->allocator()->Name()); - global->ReleaseTrackerForCurrentThreadForTesting(); - delete global; -} - - -// GlobalActivityTracker tests below. - -TEST_F(ActivityTrackerTest, BasicTest) { - GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0); - GlobalActivityTracker* global = GlobalActivityTracker::Get(); - - // Ensure the data repositories have backing store, indicated by non-zero ID. - EXPECT_NE(0U, global->process_data().id()); -} - -namespace { - -class SimpleActivityThread : public SimpleThread { - public: - SimpleActivityThread(const std::string& name, - const void* origin, - Activity::Type activity, - const ActivityData& data) - : SimpleThread(name, Options()), - origin_(origin), - activity_(activity), - data_(data), - ready_(false), - exit_(false), - exit_condition_(&lock_) {} - - ~SimpleActivityThread() override = default; - - void Run() override { - ThreadActivityTracker::ActivityId id = - GlobalActivityTracker::Get() - ->GetOrCreateTrackerForCurrentThread() - ->PushActivity(origin_, activity_, data_); - - { - AutoLock auto_lock(lock_); - ready_.store(true, std::memory_order_release); - while (!exit_.load(std::memory_order_relaxed)) - exit_condition_.Wait(); - } - - GlobalActivityTracker::Get()->GetTrackerForCurrentThread()->PopActivity(id); - } - - void Exit() { - AutoLock auto_lock(lock_); - exit_.store(true, std::memory_order_relaxed); - exit_condition_.Signal(); - } - - void WaitReady() { - SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(ready_.load(std::memory_order_acquire)); - } - - private: - const void* origin_; - Activity::Type activity_; - ActivityData data_; - - std::atomic<bool> ready_; - std::atomic<bool> exit_; - Lock lock_; - ConditionVariable exit_condition_; - - DISALLOW_COPY_AND_ASSIGN(SimpleActivityThread); -}; - -} // namespace - -TEST_F(ActivityTrackerTest, ThreadDeathTest) { - GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0); - GlobalActivityTracker::Get()->GetOrCreateTrackerForCurrentThread(); - const size_t starting_active = GetGlobalActiveTrackerCount(); - const size_t starting_inactive = GetGlobalInactiveTrackerCount(); - - SimpleActivityThread t1("t1", nullptr, Activity::ACT_TASK, - ActivityData::ForTask(11)); - t1.Start(); - t1.WaitReady(); - EXPECT_EQ(starting_active + 1, GetGlobalActiveTrackerCount()); - EXPECT_EQ(starting_inactive, GetGlobalInactiveTrackerCount()); - - t1.Exit(); - t1.Join(); - EXPECT_EQ(starting_active, GetGlobalActiveTrackerCount()); - EXPECT_EQ(starting_inactive + 1, GetGlobalInactiveTrackerCount()); - - // Start another thread and ensure it re-uses the existing memory. - - SimpleActivityThread t2("t2", nullptr, Activity::ACT_TASK, - ActivityData::ForTask(22)); - t2.Start(); - t2.WaitReady(); - EXPECT_EQ(starting_active + 1, GetGlobalActiveTrackerCount()); - EXPECT_EQ(starting_inactive, GetGlobalInactiveTrackerCount()); - - t2.Exit(); - t2.Join(); - EXPECT_EQ(starting_active, GetGlobalActiveTrackerCount()); - EXPECT_EQ(starting_inactive + 1, GetGlobalInactiveTrackerCount()); -} - -TEST_F(ActivityTrackerTest, ProcessDeathTest) { - // This doesn't actually create and destroy a process. Instead, it uses for- - // testing interfaces to simulate data created by other processes. - const int64_t other_process_id = GetCurrentProcId() + 1; - - GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0); - GlobalActivityTracker* global = GlobalActivityTracker::Get(); - ThreadActivityTracker* thread = global->GetOrCreateTrackerForCurrentThread(); - - // Get callbacks for process exit. - global->SetProcessExitCallback( - Bind(&ActivityTrackerTest::HandleProcessExit, Unretained(this))); - - // Pretend than another process has started. - global->RecordProcessLaunch(other_process_id, FILE_PATH_LITERAL("foo --bar")); - - // Do some activities. - PendingTask task(FROM_HERE, DoNothing()); - ScopedTaskRunActivity activity(task); - ActivityUserData& user_data = activity.user_data(); - ASSERT_NE(0U, user_data.id()); - - // Get the memory-allocator references to that data. - PersistentMemoryAllocator::Reference proc_data_ref = - global->allocator()->GetAsReference( - global->process_data().GetBaseAddress(), - GlobalActivityTracker::kTypeIdProcessDataRecord); - ASSERT_TRUE(proc_data_ref); - PersistentMemoryAllocator::Reference tracker_ref = - global->allocator()->GetAsReference( - thread->GetBaseAddress(), - GlobalActivityTracker::kTypeIdActivityTracker); - ASSERT_TRUE(tracker_ref); - PersistentMemoryAllocator::Reference user_data_ref = - global->allocator()->GetAsReference( - user_data.GetBaseAddress(), - GlobalActivityTracker::kTypeIdUserDataRecord); - ASSERT_TRUE(user_data_ref); - - // Make a copy of the thread-tracker state so it can be restored later. - const size_t tracker_size = global->allocator()->GetAllocSize(tracker_ref); - std::unique_ptr<char[]> tracker_copy(new char[tracker_size]); - memcpy(tracker_copy.get(), thread->GetBaseAddress(), tracker_size); - - // Change the objects to appear to be owned by another process. Use a "past" - // time so that exit-time is always later than create-time. - const int64_t past_stamp = Time::Now().ToInternalValue() - 1; - int64_t owning_id; - int64_t stamp; - ASSERT_TRUE(ActivityUserData::GetOwningProcessId( - global->process_data().GetBaseAddress(), &owning_id, &stamp)); - EXPECT_NE(other_process_id, owning_id); - ASSERT_TRUE(ThreadActivityTracker::GetOwningProcessId( - thread->GetBaseAddress(), &owning_id, &stamp)); - EXPECT_NE(other_process_id, owning_id); - ASSERT_TRUE(ActivityUserData::GetOwningProcessId(user_data.GetBaseAddress(), - &owning_id, &stamp)); - EXPECT_NE(other_process_id, owning_id); - global->process_data().SetOwningProcessIdForTesting(other_process_id, - past_stamp); - thread->SetOwningProcessIdForTesting(other_process_id, past_stamp); - user_data.SetOwningProcessIdForTesting(other_process_id, past_stamp); - ASSERT_TRUE(ActivityUserData::GetOwningProcessId( - global->process_data().GetBaseAddress(), &owning_id, &stamp)); - EXPECT_EQ(other_process_id, owning_id); - ASSERT_TRUE(ThreadActivityTracker::GetOwningProcessId( - thread->GetBaseAddress(), &owning_id, &stamp)); - EXPECT_EQ(other_process_id, owning_id); - ASSERT_TRUE(ActivityUserData::GetOwningProcessId(user_data.GetBaseAddress(), - &owning_id, &stamp)); - EXPECT_EQ(other_process_id, owning_id); - - // Check that process exit will perform callback and free the allocations. - ASSERT_EQ(0, exit_id_); - ASSERT_EQ(GlobalActivityTracker::kTypeIdProcessDataRecord, - global->allocator()->GetType(proc_data_ref)); - ASSERT_EQ(GlobalActivityTracker::kTypeIdActivityTracker, - global->allocator()->GetType(tracker_ref)); - ASSERT_EQ(GlobalActivityTracker::kTypeIdUserDataRecord, - global->allocator()->GetType(user_data_ref)); - global->RecordProcessExit(other_process_id, 0); - EXPECT_EQ(other_process_id, exit_id_); - EXPECT_EQ("foo --bar", exit_command_); - EXPECT_EQ(GlobalActivityTracker::kTypeIdProcessDataRecordFree, - global->allocator()->GetType(proc_data_ref)); - EXPECT_EQ(GlobalActivityTracker::kTypeIdActivityTrackerFree, - global->allocator()->GetType(tracker_ref)); - EXPECT_EQ(GlobalActivityTracker::kTypeIdUserDataRecordFree, - global->allocator()->GetType(user_data_ref)); - - // Restore memory contents and types so things don't crash when doing real - // process clean-up. - memcpy(const_cast<void*>(thread->GetBaseAddress()), tracker_copy.get(), - tracker_size); - global->allocator()->ChangeType( - proc_data_ref, GlobalActivityTracker::kTypeIdProcessDataRecord, - GlobalActivityTracker::kTypeIdUserDataRecordFree, false); - global->allocator()->ChangeType( - tracker_ref, GlobalActivityTracker::kTypeIdActivityTracker, - GlobalActivityTracker::kTypeIdActivityTrackerFree, false); - global->allocator()->ChangeType( - user_data_ref, GlobalActivityTracker::kTypeIdUserDataRecord, - GlobalActivityTracker::kTypeIdUserDataRecordFree, false); -} - -} // namespace debug -} // namespace base
diff --git a/base/debug/alias_unittest.cc b/base/debug/alias_unittest.cc deleted file mode 100644 index 66682f1..0000000 --- a/base/debug/alias_unittest.cc +++ /dev/null
@@ -1,28 +0,0 @@ -// 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 <memory> -#include <string> - -#include "base/debug/alias.h" -#include "testing/gtest/include/gtest/gtest.h" - -TEST(DebugAlias, Test) { - std::unique_ptr<std::string> input = - std::make_unique<std::string>("string contents"); - - // Verify the contents get copied + the new local variable has the right type. - DEBUG_ALIAS_FOR_CSTR(copy1, input->c_str(), 100 /* > input->size() */); - static_assert(sizeof(copy1) == 100, - "Verification that copy1 has expected size"); - EXPECT_STREQ("string contents", copy1); - - // Verify that the copy is properly null-terminated even when it is smaller - // than the input string. - DEBUG_ALIAS_FOR_CSTR(copy2, input->c_str(), 3 /* < input->size() */); - static_assert(sizeof(copy2) == 3, - "Verification that copy2 has expected size"); - EXPECT_STREQ("st", copy2); - EXPECT_EQ('\0', copy2[2]); -}
diff --git a/base/debug/crash_logging_unittest.cc b/base/debug/crash_logging_unittest.cc deleted file mode 100644 index c10d36e..0000000 --- a/base/debug/crash_logging_unittest.cc +++ /dev/null
@@ -1,17 +0,0 @@ -// 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/debug/crash_logging.h" - -#include "testing/gtest/include/gtest/gtest.h" - -TEST(CrashLoggingTest, UninitializedCrashKeyStringSupport) { - auto* crash_key = base::debug::AllocateCrashKeyString( - "test", base::debug::CrashKeySize::Size32); - EXPECT_FALSE(crash_key); - - base::debug::SetCrashKeyString(crash_key, "value"); - - base::debug::ClearCrashKeyString(crash_key); -}
diff --git a/base/debug/debugger_unittest.cc b/base/debug/debugger_unittest.cc deleted file mode 100644 index 23ea83d..0000000 --- a/base/debug/debugger_unittest.cc +++ /dev/null
@@ -1,43 +0,0 @@ -// 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/debug/debugger.h" - -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -#if defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID) -void CrashWithBreakDebugger() { - base::debug::SetSuppressDebugUI(false); - base::debug::BreakDebugger(); - -#if defined(OS_WIN) - // This should not be executed. - _exit(125); -#endif -} -#endif // defined(GTEST_HAS_DEATH_TEST) - -} // namespace - -// Death tests misbehave on Android. -#if defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID) - -TEST(Debugger, CrashAtBreakpoint) { - EXPECT_DEATH(CrashWithBreakDebugger(), ""); -} - -#if defined(OS_WIN) -TEST(Debugger, DoesntExecuteBeyondBreakpoint) { - EXPECT_EXIT(CrashWithBreakDebugger(), - ::testing::ExitedWithCode(0x80000003), ""); -} -#endif // defined(OS_WIN) - -#else // defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID) -TEST(Debugger, NoTest) { -} -#endif // defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
diff --git a/base/debug/elf_reader_linux_unittest.cc b/base/debug/elf_reader_linux_unittest.cc deleted file mode 100644 index 88ed502..0000000 --- a/base/debug/elf_reader_linux_unittest.cc +++ /dev/null
@@ -1,70 +0,0 @@ -// 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/debug/elf_reader_linux.h" - -#include <dlfcn.h> - -#include "base/files/memory_mapped_file.h" -#include "base/strings/string_util.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -extern char __executable_start; - -namespace base { -namespace debug { - -// The linker flag --build-id is passed only on official builds. Clang does not -// enable it by default and we do not have build id section in non-official -// builds. -#if defined(OFFICIAL_BUILD) -TEST(ElfReaderTest, ReadElfBuildId) { - Optional<std::string> build_id = ReadElfBuildId(&__executable_start); - ASSERT_TRUE(build_id); - const size_t kGuidBytes = 20; - EXPECT_EQ(2 * kGuidBytes, build_id.value().size()); - for (char c : *build_id) { - EXPECT_TRUE(IsHexDigit(c)); - EXPECT_FALSE(IsAsciiLower(c)); - } -} -#endif - -TEST(ElfReaderTest, ReadElfLibraryName) { -#if defined(OS_ANDROID) - // On Android the library loader memory maps the full so file. - const char kLibraryName[] = "lib_base_unittests__library"; - const void* addr = &__executable_start; -#else - // On Linux the executable does not contain soname and is not mapped till - // dynamic segment. So, use malloc wrapper so file on which the test already - // depends on. - const char kLibraryName[] = MALLOC_WRAPPER_LIB; - // Find any symbol in the loaded file. - void* handle = dlopen(kLibraryName, RTLD_NOW | RTLD_LOCAL); - const void* init_addr = dlsym(handle, "_init"); - // Use this symbol to get full path to the loaded library. - Dl_info info; - int res = dladdr(init_addr, &info); - ASSERT_NE(0, res); - std::string filename(info.dli_fname); - EXPECT_FALSE(filename.empty()); - EXPECT_NE(std::string::npos, filename.find(kLibraryName)); - - // Memory map the so file and use it to test reading so name. - MemoryMappedFile file; - file.Initialize(FilePath(filename)); - const void* addr = file.data(); -#endif - - auto name = ReadElfLibraryName(addr); - ASSERT_TRUE(name); - EXPECT_NE(std::string::npos, name->find(kLibraryName)) - << "Library name " << *name << " doesn't contain expected " - << kLibraryName; -} - -} // namespace debug -} // namespace base
diff --git a/base/debug/leak_tracker_unittest.cc b/base/debug/leak_tracker_unittest.cc deleted file mode 100644 index b9ecdcf..0000000 --- a/base/debug/leak_tracker_unittest.cc +++ /dev/null
@@ -1,115 +0,0 @@ -// 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/debug/leak_tracker.h" - -#include <memory> - -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace debug { - -namespace { - -class ClassA { - private: - LeakTracker<ClassA> leak_tracker_; -}; - -class ClassB { - private: - LeakTracker<ClassB> leak_tracker_; -}; - -#ifndef ENABLE_LEAK_TRACKER - -// If leak tracking is disabled, we should do nothing. -TEST(LeakTrackerTest, NotEnabled) { - EXPECT_EQ(-1, LeakTracker<ClassA>::NumLiveInstances()); - EXPECT_EQ(-1, LeakTracker<ClassB>::NumLiveInstances()); - - // Use unique_ptr so compiler doesn't complain about unused variables. - std::unique_ptr<ClassA> a1(new ClassA); - std::unique_ptr<ClassB> b1(new ClassB); - std::unique_ptr<ClassB> b2(new ClassB); - - EXPECT_EQ(-1, LeakTracker<ClassA>::NumLiveInstances()); - EXPECT_EQ(-1, LeakTracker<ClassB>::NumLiveInstances()); -} - -#else - -TEST(LeakTrackerTest, Basic) { - { - ClassA a1; - - EXPECT_EQ(1, LeakTracker<ClassA>::NumLiveInstances()); - EXPECT_EQ(0, LeakTracker<ClassB>::NumLiveInstances()); - - ClassB b1; - ClassB b2; - - EXPECT_EQ(1, LeakTracker<ClassA>::NumLiveInstances()); - EXPECT_EQ(2, LeakTracker<ClassB>::NumLiveInstances()); - - std::unique_ptr<ClassA> a2(new ClassA); - - EXPECT_EQ(2, LeakTracker<ClassA>::NumLiveInstances()); - EXPECT_EQ(2, LeakTracker<ClassB>::NumLiveInstances()); - - a2.reset(); - - EXPECT_EQ(1, LeakTracker<ClassA>::NumLiveInstances()); - EXPECT_EQ(2, LeakTracker<ClassB>::NumLiveInstances()); - } - - EXPECT_EQ(0, LeakTracker<ClassA>::NumLiveInstances()); - EXPECT_EQ(0, LeakTracker<ClassB>::NumLiveInstances()); -} - -// Try some orderings of create/remove to hit different cases in the linked-list -// assembly. -TEST(LeakTrackerTest, LinkedList) { - EXPECT_EQ(0, LeakTracker<ClassB>::NumLiveInstances()); - - std::unique_ptr<ClassA> a1(new ClassA); - std::unique_ptr<ClassA> a2(new ClassA); - std::unique_ptr<ClassA> a3(new ClassA); - std::unique_ptr<ClassA> a4(new ClassA); - - EXPECT_EQ(4, LeakTracker<ClassA>::NumLiveInstances()); - - // Remove the head of the list (a1). - a1.reset(); - EXPECT_EQ(3, LeakTracker<ClassA>::NumLiveInstances()); - - // Remove the tail of the list (a4). - a4.reset(); - EXPECT_EQ(2, LeakTracker<ClassA>::NumLiveInstances()); - - // Append to the new tail of the list (a3). - std::unique_ptr<ClassA> a5(new ClassA); - EXPECT_EQ(3, LeakTracker<ClassA>::NumLiveInstances()); - - a2.reset(); - a3.reset(); - - EXPECT_EQ(1, LeakTracker<ClassA>::NumLiveInstances()); - - a5.reset(); - EXPECT_EQ(0, LeakTracker<ClassA>::NumLiveInstances()); -} - -TEST(LeakTrackerTest, NoOpCheckForLeaks) { - // There are no live instances of ClassA, so this should do nothing. - LeakTracker<ClassA>::CheckForLeaks(); -} - -#endif // ENABLE_LEAK_TRACKER - -} // namespace - -} // namespace debug -} // namespace base
diff --git a/base/debug/proc_maps_linux_unittest.cc b/base/debug/proc_maps_linux_unittest.cc deleted file mode 100644 index d291507..0000000 --- a/base/debug/proc_maps_linux_unittest.cc +++ /dev/null
@@ -1,328 +0,0 @@ -// 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 <stddef.h> -#include <stdint.h> - -#include "base/debug/proc_maps_linux.h" -#include "base/files/file_path.h" -#include "base/macros.h" -#include "base/path_service.h" -#include "base/strings/stringprintf.h" -#include "base/threading/platform_thread.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace debug { - -TEST(ProcMapsTest, Empty) { - std::vector<MappedMemoryRegion> regions; - EXPECT_TRUE(ParseProcMaps("", ®ions)); - EXPECT_EQ(0u, regions.size()); -} - -TEST(ProcMapsTest, NoSpaces) { - static const char kNoSpaces[] = - "00400000-0040b000 r-xp 00002200 fc:00 794418 /bin/cat\n"; - - std::vector<MappedMemoryRegion> regions; - ASSERT_TRUE(ParseProcMaps(kNoSpaces, ®ions)); - ASSERT_EQ(1u, regions.size()); - - EXPECT_EQ(0x00400000u, regions[0].start); - EXPECT_EQ(0x0040b000u, regions[0].end); - EXPECT_EQ(0x00002200u, regions[0].offset); - EXPECT_EQ("/bin/cat", regions[0].path); -} - -TEST(ProcMapsTest, Spaces) { - static const char kSpaces[] = - "00400000-0040b000 r-xp 00002200 fc:00 794418 /bin/space cat\n"; - - std::vector<MappedMemoryRegion> regions; - ASSERT_TRUE(ParseProcMaps(kSpaces, ®ions)); - ASSERT_EQ(1u, regions.size()); - - EXPECT_EQ(0x00400000u, regions[0].start); - EXPECT_EQ(0x0040b000u, regions[0].end); - EXPECT_EQ(0x00002200u, regions[0].offset); - EXPECT_EQ("/bin/space cat", regions[0].path); -} - -TEST(ProcMapsTest, NoNewline) { - static const char kNoSpaces[] = - "00400000-0040b000 r-xp 00002200 fc:00 794418 /bin/cat"; - - std::vector<MappedMemoryRegion> regions; - ASSERT_FALSE(ParseProcMaps(kNoSpaces, ®ions)); -} - -TEST(ProcMapsTest, NoPath) { - static const char kNoPath[] = - "00400000-0040b000 rw-p 00000000 00:00 0 \n"; - - std::vector<MappedMemoryRegion> regions; - ASSERT_TRUE(ParseProcMaps(kNoPath, ®ions)); - ASSERT_EQ(1u, regions.size()); - - EXPECT_EQ(0x00400000u, regions[0].start); - EXPECT_EQ(0x0040b000u, regions[0].end); - EXPECT_EQ(0x00000000u, regions[0].offset); - EXPECT_EQ("", regions[0].path); -} - -TEST(ProcMapsTest, Heap) { - static const char kHeap[] = - "022ac000-022cd000 rw-p 00000000 00:00 0 [heap]\n"; - - std::vector<MappedMemoryRegion> regions; - ASSERT_TRUE(ParseProcMaps(kHeap, ®ions)); - ASSERT_EQ(1u, regions.size()); - - EXPECT_EQ(0x022ac000u, regions[0].start); - EXPECT_EQ(0x022cd000u, regions[0].end); - EXPECT_EQ(0x00000000u, regions[0].offset); - EXPECT_EQ("[heap]", regions[0].path); -} - -#if defined(ARCH_CPU_32_BITS) -TEST(ProcMapsTest, Stack32) { - static const char kStack[] = - "beb04000-beb25000 rw-p 00000000 00:00 0 [stack]\n"; - - std::vector<MappedMemoryRegion> regions; - ASSERT_TRUE(ParseProcMaps(kStack, ®ions)); - ASSERT_EQ(1u, regions.size()); - - EXPECT_EQ(0xbeb04000u, regions[0].start); - EXPECT_EQ(0xbeb25000u, regions[0].end); - EXPECT_EQ(0x00000000u, regions[0].offset); - EXPECT_EQ("[stack]", regions[0].path); -} -#elif defined(ARCH_CPU_64_BITS) -TEST(ProcMapsTest, Stack64) { - static const char kStack[] = - "7fff69c5b000-7fff69c7d000 rw-p 00000000 00:00 0 [stack]\n"; - - std::vector<MappedMemoryRegion> regions; - ASSERT_TRUE(ParseProcMaps(kStack, ®ions)); - ASSERT_EQ(1u, regions.size()); - - EXPECT_EQ(0x7fff69c5b000u, regions[0].start); - EXPECT_EQ(0x7fff69c7d000u, regions[0].end); - EXPECT_EQ(0x00000000u, regions[0].offset); - EXPECT_EQ("[stack]", regions[0].path); -} -#endif - -TEST(ProcMapsTest, Multiple) { - static const char kMultiple[] = - "00400000-0040b000 r-xp 00000000 fc:00 794418 /bin/cat\n" - "0060a000-0060b000 r--p 0000a000 fc:00 794418 /bin/cat\n" - "0060b000-0060c000 rw-p 0000b000 fc:00 794418 /bin/cat\n"; - - std::vector<MappedMemoryRegion> regions; - ASSERT_TRUE(ParseProcMaps(kMultiple, ®ions)); - ASSERT_EQ(3u, regions.size()); - - EXPECT_EQ(0x00400000u, regions[0].start); - EXPECT_EQ(0x0040b000u, regions[0].end); - EXPECT_EQ(0x00000000u, regions[0].offset); - EXPECT_EQ("/bin/cat", regions[0].path); - - EXPECT_EQ(0x0060a000u, regions[1].start); - EXPECT_EQ(0x0060b000u, regions[1].end); - EXPECT_EQ(0x0000a000u, regions[1].offset); - EXPECT_EQ("/bin/cat", regions[1].path); - - EXPECT_EQ(0x0060b000u, regions[2].start); - EXPECT_EQ(0x0060c000u, regions[2].end); - EXPECT_EQ(0x0000b000u, regions[2].offset); - EXPECT_EQ("/bin/cat", regions[2].path); -} - -TEST(ProcMapsTest, Permissions) { - static struct { - const char* input; - uint8_t permissions; - } kTestCases[] = { - {"00400000-0040b000 ---s 00000000 fc:00 794418 /bin/cat\n", 0}, - {"00400000-0040b000 ---S 00000000 fc:00 794418 /bin/cat\n", 0}, - {"00400000-0040b000 r--s 00000000 fc:00 794418 /bin/cat\n", - MappedMemoryRegion::READ}, - {"00400000-0040b000 -w-s 00000000 fc:00 794418 /bin/cat\n", - MappedMemoryRegion::WRITE}, - {"00400000-0040b000 --xs 00000000 fc:00 794418 /bin/cat\n", - MappedMemoryRegion::EXECUTE}, - {"00400000-0040b000 rwxs 00000000 fc:00 794418 /bin/cat\n", - MappedMemoryRegion::READ | MappedMemoryRegion::WRITE | - MappedMemoryRegion::EXECUTE}, - {"00400000-0040b000 ---p 00000000 fc:00 794418 /bin/cat\n", - MappedMemoryRegion::PRIVATE}, - {"00400000-0040b000 r--p 00000000 fc:00 794418 /bin/cat\n", - MappedMemoryRegion::READ | MappedMemoryRegion::PRIVATE}, - {"00400000-0040b000 -w-p 00000000 fc:00 794418 /bin/cat\n", - MappedMemoryRegion::WRITE | MappedMemoryRegion::PRIVATE}, - {"00400000-0040b000 --xp 00000000 fc:00 794418 /bin/cat\n", - MappedMemoryRegion::EXECUTE | MappedMemoryRegion::PRIVATE}, - {"00400000-0040b000 rwxp 00000000 fc:00 794418 /bin/cat\n", - MappedMemoryRegion::READ | MappedMemoryRegion::WRITE | - MappedMemoryRegion::EXECUTE | MappedMemoryRegion::PRIVATE}, - }; - - for (size_t i = 0; i < arraysize(kTestCases); ++i) { - SCOPED_TRACE( - base::StringPrintf("kTestCases[%zu] = %s", i, kTestCases[i].input)); - - std::vector<MappedMemoryRegion> regions; - EXPECT_TRUE(ParseProcMaps(kTestCases[i].input, ®ions)); - EXPECT_EQ(1u, regions.size()); - if (regions.empty()) - continue; - EXPECT_EQ(kTestCases[i].permissions, regions[0].permissions); - } -} - -#if defined(ADDRESS_SANITIZER) -// AddressSanitizer may move local variables to a dedicated "fake stack" which -// is outside the stack region listed in /proc/self/maps. We disable ASan -// instrumentation for this function to force the variable to be local. -__attribute__((no_sanitize_address)) -#endif -void CheckProcMapsRegions(const std::vector<MappedMemoryRegion> ®ions) { - // We should be able to find both the current executable as well as the stack - // mapped into memory. Use the address of |exe_path| as a way of finding the - // stack. - FilePath exe_path; - EXPECT_TRUE(PathService::Get(FILE_EXE, &exe_path)); - uintptr_t address = reinterpret_cast<uintptr_t>(&exe_path); - bool found_exe = false; - bool found_stack = false; - bool found_address = false; - - for (size_t i = 0; i < regions.size(); ++i) { - if (regions[i].path == exe_path.value()) { - // It's OK to find the executable mapped multiple times as there'll be - // multiple sections (e.g., text, data). - found_exe = true; - } - - if (regions[i].path == "[stack]") { -// On Android the test is run on a background thread, since [stack] is for -// the main thread, we cannot test this. -#if !defined(OS_ANDROID) - EXPECT_GE(address, regions[i].start); - EXPECT_LT(address, regions[i].end); -#endif - EXPECT_TRUE(regions[i].permissions & MappedMemoryRegion::READ); - EXPECT_TRUE(regions[i].permissions & MappedMemoryRegion::WRITE); - EXPECT_FALSE(regions[i].permissions & MappedMemoryRegion::EXECUTE); - EXPECT_TRUE(regions[i].permissions & MappedMemoryRegion::PRIVATE); - EXPECT_FALSE(found_stack) << "Found duplicate stacks"; - found_stack = true; - } - - if (address >= regions[i].start && address < regions[i].end) { - EXPECT_FALSE(found_address) << "Found same address in multiple regions"; - found_address = true; - } - } - - EXPECT_TRUE(found_exe); - EXPECT_TRUE(found_stack); - EXPECT_TRUE(found_address); -} - -TEST(ProcMapsTest, ReadProcMaps) { - std::string proc_maps; - ASSERT_TRUE(ReadProcMaps(&proc_maps)); - - std::vector<MappedMemoryRegion> regions; - ASSERT_TRUE(ParseProcMaps(proc_maps, ®ions)); - ASSERT_FALSE(regions.empty()); - - CheckProcMapsRegions(regions); -} - -TEST(ProcMapsTest, ReadProcMapsNonEmptyString) { - std::string old_string("I forgot to clear the string"); - std::string proc_maps(old_string); - ASSERT_TRUE(ReadProcMaps(&proc_maps)); - EXPECT_EQ(std::string::npos, proc_maps.find(old_string)); -} - -TEST(ProcMapsTest, MissingFields) { - static const char* const kTestCases[] = { - "00400000\n", // Missing end + beyond. - "00400000-0040b000\n", // Missing perms + beyond. - "00400000-0040b000 r-xp\n", // Missing offset + beyond. - "00400000-0040b000 r-xp 00000000\n", // Missing device + beyond. - "00400000-0040b000 r-xp 00000000 fc:00\n", // Missing inode + beyond. - "00400000-0040b000 00000000 fc:00 794418 /bin/cat\n", // Missing perms. - "00400000-0040b000 r-xp fc:00 794418 /bin/cat\n", // Missing offset. - "00400000-0040b000 r-xp 00000000 fc:00 /bin/cat\n", // Missing inode. - "00400000 r-xp 00000000 fc:00 794418 /bin/cat\n", // Missing end. - "-0040b000 r-xp 00000000 fc:00 794418 /bin/cat\n", // Missing start. - "00400000-0040b000 r-xp 00000000 794418 /bin/cat\n", // Missing device. - }; - - for (size_t i = 0; i < arraysize(kTestCases); ++i) { - SCOPED_TRACE(base::StringPrintf("kTestCases[%zu] = %s", i, kTestCases[i])); - std::vector<MappedMemoryRegion> regions; - EXPECT_FALSE(ParseProcMaps(kTestCases[i], ®ions)); - } -} - -TEST(ProcMapsTest, InvalidInput) { - static const char* const kTestCases[] = { - "thisisal-0040b000 rwxp 00000000 fc:00 794418 /bin/cat\n", - "0040000d-linvalid rwxp 00000000 fc:00 794418 /bin/cat\n", - "00400000-0040b000 inpu 00000000 fc:00 794418 /bin/cat\n", - "00400000-0040b000 rwxp tforproc fc:00 794418 /bin/cat\n", - "00400000-0040b000 rwxp 00000000 ma:ps 794418 /bin/cat\n", - "00400000-0040b000 rwxp 00000000 fc:00 parse! /bin/cat\n", - }; - - for (size_t i = 0; i < arraysize(kTestCases); ++i) { - SCOPED_TRACE(base::StringPrintf("kTestCases[%zu] = %s", i, kTestCases[i])); - std::vector<MappedMemoryRegion> regions; - EXPECT_FALSE(ParseProcMaps(kTestCases[i], ®ions)); - } -} - -TEST(ProcMapsTest, ParseProcMapsEmptyString) { - std::vector<MappedMemoryRegion> regions; - EXPECT_TRUE(ParseProcMaps("", ®ions)); - EXPECT_EQ(0ULL, regions.size()); -} - -// Testing a couple of remotely possible weird things in the input: -// - Line ending with \r\n or \n\r. -// - File name contains quotes. -// - File name has whitespaces. -TEST(ProcMapsTest, ParseProcMapsWeirdCorrectInput) { - std::vector<MappedMemoryRegion> regions; - const std::string kContents = - "00400000-0040b000 r-xp 00000000 fc:00 2106562 " - " /bin/cat\r\n" - "7f53b7dad000-7f53b7f62000 r-xp 00000000 fc:00 263011 " - " /lib/x86_64-linux-gnu/libc-2.15.so\n\r" - "7f53b816d000-7f53b818f000 r-xp 00000000 fc:00 264284 " - " /lib/x86_64-linux-gnu/ld-2.15.so\n" - "7fff9c7ff000-7fff9c800000 r-xp 00000000 00:00 0 " - " \"vd so\"\n" - "ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 " - " [vsys call]\n"; - EXPECT_TRUE(ParseProcMaps(kContents, ®ions)); - EXPECT_EQ(5ULL, regions.size()); - EXPECT_EQ("/bin/cat", regions[0].path); - EXPECT_EQ("/lib/x86_64-linux-gnu/libc-2.15.so", regions[1].path); - EXPECT_EQ("/lib/x86_64-linux-gnu/ld-2.15.so", regions[2].path); - EXPECT_EQ("\"vd so\"", regions[3].path); - EXPECT_EQ("[vsys call]", regions[4].path); -} - -} // namespace debug -} // namespace base
diff --git a/base/debug/stack_trace_unittest.cc b/base/debug/stack_trace_unittest.cc deleted file mode 100644 index 6d37c40..0000000 --- a/base/debug/stack_trace_unittest.cc +++ /dev/null
@@ -1,258 +0,0 @@ -// 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 <stddef.h> - -#include <limits> -#include <sstream> -#include <string> - -#include "base/debug/stack_trace.h" -#include "base/logging.h" -#include "base/process/kill.h" -#include "base/process/process_handle.h" -#include "base/test/test_timeouts.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/multiprocess_func_list.h" - -#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_IOS) -#include "base/test/multiprocess_test.h" -#endif - -namespace base { -namespace debug { - -#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_IOS) -typedef MultiProcessTest StackTraceTest; -#else -typedef testing::Test StackTraceTest; -#endif - -// Note: On Linux, this test currently only fully works on Debug builds. -// See comments in the #ifdef soup if you intend to change this. -#if defined(OS_WIN) -// Always fails on Windows: crbug.com/32070 -#define MAYBE_OutputToStream DISABLED_OutputToStream -#else -#define MAYBE_OutputToStream OutputToStream -#endif -#if !defined(__UCLIBC__) && !defined(_AIX) -TEST_F(StackTraceTest, MAYBE_OutputToStream) { - StackTrace trace; - - // Dump the trace into a string. - std::ostringstream os; - trace.OutputToStream(&os); - std::string backtrace_message = os.str(); - - // ToString() should produce the same output. - EXPECT_EQ(backtrace_message, trace.ToString()); - -#if defined(OS_POSIX) && !defined(OS_MACOSX) && NDEBUG - // Stack traces require an extra data table that bloats our binaries, - // so they're turned off for release builds. We stop the test here, - // at least letting us verify that the calls don't crash. - return; -#endif // defined(OS_POSIX) && !defined(OS_MACOSX) && NDEBUG - - size_t frames_found = 0; - trace.Addresses(&frames_found); - ASSERT_GE(frames_found, 5u) << - "No stack frames found. Skipping rest of test."; - - // Check if the output has symbol initialization warning. If it does, fail. - ASSERT_EQ(backtrace_message.find("Dumping unresolved backtrace"), - std::string::npos) << - "Unable to resolve symbols. Skipping rest of test."; - -#if defined(OS_MACOSX) -#if 0 - // Disabled due to -fvisibility=hidden in build config. - - // Symbol resolution via the backtrace_symbol function does not work well - // in OS X. - // See this thread: - // - // http://lists.apple.com/archives/darwin-dev/2009/Mar/msg00111.html - // - // Just check instead that we find our way back to the "start" symbol - // which should be the first symbol in the trace. - // - // TODO(port): Find a more reliable way to resolve symbols. - - // Expect to at least find main. - EXPECT_TRUE(backtrace_message.find("start") != std::string::npos) - << "Expected to find start in backtrace:\n" - << backtrace_message; - -#endif -#elif defined(USE_SYMBOLIZE) - // This branch is for gcc-compiled code, but not Mac due to the - // above #if. - // Expect a demangled symbol. - EXPECT_TRUE(backtrace_message.find("testing::Test::Run()") != - std::string::npos) - << "Expected a demangled symbol in backtrace:\n" - << backtrace_message; - -#elif 0 - // This is the fall-through case; it used to cover Windows. - // But it's disabled because of varying buildbot configs; - // some lack symbols. - - // Expect to at least find main. - EXPECT_TRUE(backtrace_message.find("main") != std::string::npos) - << "Expected to find main in backtrace:\n" - << backtrace_message; - -#if defined(OS_WIN) -// MSVC doesn't allow the use of C99's __func__ within C++, so we fake it with -// MSVC's __FUNCTION__ macro. -#define __func__ __FUNCTION__ -#endif - - // Expect to find this function as well. - // Note: This will fail if not linked with -rdynamic (aka -export_dynamic) - EXPECT_TRUE(backtrace_message.find(__func__) != std::string::npos) - << "Expected to find " << __func__ << " in backtrace:\n" - << backtrace_message; - -#endif // define(OS_MACOSX) -} - -#if !defined(OFFICIAL_BUILD) && !defined(NO_UNWIND_TABLES) -// Disabled in Official builds, where Link-Time Optimization can result in two -// or fewer stack frames being available, causing the test to fail. -TEST_F(StackTraceTest, TruncatedTrace) { - StackTrace trace; - - size_t count = 0; - trace.Addresses(&count); - ASSERT_LT(2u, count); - - StackTrace truncated(2); - truncated.Addresses(&count); - EXPECT_EQ(2u, count); -} -#endif // !defined(OFFICIAL_BUILD) - -// The test is used for manual testing, e.g., to see the raw output. -TEST_F(StackTraceTest, DebugOutputToStream) { - StackTrace trace; - std::ostringstream os; - trace.OutputToStream(&os); - VLOG(1) << os.str(); -} - -// The test is used for manual testing, e.g., to see the raw output. -TEST_F(StackTraceTest, DebugPrintBacktrace) { - StackTrace().Print(); -} -#endif // !defined(__UCLIBC__) - -#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_FUCHSIA) -#if !defined(OS_IOS) -static char* newArray() { - // Clang warns about the mismatched new[]/delete if they occur in the same - // function. - return new char[10]; -} - -MULTIPROCESS_TEST_MAIN(MismatchedMallocChildProcess) { - char* pointer = newArray(); - delete pointer; - return 2; -} - -// Regression test for StackDumpingSignalHandler async-signal unsafety. -// Combined with tcmalloc's debugallocation, that signal handler -// and e.g. mismatched new[]/delete would cause a hang because -// of re-entering malloc. -TEST_F(StackTraceTest, AsyncSignalUnsafeSignalHandlerHang) { - Process child = SpawnChild("MismatchedMallocChildProcess"); - ASSERT_TRUE(child.IsValid()); - int exit_code; - ASSERT_TRUE( - child.WaitForExitWithTimeout(TestTimeouts::action_timeout(), &exit_code)); -} -#endif // !defined(OS_IOS) - -namespace { - -std::string itoa_r_wrapper(intptr_t i, size_t sz, int base, size_t padding) { - char buffer[1024]; - CHECK_LE(sz, sizeof(buffer)); - - char* result = internal::itoa_r(i, buffer, sz, base, padding); - EXPECT_TRUE(result); - return std::string(buffer); -} - -} // namespace - -TEST_F(StackTraceTest, itoa_r) { - EXPECT_EQ("0", itoa_r_wrapper(0, 128, 10, 0)); - EXPECT_EQ("-1", itoa_r_wrapper(-1, 128, 10, 0)); - - // Test edge cases. - if (sizeof(intptr_t) == 4) { - EXPECT_EQ("ffffffff", itoa_r_wrapper(-1, 128, 16, 0)); - EXPECT_EQ("-2147483648", - itoa_r_wrapper(std::numeric_limits<intptr_t>::min(), 128, 10, 0)); - EXPECT_EQ("2147483647", - itoa_r_wrapper(std::numeric_limits<intptr_t>::max(), 128, 10, 0)); - - EXPECT_EQ("80000000", - itoa_r_wrapper(std::numeric_limits<intptr_t>::min(), 128, 16, 0)); - EXPECT_EQ("7fffffff", - itoa_r_wrapper(std::numeric_limits<intptr_t>::max(), 128, 16, 0)); - } else if (sizeof(intptr_t) == 8) { - EXPECT_EQ("ffffffffffffffff", itoa_r_wrapper(-1, 128, 16, 0)); - EXPECT_EQ("-9223372036854775808", - itoa_r_wrapper(std::numeric_limits<intptr_t>::min(), 128, 10, 0)); - EXPECT_EQ("9223372036854775807", - itoa_r_wrapper(std::numeric_limits<intptr_t>::max(), 128, 10, 0)); - - EXPECT_EQ("8000000000000000", - itoa_r_wrapper(std::numeric_limits<intptr_t>::min(), 128, 16, 0)); - EXPECT_EQ("7fffffffffffffff", - itoa_r_wrapper(std::numeric_limits<intptr_t>::max(), 128, 16, 0)); - } else { - ADD_FAILURE() << "Missing test case for your size of intptr_t (" - << sizeof(intptr_t) << ")"; - } - - // Test hex output. - EXPECT_EQ("688", itoa_r_wrapper(0x688, 128, 16, 0)); - EXPECT_EQ("deadbeef", itoa_r_wrapper(0xdeadbeef, 128, 16, 0)); - - // Check that itoa_r respects passed buffer size limit. - char buffer[1024]; - EXPECT_TRUE(internal::itoa_r(0xdeadbeef, buffer, 10, 16, 0)); - EXPECT_TRUE(internal::itoa_r(0xdeadbeef, buffer, 9, 16, 0)); - EXPECT_FALSE(internal::itoa_r(0xdeadbeef, buffer, 8, 16, 0)); - EXPECT_FALSE(internal::itoa_r(0xdeadbeef, buffer, 7, 16, 0)); - EXPECT_TRUE(internal::itoa_r(0xbeef, buffer, 5, 16, 4)); - EXPECT_FALSE(internal::itoa_r(0xbeef, buffer, 5, 16, 5)); - EXPECT_FALSE(internal::itoa_r(0xbeef, buffer, 5, 16, 6)); - - // Test padding. - EXPECT_EQ("1", itoa_r_wrapper(1, 128, 10, 0)); - EXPECT_EQ("1", itoa_r_wrapper(1, 128, 10, 1)); - EXPECT_EQ("01", itoa_r_wrapper(1, 128, 10, 2)); - EXPECT_EQ("001", itoa_r_wrapper(1, 128, 10, 3)); - EXPECT_EQ("0001", itoa_r_wrapper(1, 128, 10, 4)); - EXPECT_EQ("00001", itoa_r_wrapper(1, 128, 10, 5)); - EXPECT_EQ("688", itoa_r_wrapper(0x688, 128, 16, 0)); - EXPECT_EQ("688", itoa_r_wrapper(0x688, 128, 16, 1)); - EXPECT_EQ("688", itoa_r_wrapper(0x688, 128, 16, 2)); - EXPECT_EQ("688", itoa_r_wrapper(0x688, 128, 16, 3)); - EXPECT_EQ("0688", itoa_r_wrapper(0x688, 128, 16, 4)); - EXPECT_EQ("00688", itoa_r_wrapper(0x688, 128, 16, 5)); -} -#endif // defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_FUCHSIA) - -} // namespace debug -} // namespace base
diff --git a/base/debug/task_annotator_unittest.cc b/base/debug/task_annotator_unittest.cc deleted file mode 100644 index 51a5d32..0000000 --- a/base/debug/task_annotator_unittest.cc +++ /dev/null
@@ -1,371 +0,0 @@ -// 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/debug/task_annotator.h" - -#include <algorithm> -#include <vector> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/callback.h" -#include "base/macros.h" -#include "base/message_loop/message_loop.h" -#include "base/pending_task.h" -#include "base/run_loop.h" -#include "base/strings/stringprintf.h" -#include "base/synchronization/lock.h" -#include "base/synchronization/waitable_event.h" -#include "base/task_scheduler/post_task.h" -#include "base/test/scoped_task_environment.h" -#include "base/threading/thread.h" -#include "base/threading/thread_task_runner_handle.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace debug { -namespace { - -void TestTask(int* result) { - *result = 123; -} - -} // namespace - -TEST(TaskAnnotatorTest, QueueAndRunTask) { - int result = 0; - PendingTask pending_task(FROM_HERE, BindOnce(&TestTask, &result)); - - TaskAnnotator annotator; - annotator.DidQueueTask("TaskAnnotatorTest::Queue", pending_task); - EXPECT_EQ(0, result); - annotator.RunTask("TaskAnnotatorTest::Queue", &pending_task); - EXPECT_EQ(123, result); -} - -// Test task annotator integration in base APIs and ensuing support for -// backtraces. Tasks posted across multiple threads in this test fixture should -// be synchronized as BeforeRunTask() and VerifyTraceAndPost() assume tasks are -// observed in lock steps, one at a time. -class TaskAnnotatorBacktraceIntegrationTest - : public ::testing::Test, - public TaskAnnotator::ObserverForTesting { - public: - using ExpectedTrace = std::vector<const void*>; - - TaskAnnotatorBacktraceIntegrationTest() = default; - - ~TaskAnnotatorBacktraceIntegrationTest() override = default; - - // TaskAnnotator::ObserverForTesting: - void BeforeRunTask(const PendingTask* pending_task) override { - AutoLock auto_lock(on_before_run_task_lock_); - last_posted_from_ = pending_task->posted_from; - last_task_backtrace_ = pending_task->task_backtrace; - } - - void SetUp() override { TaskAnnotator::RegisterObserverForTesting(this); } - - void TearDown() override { TaskAnnotator::ClearObserverForTesting(); } - - void VerifyTraceAndPost(const scoped_refptr<SequencedTaskRunner>& task_runner, - const Location& posted_from, - const Location& next_from_here, - const ExpectedTrace& expected_trace, - OnceClosure task) { - SCOPED_TRACE(StringPrintf("Callback Depth: %zu", expected_trace.size())); - - EXPECT_EQ(posted_from, last_posted_from_); - for (size_t i = 0; i < last_task_backtrace_.size(); i++) { - SCOPED_TRACE(StringPrintf("Trace frame: %zu", i)); - if (i < expected_trace.size()) - EXPECT_EQ(expected_trace[i], last_task_backtrace_[i]); - else - EXPECT_EQ(nullptr, last_task_backtrace_[i]); - } - - task_runner->PostTask(next_from_here, std::move(task)); - } - - // Same as VerifyTraceAndPost() with the exception that it also posts a task - // that will prevent |task| from running until |wait_before_next_task| is - // signaled. - void VerifyTraceAndPostWithBlocker( - const scoped_refptr<SequencedTaskRunner>& task_runner, - const Location& posted_from, - const Location& next_from_here, - const ExpectedTrace& expected_trace, - OnceClosure task, - WaitableEvent* wait_before_next_task) { - DCHECK(wait_before_next_task); - - // Need to lock to ensure the upcoming VerifyTraceAndPost() runs before the - // BeforeRunTask() hook for the posted WaitableEvent::Wait(). Otherwise the - // upcoming VerifyTraceAndPost() will race to read the state saved in the - // BeforeRunTask() hook preceding the current task. - AutoLock auto_lock(on_before_run_task_lock_); - task_runner->PostTask( - FROM_HERE, - BindOnce(&WaitableEvent::Wait, Unretained(wait_before_next_task))); - VerifyTraceAndPost(task_runner, posted_from, next_from_here, expected_trace, - std::move(task)); - } - - protected: - static void RunTwo(OnceClosure c1, OnceClosure c2) { - std::move(c1).Run(); - std::move(c2).Run(); - } - - private: - // While calls to VerifyTraceAndPost() are strictly ordered in tests below - // (and hence non-racy), some helper methods (e.g. Wait/Signal) do racily call - // into BeforeRunTask(). This Lock ensures these unobserved writes are not - // racing. Locking isn't required on read per the VerifyTraceAndPost() - // themselves being ordered. - Lock on_before_run_task_lock_; - - Location last_posted_from_ = {}; - std::array<const void*, 4> last_task_backtrace_ = {}; - - DISALLOW_COPY_AND_ASSIGN(TaskAnnotatorBacktraceIntegrationTest); -}; - -// Ensure the task backtrace populates correctly. -TEST_F(TaskAnnotatorBacktraceIntegrationTest, SingleThreadedSimple) { - MessageLoop loop; - const Location location0 = FROM_HERE; - const Location location1 = FROM_HERE; - const Location location2 = FROM_HERE; - const Location location3 = FROM_HERE; - const Location location4 = FROM_HERE; - const Location location5 = FROM_HERE; - - RunLoop run_loop; - - // Task 5 has tasks 4/3/2/1 as parents (task 0 isn't visible as only the - // last 4 parents are kept). - OnceClosure task5 = BindOnce( - &TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost, - Unretained(this), loop.task_runner(), location5, FROM_HERE, - ExpectedTrace({location4.program_counter(), location3.program_counter(), - location2.program_counter(), location1.program_counter()}), - run_loop.QuitClosure()); - - // Task i=4/3/2/1/0 have tasks [0,i) as parents. - OnceClosure task4 = BindOnce( - &TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost, - Unretained(this), loop.task_runner(), location4, location5, - ExpectedTrace({location3.program_counter(), location2.program_counter(), - location1.program_counter(), location0.program_counter()}), - std::move(task5)); - OnceClosure task3 = BindOnce( - &TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost, - Unretained(this), loop.task_runner(), location3, location4, - ExpectedTrace({location2.program_counter(), location1.program_counter(), - location0.program_counter()}), - std::move(task4)); - OnceClosure task2 = BindOnce( - &TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost, - Unretained(this), loop.task_runner(), location2, location3, - ExpectedTrace({location1.program_counter(), location0.program_counter()}), - std::move(task3)); - OnceClosure task1 = - BindOnce(&TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost, - Unretained(this), loop.task_runner(), location1, location2, - ExpectedTrace({location0.program_counter()}), std::move(task2)); - OnceClosure task0 = - BindOnce(&TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost, - Unretained(this), loop.task_runner(), location0, location1, - ExpectedTrace({}), std::move(task1)); - - loop.task_runner()->PostTask(location0, std::move(task0)); - - run_loop.Run(); -} - -// Ensure it works when posting tasks across multiple threads managed by //base. -TEST_F(TaskAnnotatorBacktraceIntegrationTest, MultipleThreads) { - test::ScopedTaskEnvironment scoped_task_environment; - - // Use diverse task runners (a MessageLoop on the main thread, a TaskScheduler - // based SequencedTaskRunner, and a TaskScheduler based - // SingleThreadTaskRunner) to verify that TaskAnnotator can capture backtraces - // for PostTasks back-and-forth between these. - auto main_thread_a = ThreadTaskRunnerHandle::Get(); - auto task_runner_b = CreateSingleThreadTaskRunnerWithTraits({}); - auto task_runner_c = CreateSequencedTaskRunnerWithTraits( - {base::MayBlock(), base::WithBaseSyncPrimitives()}); - - const Location& location_a0 = FROM_HERE; - const Location& location_a1 = FROM_HERE; - const Location& location_a2 = FROM_HERE; - const Location& location_a3 = FROM_HERE; - - const Location& location_b0 = FROM_HERE; - const Location& location_b1 = FROM_HERE; - - const Location& location_c0 = FROM_HERE; - - RunLoop run_loop; - - // All tasks below happen in lock step by nature of being posted by the - // previous one (plus the synchronous nature of RunTwo()) with the exception - // of the follow-up local task to |task_b0_local|. This WaitableEvent ensures - // it completes before |task_c0| runs to avoid racy invocations of - // BeforeRunTask()+VerifyTraceAndPost(). - WaitableEvent lock_step(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - - // Here is the execution order generated below: - // A: TA0 -> TA1 \ TA2 - // B: TB0L \ + TB0F \ Signal \ / - // ---------\--/ \ / - // \ \ / - // C: Wait........ TC0 / - - // On task runner c, post a task back to main thread that verifies its trace - // and terminates after one more self-post. - OnceClosure task_a2 = BindOnce( - &TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost, - Unretained(this), main_thread_a, location_a2, location_a3, - ExpectedTrace( - {location_c0.program_counter(), location_b0.program_counter(), - location_a1.program_counter(), location_a0.program_counter()}), - run_loop.QuitClosure()); - OnceClosure task_c0 = - BindOnce(&TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost, - Unretained(this), main_thread_a, location_c0, location_a2, - ExpectedTrace({location_b0.program_counter(), - location_a1.program_counter(), - location_a0.program_counter()}), - std::move(task_a2)); - - // On task runner b run two tasks that conceptually come from the same - // location (managed via RunTwo().) One will post back to task runner b and - // another will post to task runner c to test spawning multiple tasks on - // different message loops. The task posted to task runner c will not get - // location b1 whereas the one posted back to task runner b will. - OnceClosure task_b0_fork = BindOnce( - &TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPostWithBlocker, - Unretained(this), task_runner_c, location_b0, location_c0, - ExpectedTrace( - {location_a1.program_counter(), location_a0.program_counter()}), - std::move(task_c0), &lock_step); - OnceClosure task_b0_local = - BindOnce(&TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost, - Unretained(this), task_runner_b, location_b0, location_b1, - ExpectedTrace({location_a1.program_counter(), - location_a0.program_counter()}), - BindOnce(&WaitableEvent::Signal, Unretained(&lock_step))); - - OnceClosure task_a1 = - BindOnce(&TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost, - Unretained(this), task_runner_b, location_a1, location_b0, - ExpectedTrace({location_a0.program_counter()}), - BindOnce(&TaskAnnotatorBacktraceIntegrationTest::RunTwo, - std::move(task_b0_local), std::move(task_b0_fork))); - OnceClosure task_a0 = - BindOnce(&TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost, - Unretained(this), main_thread_a, location_a0, location_a1, - ExpectedTrace({}), std::move(task_a1)); - - main_thread_a->PostTask(location_a0, std::move(task_a0)); - - run_loop.Run(); -} - -// Ensure nesting doesn't break the chain. -TEST_F(TaskAnnotatorBacktraceIntegrationTest, SingleThreadedNested) { - MessageLoop loop; - const Location location0 = FROM_HERE; - const Location location1 = FROM_HERE; - const Location location2 = FROM_HERE; - const Location location3 = FROM_HERE; - const Location location4 = FROM_HERE; - const Location location5 = FROM_HERE; - - RunLoop run_loop; - - // Task execution below looks like this, w.r.t. to RunLoop depths: - // 1 : T0 \ + NRL1 \ ---------> T4 -> T5 - // 2 : ---------> T1 \ -> NRL2 \ ----> T2 -> T3 / + Quit / - // 3 : ---------> DN / - - // NRL1 tests that tasks that occur at a different nesting depth than their - // parent have a sane backtrace nonetheless (both ways). - - // NRL2 tests that posting T2 right after exiting the RunLoop (from the same - // task) results in NRL2 being its parent (and not the DoNothing() task that - // just ran -- which would have been the case if the "current task" wasn't - // restored properly when returning from a task within a task). - - // In other words, this is regression test for a bug in the previous - // implementation. In the current implementation, replacing - // tls_for_current_pending_task->Set(previous_pending_task); - // by - // tls_for_current_pending_task->Set(nullptr); - // at the end of TaskAnnotator::RunTask() makes this test fail. - - RunLoop nested_run_loop1(RunLoop::Type::kNestableTasksAllowed); - - // Expectations are the same as in SingleThreadedSimple test despite the - // nested loop starting between tasks 0 and 1 and stopping between tasks 3 and - // 4. - OnceClosure task5 = BindOnce( - &TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost, - Unretained(this), loop.task_runner(), location5, FROM_HERE, - ExpectedTrace({location4.program_counter(), location3.program_counter(), - location2.program_counter(), location1.program_counter()}), - run_loop.QuitClosure()); - OnceClosure task4 = BindOnce( - &TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost, - Unretained(this), loop.task_runner(), location4, location5, - ExpectedTrace({location3.program_counter(), location2.program_counter(), - location1.program_counter(), location0.program_counter()}), - std::move(task5)); - OnceClosure task3 = BindOnce( - &TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost, - Unretained(this), loop.task_runner(), location3, location4, - ExpectedTrace({location2.program_counter(), location1.program_counter(), - location0.program_counter()}), - std::move(task4)); - - OnceClosure run_task_3_then_quit_nested_loop1 = - BindOnce(&TaskAnnotatorBacktraceIntegrationTest::RunTwo, std::move(task3), - nested_run_loop1.QuitClosure()); - - OnceClosure task2 = BindOnce( - &TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost, - Unretained(this), loop.task_runner(), location2, location3, - ExpectedTrace({location1.program_counter(), location0.program_counter()}), - std::move(run_task_3_then_quit_nested_loop1)); - - // Task 1 is custom. It enters another nested RunLoop, has it do work and exit - // before posting the next task. This confirms that |task1| is restored as the - // current task before posting |task2| after returning from the nested loop. - RunLoop nested_run_loop2(RunLoop::Type::kNestableTasksAllowed); - OnceClosure task1 = BindOnce( - [](RunLoop* nested_run_loop, const Location& location2, - OnceClosure task2) { - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, DoNothing()); - nested_run_loop->RunUntilIdle(); - ThreadTaskRunnerHandle::Get()->PostTask(location2, std::move(task2)); - }, - Unretained(&nested_run_loop2), location2, std::move(task2)); - - OnceClosure task0 = - BindOnce(&TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost, - Unretained(this), loop.task_runner(), location0, location1, - ExpectedTrace({}), std::move(task1)); - - loop.task_runner()->PostTask(location0, std::move(task0)); - loop.task_runner()->PostTask( - FROM_HERE, BindOnce(&RunLoop::Run, Unretained(&nested_run_loop1))); - - run_loop.Run(); -} - -} // namespace debug -} // namespace base
diff --git a/base/debug/thread_heap_usage_tracker_unittest.cc b/base/debug/thread_heap_usage_tracker_unittest.cc deleted file mode 100644 index fc7fda4..0000000 --- a/base/debug/thread_heap_usage_tracker_unittest.cc +++ /dev/null
@@ -1,556 +0,0 @@ -// 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/debug/thread_heap_usage_tracker.h" - -#include <map> - -#include "base/allocator/allocator_shim.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(OS_MACOSX) -#include "base/allocator/allocator_interception_mac.h" -#endif - -namespace base { -namespace debug { - -namespace { - -class TestingThreadHeapUsageTracker : public ThreadHeapUsageTracker { - public: - using ThreadHeapUsageTracker::DisableHeapTrackingForTesting; - using ThreadHeapUsageTracker::EnsureTLSInitialized; - using ThreadHeapUsageTracker::GetDispatchForTesting; -}; - -// A fixture class that allows testing the AllocatorDispatch associated with -// the ThreadHeapUsageTracker class in isolation against a mocked -// underlying -// heap implementation. -class ThreadHeapUsageTrackerTest : public testing::Test { - public: - using AllocatorDispatch = base::allocator::AllocatorDispatch; - - static const size_t kAllocationPadding; - enum SizeFunctionKind { - EXACT_SIZE_FUNCTION, - PADDING_SIZE_FUNCTION, - ZERO_SIZE_FUNCTION, - }; - - ThreadHeapUsageTrackerTest() : size_function_kind_(EXACT_SIZE_FUNCTION) { - EXPECT_EQ(nullptr, g_self); - g_self = this; - } - - ~ThreadHeapUsageTrackerTest() override { - EXPECT_EQ(this, g_self); - g_self = nullptr; - } - - void set_size_function_kind(SizeFunctionKind kind) { - size_function_kind_ = kind; - } - - void SetUp() override { - TestingThreadHeapUsageTracker::EnsureTLSInitialized(); - - dispatch_under_test_ = - TestingThreadHeapUsageTracker::GetDispatchForTesting(); - ASSERT_EQ(nullptr, dispatch_under_test_->next); - - dispatch_under_test_->next = &g_mock_dispatch; - } - - void TearDown() override { - ASSERT_EQ(&g_mock_dispatch, dispatch_under_test_->next); - - dispatch_under_test_->next = nullptr; - } - - void* MockMalloc(size_t size) { - return dispatch_under_test_->alloc_function(dispatch_under_test_, size, - nullptr); - } - - void* MockCalloc(size_t n, size_t size) { - return dispatch_under_test_->alloc_zero_initialized_function( - dispatch_under_test_, n, size, nullptr); - } - - void* MockAllocAligned(size_t alignment, size_t size) { - return dispatch_under_test_->alloc_aligned_function( - dispatch_under_test_, alignment, size, nullptr); - } - - void* MockRealloc(void* address, size_t size) { - return dispatch_under_test_->realloc_function(dispatch_under_test_, address, - size, nullptr); - } - - void MockFree(void* address) { - dispatch_under_test_->free_function(dispatch_under_test_, address, nullptr); - } - - size_t MockGetSizeEstimate(void* address) { - return dispatch_under_test_->get_size_estimate_function( - dispatch_under_test_, address, nullptr); - } - - private: - void RecordAlloc(void* address, size_t size) { - if (address != nullptr) - allocation_size_map_[address] = size; - } - - void DeleteAlloc(void* address) { - if (address != nullptr) - EXPECT_EQ(1U, allocation_size_map_.erase(address)); - } - - size_t GetSizeEstimate(void* address) { - auto it = allocation_size_map_.find(address); - if (it == allocation_size_map_.end()) - return 0; - - size_t ret = it->second; - switch (size_function_kind_) { - case EXACT_SIZE_FUNCTION: - break; - case PADDING_SIZE_FUNCTION: - ret += kAllocationPadding; - break; - case ZERO_SIZE_FUNCTION: - ret = 0; - break; - } - - return ret; - } - - static void* OnAllocFn(const AllocatorDispatch* self, - size_t size, - void* context) { - EXPECT_EQ(&g_mock_dispatch, self); - - void* ret = malloc(size); - g_self->RecordAlloc(ret, size); - return ret; - } - - static void* OnAllocZeroInitializedFn(const AllocatorDispatch* self, - size_t n, - size_t size, - void* context) { - EXPECT_EQ(&g_mock_dispatch, self); - - void* ret = calloc(n, size); - g_self->RecordAlloc(ret, n * size); - return ret; - } - - static void* OnAllocAlignedFn(const AllocatorDispatch* self, - size_t alignment, - size_t size, - void* context) { - EXPECT_EQ(&g_mock_dispatch, self); - - // This is a cheat as it doesn't return aligned allocations. This has the - // advantage of working for all platforms for this test. - void* ret = malloc(size); - g_self->RecordAlloc(ret, size); - return ret; - } - - static void* OnReallocFn(const AllocatorDispatch* self, - void* address, - size_t size, - void* context) { - EXPECT_EQ(&g_mock_dispatch, self); - - g_self->DeleteAlloc(address); - void* ret = realloc(address, size); - g_self->RecordAlloc(ret, size); - return ret; - } - - static void OnFreeFn(const AllocatorDispatch* self, - void* address, - void* context) { - EXPECT_EQ(&g_mock_dispatch, self); - - g_self->DeleteAlloc(address); - free(address); - } - - static size_t OnGetSizeEstimateFn(const AllocatorDispatch* self, - void* address, - void* context) { - EXPECT_EQ(&g_mock_dispatch, self); - - return g_self->GetSizeEstimate(address); - } - - using AllocationSizeMap = std::map<void*, size_t>; - - SizeFunctionKind size_function_kind_; - AllocationSizeMap allocation_size_map_; - AllocatorDispatch* dispatch_under_test_; - - static base::allocator::AllocatorDispatch g_mock_dispatch; - static ThreadHeapUsageTrackerTest* g_self; -}; - -const size_t ThreadHeapUsageTrackerTest::kAllocationPadding = 23; - -ThreadHeapUsageTrackerTest* ThreadHeapUsageTrackerTest::g_self = nullptr; - -base::allocator::AllocatorDispatch ThreadHeapUsageTrackerTest::g_mock_dispatch = - { - &ThreadHeapUsageTrackerTest::OnAllocFn, // alloc_function - &ThreadHeapUsageTrackerTest:: - OnAllocZeroInitializedFn, // alloc_zero_initialized_function - &ThreadHeapUsageTrackerTest:: - OnAllocAlignedFn, // alloc_aligned_function - &ThreadHeapUsageTrackerTest::OnReallocFn, // realloc_function - &ThreadHeapUsageTrackerTest::OnFreeFn, // free_function - &ThreadHeapUsageTrackerTest:: - OnGetSizeEstimateFn, // get_size_estimate_function - nullptr, // batch_malloc - nullptr, // batch_free - nullptr, // free_definite_size_function - nullptr, // next -}; - -} // namespace - -TEST_F(ThreadHeapUsageTrackerTest, SimpleUsageWithExactSizeFunction) { - set_size_function_kind(EXACT_SIZE_FUNCTION); - - ThreadHeapUsageTracker usage_tracker; - usage_tracker.Start(); - - ThreadHeapUsage u1 = ThreadHeapUsageTracker::GetUsageSnapshot(); - - EXPECT_EQ(0U, u1.alloc_ops); - EXPECT_EQ(0U, u1.alloc_bytes); - EXPECT_EQ(0U, u1.alloc_overhead_bytes); - EXPECT_EQ(0U, u1.free_ops); - EXPECT_EQ(0U, u1.free_bytes); - EXPECT_EQ(0U, u1.max_allocated_bytes); - - const size_t kAllocSize = 1029U; - void* ptr = MockMalloc(kAllocSize); - MockFree(ptr); - - usage_tracker.Stop(false); - ThreadHeapUsage u2 = usage_tracker.usage(); - - EXPECT_EQ(1U, u2.alloc_ops); - EXPECT_EQ(kAllocSize, u2.alloc_bytes); - EXPECT_EQ(0U, u2.alloc_overhead_bytes); - EXPECT_EQ(1U, u2.free_ops); - EXPECT_EQ(kAllocSize, u2.free_bytes); - EXPECT_EQ(kAllocSize, u2.max_allocated_bytes); -} - -TEST_F(ThreadHeapUsageTrackerTest, SimpleUsageWithPaddingSizeFunction) { - set_size_function_kind(PADDING_SIZE_FUNCTION); - - ThreadHeapUsageTracker usage_tracker; - usage_tracker.Start(); - - ThreadHeapUsage u1 = ThreadHeapUsageTracker::GetUsageSnapshot(); - - EXPECT_EQ(0U, u1.alloc_ops); - EXPECT_EQ(0U, u1.alloc_bytes); - EXPECT_EQ(0U, u1.alloc_overhead_bytes); - EXPECT_EQ(0U, u1.free_ops); - EXPECT_EQ(0U, u1.free_bytes); - EXPECT_EQ(0U, u1.max_allocated_bytes); - - const size_t kAllocSize = 1029U; - void* ptr = MockMalloc(kAllocSize); - MockFree(ptr); - - usage_tracker.Stop(false); - ThreadHeapUsage u2 = usage_tracker.usage(); - - EXPECT_EQ(1U, u2.alloc_ops); - EXPECT_EQ(kAllocSize + kAllocationPadding, u2.alloc_bytes); - EXPECT_EQ(kAllocationPadding, u2.alloc_overhead_bytes); - EXPECT_EQ(1U, u2.free_ops); - EXPECT_EQ(kAllocSize + kAllocationPadding, u2.free_bytes); - EXPECT_EQ(kAllocSize + kAllocationPadding, u2.max_allocated_bytes); -} - -TEST_F(ThreadHeapUsageTrackerTest, SimpleUsageWithZeroSizeFunction) { - set_size_function_kind(ZERO_SIZE_FUNCTION); - - ThreadHeapUsageTracker usage_tracker; - usage_tracker.Start(); - - ThreadHeapUsage u1 = ThreadHeapUsageTracker::GetUsageSnapshot(); - EXPECT_EQ(0U, u1.alloc_ops); - EXPECT_EQ(0U, u1.alloc_bytes); - EXPECT_EQ(0U, u1.alloc_overhead_bytes); - EXPECT_EQ(0U, u1.free_ops); - EXPECT_EQ(0U, u1.free_bytes); - EXPECT_EQ(0U, u1.max_allocated_bytes); - - const size_t kAllocSize = 1029U; - void* ptr = MockMalloc(kAllocSize); - MockFree(ptr); - - usage_tracker.Stop(false); - ThreadHeapUsage u2 = usage_tracker.usage(); - - // With a get-size function that returns zero, there's no way to get the size - // of an allocation that's being freed, hence the shim can't tally freed bytes - // nor the high-watermark allocated bytes. - EXPECT_EQ(1U, u2.alloc_ops); - EXPECT_EQ(kAllocSize, u2.alloc_bytes); - EXPECT_EQ(0U, u2.alloc_overhead_bytes); - EXPECT_EQ(1U, u2.free_ops); - EXPECT_EQ(0U, u2.free_bytes); - EXPECT_EQ(0U, u2.max_allocated_bytes); -} - -TEST_F(ThreadHeapUsageTrackerTest, ReallocCorrectlyTallied) { - const size_t kAllocSize = 237U; - - { - ThreadHeapUsageTracker usage_tracker; - usage_tracker.Start(); - - // Reallocating nullptr should count as a single alloc. - void* ptr = MockRealloc(nullptr, kAllocSize); - ThreadHeapUsage usage = ThreadHeapUsageTracker::GetUsageSnapshot(); - EXPECT_EQ(1U, usage.alloc_ops); - EXPECT_EQ(kAllocSize, usage.alloc_bytes); - EXPECT_EQ(0U, usage.alloc_overhead_bytes); - EXPECT_EQ(0U, usage.free_ops); - EXPECT_EQ(0U, usage.free_bytes); - EXPECT_EQ(kAllocSize, usage.max_allocated_bytes); - - // Reallocating a valid pointer to a zero size should count as a single - // free. - ptr = MockRealloc(ptr, 0U); - - usage_tracker.Stop(false); - EXPECT_EQ(1U, usage_tracker.usage().alloc_ops); - EXPECT_EQ(kAllocSize, usage_tracker.usage().alloc_bytes); - EXPECT_EQ(0U, usage_tracker.usage().alloc_overhead_bytes); - EXPECT_EQ(1U, usage_tracker.usage().free_ops); - EXPECT_EQ(kAllocSize, usage_tracker.usage().free_bytes); - EXPECT_EQ(kAllocSize, usage_tracker.usage().max_allocated_bytes); - - // Realloc to zero size may or may not return a nullptr - make sure to - // free the zero-size alloc in the latter case. - if (ptr != nullptr) - MockFree(ptr); - } - - { - ThreadHeapUsageTracker usage_tracker; - usage_tracker.Start(); - - void* ptr = MockMalloc(kAllocSize); - ThreadHeapUsage usage = ThreadHeapUsageTracker::GetUsageSnapshot(); - EXPECT_EQ(1U, usage.alloc_ops); - - // Now try reallocating a valid pointer to a larger size, this should count - // as one free and one alloc. - const size_t kLargerAllocSize = kAllocSize + 928U; - ptr = MockRealloc(ptr, kLargerAllocSize); - - usage_tracker.Stop(false); - EXPECT_EQ(2U, usage_tracker.usage().alloc_ops); - EXPECT_EQ(kAllocSize + kLargerAllocSize, usage_tracker.usage().alloc_bytes); - EXPECT_EQ(0U, usage_tracker.usage().alloc_overhead_bytes); - EXPECT_EQ(1U, usage_tracker.usage().free_ops); - EXPECT_EQ(kAllocSize, usage_tracker.usage().free_bytes); - EXPECT_EQ(kLargerAllocSize, usage_tracker.usage().max_allocated_bytes); - - MockFree(ptr); - } -} - -TEST_F(ThreadHeapUsageTrackerTest, NestedMaxWorks) { - ThreadHeapUsageTracker usage_tracker; - usage_tracker.Start(); - - const size_t kOuterAllocSize = 1029U; - void* ptr = MockMalloc(kOuterAllocSize); - MockFree(ptr); - - EXPECT_EQ(kOuterAllocSize, - ThreadHeapUsageTracker::GetUsageSnapshot().max_allocated_bytes); - - { - ThreadHeapUsageTracker inner_usage_tracker; - inner_usage_tracker.Start(); - - const size_t kInnerAllocSize = 673U; - ptr = MockMalloc(kInnerAllocSize); - MockFree(ptr); - - inner_usage_tracker.Stop(false); - - EXPECT_EQ(kInnerAllocSize, inner_usage_tracker.usage().max_allocated_bytes); - } - - // The greater, outer allocation size should have been restored. - EXPECT_EQ(kOuterAllocSize, - ThreadHeapUsageTracker::GetUsageSnapshot().max_allocated_bytes); - - const size_t kLargerInnerAllocSize = kOuterAllocSize + 673U; - { - ThreadHeapUsageTracker inner_usage_tracker; - inner_usage_tracker.Start(); - - ptr = MockMalloc(kLargerInnerAllocSize); - MockFree(ptr); - - inner_usage_tracker.Stop(false); - EXPECT_EQ(kLargerInnerAllocSize, - inner_usage_tracker.usage().max_allocated_bytes); - } - - // The greater, inner allocation size should have been preserved. - EXPECT_EQ(kLargerInnerAllocSize, - ThreadHeapUsageTracker::GetUsageSnapshot().max_allocated_bytes); - - // Now try the case with an outstanding net alloc size when entering the - // inner scope. - void* outer_ptr = MockMalloc(kOuterAllocSize); - EXPECT_EQ(kLargerInnerAllocSize, - ThreadHeapUsageTracker::GetUsageSnapshot().max_allocated_bytes); - { - ThreadHeapUsageTracker inner_usage_tracker; - inner_usage_tracker.Start(); - - ptr = MockMalloc(kLargerInnerAllocSize); - MockFree(ptr); - - inner_usage_tracker.Stop(false); - EXPECT_EQ(kLargerInnerAllocSize, - inner_usage_tracker.usage().max_allocated_bytes); - } - - // While the inner scope saw only the inner net outstanding allocation size, - // the outer scope saw both outstanding at the same time. - EXPECT_EQ(kOuterAllocSize + kLargerInnerAllocSize, - ThreadHeapUsageTracker::GetUsageSnapshot().max_allocated_bytes); - - MockFree(outer_ptr); - - // Test a net-negative scope. - ptr = MockMalloc(kLargerInnerAllocSize); - { - ThreadHeapUsageTracker inner_usage_tracker; - inner_usage_tracker.Start(); - - MockFree(ptr); - - const size_t kInnerAllocSize = 1; - ptr = MockMalloc(kInnerAllocSize); - - inner_usage_tracker.Stop(false); - // Since the scope is still net-negative, the max is clamped at zero. - EXPECT_EQ(0U, inner_usage_tracker.usage().max_allocated_bytes); - } - - MockFree(ptr); -} - -TEST_F(ThreadHeapUsageTrackerTest, NoStopImpliesInclusive) { - ThreadHeapUsageTracker usage_tracker; - usage_tracker.Start(); - - const size_t kOuterAllocSize = 1029U; - void* ptr = MockMalloc(kOuterAllocSize); - MockFree(ptr); - - ThreadHeapUsage usage = ThreadHeapUsageTracker::GetUsageSnapshot(); - EXPECT_EQ(kOuterAllocSize, usage.max_allocated_bytes); - - const size_t kInnerLargerAllocSize = kOuterAllocSize + 673U; - - { - ThreadHeapUsageTracker inner_usage_tracker; - inner_usage_tracker.Start(); - - // Make a larger allocation than the outer scope. - ptr = MockMalloc(kInnerLargerAllocSize); - MockFree(ptr); - - // inner_usage_tracker goes out of scope without a Stop(). - } - - ThreadHeapUsage current = ThreadHeapUsageTracker::GetUsageSnapshot(); - EXPECT_EQ(usage.alloc_ops + 1, current.alloc_ops); - EXPECT_EQ(usage.alloc_bytes + kInnerLargerAllocSize, current.alloc_bytes); - EXPECT_EQ(usage.free_ops + 1, current.free_ops); - EXPECT_EQ(usage.free_bytes + kInnerLargerAllocSize, current.free_bytes); - EXPECT_EQ(kInnerLargerAllocSize, current.max_allocated_bytes); -} - -TEST_F(ThreadHeapUsageTrackerTest, ExclusiveScopesWork) { - ThreadHeapUsageTracker usage_tracker; - usage_tracker.Start(); - - const size_t kOuterAllocSize = 1029U; - void* ptr = MockMalloc(kOuterAllocSize); - MockFree(ptr); - - ThreadHeapUsage usage = ThreadHeapUsageTracker::GetUsageSnapshot(); - EXPECT_EQ(kOuterAllocSize, usage.max_allocated_bytes); - - { - ThreadHeapUsageTracker inner_usage_tracker; - inner_usage_tracker.Start(); - - // Make a larger allocation than the outer scope. - ptr = MockMalloc(kOuterAllocSize + 673U); - MockFree(ptr); - - // This tracker is exlusive, all activity should be private to this scope. - inner_usage_tracker.Stop(true); - } - - ThreadHeapUsage current = ThreadHeapUsageTracker::GetUsageSnapshot(); - EXPECT_EQ(usage.alloc_ops, current.alloc_ops); - EXPECT_EQ(usage.alloc_bytes, current.alloc_bytes); - EXPECT_EQ(usage.alloc_overhead_bytes, current.alloc_overhead_bytes); - EXPECT_EQ(usage.free_ops, current.free_ops); - EXPECT_EQ(usage.free_bytes, current.free_bytes); - EXPECT_EQ(usage.max_allocated_bytes, current.max_allocated_bytes); -} - -TEST_F(ThreadHeapUsageTrackerTest, AllShimFunctionsAreProvided) { - const size_t kAllocSize = 100; - void* alloc = MockMalloc(kAllocSize); - size_t estimate = MockGetSizeEstimate(alloc); - ASSERT_TRUE(estimate == 0 || estimate >= kAllocSize); - MockFree(alloc); - - alloc = MockCalloc(kAllocSize, 1); - estimate = MockGetSizeEstimate(alloc); - ASSERT_TRUE(estimate == 0 || estimate >= kAllocSize); - MockFree(alloc); - - alloc = MockAllocAligned(1, kAllocSize); - estimate = MockGetSizeEstimate(alloc); - ASSERT_TRUE(estimate == 0 || estimate >= kAllocSize); - - alloc = MockRealloc(alloc, kAllocSize); - estimate = MockGetSizeEstimate(alloc); - ASSERT_TRUE(estimate == 0 || estimate >= kAllocSize); - MockFree(alloc); -} - -} // namespace debug -} // namespace base
diff --git a/base/deferred_sequenced_task_runner_unittest.cc b/base/deferred_sequenced_task_runner_unittest.cc deleted file mode 100644 index 5cb220f..0000000 --- a/base/deferred_sequenced_task_runner_unittest.cc +++ /dev/null
@@ -1,214 +0,0 @@ -// 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/deferred_sequenced_task_runner.h" - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/callback_forward.h" -#include "base/location.h" -#include "base/memory/ref_counted.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "base/single_thread_task_runner.h" -#include "base/threading/thread.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -class DeferredSequencedTaskRunnerTest : public testing::Test { - public: - class ExecuteTaskOnDestructor : public RefCounted<ExecuteTaskOnDestructor> { - public: - ExecuteTaskOnDestructor( - DeferredSequencedTaskRunnerTest* executor, - int task_id) - : executor_(executor), - task_id_(task_id) { - } - private: - friend class RefCounted<ExecuteTaskOnDestructor>; - virtual ~ExecuteTaskOnDestructor() { executor_->ExecuteTask(task_id_); } - DeferredSequencedTaskRunnerTest* executor_; - int task_id_; - }; - - void ExecuteTask(int task_id) { - AutoLock lock(lock_); - executed_task_ids_.push_back(task_id); - } - - void PostExecuteTask(int task_id) { - runner_->PostTask(FROM_HERE, - BindOnce(&DeferredSequencedTaskRunnerTest::ExecuteTask, - Unretained(this), task_id)); - } - - void StartRunner() { - runner_->Start(); - } - - void DoNothing(ExecuteTaskOnDestructor* object) { - } - - protected: - DeferredSequencedTaskRunnerTest() - : loop_(), - runner_(new DeferredSequencedTaskRunner(loop_.task_runner())) {} - - MessageLoop loop_; - scoped_refptr<DeferredSequencedTaskRunner> runner_; - mutable Lock lock_; - std::vector<int> executed_task_ids_; -}; - -TEST_F(DeferredSequencedTaskRunnerTest, Stopped) { - PostExecuteTask(1); - RunLoop().RunUntilIdle(); - EXPECT_THAT(executed_task_ids_, testing::ElementsAre()); -} - -TEST_F(DeferredSequencedTaskRunnerTest, Start) { - StartRunner(); - PostExecuteTask(1); - RunLoop().RunUntilIdle(); - EXPECT_THAT(executed_task_ids_, testing::ElementsAre(1)); -} - -TEST_F(DeferredSequencedTaskRunnerTest, StartWithMultipleElements) { - StartRunner(); - for (int i = 1; i < 5; ++i) - PostExecuteTask(i); - - RunLoop().RunUntilIdle(); - EXPECT_THAT(executed_task_ids_, testing::ElementsAre(1, 2, 3, 4)); -} - -TEST_F(DeferredSequencedTaskRunnerTest, DeferredStart) { - PostExecuteTask(1); - RunLoop().RunUntilIdle(); - EXPECT_THAT(executed_task_ids_, testing::ElementsAre()); - - StartRunner(); - RunLoop().RunUntilIdle(); - EXPECT_THAT(executed_task_ids_, testing::ElementsAre(1)); - - PostExecuteTask(2); - RunLoop().RunUntilIdle(); - EXPECT_THAT(executed_task_ids_, testing::ElementsAre(1, 2)); -} - -TEST_F(DeferredSequencedTaskRunnerTest, DeferredStartWithMultipleElements) { - for (int i = 1; i < 5; ++i) - PostExecuteTask(i); - RunLoop().RunUntilIdle(); - EXPECT_THAT(executed_task_ids_, testing::ElementsAre()); - - StartRunner(); - for (int i = 5; i < 9; ++i) - PostExecuteTask(i); - RunLoop().RunUntilIdle(); - EXPECT_THAT(executed_task_ids_, testing::ElementsAre(1, 2, 3, 4, 5, 6, 7, 8)); -} - -TEST_F(DeferredSequencedTaskRunnerTest, DeferredStartWithMultipleThreads) { - { - Thread thread1("DeferredSequencedTaskRunnerTestThread1"); - Thread thread2("DeferredSequencedTaskRunnerTestThread2"); - thread1.Start(); - thread2.Start(); - for (int i = 0; i < 5; ++i) { - thread1.task_runner()->PostTask( - FROM_HERE, BindOnce(&DeferredSequencedTaskRunnerTest::PostExecuteTask, - Unretained(this), 2 * i)); - thread2.task_runner()->PostTask( - FROM_HERE, BindOnce(&DeferredSequencedTaskRunnerTest::PostExecuteTask, - Unretained(this), 2 * i + 1)); - if (i == 2) { - thread1.task_runner()->PostTask( - FROM_HERE, BindOnce(&DeferredSequencedTaskRunnerTest::StartRunner, - Unretained(this))); - } - } - } - - RunLoop().RunUntilIdle(); - EXPECT_THAT(executed_task_ids_, - testing::WhenSorted(testing::ElementsAre(0, 1, 2, 3, 4, 5, 6, 7, 8, 9))); -} - -TEST_F(DeferredSequencedTaskRunnerTest, ObjectDestructionOrder) { - { - Thread thread("DeferredSequencedTaskRunnerTestThread"); - thread.Start(); - runner_ = new DeferredSequencedTaskRunner(thread.task_runner()); - for (int i = 0; i < 5; ++i) { - { - // Use a block to ensure that no reference to |short_lived_object| - // is kept on the main thread after it is posted to |runner_|. - scoped_refptr<ExecuteTaskOnDestructor> short_lived_object = - new ExecuteTaskOnDestructor(this, 2 * i); - runner_->PostTask( - FROM_HERE, - BindOnce(&DeferredSequencedTaskRunnerTest::DoNothing, - Unretained(this), RetainedRef(short_lived_object))); - } - // |short_lived_object| with id |2 * i| should be destroyed before the - // task |2 * i + 1| is executed. - PostExecuteTask(2 * i + 1); - } - StartRunner(); - } - - // All |short_lived_object| with id |2 * i| are destroyed before the task - // |2 * i + 1| is executed. - EXPECT_THAT(executed_task_ids_, - testing::ElementsAre(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)); -} - -void GetRunsTasksInCurrentSequence(bool* result, - scoped_refptr<SequencedTaskRunner> runner, - OnceClosure quit) { - *result = runner->RunsTasksInCurrentSequence(); - std::move(quit).Run(); -} - -TEST_F(DeferredSequencedTaskRunnerTest, RunsTasksInCurrentSequence) { - scoped_refptr<DeferredSequencedTaskRunner> runner = - MakeRefCounted<DeferredSequencedTaskRunner>(); - EXPECT_TRUE(runner->RunsTasksInCurrentSequence()); - - Thread thread1("DeferredSequencedTaskRunnerTestThread1"); - thread1.Start(); - bool runs_task_in_current_thread = true; - base::RunLoop run_loop; - thread1.task_runner()->PostTask( - FROM_HERE, - BindOnce(&GetRunsTasksInCurrentSequence, &runs_task_in_current_thread, - runner, run_loop.QuitClosure())); - run_loop.Run(); - EXPECT_FALSE(runs_task_in_current_thread); -} - -TEST_F(DeferredSequencedTaskRunnerTest, StartWithTaskRunner) { - scoped_refptr<DeferredSequencedTaskRunner> runner = - MakeRefCounted<DeferredSequencedTaskRunner>(); - bool run_called = false; - base::RunLoop run_loop; - runner->PostTask(FROM_HERE, - BindOnce( - [](bool* run_called, base::Closure quit_closure) { - *run_called = true; - std::move(quit_closure).Run(); - }, - &run_called, run_loop.QuitClosure())); - runner->StartWithTaskRunner(loop_.task_runner()); - run_loop.Run(); - EXPECT_TRUE(run_called); -} - -} // namespace -} // namespace base
diff --git a/base/environment_unittest.cc b/base/environment_unittest.cc deleted file mode 100644 index 79800ad..0000000 --- a/base/environment_unittest.cc +++ /dev/null
@@ -1,171 +0,0 @@ -// 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/environment.h" - -#include <memory> - -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/platform_test.h" - -typedef PlatformTest EnvironmentTest; - -namespace base { - -namespace { - -constexpr char kValidEnvironmentVariable[] = "PATH"; - -} // namespace - -TEST_F(EnvironmentTest, GetVar) { - std::unique_ptr<Environment> env(Environment::Create()); - std::string env_value; - EXPECT_TRUE(env->GetVar(kValidEnvironmentVariable, &env_value)); - EXPECT_NE(env_value, ""); -} - -TEST_F(EnvironmentTest, GetVarReverse) { - std::unique_ptr<Environment> env(Environment::Create()); - const char kFooUpper[] = "FOO"; - const char kFooLower[] = "foo"; - - // Set a variable in UPPER case. - EXPECT_TRUE(env->SetVar(kFooUpper, kFooLower)); - - // And then try to get this variable passing the lower case. - std::string env_value; - EXPECT_TRUE(env->GetVar(kFooLower, &env_value)); - - EXPECT_STREQ(env_value.c_str(), kFooLower); - - EXPECT_TRUE(env->UnSetVar(kFooUpper)); - - const char kBar[] = "bar"; - // Now do the opposite, set the variable in the lower case. - EXPECT_TRUE(env->SetVar(kFooLower, kBar)); - - // And then try to get this variable passing the UPPER case. - EXPECT_TRUE(env->GetVar(kFooUpper, &env_value)); - - EXPECT_STREQ(env_value.c_str(), kBar); - - EXPECT_TRUE(env->UnSetVar(kFooLower)); -} - -TEST_F(EnvironmentTest, HasVar) { - std::unique_ptr<Environment> env(Environment::Create()); - EXPECT_TRUE(env->HasVar(kValidEnvironmentVariable)); -} - -TEST_F(EnvironmentTest, SetVar) { - std::unique_ptr<Environment> env(Environment::Create()); - - const char kFooUpper[] = "FOO"; - const char kFooLower[] = "foo"; - EXPECT_TRUE(env->SetVar(kFooUpper, kFooLower)); - - // Now verify that the environment has the new variable. - EXPECT_TRUE(env->HasVar(kFooUpper)); - - std::string var_value; - EXPECT_TRUE(env->GetVar(kFooUpper, &var_value)); - EXPECT_EQ(var_value, kFooLower); -} - -TEST_F(EnvironmentTest, UnSetVar) { - std::unique_ptr<Environment> env(Environment::Create()); - - const char kFooUpper[] = "FOO"; - const char kFooLower[] = "foo"; - // First set some environment variable. - EXPECT_TRUE(env->SetVar(kFooUpper, kFooLower)); - - // Now verify that the environment has the new variable. - EXPECT_TRUE(env->HasVar(kFooUpper)); - - // Finally verify that the environment variable was erased. - EXPECT_TRUE(env->UnSetVar(kFooUpper)); - - // And check that the variable has been unset. - EXPECT_FALSE(env->HasVar(kFooUpper)); -} - -#if defined(OS_WIN) - -TEST_F(EnvironmentTest, AlterEnvironment) { - const wchar_t empty[] = L"\0"; - const wchar_t a2[] = L"A=2\0"; - EnvironmentMap changes; - string16 e; - - e = AlterEnvironment(empty, changes); - EXPECT_EQ(0, e[0]); - - changes[L"A"] = L"1"; - e = AlterEnvironment(empty, changes); - EXPECT_EQ(string16(L"A=1\0\0", 5), e); - - changes.clear(); - changes[L"A"] = string16(); - e = AlterEnvironment(empty, changes); - EXPECT_EQ(string16(L"\0\0", 2), e); - - changes.clear(); - e = AlterEnvironment(a2, changes); - EXPECT_EQ(string16(L"A=2\0\0", 5), e); - - changes.clear(); - changes[L"A"] = L"1"; - e = AlterEnvironment(a2, changes); - EXPECT_EQ(string16(L"A=1\0\0", 5), e); - - changes.clear(); - changes[L"A"] = string16(); - e = AlterEnvironment(a2, changes); - EXPECT_EQ(string16(L"\0\0", 2), e); -} - -#else - -TEST_F(EnvironmentTest, AlterEnvironment) { - const char* const empty[] = {nullptr}; - const char* const a2[] = {"A=2", nullptr}; - EnvironmentMap changes; - std::unique_ptr<char* []> e; - - e = AlterEnvironment(empty, changes); - EXPECT_TRUE(e[0] == nullptr); - - changes["A"] = "1"; - e = AlterEnvironment(empty, changes); - EXPECT_EQ(std::string("A=1"), e[0]); - EXPECT_TRUE(e[1] == nullptr); - - changes.clear(); - changes["A"] = std::string(); - e = AlterEnvironment(empty, changes); - EXPECT_TRUE(e[0] == nullptr); - - changes.clear(); - e = AlterEnvironment(a2, changes); - EXPECT_EQ(std::string("A=2"), e[0]); - EXPECT_TRUE(e[1] == nullptr); - - changes.clear(); - changes["A"] = "1"; - e = AlterEnvironment(a2, changes); - EXPECT_EQ(std::string("A=1"), e[0]); - EXPECT_TRUE(e[1] == nullptr); - - changes.clear(); - changes["A"] = std::string(); - e = AlterEnvironment(a2, changes); - EXPECT_TRUE(e[0] == nullptr); -} - -#endif - -} // namespace base
diff --git a/base/feature_list_unittest.cc b/base/feature_list_unittest.cc deleted file mode 100644 index 164997a..0000000 --- a/base/feature_list_unittest.cc +++ /dev/null
@@ -1,542 +0,0 @@ -// 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/feature_list.h" - -#include <stddef.h> - -#include <algorithm> -#include <utility> - -#include "base/format_macros.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/metrics/field_trial.h" -#include "base/metrics/persistent_memory_allocator.h" -#include "base/strings/string_piece.h" -#include "base/strings/string_util.h" -#include "base/strings/stringprintf.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -constexpr char kFeatureOnByDefaultName[] = "OnByDefault"; -struct Feature kFeatureOnByDefault { - kFeatureOnByDefaultName, FEATURE_ENABLED_BY_DEFAULT -}; - -constexpr char kFeatureOffByDefaultName[] = "OffByDefault"; -struct Feature kFeatureOffByDefault { - kFeatureOffByDefaultName, FEATURE_DISABLED_BY_DEFAULT -}; - -std::string SortFeatureListString(const std::string& feature_list) { - std::vector<base::StringPiece> features = - FeatureList::SplitFeatureListString(feature_list); - std::sort(features.begin(), features.end()); - return JoinString(features, ","); -} - -} // namespace - -class FeatureListTest : public testing::Test { - public: - FeatureListTest() : feature_list_(nullptr) { - RegisterFeatureListInstance(WrapUnique(new FeatureList)); - } - ~FeatureListTest() override { ClearFeatureListInstance(); } - - void RegisterFeatureListInstance(std::unique_ptr<FeatureList> feature_list) { - FeatureList::ClearInstanceForTesting(); - feature_list_ = feature_list.get(); - FeatureList::SetInstance(std::move(feature_list)); - } - void ClearFeatureListInstance() { - FeatureList::ClearInstanceForTesting(); - feature_list_ = nullptr; - } - - FeatureList* feature_list() { return feature_list_; } - - private: - // Weak. Owned by the FeatureList::SetInstance(). - FeatureList* feature_list_; - - DISALLOW_COPY_AND_ASSIGN(FeatureListTest); -}; - -TEST_F(FeatureListTest, DefaultStates) { - EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault)); - EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault)); -} - -TEST_F(FeatureListTest, InitializeFromCommandLine) { - struct { - const char* enable_features; - const char* disable_features; - bool expected_feature_on_state; - bool expected_feature_off_state; - } test_cases[] = { - {"", "", true, false}, - {"OffByDefault", "", true, true}, - {"OffByDefault", "OnByDefault", false, true}, - {"OnByDefault,OffByDefault", "", true, true}, - {"", "OnByDefault,OffByDefault", false, false}, - // In the case an entry is both, disable takes precedence. - {"OnByDefault", "OnByDefault,OffByDefault", false, false}, - }; - - for (size_t i = 0; i < arraysize(test_cases); ++i) { - const auto& test_case = test_cases[i]; - SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: [%s] [%s]", i, - test_case.enable_features, - test_case.disable_features)); - - ClearFeatureListInstance(); - std::unique_ptr<FeatureList> feature_list(new FeatureList); - feature_list->InitializeFromCommandLine(test_case.enable_features, - test_case.disable_features); - RegisterFeatureListInstance(std::move(feature_list)); - - EXPECT_EQ(test_case.expected_feature_on_state, - FeatureList::IsEnabled(kFeatureOnByDefault)) - << i; - EXPECT_EQ(test_case.expected_feature_off_state, - FeatureList::IsEnabled(kFeatureOffByDefault)) - << i; - } -} - -TEST_F(FeatureListTest, CheckFeatureIdentity) { - // Tests that CheckFeatureIdentity() correctly detects when two different - // structs with the same feature name are passed to it. - - // Call it twice for each feature at the top of the file, since the first call - // makes it remember the entry and the second call will verify it. - EXPECT_TRUE(feature_list()->CheckFeatureIdentity(kFeatureOnByDefault)); - EXPECT_TRUE(feature_list()->CheckFeatureIdentity(kFeatureOnByDefault)); - EXPECT_TRUE(feature_list()->CheckFeatureIdentity(kFeatureOffByDefault)); - EXPECT_TRUE(feature_list()->CheckFeatureIdentity(kFeatureOffByDefault)); - - // Now, call it with a distinct struct for |kFeatureOnByDefaultName|, which - // should return false. - struct Feature kFeatureOnByDefault2 { - kFeatureOnByDefaultName, FEATURE_ENABLED_BY_DEFAULT - }; - EXPECT_FALSE(feature_list()->CheckFeatureIdentity(kFeatureOnByDefault2)); -} - -TEST_F(FeatureListTest, FieldTrialOverrides) { - struct { - FeatureList::OverrideState trial1_state; - FeatureList::OverrideState trial2_state; - } test_cases[] = { - {FeatureList::OVERRIDE_DISABLE_FEATURE, - FeatureList::OVERRIDE_DISABLE_FEATURE}, - {FeatureList::OVERRIDE_DISABLE_FEATURE, - FeatureList::OVERRIDE_ENABLE_FEATURE}, - {FeatureList::OVERRIDE_ENABLE_FEATURE, - FeatureList::OVERRIDE_DISABLE_FEATURE}, - {FeatureList::OVERRIDE_ENABLE_FEATURE, - FeatureList::OVERRIDE_ENABLE_FEATURE}, - }; - - FieldTrial::ActiveGroup active_group; - for (size_t i = 0; i < arraysize(test_cases); ++i) { - const auto& test_case = test_cases[i]; - SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]", i)); - - ClearFeatureListInstance(); - - FieldTrialList field_trial_list(nullptr); - std::unique_ptr<FeatureList> feature_list(new FeatureList); - - FieldTrial* trial1 = FieldTrialList::CreateFieldTrial("TrialExample1", "A"); - FieldTrial* trial2 = FieldTrialList::CreateFieldTrial("TrialExample2", "B"); - feature_list->RegisterFieldTrialOverride(kFeatureOnByDefaultName, - test_case.trial1_state, trial1); - feature_list->RegisterFieldTrialOverride(kFeatureOffByDefaultName, - test_case.trial2_state, trial2); - RegisterFeatureListInstance(std::move(feature_list)); - - // Initially, neither trial should be active. - EXPECT_FALSE(FieldTrialList::IsTrialActive(trial1->trial_name())); - EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name())); - - const bool expected_enabled_1 = - (test_case.trial1_state == FeatureList::OVERRIDE_ENABLE_FEATURE); - EXPECT_EQ(expected_enabled_1, FeatureList::IsEnabled(kFeatureOnByDefault)); - // The above should have activated |trial1|. - EXPECT_TRUE(FieldTrialList::IsTrialActive(trial1->trial_name())); - EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name())); - - const bool expected_enabled_2 = - (test_case.trial2_state == FeatureList::OVERRIDE_ENABLE_FEATURE); - EXPECT_EQ(expected_enabled_2, FeatureList::IsEnabled(kFeatureOffByDefault)); - // The above should have activated |trial2|. - EXPECT_TRUE(FieldTrialList::IsTrialActive(trial1->trial_name())); - EXPECT_TRUE(FieldTrialList::IsTrialActive(trial2->trial_name())); - } -} - -TEST_F(FeatureListTest, FieldTrialAssociateUseDefault) { - FieldTrialList field_trial_list(nullptr); - std::unique_ptr<FeatureList> feature_list(new FeatureList); - - FieldTrial* trial1 = FieldTrialList::CreateFieldTrial("TrialExample1", "A"); - FieldTrial* trial2 = FieldTrialList::CreateFieldTrial("TrialExample2", "B"); - feature_list->RegisterFieldTrialOverride( - kFeatureOnByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial1); - feature_list->RegisterFieldTrialOverride( - kFeatureOffByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial2); - RegisterFeatureListInstance(std::move(feature_list)); - - // Initially, neither trial should be active. - EXPECT_FALSE(FieldTrialList::IsTrialActive(trial1->trial_name())); - EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name())); - - // Check the feature enabled state is its default. - EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault)); - // The above should have activated |trial1|. - EXPECT_TRUE(FieldTrialList::IsTrialActive(trial1->trial_name())); - EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name())); - - // Check the feature enabled state is its default. - EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault)); - // The above should have activated |trial2|. - EXPECT_TRUE(FieldTrialList::IsTrialActive(trial1->trial_name())); - EXPECT_TRUE(FieldTrialList::IsTrialActive(trial2->trial_name())); -} - -TEST_F(FeatureListTest, CommandLineTakesPrecedenceOverFieldTrial) { - ClearFeatureListInstance(); - - FieldTrialList field_trial_list(nullptr); - std::unique_ptr<FeatureList> feature_list(new FeatureList); - - // The feature is explicitly enabled on the command-line. - feature_list->InitializeFromCommandLine(kFeatureOffByDefaultName, ""); - - // But the FieldTrial would set the feature to disabled. - FieldTrial* trial = FieldTrialList::CreateFieldTrial("TrialExample2", "A"); - feature_list->RegisterFieldTrialOverride( - kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE, trial); - RegisterFeatureListInstance(std::move(feature_list)); - - EXPECT_FALSE(FieldTrialList::IsTrialActive(trial->trial_name())); - // Command-line should take precedence. - EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault)); - // Since the feature is on due to the command-line, and not as a result of the - // field trial, the field trial should not be activated (since the Associate* - // API wasn't used.) - EXPECT_FALSE(FieldTrialList::IsTrialActive(trial->trial_name())); -} - -TEST_F(FeatureListTest, IsFeatureOverriddenFromCommandLine) { - ClearFeatureListInstance(); - - FieldTrialList field_trial_list(nullptr); - std::unique_ptr<FeatureList> feature_list(new FeatureList); - - // No features are overridden from the command line yet - EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine( - kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE)); - EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine( - kFeatureOnByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE)); - EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine( - kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE)); - EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine( - kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE)); - - // Now, enable |kFeatureOffByDefaultName| via the command-line. - feature_list->InitializeFromCommandLine(kFeatureOffByDefaultName, ""); - - // It should now be overridden for the enabled group. - EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine( - kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE)); - EXPECT_TRUE(feature_list->IsFeatureOverriddenFromCommandLine( - kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE)); - - // Register a field trial to associate with the feature and ensure that the - // results are still the same. - feature_list->AssociateReportingFieldTrial( - kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE, - FieldTrialList::CreateFieldTrial("Trial1", "A")); - EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine( - kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE)); - EXPECT_TRUE(feature_list->IsFeatureOverriddenFromCommandLine( - kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE)); - - // Now, register a field trial to override |kFeatureOnByDefaultName| state - // and check that the function still returns false for that feature. - feature_list->RegisterFieldTrialOverride( - kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE, - FieldTrialList::CreateFieldTrial("Trial2", "A")); - EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine( - kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE)); - EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine( - kFeatureOnByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE)); - RegisterFeatureListInstance(std::move(feature_list)); - - // Check the expected feature states for good measure. - EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault)); - EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault)); -} - -TEST_F(FeatureListTest, AssociateReportingFieldTrial) { - struct { - const char* enable_features; - const char* disable_features; - bool expected_enable_trial_created; - bool expected_disable_trial_created; - } test_cases[] = { - // If no enable/disable flags are specified, no trials should be created. - {"", "", false, false}, - // Enabling the feature should result in the enable trial created. - {kFeatureOffByDefaultName, "", true, false}, - // Disabling the feature should result in the disable trial created. - {"", kFeatureOffByDefaultName, false, true}, - }; - - const char kTrialName[] = "ForcingTrial"; - const char kForcedOnGroupName[] = "ForcedOn"; - const char kForcedOffGroupName[] = "ForcedOff"; - - for (size_t i = 0; i < arraysize(test_cases); ++i) { - const auto& test_case = test_cases[i]; - SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: [%s] [%s]", i, - test_case.enable_features, - test_case.disable_features)); - - ClearFeatureListInstance(); - - FieldTrialList field_trial_list(nullptr); - std::unique_ptr<FeatureList> feature_list(new FeatureList); - feature_list->InitializeFromCommandLine(test_case.enable_features, - test_case.disable_features); - - FieldTrial* enable_trial = nullptr; - if (feature_list->IsFeatureOverriddenFromCommandLine( - kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE)) { - enable_trial = base::FieldTrialList::CreateFieldTrial(kTrialName, - kForcedOnGroupName); - feature_list->AssociateReportingFieldTrial( - kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE, - enable_trial); - } - FieldTrial* disable_trial = nullptr; - if (feature_list->IsFeatureOverriddenFromCommandLine( - kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE)) { - disable_trial = base::FieldTrialList::CreateFieldTrial( - kTrialName, kForcedOffGroupName); - feature_list->AssociateReportingFieldTrial( - kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE, - disable_trial); - } - EXPECT_EQ(test_case.expected_enable_trial_created, enable_trial != nullptr); - EXPECT_EQ(test_case.expected_disable_trial_created, - disable_trial != nullptr); - RegisterFeatureListInstance(std::move(feature_list)); - - EXPECT_FALSE(FieldTrialList::IsTrialActive(kTrialName)); - if (disable_trial) { - EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault)); - EXPECT_TRUE(FieldTrialList::IsTrialActive(kTrialName)); - EXPECT_EQ(kForcedOffGroupName, disable_trial->group_name()); - } else if (enable_trial) { - EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault)); - EXPECT_TRUE(FieldTrialList::IsTrialActive(kTrialName)); - EXPECT_EQ(kForcedOnGroupName, enable_trial->group_name()); - } - } -} - -TEST_F(FeatureListTest, GetFeatureOverrides) { - ClearFeatureListInstance(); - FieldTrialList field_trial_list(nullptr); - std::unique_ptr<FeatureList> feature_list(new FeatureList); - feature_list->InitializeFromCommandLine("A,X", "D"); - - FieldTrial* trial = FieldTrialList::CreateFieldTrial("Trial", "Group"); - feature_list->RegisterFieldTrialOverride(kFeatureOffByDefaultName, - FeatureList::OVERRIDE_ENABLE_FEATURE, - trial); - - RegisterFeatureListInstance(std::move(feature_list)); - - std::string enable_features; - std::string disable_features; - FeatureList::GetInstance()->GetFeatureOverrides(&enable_features, - &disable_features); - EXPECT_EQ("A,OffByDefault<Trial,X", SortFeatureListString(enable_features)); - EXPECT_EQ("D", SortFeatureListString(disable_features)); - - FeatureList::GetInstance()->GetCommandLineFeatureOverrides(&enable_features, - &disable_features); - EXPECT_EQ("A,X", SortFeatureListString(enable_features)); - EXPECT_EQ("D", SortFeatureListString(disable_features)); -} - -TEST_F(FeatureListTest, GetFeatureOverrides_UseDefault) { - ClearFeatureListInstance(); - FieldTrialList field_trial_list(nullptr); - std::unique_ptr<FeatureList> feature_list(new FeatureList); - feature_list->InitializeFromCommandLine("A,X", "D"); - - FieldTrial* trial = FieldTrialList::CreateFieldTrial("Trial", "Group"); - feature_list->RegisterFieldTrialOverride( - kFeatureOffByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial); - - RegisterFeatureListInstance(std::move(feature_list)); - - std::string enable_features; - std::string disable_features; - FeatureList::GetInstance()->GetFeatureOverrides(&enable_features, - &disable_features); - EXPECT_EQ("*OffByDefault<Trial,A,X", SortFeatureListString(enable_features)); - EXPECT_EQ("D", SortFeatureListString(disable_features)); -} - -TEST_F(FeatureListTest, GetFieldTrial) { - ClearFeatureListInstance(); - FieldTrialList field_trial_list(nullptr); - FieldTrial* trial = FieldTrialList::CreateFieldTrial("Trial", "Group"); - std::unique_ptr<FeatureList> feature_list(new FeatureList); - feature_list->RegisterFieldTrialOverride( - kFeatureOnByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial); - RegisterFeatureListInstance(std::move(feature_list)); - - EXPECT_EQ(trial, FeatureList::GetFieldTrial(kFeatureOnByDefault)); - EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kFeatureOffByDefault)); -} - -TEST_F(FeatureListTest, InitializeFromCommandLine_WithFieldTrials) { - ClearFeatureListInstance(); - FieldTrialList field_trial_list(nullptr); - FieldTrialList::CreateFieldTrial("Trial", "Group"); - std::unique_ptr<FeatureList> feature_list(new FeatureList); - feature_list->InitializeFromCommandLine("A,OffByDefault<Trial,X", "D"); - RegisterFeatureListInstance(std::move(feature_list)); - - EXPECT_FALSE(FieldTrialList::IsTrialActive("Trial")); - EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault)); - EXPECT_TRUE(FieldTrialList::IsTrialActive("Trial")); -} - -TEST_F(FeatureListTest, InitializeFromCommandLine_UseDefault) { - ClearFeatureListInstance(); - FieldTrialList field_trial_list(nullptr); - FieldTrialList::CreateFieldTrial("T1", "Group"); - FieldTrialList::CreateFieldTrial("T2", "Group"); - std::unique_ptr<FeatureList> feature_list(new FeatureList); - feature_list->InitializeFromCommandLine( - "A,*OffByDefault<T1,*OnByDefault<T2,X", "D"); - RegisterFeatureListInstance(std::move(feature_list)); - - EXPECT_FALSE(FieldTrialList::IsTrialActive("T1")); - EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault)); - EXPECT_TRUE(FieldTrialList::IsTrialActive("T1")); - - EXPECT_FALSE(FieldTrialList::IsTrialActive("T2")); - EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault)); - EXPECT_TRUE(FieldTrialList::IsTrialActive("T2")); -} - -TEST_F(FeatureListTest, InitializeInstance) { - ClearFeatureListInstance(); - - std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList); - FeatureList::SetInstance(std::move(feature_list)); - EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault)); - EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault)); - - // Initialize from command line if we haven't yet. - FeatureList::InitializeInstance("", kFeatureOnByDefaultName); - EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault)); - EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault)); - - // Do not initialize from commandline if we have already. - FeatureList::InitializeInstance(kFeatureOffByDefaultName, ""); - EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault)); - EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault)); -} - -TEST_F(FeatureListTest, UninitializedInstance_IsEnabledReturnsFalse) { - ClearFeatureListInstance(); - // This test case simulates the calling pattern found in code which does not - // explicitly initialize the features list. - // All IsEnabled() calls should return the default value in this scenario. - EXPECT_EQ(nullptr, FeatureList::GetInstance()); - EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault)); - EXPECT_EQ(nullptr, FeatureList::GetInstance()); - EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault)); -} - -TEST_F(FeatureListTest, StoreAndRetrieveFeaturesFromSharedMemory) { - std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList); - - // Create some overrides. - feature_list->RegisterOverride(kFeatureOffByDefaultName, - FeatureList::OVERRIDE_ENABLE_FEATURE, nullptr); - feature_list->RegisterOverride( - kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE, nullptr); - feature_list->FinalizeInitialization(); - - // Create an allocator and store the overrides. - std::unique_ptr<SharedMemory> shm(new SharedMemory()); - shm->CreateAndMapAnonymous(4 << 10); - SharedPersistentMemoryAllocator allocator(std::move(shm), 1, "", false); - feature_list->AddFeaturesToAllocator(&allocator); - - std::unique_ptr<base::FeatureList> feature_list2(new base::FeatureList); - - // Check that the new feature list is empty. - EXPECT_FALSE(feature_list2->IsFeatureOverriddenFromCommandLine( - kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE)); - EXPECT_FALSE(feature_list2->IsFeatureOverriddenFromCommandLine( - kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE)); - - feature_list2->InitializeFromSharedMemory(&allocator); - // Check that the new feature list now has 2 overrides. - EXPECT_TRUE(feature_list2->IsFeatureOverriddenFromCommandLine( - kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE)); - EXPECT_TRUE(feature_list2->IsFeatureOverriddenFromCommandLine( - kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE)); -} - -TEST_F(FeatureListTest, StoreAndRetrieveAssociatedFeaturesFromSharedMemory) { - FieldTrialList field_trial_list(nullptr); - std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList); - - // Create some overrides. - FieldTrial* trial1 = FieldTrialList::CreateFieldTrial("TrialExample1", "A"); - FieldTrial* trial2 = FieldTrialList::CreateFieldTrial("TrialExample2", "B"); - feature_list->RegisterFieldTrialOverride( - kFeatureOnByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial1); - feature_list->RegisterFieldTrialOverride( - kFeatureOffByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial2); - feature_list->FinalizeInitialization(); - - // Create an allocator and store the overrides. - std::unique_ptr<SharedMemory> shm(new SharedMemory()); - shm->CreateAndMapAnonymous(4 << 10); - SharedPersistentMemoryAllocator allocator(std::move(shm), 1, "", false); - feature_list->AddFeaturesToAllocator(&allocator); - - std::unique_ptr<base::FeatureList> feature_list2(new base::FeatureList); - feature_list2->InitializeFromSharedMemory(&allocator); - feature_list2->FinalizeInitialization(); - - // Check that the field trials are still associated. - FieldTrial* associated_trial1 = - feature_list2->GetAssociatedFieldTrial(kFeatureOnByDefault); - FieldTrial* associated_trial2 = - feature_list2->GetAssociatedFieldTrial(kFeatureOffByDefault); - EXPECT_EQ(associated_trial1, trial1); - EXPECT_EQ(associated_trial2, trial2); -} - -} // namespace base
diff --git a/base/file_version_info_win_unittest.cc b/base/file_version_info_win_unittest.cc deleted file mode 100644 index a4acc4c..0000000 --- a/base/file_version_info_win_unittest.cc +++ /dev/null
@@ -1,175 +0,0 @@ -// 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/file_version_info_win.h" - -#include <windows.h> - -#include <stddef.h> - -#include <memory> - -#include "base/file_version_info.h" -#include "base/files/file_path.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/path_service.h" -#include "base/scoped_native_library.h" -#include "testing/gtest/include/gtest/gtest.h" - -using base::FilePath; - -namespace { - -FilePath GetTestDataPath() { - FilePath path; - base::PathService::Get(base::DIR_SOURCE_ROOT, &path); - path = path.AppendASCII("base"); - path = path.AppendASCII("test"); - path = path.AppendASCII("data"); - path = path.AppendASCII("file_version_info_unittest"); - return path; -} - -class FileVersionInfoFactory { - public: - explicit FileVersionInfoFactory(const FilePath& path) : path_(path) {} - - std::unique_ptr<FileVersionInfo> Create() const { - return base::WrapUnique(FileVersionInfo::CreateFileVersionInfo(path_)); - } - - private: - const FilePath path_; - - DISALLOW_COPY_AND_ASSIGN(FileVersionInfoFactory); -}; - -class FileVersionInfoForModuleFactory { - public: - explicit FileVersionInfoForModuleFactory(const FilePath& path) - // Load the library with LOAD_LIBRARY_AS_IMAGE_RESOURCE since it shouldn't - // be executed. - : library_(::LoadLibraryEx(path.value().c_str(), - nullptr, - LOAD_LIBRARY_AS_IMAGE_RESOURCE)) { - EXPECT_TRUE(library_.is_valid()); - } - - std::unique_ptr<FileVersionInfo> Create() const { - return base::WrapUnique( - FileVersionInfo::CreateFileVersionInfoForModule(library_.get())); - } - - private: - const base::ScopedNativeLibrary library_; - - DISALLOW_COPY_AND_ASSIGN(FileVersionInfoForModuleFactory); -}; - -template <typename T> -class FileVersionInfoTest : public testing::Test {}; - -using FileVersionInfoFactories = - ::testing::Types<FileVersionInfoFactory, FileVersionInfoForModuleFactory>; - -} // namespace - -TYPED_TEST_CASE(FileVersionInfoTest, FileVersionInfoFactories); - -TYPED_TEST(FileVersionInfoTest, HardCodedProperties) { - const wchar_t kDLLName[] = {L"FileVersionInfoTest1.dll"}; - - const wchar_t* const kExpectedValues[15] = { - // FileVersionInfoTest.dll - L"Goooooogle", // company_name - L"Google", // company_short_name - L"This is the product name", // product_name - L"This is the product short name", // product_short_name - L"The Internal Name", // internal_name - L"4.3.2.1", // product_version - L"Private build property", // private_build - L"Special build property", // special_build - L"This is a particularly interesting comment", // comments - L"This is the original filename", // original_filename - L"This is my file description", // file_description - L"1.2.3.4", // file_version - L"This is the legal copyright", // legal_copyright - L"This is the legal trademarks", // legal_trademarks - L"This is the last change", // last_change - }; - - FilePath dll_path = GetTestDataPath(); - dll_path = dll_path.Append(kDLLName); - - TypeParam factory(dll_path); - std::unique_ptr<FileVersionInfo> version_info(factory.Create()); - ASSERT_TRUE(version_info); - - int j = 0; - EXPECT_EQ(kExpectedValues[j++], version_info->company_name()); - EXPECT_EQ(kExpectedValues[j++], version_info->company_short_name()); - EXPECT_EQ(kExpectedValues[j++], version_info->product_name()); - EXPECT_EQ(kExpectedValues[j++], version_info->product_short_name()); - EXPECT_EQ(kExpectedValues[j++], version_info->internal_name()); - EXPECT_EQ(kExpectedValues[j++], version_info->product_version()); - EXPECT_EQ(kExpectedValues[j++], version_info->private_build()); - EXPECT_EQ(kExpectedValues[j++], version_info->special_build()); - EXPECT_EQ(kExpectedValues[j++], version_info->comments()); - EXPECT_EQ(kExpectedValues[j++], version_info->original_filename()); - EXPECT_EQ(kExpectedValues[j++], version_info->file_description()); - EXPECT_EQ(kExpectedValues[j++], version_info->file_version()); - EXPECT_EQ(kExpectedValues[j++], version_info->legal_copyright()); - EXPECT_EQ(kExpectedValues[j++], version_info->legal_trademarks()); - EXPECT_EQ(kExpectedValues[j++], version_info->last_change()); -} - -TYPED_TEST(FileVersionInfoTest, IsOfficialBuild) { - constexpr struct { - const wchar_t* const dll_name; - const bool is_official_build; - } kTestItems[]{ - {L"FileVersionInfoTest1.dll", true}, {L"FileVersionInfoTest2.dll", false}, - }; - - for (const auto& test_item : kTestItems) { - const FilePath dll_path = GetTestDataPath().Append(test_item.dll_name); - - TypeParam factory(dll_path); - std::unique_ptr<FileVersionInfo> version_info(factory.Create()); - ASSERT_TRUE(version_info); - - EXPECT_EQ(test_item.is_official_build, version_info->is_official_build()); - } -} - -TYPED_TEST(FileVersionInfoTest, CustomProperties) { - FilePath dll_path = GetTestDataPath(); - dll_path = dll_path.AppendASCII("FileVersionInfoTest1.dll"); - - TypeParam factory(dll_path); - std::unique_ptr<FileVersionInfo> version_info(factory.Create()); - ASSERT_TRUE(version_info); - - // Test few existing properties. - std::wstring str; - FileVersionInfoWin* version_info_win = - static_cast<FileVersionInfoWin*>(version_info.get()); - EXPECT_TRUE(version_info_win->GetValue(L"Custom prop 1", &str)); - EXPECT_EQ(L"Un", str); - EXPECT_EQ(L"Un", version_info_win->GetStringValue(L"Custom prop 1")); - - EXPECT_TRUE(version_info_win->GetValue(L"Custom prop 2", &str)); - EXPECT_EQ(L"Deux", str); - EXPECT_EQ(L"Deux", version_info_win->GetStringValue(L"Custom prop 2")); - - EXPECT_TRUE(version_info_win->GetValue(L"Custom prop 3", &str)); - EXPECT_EQ(L"1600 Amphitheatre Parkway Mountain View, CA 94043", str); - EXPECT_EQ(L"1600 Amphitheatre Parkway Mountain View, CA 94043", - version_info_win->GetStringValue(L"Custom prop 3")); - - // Test an non-existing property. - EXPECT_FALSE(version_info_win->GetValue(L"Unknown property", &str)); - EXPECT_EQ(L"", version_info_win->GetStringValue(L"Unknown property")); -}
diff --git a/base/files/dir_reader_posix_unittest.cc b/base/files/dir_reader_posix_unittest.cc deleted file mode 100644 index f82619b..0000000 --- a/base/files/dir_reader_posix_unittest.cc +++ /dev/null
@@ -1,95 +0,0 @@ -// 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/files/dir_reader_posix.h" - -#include <fcntl.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "base/files/scoped_temp_dir.h" -#include "base/logging.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(OS_ANDROID) -#include "base/os_compat_android.h" -#endif - -namespace base { - -TEST(DirReaderPosixUnittest, Read) { - static const unsigned kNumFiles = 100; - - if (DirReaderPosix::IsFallback()) - return; - - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - const char* dir = temp_dir.GetPath().value().c_str(); - ASSERT_TRUE(dir); - - char wdbuf[PATH_MAX]; - PCHECK(getcwd(wdbuf, PATH_MAX)); - - PCHECK(chdir(dir) == 0); - - for (unsigned i = 0; i < kNumFiles; i++) { - char buf[16]; - snprintf(buf, sizeof(buf), "%d", i); - const int fd = open(buf, O_CREAT | O_RDONLY | O_EXCL, 0600); - PCHECK(fd >= 0); - PCHECK(close(fd) == 0); - } - - std::set<unsigned> seen; - - DirReaderPosix reader(dir); - EXPECT_TRUE(reader.IsValid()); - - if (!reader.IsValid()) - return; - - bool seen_dot = false, seen_dotdot = false; - - for (; reader.Next(); ) { - if (strcmp(reader.name(), ".") == 0) { - seen_dot = true; - continue; - } - if (strcmp(reader.name(), "..") == 0) { - seen_dotdot = true; - continue; - } - - SCOPED_TRACE(testing::Message() << "reader.name(): " << reader.name()); - - char *endptr; - const unsigned long value = strtoul(reader.name(), &endptr, 10); - - EXPECT_FALSE(*endptr); - EXPECT_LT(value, kNumFiles); - EXPECT_EQ(0u, seen.count(value)); - seen.insert(value); - } - - for (unsigned i = 0; i < kNumFiles; i++) { - char buf[16]; - snprintf(buf, sizeof(buf), "%d", i); - PCHECK(unlink(buf) == 0); - } - - PCHECK(rmdir(dir) == 0); - - PCHECK(chdir(wdbuf) == 0); - - EXPECT_TRUE(seen_dot); - EXPECT_TRUE(seen_dotdot); - EXPECT_EQ(kNumFiles, seen.size()); -} - -} // namespace base
diff --git a/base/files/file_descriptor_watcher_posix_unittest.cc b/base/files/file_descriptor_watcher_posix_unittest.cc deleted file mode 100644 index 8fc57ce..0000000 --- a/base/files/file_descriptor_watcher_posix_unittest.cc +++ /dev/null
@@ -1,318 +0,0 @@ -// 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/files/file_descriptor_watcher_posix.h" - -#include <unistd.h> - -#include <memory> - -#include "base/bind.h" -#include "base/files/file_util.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/message_loop/message_loop.h" -#include "base/posix/eintr_wrapper.h" -#include "base/run_loop.h" -#include "base/test/test_timeouts.h" -#include "base/threading/platform_thread.h" -#include "base/threading/thread.h" -#include "base/threading/thread_checker_impl.h" -#include "build_config.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -class Mock { - public: - Mock() = default; - - MOCK_METHOD0(ReadableCallback, void()); - MOCK_METHOD0(WritableCallback, void()); - - private: - DISALLOW_COPY_AND_ASSIGN(Mock); -}; - -enum class FileDescriptorWatcherTestType { - MESSAGE_LOOP_FOR_IO_ON_MAIN_THREAD, - MESSAGE_LOOP_FOR_IO_ON_OTHER_THREAD, -}; - -class FileDescriptorWatcherTest - : public testing::TestWithParam<FileDescriptorWatcherTestType> { - public: - FileDescriptorWatcherTest() - : message_loop_(GetParam() == FileDescriptorWatcherTestType:: - MESSAGE_LOOP_FOR_IO_ON_MAIN_THREAD - ? new MessageLoopForIO - : new MessageLoop), - other_thread_("FileDescriptorWatcherTest_OtherThread") {} - ~FileDescriptorWatcherTest() override = default; - - void SetUp() override { - ASSERT_EQ(0, pipe(pipe_fds_)); - - MessageLoop* message_loop_for_io; - if (GetParam() == - FileDescriptorWatcherTestType::MESSAGE_LOOP_FOR_IO_ON_OTHER_THREAD) { - Thread::Options options; - options.message_loop_type = MessageLoop::TYPE_IO; - ASSERT_TRUE(other_thread_.StartWithOptions(options)); - message_loop_for_io = other_thread_.message_loop(); - } else { - message_loop_for_io = message_loop_.get(); - } - - ASSERT_TRUE(message_loop_for_io->IsType(MessageLoop::TYPE_IO)); - file_descriptor_watcher_ = std::make_unique<FileDescriptorWatcher>( - static_cast<MessageLoopForIO*>(message_loop_for_io)); - } - - void TearDown() override { - if (GetParam() == - FileDescriptorWatcherTestType::MESSAGE_LOOP_FOR_IO_ON_MAIN_THREAD && - message_loop_) { - // Allow the delete task posted by the Controller's destructor to run. - base::RunLoop().RunUntilIdle(); - } - - // Ensure that OtherThread is done processing before closing fds. - other_thread_.Stop(); - - EXPECT_EQ(0, IGNORE_EINTR(close(pipe_fds_[0]))); - EXPECT_EQ(0, IGNORE_EINTR(close(pipe_fds_[1]))); - } - - protected: - int read_file_descriptor() const { return pipe_fds_[0]; } - int write_file_descriptor() const { return pipe_fds_[1]; } - - // Waits for a short delay and run pending tasks. - void WaitAndRunPendingTasks() { - PlatformThread::Sleep(TestTimeouts::tiny_timeout()); - RunLoop().RunUntilIdle(); - } - - // Registers ReadableCallback() to be called on |mock_| when - // read_file_descriptor() is readable without blocking. - std::unique_ptr<FileDescriptorWatcher::Controller> WatchReadable() { - std::unique_ptr<FileDescriptorWatcher::Controller> controller = - FileDescriptorWatcher::WatchReadable( - read_file_descriptor(), - Bind(&Mock::ReadableCallback, Unretained(&mock_))); - EXPECT_TRUE(controller); - - // Unless read_file_descriptor() was readable before the callback was - // registered, this shouldn't do anything. - WaitAndRunPendingTasks(); - - return controller; - } - - // Registers WritableCallback() to be called on |mock_| when - // write_file_descriptor() is writable without blocking. - std::unique_ptr<FileDescriptorWatcher::Controller> WatchWritable() { - std::unique_ptr<FileDescriptorWatcher::Controller> controller = - FileDescriptorWatcher::WatchWritable( - write_file_descriptor(), - Bind(&Mock::WritableCallback, Unretained(&mock_))); - EXPECT_TRUE(controller); - return controller; - } - - void WriteByte() { - constexpr char kByte = '!'; - ASSERT_TRUE( - WriteFileDescriptor(write_file_descriptor(), &kByte, sizeof(kByte))); - } - - void ReadByte() { - // This is always called as part of the WatchReadable() callback, which - // should run on the main thread. - EXPECT_TRUE(thread_checker_.CalledOnValidThread()); - - char buffer; - ASSERT_TRUE(ReadFromFD(read_file_descriptor(), &buffer, sizeof(buffer))); - } - - // Mock on wich callbacks are invoked. - testing::StrictMock<Mock> mock_; - - // MessageLoop bound to the main thread. - std::unique_ptr<MessageLoop> message_loop_; - - // Thread running a MessageLoopForIO. Used when the test type is - // MESSAGE_LOOP_FOR_IO_ON_OTHER_THREAD. - Thread other_thread_; - - private: - // Determines which MessageLoopForIO is used to watch file descriptors for - // which callbacks are registered on the main thread. - std::unique_ptr<FileDescriptorWatcher> file_descriptor_watcher_; - - // Watched file descriptors. - int pipe_fds_[2]; - - // Used to verify that callbacks run on the thread on which they are - // registered. - ThreadCheckerImpl thread_checker_; - - DISALLOW_COPY_AND_ASSIGN(FileDescriptorWatcherTest); -}; - -} // namespace - -TEST_P(FileDescriptorWatcherTest, WatchWritable) { - auto controller = WatchWritable(); - - // The write end of a newly created pipe is immediately writable. - RunLoop run_loop; - EXPECT_CALL(mock_, WritableCallback()) - .WillOnce(testing::Invoke(&run_loop, &RunLoop::Quit)); - run_loop.Run(); -} - -TEST_P(FileDescriptorWatcherTest, WatchReadableOneByte) { - auto controller = WatchReadable(); - - // Write 1 byte to the pipe, making it readable without blocking. Expect one - // call to ReadableCallback() which will read 1 byte from the pipe. - WriteByte(); - RunLoop run_loop; - EXPECT_CALL(mock_, ReadableCallback()) - .WillOnce(testing::Invoke([this, &run_loop]() { - ReadByte(); - run_loop.Quit(); - })); - run_loop.Run(); - testing::Mock::VerifyAndClear(&mock_); - - // No more call to ReadableCallback() is expected. - WaitAndRunPendingTasks(); -} - -TEST_P(FileDescriptorWatcherTest, WatchReadableTwoBytes) { - auto controller = WatchReadable(); - - // Write 2 bytes to the pipe. Expect two calls to ReadableCallback() which - // will each read 1 byte from the pipe. - WriteByte(); - WriteByte(); - RunLoop run_loop; - EXPECT_CALL(mock_, ReadableCallback()) - .WillOnce(testing::Invoke([this]() { ReadByte(); })) - .WillOnce(testing::Invoke([this, &run_loop]() { - ReadByte(); - run_loop.Quit(); - })); - run_loop.Run(); - testing::Mock::VerifyAndClear(&mock_); - - // No more call to ReadableCallback() is expected. - WaitAndRunPendingTasks(); -} - -TEST_P(FileDescriptorWatcherTest, WatchReadableByteWrittenFromCallback) { - auto controller = WatchReadable(); - - // Write 1 byte to the pipe. Expect one call to ReadableCallback() from which - // 1 byte is read and 1 byte is written to the pipe. Then, expect another call - // to ReadableCallback() from which the remaining byte is read from the pipe. - WriteByte(); - RunLoop run_loop; - EXPECT_CALL(mock_, ReadableCallback()) - .WillOnce(testing::Invoke([this]() { - ReadByte(); - WriteByte(); - })) - .WillOnce(testing::Invoke([this, &run_loop]() { - ReadByte(); - run_loop.Quit(); - })); - run_loop.Run(); - testing::Mock::VerifyAndClear(&mock_); - - // No more call to ReadableCallback() is expected. - WaitAndRunPendingTasks(); -} - -TEST_P(FileDescriptorWatcherTest, DeleteControllerFromCallback) { - auto controller = WatchReadable(); - - // Write 1 byte to the pipe. Expect one call to ReadableCallback() from which - // |controller| is deleted. - WriteByte(); - RunLoop run_loop; - EXPECT_CALL(mock_, ReadableCallback()) - .WillOnce(testing::Invoke([&run_loop, &controller]() { - controller = nullptr; - run_loop.Quit(); - })); - run_loop.Run(); - testing::Mock::VerifyAndClear(&mock_); - - // Since |controller| has been deleted, no call to ReadableCallback() is - // expected even though the pipe is still readable without blocking. - WaitAndRunPendingTasks(); -} - -TEST_P(FileDescriptorWatcherTest, - DeleteControllerBeforeFileDescriptorReadable) { - auto controller = WatchReadable(); - - // Cancel the watch. - controller = nullptr; - - // Write 1 byte to the pipe to make it readable without blocking. - WriteByte(); - - // No call to ReadableCallback() is expected. - WaitAndRunPendingTasks(); -} - -TEST_P(FileDescriptorWatcherTest, DeleteControllerAfterFileDescriptorReadable) { - auto controller = WatchReadable(); - - // Write 1 byte to the pipe to make it readable without blocking. - WriteByte(); - - // Cancel the watch. - controller = nullptr; - - // No call to ReadableCallback() is expected. - WaitAndRunPendingTasks(); -} - -TEST_P(FileDescriptorWatcherTest, DeleteControllerAfterDeleteMessageLoopForIO) { - auto controller = WatchReadable(); - - // Delete the MessageLoopForIO. - if (GetParam() == - FileDescriptorWatcherTestType::MESSAGE_LOOP_FOR_IO_ON_MAIN_THREAD) { - message_loop_ = nullptr; - } else { - other_thread_.Stop(); - } - - // Deleting |controller| shouldn't crash even though that causes a task to be - // posted to the MessageLoopForIO thread. - controller = nullptr; -} - -INSTANTIATE_TEST_CASE_P( - MessageLoopForIOOnMainThread, - FileDescriptorWatcherTest, - ::testing::Values( - FileDescriptorWatcherTestType::MESSAGE_LOOP_FOR_IO_ON_MAIN_THREAD)); -INSTANTIATE_TEST_CASE_P( - MessageLoopForIOOnOtherThread, - FileDescriptorWatcherTest, - ::testing::Values( - FileDescriptorWatcherTestType::MESSAGE_LOOP_FOR_IO_ON_OTHER_THREAD)); - -} // namespace base
diff --git a/base/files/file_enumerator_unittest.cc b/base/files/file_enumerator_unittest.cc deleted file mode 100644 index 11df075..0000000 --- a/base/files/file_enumerator_unittest.cc +++ /dev/null
@@ -1,312 +0,0 @@ -// 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/files/file_enumerator.h" - -#include <utility> -#include <vector> - -#include "base/containers/circular_deque.h" -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/files/scoped_temp_dir.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using testing::ElementsAre; -using testing::IsEmpty; -using testing::UnorderedElementsAre; - -namespace base { -namespace { - -const FilePath::StringType kEmptyPattern; - -const std::vector<FileEnumerator::FolderSearchPolicy> kFolderSearchPolicies{ - FileEnumerator::FolderSearchPolicy::MATCH_ONLY, - FileEnumerator::FolderSearchPolicy::ALL}; - -circular_deque<FilePath> RunEnumerator( - const FilePath& root_path, - bool recursive, - int file_type, - const FilePath::StringType& pattern, - FileEnumerator::FolderSearchPolicy folder_search_policy) { - circular_deque<FilePath> rv; - FileEnumerator enumerator(root_path, recursive, file_type, pattern, - folder_search_policy); - for (auto file = enumerator.Next(); !file.empty(); file = enumerator.Next()) - rv.emplace_back(std::move(file)); - return rv; -} - -bool CreateDummyFile(const FilePath& path) { - return WriteFile(path, "42", sizeof("42")) == sizeof("42"); -} - -} // namespace - -TEST(FileEnumerator, NotExistingPath) { - const FilePath path = FilePath::FromUTF8Unsafe("some_not_existing_path"); - ASSERT_FALSE(PathExists(path)); - - for (auto policy : kFolderSearchPolicies) { - const auto files = RunEnumerator( - path, true, FileEnumerator::FILES & FileEnumerator::DIRECTORIES, - FILE_PATH_LITERAL(""), policy); - EXPECT_THAT(files, IsEmpty()); - } -} - -TEST(FileEnumerator, EmptyFolder) { - ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - - for (auto policy : kFolderSearchPolicies) { - const auto files = - RunEnumerator(temp_dir.GetPath(), true, - FileEnumerator::FILES & FileEnumerator::DIRECTORIES, - kEmptyPattern, policy); - EXPECT_THAT(files, IsEmpty()); - } -} - -TEST(FileEnumerator, SingleFileInFolderForFileSearch) { - ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - - const FilePath& path = temp_dir.GetPath(); - const FilePath file = path.AppendASCII("test.txt"); - ASSERT_TRUE(CreateDummyFile(file)); - - for (auto policy : kFolderSearchPolicies) { - const auto files = RunEnumerator( - temp_dir.GetPath(), true, FileEnumerator::FILES, kEmptyPattern, policy); - EXPECT_THAT(files, ElementsAre(file)); - } -} - -TEST(FileEnumerator, SingleFileInFolderForDirSearch) { - ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - - const FilePath& path = temp_dir.GetPath(); - ASSERT_TRUE(CreateDummyFile(path.AppendASCII("test.txt"))); - - for (auto policy : kFolderSearchPolicies) { - const auto files = RunEnumerator(path, true, FileEnumerator::DIRECTORIES, - kEmptyPattern, policy); - EXPECT_THAT(files, IsEmpty()); - } -} - -TEST(FileEnumerator, SingleFileInFolderWithFiltering) { - ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - - const FilePath& path = temp_dir.GetPath(); - const FilePath file = path.AppendASCII("test.txt"); - ASSERT_TRUE(CreateDummyFile(file)); - - for (auto policy : kFolderSearchPolicies) { - auto files = RunEnumerator(path, true, FileEnumerator::FILES, - FILE_PATH_LITERAL("*.txt"), policy); - EXPECT_THAT(files, ElementsAre(file)); - - files = RunEnumerator(path, true, FileEnumerator::FILES, - FILE_PATH_LITERAL("*.pdf"), policy); - EXPECT_THAT(files, IsEmpty()); - } -} - -TEST(FileEnumerator, TwoFilesInFolder) { - ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - - const FilePath& path = temp_dir.GetPath(); - const FilePath foo_txt = path.AppendASCII("foo.txt"); - const FilePath bar_txt = path.AppendASCII("bar.txt"); - ASSERT_TRUE(CreateDummyFile(foo_txt)); - ASSERT_TRUE(CreateDummyFile(bar_txt)); - - for (auto policy : kFolderSearchPolicies) { - auto files = RunEnumerator(path, true, FileEnumerator::FILES, - FILE_PATH_LITERAL("*.txt"), policy); - EXPECT_THAT(files, UnorderedElementsAre(foo_txt, bar_txt)); - - files = RunEnumerator(path, true, FileEnumerator::FILES, - FILE_PATH_LITERAL("foo*"), policy); - EXPECT_THAT(files, ElementsAre(foo_txt)); - - files = RunEnumerator(path, true, FileEnumerator::FILES, - FILE_PATH_LITERAL("*.pdf"), policy); - EXPECT_THAT(files, IsEmpty()); - - files = - RunEnumerator(path, true, FileEnumerator::FILES, kEmptyPattern, policy); - EXPECT_THAT(files, UnorderedElementsAre(foo_txt, bar_txt)); - } -} - -TEST(FileEnumerator, SingleFolderInFolderForFileSearch) { - ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - - const FilePath& path = temp_dir.GetPath(); - - ScopedTempDir temp_subdir; - ASSERT_TRUE(temp_subdir.CreateUniqueTempDirUnderPath(path)); - - for (auto policy : kFolderSearchPolicies) { - const auto files = - RunEnumerator(path, true, FileEnumerator::FILES, kEmptyPattern, policy); - EXPECT_THAT(files, IsEmpty()); - } -} - -TEST(FileEnumerator, SingleFolderInFolderForDirSearch) { - ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - - const FilePath& path = temp_dir.GetPath(); - - ScopedTempDir temp_subdir; - ASSERT_TRUE(temp_subdir.CreateUniqueTempDirUnderPath(path)); - - for (auto policy : kFolderSearchPolicies) { - const auto files = RunEnumerator(path, true, FileEnumerator::DIRECTORIES, - kEmptyPattern, policy); - EXPECT_THAT(files, ElementsAre(temp_subdir.GetPath())); - } -} - -TEST(FileEnumerator, TwoFoldersInFolder) { - ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - - const FilePath& path = temp_dir.GetPath(); - - const FilePath subdir_foo = path.AppendASCII("foo"); - const FilePath subdir_bar = path.AppendASCII("bar"); - ASSERT_TRUE(CreateDirectory(subdir_foo)); - ASSERT_TRUE(CreateDirectory(subdir_bar)); - - for (auto policy : kFolderSearchPolicies) { - auto files = RunEnumerator(path, true, FileEnumerator::DIRECTORIES, - kEmptyPattern, policy); - EXPECT_THAT(files, UnorderedElementsAre(subdir_foo, subdir_bar)); - - files = RunEnumerator(path, true, FileEnumerator::DIRECTORIES, - FILE_PATH_LITERAL("foo"), policy); - EXPECT_THAT(files, ElementsAre(subdir_foo)); - } -} - -TEST(FileEnumerator, FolderAndFileInFolder) { - ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - - const FilePath& path = temp_dir.GetPath(); - - ScopedTempDir temp_subdir; - ASSERT_TRUE(temp_subdir.CreateUniqueTempDirUnderPath(path)); - const FilePath file = path.AppendASCII("test.txt"); - ASSERT_TRUE(CreateDummyFile(file)); - - for (auto policy : kFolderSearchPolicies) { - auto files = - RunEnumerator(path, true, FileEnumerator::FILES, kEmptyPattern, policy); - EXPECT_THAT(files, ElementsAre(file)); - - files = RunEnumerator(path, true, FileEnumerator::DIRECTORIES, - kEmptyPattern, policy); - EXPECT_THAT(files, ElementsAre(temp_subdir.GetPath())); - - files = RunEnumerator(path, true, - FileEnumerator::FILES | FileEnumerator::DIRECTORIES, - kEmptyPattern, policy); - EXPECT_THAT(files, UnorderedElementsAre(file, temp_subdir.GetPath())); - } -} - -TEST(FileEnumerator, FilesInParentFolderAlwaysFirst) { - ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - - const FilePath& path = temp_dir.GetPath(); - - ScopedTempDir temp_subdir; - ASSERT_TRUE(temp_subdir.CreateUniqueTempDirUnderPath(path)); - const FilePath foo_txt = path.AppendASCII("foo.txt"); - const FilePath bar_txt = temp_subdir.GetPath().AppendASCII("bar.txt"); - ASSERT_TRUE(CreateDummyFile(foo_txt)); - ASSERT_TRUE(CreateDummyFile(bar_txt)); - - for (auto policy : kFolderSearchPolicies) { - const auto files = - RunEnumerator(path, true, FileEnumerator::FILES, kEmptyPattern, policy); - EXPECT_THAT(files, ElementsAre(foo_txt, bar_txt)); - } -} - -TEST(FileEnumerator, FileInSubfolder) { - ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - - const FilePath subdir = temp_dir.GetPath().AppendASCII("subdir"); - ASSERT_TRUE(CreateDirectory(subdir)); - - const FilePath file = subdir.AppendASCII("test.txt"); - ASSERT_TRUE(CreateDummyFile(file)); - - for (auto policy : kFolderSearchPolicies) { - auto files = RunEnumerator(temp_dir.GetPath(), true, FileEnumerator::FILES, - kEmptyPattern, policy); - EXPECT_THAT(files, ElementsAre(file)); - - files = RunEnumerator(temp_dir.GetPath(), false, FileEnumerator::FILES, - kEmptyPattern, policy); - EXPECT_THAT(files, IsEmpty()); - } -} - -TEST(FileEnumerator, FilesInSubfoldersWithFiltering) { - ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - - const FilePath test_txt = temp_dir.GetPath().AppendASCII("test.txt"); - const FilePath subdir_foo = temp_dir.GetPath().AppendASCII("foo_subdir"); - const FilePath subdir_bar = temp_dir.GetPath().AppendASCII("bar_subdir"); - const FilePath foo_test = subdir_foo.AppendASCII("test.txt"); - const FilePath foo_foo = subdir_foo.AppendASCII("foo.txt"); - const FilePath foo_bar = subdir_foo.AppendASCII("bar.txt"); - const FilePath bar_test = subdir_bar.AppendASCII("test.txt"); - const FilePath bar_foo = subdir_bar.AppendASCII("foo.txt"); - const FilePath bar_bar = subdir_bar.AppendASCII("bar.txt"); - ASSERT_TRUE(CreateDummyFile(test_txt)); - ASSERT_TRUE(CreateDirectory(subdir_foo)); - ASSERT_TRUE(CreateDirectory(subdir_bar)); - ASSERT_TRUE(CreateDummyFile(foo_test)); - ASSERT_TRUE(CreateDummyFile(foo_foo)); - ASSERT_TRUE(CreateDummyFile(foo_bar)); - ASSERT_TRUE(CreateDummyFile(bar_test)); - ASSERT_TRUE(CreateDummyFile(bar_foo)); - ASSERT_TRUE(CreateDummyFile(bar_bar)); - - auto files = - RunEnumerator(temp_dir.GetPath(), true, - FileEnumerator::FILES | FileEnumerator::DIRECTORIES, - FILE_PATH_LITERAL("foo*"), - FileEnumerator::FolderSearchPolicy::MATCH_ONLY); - EXPECT_THAT(files, - UnorderedElementsAre(subdir_foo, foo_test, foo_foo, foo_bar)); - - files = RunEnumerator(temp_dir.GetPath(), true, - FileEnumerator::FILES | FileEnumerator::DIRECTORIES, - FILE_PATH_LITERAL("foo*"), - FileEnumerator::FolderSearchPolicy::ALL); - EXPECT_THAT(files, UnorderedElementsAre(subdir_foo, foo_foo, bar_foo)); -} - -} // namespace base
diff --git a/base/files/file_locking_unittest.cc b/base/files/file_locking_unittest.cc deleted file mode 100644 index bfe62ce..0000000 --- a/base/files/file_locking_unittest.cc +++ /dev/null
@@ -1,232 +0,0 @@ -// 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/command_line.h" -#include "base/files/file.h" -#include "base/files/file_util.h" -#include "base/files/scoped_temp_dir.h" -#include "base/macros.h" -#include "base/test/multiprocess_test.h" -#include "base/test/test_timeouts.h" -#include "base/threading/platform_thread.h" -#include "base/time/time.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/multiprocess_func_list.h" - -using base::File; -using base::FilePath; - -namespace { - -// Flag for the parent to share a temp dir to the child. -const char kTempDirFlag[] = "temp-dir"; - -// Flags to control how the subprocess unlocks the file. -const char kFileUnlock[] = "file-unlock"; -const char kCloseUnlock[] = "close-unlock"; -const char kExitUnlock[] = "exit-unlock"; - -// File to lock in temp dir. -const char kLockFile[] = "lockfile"; - -// Constants for various requests and responses, used as |signal_file| parameter -// to signal/wait helpers. -const char kSignalLockFileLocked[] = "locked.signal"; -const char kSignalLockFileClose[] = "close.signal"; -const char kSignalLockFileClosed[] = "closed.signal"; -const char kSignalLockFileUnlock[] = "unlock.signal"; -const char kSignalLockFileUnlocked[] = "unlocked.signal"; -const char kSignalExit[] = "exit.signal"; - -// Signal an event by creating a file which didn't previously exist. -bool SignalEvent(const FilePath& signal_dir, const char* signal_file) { - File file(signal_dir.AppendASCII(signal_file), - File::FLAG_CREATE | File::FLAG_WRITE); - return file.IsValid(); -} - -// Check whether an event was signaled. -bool CheckEvent(const FilePath& signal_dir, const char* signal_file) { - File file(signal_dir.AppendASCII(signal_file), - File::FLAG_OPEN | File::FLAG_READ); - return file.IsValid(); -} - -// Busy-wait for an event to be signaled, returning false for timeout. -bool WaitForEventWithTimeout(const FilePath& signal_dir, - const char* signal_file, - const base::TimeDelta& timeout) { - const base::Time finish_by = base::Time::Now() + timeout; - while (!CheckEvent(signal_dir, signal_file)) { - if (base::Time::Now() > finish_by) - return false; - base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10)); - } - return true; -} - -// Wait forever for the event to be signaled (should never return false). -bool WaitForEvent(const FilePath& signal_dir, const char* signal_file) { - return WaitForEventWithTimeout(signal_dir, signal_file, - base::TimeDelta::Max()); -} - -// Keep these in sync so StartChild*() can refer to correct test main. -#define ChildMain ChildLockUnlock -#define ChildMainString "ChildLockUnlock" - -// Subprocess to test getting a file lock then releasing it. |kTempDirFlag| -// must pass in an existing temporary directory for the lockfile and signal -// files. One of the following flags must be passed to determine how to unlock -// the lock file: -// - |kFileUnlock| calls Unlock() to unlock. -// - |kCloseUnlock| calls Close() while the lock is held. -// - |kExitUnlock| exits while the lock is held. -MULTIPROCESS_TEST_MAIN(ChildMain) { - base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - const FilePath temp_path = command_line->GetSwitchValuePath(kTempDirFlag); - CHECK(base::DirectoryExists(temp_path)); - - // Immediately lock the file. - File file(temp_path.AppendASCII(kLockFile), - File::FLAG_OPEN | File::FLAG_READ | File::FLAG_WRITE); - CHECK(file.IsValid()); - CHECK_EQ(File::FILE_OK, file.Lock()); - CHECK(SignalEvent(temp_path, kSignalLockFileLocked)); - - if (command_line->HasSwitch(kFileUnlock)) { - // Wait for signal to unlock, then unlock the file. - CHECK(WaitForEvent(temp_path, kSignalLockFileUnlock)); - CHECK_EQ(File::FILE_OK, file.Unlock()); - CHECK(SignalEvent(temp_path, kSignalLockFileUnlocked)); - } else if (command_line->HasSwitch(kCloseUnlock)) { - // Wait for the signal to close, then close the file. - CHECK(WaitForEvent(temp_path, kSignalLockFileClose)); - file.Close(); - CHECK(!file.IsValid()); - CHECK(SignalEvent(temp_path, kSignalLockFileClosed)); - } else { - CHECK(command_line->HasSwitch(kExitUnlock)); - } - - // Wait for signal to exit, so that unlock or close can be distinguished from - // exit. - CHECK(WaitForEvent(temp_path, kSignalExit)); - return 0; -} - -} // namespace - -class FileLockingTest : public testing::Test { - public: - FileLockingTest() = default; - - protected: - void SetUp() override { - testing::Test::SetUp(); - - // Setup the temp dir and the lock file. - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - lock_file_.Initialize( - temp_dir_.GetPath().AppendASCII(kLockFile), - File::FLAG_CREATE | File::FLAG_READ | File::FLAG_WRITE); - ASSERT_TRUE(lock_file_.IsValid()); - } - - bool SignalEvent(const char* signal_file) { - return ::SignalEvent(temp_dir_.GetPath(), signal_file); - } - - bool WaitForEventOrTimeout(const char* signal_file) { - return ::WaitForEventWithTimeout(temp_dir_.GetPath(), signal_file, - TestTimeouts::action_timeout()); - } - - // Start a child process set to use the specified unlock action, and wait for - // it to lock the file. - void StartChildAndSignalLock(const char* unlock_action) { - // Create a temporary dir and spin up a ChildLockExit subprocess against it. - const FilePath temp_path = temp_dir_.GetPath(); - base::CommandLine child_command_line( - base::GetMultiProcessTestChildBaseCommandLine()); - child_command_line.AppendSwitchPath(kTempDirFlag, temp_path); - child_command_line.AppendSwitch(unlock_action); - lock_child_ = base::SpawnMultiProcessTestChild( - ChildMainString, child_command_line, base::LaunchOptions()); - ASSERT_TRUE(lock_child_.IsValid()); - - // Wait for the child to lock the file. - ASSERT_TRUE(WaitForEventOrTimeout(kSignalLockFileLocked)); - } - - // Signal the child to exit cleanly. - void ExitChildCleanly() { - ASSERT_TRUE(SignalEvent(kSignalExit)); - int rv = -1; - ASSERT_TRUE(WaitForMultiprocessTestChildExit( - lock_child_, TestTimeouts::action_timeout(), &rv)); - ASSERT_EQ(0, rv); - } - - base::ScopedTempDir temp_dir_; - base::File lock_file_; - base::Process lock_child_; - - private: - DISALLOW_COPY_AND_ASSIGN(FileLockingTest); -}; - -// Test that locks are released by Unlock(). -TEST_F(FileLockingTest, LockAndUnlock) { - StartChildAndSignalLock(kFileUnlock); - - ASSERT_NE(File::FILE_OK, lock_file_.Lock()); - ASSERT_TRUE(SignalEvent(kSignalLockFileUnlock)); - ASSERT_TRUE(WaitForEventOrTimeout(kSignalLockFileUnlocked)); - ASSERT_EQ(File::FILE_OK, lock_file_.Lock()); - ASSERT_EQ(File::FILE_OK, lock_file_.Unlock()); - - ExitChildCleanly(); -} - -// Test that locks are released on Close(). -TEST_F(FileLockingTest, UnlockOnClose) { - StartChildAndSignalLock(kCloseUnlock); - - ASSERT_NE(File::FILE_OK, lock_file_.Lock()); - ASSERT_TRUE(SignalEvent(kSignalLockFileClose)); - ASSERT_TRUE(WaitForEventOrTimeout(kSignalLockFileClosed)); - ASSERT_EQ(File::FILE_OK, lock_file_.Lock()); - ASSERT_EQ(File::FILE_OK, lock_file_.Unlock()); - - ExitChildCleanly(); -} - -// Test that locks are released on exit. -TEST_F(FileLockingTest, UnlockOnExit) { - StartChildAndSignalLock(kExitUnlock); - - ASSERT_NE(File::FILE_OK, lock_file_.Lock()); - ExitChildCleanly(); - ASSERT_EQ(File::FILE_OK, lock_file_.Lock()); - ASSERT_EQ(File::FILE_OK, lock_file_.Unlock()); -} - -// Test that killing the process releases the lock. This should cover crashing. -// Flaky on Android (http://crbug.com/747518) -#if defined(OS_ANDROID) -#define MAYBE_UnlockOnTerminate DISABLED_UnlockOnTerminate -#else -#define MAYBE_UnlockOnTerminate UnlockOnTerminate -#endif -TEST_F(FileLockingTest, MAYBE_UnlockOnTerminate) { - // The child will wait for an exit which never arrives. - StartChildAndSignalLock(kExitUnlock); - - ASSERT_NE(File::FILE_OK, lock_file_.Lock()); - ASSERT_TRUE(TerminateMultiProcessTestChild(lock_child_, 0, true)); - ASSERT_EQ(File::FILE_OK, lock_file_.Lock()); - ASSERT_EQ(File::FILE_OK, lock_file_.Unlock()); -}
diff --git a/base/files/file_path_unittest.cc b/base/files/file_path_unittest.cc deleted file mode 100644 index d0fd00e..0000000 --- a/base/files/file_path_unittest.cc +++ /dev/null
@@ -1,1319 +0,0 @@ -// 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 <stddef.h> - -#include <sstream> - -#include "base/files/file_path.h" -#include "base/macros.h" -#include "base/strings/utf_string_conversions.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/platform_test.h" - -#if defined(OS_POSIX) || defined(OS_FUCHSIA) -#include "base/test/scoped_locale.h" -#endif - -// This macro helps avoid wrapped lines in the test structs. -#define FPL(x) FILE_PATH_LITERAL(x) - -// This macro constructs strings which can contain NULs. -#define FPS(x) FilePath::StringType(FPL(x), arraysize(FPL(x)) - 1) - -namespace base { - -struct UnaryTestData { - const FilePath::CharType* input; - const FilePath::CharType* expected; -}; - -struct UnaryBooleanTestData { - const FilePath::CharType* input; - bool expected; -}; - -struct BinaryTestData { - const FilePath::CharType* inputs[2]; - const FilePath::CharType* expected; -}; - -struct BinaryBooleanTestData { - const FilePath::CharType* inputs[2]; - bool expected; -}; - -struct BinaryIntTestData { - const FilePath::CharType* inputs[2]; - int expected; -}; - -struct UTF8TestData { - const FilePath::CharType* native; - const char* utf8; -}; - -// file_util winds up using autoreleased objects on the Mac, so this needs -// to be a PlatformTest -typedef PlatformTest FilePathTest; - -TEST_F(FilePathTest, DirName) { - const struct UnaryTestData cases[] = { - { FPL(""), FPL(".") }, - { FPL("aa"), FPL(".") }, - { FPL("/aa/bb"), FPL("/aa") }, - { FPL("/aa/bb/"), FPL("/aa") }, - { FPL("/aa/bb//"), FPL("/aa") }, - { FPL("/aa/bb/ccc"), FPL("/aa/bb") }, - { FPL("/aa"), FPL("/") }, - { FPL("/aa/"), FPL("/") }, - { FPL("/"), FPL("/") }, - { FPL("//"), FPL("//") }, - { FPL("///"), FPL("/") }, - { FPL("aa/"), FPL(".") }, - { FPL("aa/bb"), FPL("aa") }, - { FPL("aa/bb/"), FPL("aa") }, - { FPL("aa/bb//"), FPL("aa") }, - { FPL("aa//bb//"), FPL("aa") }, - { FPL("aa//bb/"), FPL("aa") }, - { FPL("aa//bb"), FPL("aa") }, - { FPL("//aa/bb"), FPL("//aa") }, - { FPL("//aa/"), FPL("//") }, - { FPL("//aa"), FPL("//") }, - { FPL("0:"), FPL(".") }, - { FPL("@:"), FPL(".") }, - { FPL("[:"), FPL(".") }, - { FPL("`:"), FPL(".") }, - { FPL("{:"), FPL(".") }, - { FPL("\xB3:"), FPL(".") }, - { FPL("\xC5:"), FPL(".") }, - { FPL("/aa/../bb/cc"), FPL("/aa/../bb")}, -#if defined(OS_WIN) - { FPL("\x0143:"), FPL(".") }, -#endif // OS_WIN -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - { FPL("c:"), FPL("c:") }, - { FPL("C:"), FPL("C:") }, - { FPL("A:"), FPL("A:") }, - { FPL("Z:"), FPL("Z:") }, - { FPL("a:"), FPL("a:") }, - { FPL("z:"), FPL("z:") }, - { FPL("c:aa"), FPL("c:") }, - { FPL("c:/"), FPL("c:/") }, - { FPL("c://"), FPL("c://") }, - { FPL("c:///"), FPL("c:/") }, - { FPL("c:/aa"), FPL("c:/") }, - { FPL("c:/aa/"), FPL("c:/") }, - { FPL("c:/aa/bb"), FPL("c:/aa") }, - { FPL("c:aa/bb"), FPL("c:aa") }, -#endif // FILE_PATH_USES_DRIVE_LETTERS -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - { FPL("\\aa\\bb"), FPL("\\aa") }, - { FPL("\\aa\\bb\\"), FPL("\\aa") }, - { FPL("\\aa\\bb\\\\"), FPL("\\aa") }, - { FPL("\\aa\\bb\\ccc"), FPL("\\aa\\bb") }, - { FPL("\\aa"), FPL("\\") }, - { FPL("\\aa\\"), FPL("\\") }, - { FPL("\\"), FPL("\\") }, - { FPL("\\\\"), FPL("\\\\") }, - { FPL("\\\\\\"), FPL("\\") }, - { FPL("aa\\"), FPL(".") }, - { FPL("aa\\bb"), FPL("aa") }, - { FPL("aa\\bb\\"), FPL("aa") }, - { FPL("aa\\bb\\\\"), FPL("aa") }, - { FPL("aa\\\\bb\\\\"), FPL("aa") }, - { FPL("aa\\\\bb\\"), FPL("aa") }, - { FPL("aa\\\\bb"), FPL("aa") }, - { FPL("\\\\aa\\bb"), FPL("\\\\aa") }, - { FPL("\\\\aa\\"), FPL("\\\\") }, - { FPL("\\\\aa"), FPL("\\\\") }, - { FPL("aa\\..\\bb\\c"), FPL("aa\\..\\bb")}, -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - { FPL("c:\\"), FPL("c:\\") }, - { FPL("c:\\\\"), FPL("c:\\\\") }, - { FPL("c:\\\\\\"), FPL("c:\\") }, - { FPL("c:\\aa"), FPL("c:\\") }, - { FPL("c:\\aa\\"), FPL("c:\\") }, - { FPL("c:\\aa\\bb"), FPL("c:\\aa") }, - { FPL("c:aa\\bb"), FPL("c:aa") }, -#endif // FILE_PATH_USES_DRIVE_LETTERS -#endif // FILE_PATH_USES_WIN_SEPARATORS - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - FilePath input(cases[i].input); - FilePath observed = input.DirName(); - EXPECT_EQ(FilePath::StringType(cases[i].expected), observed.value()) << - "i: " << i << ", input: " << input.value(); - } -} - -TEST_F(FilePathTest, BaseName) { - const struct UnaryTestData cases[] = { - { FPL(""), FPL("") }, - { FPL("aa"), FPL("aa") }, - { FPL("/aa/bb"), FPL("bb") }, - { FPL("/aa/bb/"), FPL("bb") }, - { FPL("/aa/bb//"), FPL("bb") }, - { FPL("/aa/bb/ccc"), FPL("ccc") }, - { FPL("/aa"), FPL("aa") }, - { FPL("/"), FPL("/") }, - { FPL("//"), FPL("//") }, - { FPL("///"), FPL("/") }, - { FPL("aa/"), FPL("aa") }, - { FPL("aa/bb"), FPL("bb") }, - { FPL("aa/bb/"), FPL("bb") }, - { FPL("aa/bb//"), FPL("bb") }, - { FPL("aa//bb//"), FPL("bb") }, - { FPL("aa//bb/"), FPL("bb") }, - { FPL("aa//bb"), FPL("bb") }, - { FPL("//aa/bb"), FPL("bb") }, - { FPL("//aa/"), FPL("aa") }, - { FPL("//aa"), FPL("aa") }, - { FPL("0:"), FPL("0:") }, - { FPL("@:"), FPL("@:") }, - { FPL("[:"), FPL("[:") }, - { FPL("`:"), FPL("`:") }, - { FPL("{:"), FPL("{:") }, - { FPL("\xB3:"), FPL("\xB3:") }, - { FPL("\xC5:"), FPL("\xC5:") }, -#if defined(OS_WIN) - { FPL("\x0143:"), FPL("\x0143:") }, -#endif // OS_WIN -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - { FPL("c:"), FPL("") }, - { FPL("C:"), FPL("") }, - { FPL("A:"), FPL("") }, - { FPL("Z:"), FPL("") }, - { FPL("a:"), FPL("") }, - { FPL("z:"), FPL("") }, - { FPL("c:aa"), FPL("aa") }, - { FPL("c:/"), FPL("/") }, - { FPL("c://"), FPL("//") }, - { FPL("c:///"), FPL("/") }, - { FPL("c:/aa"), FPL("aa") }, - { FPL("c:/aa/"), FPL("aa") }, - { FPL("c:/aa/bb"), FPL("bb") }, - { FPL("c:aa/bb"), FPL("bb") }, -#endif // FILE_PATH_USES_DRIVE_LETTERS -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - { FPL("\\aa\\bb"), FPL("bb") }, - { FPL("\\aa\\bb\\"), FPL("bb") }, - { FPL("\\aa\\bb\\\\"), FPL("bb") }, - { FPL("\\aa\\bb\\ccc"), FPL("ccc") }, - { FPL("\\aa"), FPL("aa") }, - { FPL("\\"), FPL("\\") }, - { FPL("\\\\"), FPL("\\\\") }, - { FPL("\\\\\\"), FPL("\\") }, - { FPL("aa\\"), FPL("aa") }, - { FPL("aa\\bb"), FPL("bb") }, - { FPL("aa\\bb\\"), FPL("bb") }, - { FPL("aa\\bb\\\\"), FPL("bb") }, - { FPL("aa\\\\bb\\\\"), FPL("bb") }, - { FPL("aa\\\\bb\\"), FPL("bb") }, - { FPL("aa\\\\bb"), FPL("bb") }, - { FPL("\\\\aa\\bb"), FPL("bb") }, - { FPL("\\\\aa\\"), FPL("aa") }, - { FPL("\\\\aa"), FPL("aa") }, -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - { FPL("c:\\"), FPL("\\") }, - { FPL("c:\\\\"), FPL("\\\\") }, - { FPL("c:\\\\\\"), FPL("\\") }, - { FPL("c:\\aa"), FPL("aa") }, - { FPL("c:\\aa\\"), FPL("aa") }, - { FPL("c:\\aa\\bb"), FPL("bb") }, - { FPL("c:aa\\bb"), FPL("bb") }, -#endif // FILE_PATH_USES_DRIVE_LETTERS -#endif // FILE_PATH_USES_WIN_SEPARATORS - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - FilePath input(cases[i].input); - FilePath observed = input.BaseName(); - EXPECT_EQ(FilePath::StringType(cases[i].expected), observed.value()) << - "i: " << i << ", input: " << input.value(); - } -} - -TEST_F(FilePathTest, Append) { - const struct BinaryTestData cases[] = { - { { FPL(""), FPL("cc") }, FPL("cc") }, - { { FPL("."), FPL("ff") }, FPL("ff") }, - { { FPL("."), FPL("") }, FPL(".") }, - { { FPL("/"), FPL("cc") }, FPL("/cc") }, - { { FPL("/aa"), FPL("") }, FPL("/aa") }, - { { FPL("/aa/"), FPL("") }, FPL("/aa") }, - { { FPL("//aa"), FPL("") }, FPL("//aa") }, - { { FPL("//aa/"), FPL("") }, FPL("//aa") }, - { { FPL("//"), FPL("aa") }, FPL("//aa") }, -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - { { FPL("c:"), FPL("a") }, FPL("c:a") }, - { { FPL("c:"), FPL("") }, FPL("c:") }, - { { FPL("c:/"), FPL("a") }, FPL("c:/a") }, - { { FPL("c://"), FPL("a") }, FPL("c://a") }, - { { FPL("c:///"), FPL("a") }, FPL("c:/a") }, -#endif // FILE_PATH_USES_DRIVE_LETTERS -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - // Append introduces the default separator character, so these test cases - // need to be defined with different expected results on platforms that use - // different default separator characters. - { { FPL("\\"), FPL("cc") }, FPL("\\cc") }, - { { FPL("\\aa"), FPL("") }, FPL("\\aa") }, - { { FPL("\\aa\\"), FPL("") }, FPL("\\aa") }, - { { FPL("\\\\aa"), FPL("") }, FPL("\\\\aa") }, - { { FPL("\\\\aa\\"), FPL("") }, FPL("\\\\aa") }, - { { FPL("\\\\"), FPL("aa") }, FPL("\\\\aa") }, - { { FPL("/aa/bb"), FPL("cc") }, FPL("/aa/bb\\cc") }, - { { FPL("/aa/bb/"), FPL("cc") }, FPL("/aa/bb\\cc") }, - { { FPL("aa/bb/"), FPL("cc") }, FPL("aa/bb\\cc") }, - { { FPL("aa/bb"), FPL("cc") }, FPL("aa/bb\\cc") }, - { { FPL("a/b"), FPL("c") }, FPL("a/b\\c") }, - { { FPL("a/b/"), FPL("c") }, FPL("a/b\\c") }, - { { FPL("//aa"), FPL("bb") }, FPL("//aa\\bb") }, - { { FPL("//aa/"), FPL("bb") }, FPL("//aa\\bb") }, - { { FPL("\\aa\\bb"), FPL("cc") }, FPL("\\aa\\bb\\cc") }, - { { FPL("\\aa\\bb\\"), FPL("cc") }, FPL("\\aa\\bb\\cc") }, - { { FPL("aa\\bb\\"), FPL("cc") }, FPL("aa\\bb\\cc") }, - { { FPL("aa\\bb"), FPL("cc") }, FPL("aa\\bb\\cc") }, - { { FPL("a\\b"), FPL("c") }, FPL("a\\b\\c") }, - { { FPL("a\\b\\"), FPL("c") }, FPL("a\\b\\c") }, - { { FPL("\\\\aa"), FPL("bb") }, FPL("\\\\aa\\bb") }, - { { FPL("\\\\aa\\"), FPL("bb") }, FPL("\\\\aa\\bb") }, -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - { { FPL("c:\\"), FPL("a") }, FPL("c:\\a") }, - { { FPL("c:\\\\"), FPL("a") }, FPL("c:\\\\a") }, - { { FPL("c:\\\\\\"), FPL("a") }, FPL("c:\\a") }, - { { FPL("c:\\"), FPL("") }, FPL("c:\\") }, - { { FPL("c:\\a"), FPL("b") }, FPL("c:\\a\\b") }, - { { FPL("c:\\a\\"), FPL("b") }, FPL("c:\\a\\b") }, -#endif // FILE_PATH_USES_DRIVE_LETTERS -#else // FILE_PATH_USES_WIN_SEPARATORS - { { FPL("/aa/bb"), FPL("cc") }, FPL("/aa/bb/cc") }, - { { FPL("/aa/bb/"), FPL("cc") }, FPL("/aa/bb/cc") }, - { { FPL("aa/bb/"), FPL("cc") }, FPL("aa/bb/cc") }, - { { FPL("aa/bb"), FPL("cc") }, FPL("aa/bb/cc") }, - { { FPL("a/b"), FPL("c") }, FPL("a/b/c") }, - { { FPL("a/b/"), FPL("c") }, FPL("a/b/c") }, - { { FPL("//aa"), FPL("bb") }, FPL("//aa/bb") }, - { { FPL("//aa/"), FPL("bb") }, FPL("//aa/bb") }, -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - { { FPL("c:/"), FPL("a") }, FPL("c:/a") }, - { { FPL("c:/"), FPL("") }, FPL("c:/") }, - { { FPL("c:/a"), FPL("b") }, FPL("c:/a/b") }, - { { FPL("c:/a/"), FPL("b") }, FPL("c:/a/b") }, -#endif // FILE_PATH_USES_DRIVE_LETTERS -#endif // FILE_PATH_USES_WIN_SEPARATORS - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - FilePath root(cases[i].inputs[0]); - FilePath::StringType leaf(cases[i].inputs[1]); - FilePath observed_str = root.Append(leaf); - EXPECT_EQ(FilePath::StringType(cases[i].expected), observed_str.value()) << - "i: " << i << ", root: " << root.value() << ", leaf: " << leaf; - FilePath observed_path = root.Append(FilePath(leaf)); - EXPECT_EQ(FilePath::StringType(cases[i].expected), observed_path.value()) << - "i: " << i << ", root: " << root.value() << ", leaf: " << leaf; - - // TODO(erikkay): It would be nice to have a unicode test append value to - // handle the case when AppendASCII is passed UTF8 -#if defined(OS_WIN) - std::string ascii = WideToUTF8(leaf); -#elif defined(OS_POSIX) || defined(OS_FUCHSIA) - std::string ascii = leaf; -#endif - observed_str = root.AppendASCII(ascii); - EXPECT_EQ(FilePath::StringType(cases[i].expected), observed_str.value()) << - "i: " << i << ", root: " << root.value() << ", leaf: " << leaf; - } -} - -TEST_F(FilePathTest, StripTrailingSeparators) { - const struct UnaryTestData cases[] = { - { FPL(""), FPL("") }, - { FPL("/"), FPL("/") }, - { FPL("//"), FPL("//") }, - { FPL("///"), FPL("/") }, - { FPL("////"), FPL("/") }, - { FPL("a/"), FPL("a") }, - { FPL("a//"), FPL("a") }, - { FPL("a///"), FPL("a") }, - { FPL("a////"), FPL("a") }, - { FPL("/a"), FPL("/a") }, - { FPL("/a/"), FPL("/a") }, - { FPL("/a//"), FPL("/a") }, - { FPL("/a///"), FPL("/a") }, - { FPL("/a////"), FPL("/a") }, -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - { FPL("c:"), FPL("c:") }, - { FPL("c:/"), FPL("c:/") }, - { FPL("c://"), FPL("c://") }, - { FPL("c:///"), FPL("c:/") }, - { FPL("c:////"), FPL("c:/") }, - { FPL("c:/a"), FPL("c:/a") }, - { FPL("c:/a/"), FPL("c:/a") }, - { FPL("c:/a//"), FPL("c:/a") }, - { FPL("c:/a///"), FPL("c:/a") }, - { FPL("c:/a////"), FPL("c:/a") }, -#endif // FILE_PATH_USES_DRIVE_LETTERS -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - { FPL("\\"), FPL("\\") }, - { FPL("\\\\"), FPL("\\\\") }, - { FPL("\\\\\\"), FPL("\\") }, - { FPL("\\\\\\\\"), FPL("\\") }, - { FPL("a\\"), FPL("a") }, - { FPL("a\\\\"), FPL("a") }, - { FPL("a\\\\\\"), FPL("a") }, - { FPL("a\\\\\\\\"), FPL("a") }, - { FPL("\\a"), FPL("\\a") }, - { FPL("\\a\\"), FPL("\\a") }, - { FPL("\\a\\\\"), FPL("\\a") }, - { FPL("\\a\\\\\\"), FPL("\\a") }, - { FPL("\\a\\\\\\\\"), FPL("\\a") }, -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - { FPL("c:\\"), FPL("c:\\") }, - { FPL("c:\\\\"), FPL("c:\\\\") }, - { FPL("c:\\\\\\"), FPL("c:\\") }, - { FPL("c:\\\\\\\\"), FPL("c:\\") }, - { FPL("c:\\a"), FPL("c:\\a") }, - { FPL("c:\\a\\"), FPL("c:\\a") }, - { FPL("c:\\a\\\\"), FPL("c:\\a") }, - { FPL("c:\\a\\\\\\"), FPL("c:\\a") }, - { FPL("c:\\a\\\\\\\\"), FPL("c:\\a") }, -#endif // FILE_PATH_USES_DRIVE_LETTERS -#endif // FILE_PATH_USES_WIN_SEPARATORS - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - FilePath input(cases[i].input); - FilePath observed = input.StripTrailingSeparators(); - EXPECT_EQ(FilePath::StringType(cases[i].expected), observed.value()) << - "i: " << i << ", input: " << input.value(); - } -} - -TEST_F(FilePathTest, IsAbsolute) { - const struct UnaryBooleanTestData cases[] = { - { FPL(""), false }, - { FPL("a"), false }, - { FPL("c:"), false }, - { FPL("c:a"), false }, - { FPL("a/b"), false }, - { FPL("//"), true }, - { FPL("//a"), true }, - { FPL("c:a/b"), false }, - { FPL("?:/a"), false }, -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - { FPL("/"), false }, - { FPL("/a"), false }, - { FPL("/."), false }, - { FPL("/.."), false }, - { FPL("c:/"), true }, - { FPL("c:/a"), true }, - { FPL("c:/."), true }, - { FPL("c:/.."), true }, - { FPL("C:/a"), true }, - { FPL("d:/a"), true }, -#else // FILE_PATH_USES_DRIVE_LETTERS - { FPL("/"), true }, - { FPL("/a"), true }, - { FPL("/."), true }, - { FPL("/.."), true }, - { FPL("c:/"), false }, -#endif // FILE_PATH_USES_DRIVE_LETTERS -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - { FPL("a\\b"), false }, - { FPL("\\\\"), true }, - { FPL("\\\\a"), true }, - { FPL("a\\b"), false }, - { FPL("\\\\"), true }, - { FPL("//a"), true }, - { FPL("c:a\\b"), false }, - { FPL("?:\\a"), false }, -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - { FPL("\\"), false }, - { FPL("\\a"), false }, - { FPL("\\."), false }, - { FPL("\\.."), false }, - { FPL("c:\\"), true }, - { FPL("c:\\"), true }, - { FPL("c:\\a"), true }, - { FPL("c:\\."), true }, - { FPL("c:\\.."), true }, - { FPL("C:\\a"), true }, - { FPL("d:\\a"), true }, -#else // FILE_PATH_USES_DRIVE_LETTERS - { FPL("\\"), true }, - { FPL("\\a"), true }, - { FPL("\\."), true }, - { FPL("\\.."), true }, - { FPL("c:\\"), false }, -#endif // FILE_PATH_USES_DRIVE_LETTERS -#endif // FILE_PATH_USES_WIN_SEPARATORS - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - FilePath input(cases[i].input); - bool observed = input.IsAbsolute(); - EXPECT_EQ(cases[i].expected, observed) << - "i: " << i << ", input: " << input.value(); - } -} - -TEST_F(FilePathTest, PathComponentsTest) { - const struct UnaryTestData cases[] = { - { FPL("//foo/bar/baz/"), FPL("|//|foo|bar|baz")}, - { FPL("///"), FPL("|/")}, - { FPL("/foo//bar//baz/"), FPL("|/|foo|bar|baz")}, - { FPL("/foo/bar/baz/"), FPL("|/|foo|bar|baz")}, - { FPL("/foo/bar/baz//"), FPL("|/|foo|bar|baz")}, - { FPL("/foo/bar/baz///"), FPL("|/|foo|bar|baz")}, - { FPL("/foo/bar/baz"), FPL("|/|foo|bar|baz")}, - { FPL("/foo/bar.bot/baz.txt"), FPL("|/|foo|bar.bot|baz.txt")}, - { FPL("//foo//bar/baz"), FPL("|//|foo|bar|baz")}, - { FPL("/"), FPL("|/")}, - { FPL("foo"), FPL("|foo")}, - { FPL(""), FPL("")}, -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - { FPL("e:/foo"), FPL("|e:|/|foo")}, - { FPL("e:/"), FPL("|e:|/")}, - { FPL("e:"), FPL("|e:")}, -#endif // FILE_PATH_USES_DRIVE_LETTERS -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - { FPL("../foo"), FPL("|..|foo")}, - { FPL("./foo"), FPL("|foo")}, - { FPL("../foo/bar/"), FPL("|..|foo|bar") }, - { FPL("\\\\foo\\bar\\baz\\"), FPL("|\\\\|foo|bar|baz")}, - { FPL("\\\\\\"), FPL("|\\")}, - { FPL("\\foo\\\\bar\\\\baz\\"), FPL("|\\|foo|bar|baz")}, - { FPL("\\foo\\bar\\baz\\"), FPL("|\\|foo|bar|baz")}, - { FPL("\\foo\\bar\\baz\\\\"), FPL("|\\|foo|bar|baz")}, - { FPL("\\foo\\bar\\baz\\\\\\"), FPL("|\\|foo|bar|baz")}, - { FPL("\\foo\\bar\\baz"), FPL("|\\|foo|bar|baz")}, - { FPL("\\foo\\bar/baz\\\\\\"), FPL("|\\|foo|bar|baz")}, - { FPL("/foo\\bar\\baz"), FPL("|/|foo|bar|baz")}, - { FPL("\\foo\\bar.bot\\baz.txt"), FPL("|\\|foo|bar.bot|baz.txt")}, - { FPL("\\\\foo\\\\bar\\baz"), FPL("|\\\\|foo|bar|baz")}, - { FPL("\\"), FPL("|\\")}, -#endif // FILE_PATH_USES_WIN_SEPARATORS - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - FilePath input(cases[i].input); - std::vector<FilePath::StringType> comps; - input.GetComponents(&comps); - - FilePath::StringType observed; - for (size_t j = 0; j < comps.size(); ++j) { - observed.append(FILE_PATH_LITERAL("|"), 1); - observed.append(comps[j]); - } - EXPECT_EQ(FilePath::StringType(cases[i].expected), observed) << - "i: " << i << ", input: " << input.value(); - } -} - -TEST_F(FilePathTest, IsParentTest) { - const struct BinaryBooleanTestData cases[] = { - { { FPL("/"), FPL("/foo/bar/baz") }, true}, - { { FPL("/foo/bar"), FPL("/foo/bar/baz") }, true}, - { { FPL("/foo/bar/"), FPL("/foo/bar/baz") }, true}, - { { FPL("//foo/bar/"), FPL("//foo/bar/baz") }, true}, - { { FPL("/foo/bar"), FPL("/foo2/bar/baz") }, false}, - { { FPL("/foo/bar.txt"), FPL("/foo/bar/baz") }, false}, - { { FPL("/foo/bar"), FPL("/foo/bar2/baz") }, false}, - { { FPL("/foo/bar"), FPL("/foo/bar") }, false}, - { { FPL("/foo/bar/baz"), FPL("/foo/bar") }, false}, - { { FPL("foo/bar"), FPL("foo/bar/baz") }, true}, - { { FPL("foo/bar"), FPL("foo2/bar/baz") }, false}, - { { FPL("foo/bar"), FPL("foo/bar2/baz") }, false}, - { { FPL(""), FPL("foo") }, false}, -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - { { FPL("c:/foo/bar"), FPL("c:/foo/bar/baz") }, true}, - { { FPL("E:/foo/bar"), FPL("e:/foo/bar/baz") }, true}, - { { FPL("f:/foo/bar"), FPL("F:/foo/bar/baz") }, true}, - { { FPL("E:/Foo/bar"), FPL("e:/foo/bar/baz") }, false}, - { { FPL("f:/foo/bar"), FPL("F:/foo/Bar/baz") }, false}, - { { FPL("c:/"), FPL("c:/foo/bar/baz") }, true}, - { { FPL("c:"), FPL("c:/foo/bar/baz") }, true}, - { { FPL("c:/foo/bar"), FPL("d:/foo/bar/baz") }, false}, - { { FPL("c:/foo/bar"), FPL("D:/foo/bar/baz") }, false}, - { { FPL("C:/foo/bar"), FPL("d:/foo/bar/baz") }, false}, - { { FPL("c:/foo/bar"), FPL("c:/foo2/bar/baz") }, false}, - { { FPL("e:/foo/bar"), FPL("E:/foo2/bar/baz") }, false}, - { { FPL("F:/foo/bar"), FPL("f:/foo2/bar/baz") }, false}, - { { FPL("c:/foo/bar"), FPL("c:/foo/bar2/baz") }, false}, -#endif // FILE_PATH_USES_DRIVE_LETTERS -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - { { FPL("\\foo\\bar"), FPL("\\foo\\bar\\baz") }, true}, - { { FPL("\\foo/bar"), FPL("\\foo\\bar\\baz") }, true}, - { { FPL("\\foo/bar"), FPL("\\foo/bar/baz") }, true}, - { { FPL("\\"), FPL("\\foo\\bar\\baz") }, true}, - { { FPL(""), FPL("\\foo\\bar\\baz") }, false}, - { { FPL("\\foo\\bar"), FPL("\\foo2\\bar\\baz") }, false}, - { { FPL("\\foo\\bar"), FPL("\\foo\\bar2\\baz") }, false}, -#endif // FILE_PATH_USES_WIN_SEPARATORS - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - FilePath parent(cases[i].inputs[0]); - FilePath child(cases[i].inputs[1]); - - EXPECT_EQ(parent.IsParent(child), cases[i].expected) << - "i: " << i << ", parent: " << parent.value() << ", child: " << - child.value(); - } -} - -TEST_F(FilePathTest, AppendRelativePathTest) { - const struct BinaryTestData cases[] = { -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - { { FPL("/"), FPL("/foo/bar/baz") }, FPL("foo\\bar\\baz")}, -#else // FILE_PATH_USES_WIN_SEPARATORS - { { FPL("/"), FPL("/foo/bar/baz") }, FPL("foo/bar/baz")}, -#endif // FILE_PATH_USES_WIN_SEPARATORS - { { FPL("/foo/bar"), FPL("/foo/bar/baz") }, FPL("baz")}, - { { FPL("/foo/bar/"), FPL("/foo/bar/baz") }, FPL("baz")}, - { { FPL("//foo/bar/"), FPL("//foo/bar/baz") }, FPL("baz")}, - { { FPL("/foo/bar"), FPL("/foo2/bar/baz") }, FPL("")}, - { { FPL("/foo/bar.txt"), FPL("/foo/bar/baz") }, FPL("")}, - { { FPL("/foo/bar"), FPL("/foo/bar2/baz") }, FPL("")}, - { { FPL("/foo/bar"), FPL("/foo/bar") }, FPL("")}, - { { FPL("/foo/bar/baz"), FPL("/foo/bar") }, FPL("")}, - { { FPL("foo/bar"), FPL("foo/bar/baz") }, FPL("baz")}, - { { FPL("foo/bar"), FPL("foo2/bar/baz") }, FPL("")}, - { { FPL("foo/bar"), FPL("foo/bar2/baz") }, FPL("")}, - { { FPL(""), FPL("foo") }, FPL("")}, -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - { { FPL("c:/foo/bar"), FPL("c:/foo/bar/baz") }, FPL("baz")}, - { { FPL("E:/foo/bar"), FPL("e:/foo/bar/baz") }, FPL("baz")}, - { { FPL("f:/foo/bar"), FPL("F:/foo/bar/baz") }, FPL("baz")}, - { { FPL("E:/Foo/bar"), FPL("e:/foo/bar/baz") }, FPL("")}, - { { FPL("f:/foo/bar"), FPL("F:/foo/Bar/baz") }, FPL("")}, -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - { { FPL("c:/"), FPL("c:/foo/bar/baz") }, FPL("foo\\bar\\baz")}, - // TODO(akalin): Figure out how to handle the corner case in the - // commented-out test case below. Appending to an empty path gives - // /foo\bar\baz but appending to a nonempty path "blah" gives - // blah\foo\bar\baz. - // { { FPL("c:"), FPL("c:/foo/bar/baz") }, FPL("foo\\bar\\baz")}, -#endif // FILE_PATH_USES_WIN_SEPARATORS - { { FPL("c:/foo/bar"), FPL("d:/foo/bar/baz") }, FPL("")}, - { { FPL("c:/foo/bar"), FPL("D:/foo/bar/baz") }, FPL("")}, - { { FPL("C:/foo/bar"), FPL("d:/foo/bar/baz") }, FPL("")}, - { { FPL("c:/foo/bar"), FPL("c:/foo2/bar/baz") }, FPL("")}, - { { FPL("e:/foo/bar"), FPL("E:/foo2/bar/baz") }, FPL("")}, - { { FPL("F:/foo/bar"), FPL("f:/foo2/bar/baz") }, FPL("")}, - { { FPL("c:/foo/bar"), FPL("c:/foo/bar2/baz") }, FPL("")}, -#endif // FILE_PATH_USES_DRIVE_LETTERS -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - { { FPL("\\foo\\bar"), FPL("\\foo\\bar\\baz") }, FPL("baz")}, - { { FPL("\\foo/bar"), FPL("\\foo\\bar\\baz") }, FPL("baz")}, - { { FPL("\\foo/bar"), FPL("\\foo/bar/baz") }, FPL("baz")}, - { { FPL("\\"), FPL("\\foo\\bar\\baz") }, FPL("foo\\bar\\baz")}, - { { FPL(""), FPL("\\foo\\bar\\baz") }, FPL("")}, - { { FPL("\\foo\\bar"), FPL("\\foo2\\bar\\baz") }, FPL("")}, - { { FPL("\\foo\\bar"), FPL("\\foo\\bar2\\baz") }, FPL("")}, -#endif // FILE_PATH_USES_WIN_SEPARATORS - }; - - const FilePath base(FPL("blah")); - - for (size_t i = 0; i < arraysize(cases); ++i) { - FilePath parent(cases[i].inputs[0]); - FilePath child(cases[i].inputs[1]); - { - FilePath result; - bool success = parent.AppendRelativePath(child, &result); - EXPECT_EQ(cases[i].expected[0] != '\0', success) << - "i: " << i << ", parent: " << parent.value() << ", child: " << - child.value(); - EXPECT_STREQ(cases[i].expected, result.value().c_str()) << - "i: " << i << ", parent: " << parent.value() << ", child: " << - child.value(); - } - { - FilePath result(base); - bool success = parent.AppendRelativePath(child, &result); - EXPECT_EQ(cases[i].expected[0] != '\0', success) << - "i: " << i << ", parent: " << parent.value() << ", child: " << - child.value(); - EXPECT_EQ(base.Append(cases[i].expected).value(), result.value()) << - "i: " << i << ", parent: " << parent.value() << ", child: " << - child.value(); - } - } -} - -TEST_F(FilePathTest, EqualityTest) { - const struct BinaryBooleanTestData cases[] = { - { { FPL("/foo/bar/baz"), FPL("/foo/bar/baz") }, true}, - { { FPL("/foo/bar"), FPL("/foo/bar/baz") }, false}, - { { FPL("/foo/bar/baz"), FPL("/foo/bar") }, false}, - { { FPL("//foo/bar/"), FPL("//foo/bar/") }, true}, - { { FPL("/foo/bar"), FPL("/foo2/bar") }, false}, - { { FPL("/foo/bar.txt"), FPL("/foo/bar") }, false}, - { { FPL("foo/bar"), FPL("foo/bar") }, true}, - { { FPL("foo/bar"), FPL("foo/bar/baz") }, false}, - { { FPL(""), FPL("foo") }, false}, -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - { { FPL("c:/foo/bar"), FPL("c:/foo/bar") }, true}, - { { FPL("E:/foo/bar"), FPL("e:/foo/bar") }, true}, - { { FPL("f:/foo/bar"), FPL("F:/foo/bar") }, true}, - { { FPL("E:/Foo/bar"), FPL("e:/foo/bar") }, false}, - { { FPL("f:/foo/bar"), FPL("F:/foo/Bar") }, false}, - { { FPL("c:/"), FPL("c:/") }, true}, - { { FPL("c:"), FPL("c:") }, true}, - { { FPL("c:/foo/bar"), FPL("d:/foo/bar") }, false}, - { { FPL("c:/foo/bar"), FPL("D:/foo/bar") }, false}, - { { FPL("C:/foo/bar"), FPL("d:/foo/bar") }, false}, - { { FPL("c:/foo/bar"), FPL("c:/foo2/bar") }, false}, -#endif // FILE_PATH_USES_DRIVE_LETTERS -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - { { FPL("\\foo\\bar"), FPL("\\foo\\bar") }, true}, - { { FPL("\\foo/bar"), FPL("\\foo/bar") }, true}, - { { FPL("\\foo/bar"), FPL("\\foo\\bar") }, false}, - { { FPL("\\"), FPL("\\") }, true}, - { { FPL("\\"), FPL("/") }, false}, - { { FPL(""), FPL("\\") }, false}, - { { FPL("\\foo\\bar"), FPL("\\foo2\\bar") }, false}, - { { FPL("\\foo\\bar"), FPL("\\foo\\bar2") }, false}, -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - { { FPL("c:\\foo\\bar"), FPL("c:\\foo\\bar") }, true}, - { { FPL("E:\\foo\\bar"), FPL("e:\\foo\\bar") }, true}, - { { FPL("f:\\foo\\bar"), FPL("F:\\foo/bar") }, false}, -#endif // FILE_PATH_USES_DRIVE_LETTERS -#endif // FILE_PATH_USES_WIN_SEPARATORS - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - FilePath a(cases[i].inputs[0]); - FilePath b(cases[i].inputs[1]); - - EXPECT_EQ(a == b, cases[i].expected) << - "equality i: " << i << ", a: " << a.value() << ", b: " << - b.value(); - } - - for (size_t i = 0; i < arraysize(cases); ++i) { - FilePath a(cases[i].inputs[0]); - FilePath b(cases[i].inputs[1]); - - EXPECT_EQ(a != b, !cases[i].expected) << - "inequality i: " << i << ", a: " << a.value() << ", b: " << - b.value(); - } -} - -TEST_F(FilePathTest, Extension) { - FilePath base_dir(FILE_PATH_LITERAL("base_dir")); - - FilePath jpg = base_dir.Append(FILE_PATH_LITERAL("foo.jpg")); - EXPECT_EQ(FILE_PATH_LITERAL(".jpg"), jpg.Extension()); - EXPECT_EQ(FILE_PATH_LITERAL(".jpg"), jpg.FinalExtension()); - - FilePath base = jpg.BaseName().RemoveExtension(); - EXPECT_EQ(FILE_PATH_LITERAL("foo"), base.value()); - - FilePath path_no_ext = base_dir.Append(base); - EXPECT_EQ(path_no_ext.value(), jpg.RemoveExtension().value()); - - EXPECT_EQ(path_no_ext.value(), path_no_ext.RemoveExtension().value()); - EXPECT_EQ(FILE_PATH_LITERAL(""), path_no_ext.Extension()); - EXPECT_EQ(FILE_PATH_LITERAL(""), path_no_ext.FinalExtension()); -} - -TEST_F(FilePathTest, Extension2) { - const struct UnaryTestData cases[] = { -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - { FPL("C:\\a\\b\\c.ext"), FPL(".ext") }, - { FPL("C:\\a\\b\\c."), FPL(".") }, - { FPL("C:\\a\\b\\c"), FPL("") }, - { FPL("C:\\a\\b\\"), FPL("") }, - { FPL("C:\\a\\b.\\"), FPL(".") }, - { FPL("C:\\a\\b\\c.ext1.ext2"), FPL(".ext2") }, - { FPL("C:\\foo.bar\\\\\\"), FPL(".bar") }, - { FPL("C:\\foo.bar\\.."), FPL("") }, - { FPL("C:\\foo.bar\\..\\\\"), FPL("") }, -#endif - { FPL("/foo/bar/baz.ext"), FPL(".ext") }, - { FPL("/foo/bar/baz."), FPL(".") }, - { FPL("/foo/bar/baz.."), FPL(".") }, - { FPL("/foo/bar/baz"), FPL("") }, - { FPL("/foo/bar/"), FPL("") }, - { FPL("/foo/bar./"), FPL(".") }, - { FPL("/foo/bar/baz.ext1.ext2"), FPL(".ext2") }, - { FPL("/subversion-1.6.12.zip"), FPL(".zip") }, - { FPL("/foo.12345.gz"), FPL(".gz") }, - { FPL("/foo..gz"), FPL(".gz") }, - { FPL("."), FPL("") }, - { FPL(".."), FPL("") }, - { FPL("./foo"), FPL("") }, - { FPL("./foo.ext"), FPL(".ext") }, - { FPL("/foo.ext1/bar.ext2"), FPL(".ext2") }, - { FPL("/foo.bar////"), FPL(".bar") }, - { FPL("/foo.bar/.."), FPL("") }, - { FPL("/foo.bar/..////"), FPL("") }, - { FPL("/foo.1234.luser.js"), FPL(".js") }, - { FPL("/user.js"), FPL(".js") }, - }; - const struct UnaryTestData double_extension_cases[] = { - { FPL("/foo.tar.gz"), FPL(".tar.gz") }, - { FPL("/foo.tar.Z"), FPL(".tar.Z") }, - { FPL("/foo.tar.bz2"), FPL(".tar.bz2") }, - { FPL("/foo.1234.gz"), FPL(".1234.gz") }, - { FPL("/foo.1234.tar.gz"), FPL(".tar.gz") }, - { FPL("/foo.tar.tar.gz"), FPL(".tar.gz") }, - { FPL("/foo.tar.gz.gz"), FPL(".gz.gz") }, - { FPL("/foo.1234.user.js"), FPL(".user.js") }, - { FPL("foo.user.js"), FPL(".user.js") }, - { FPL("/foo.tar.bz"), FPL(".tar.bz") }, - }; - for (unsigned int i = 0; i < arraysize(cases); ++i) { - FilePath path(cases[i].input); - FilePath::StringType extension = path.Extension(); - FilePath::StringType final_extension = path.FinalExtension(); - EXPECT_STREQ(cases[i].expected, extension.c_str()) - << "i: " << i << ", path: " << path.value(); - EXPECT_STREQ(cases[i].expected, final_extension.c_str()) - << "i: " << i << ", path: " << path.value(); - } - for (unsigned int i = 0; i < arraysize(double_extension_cases); ++i) { - FilePath path(double_extension_cases[i].input); - FilePath::StringType extension = path.Extension(); - EXPECT_STREQ(double_extension_cases[i].expected, extension.c_str()) - << "i: " << i << ", path: " << path.value(); - } -} - -TEST_F(FilePathTest, InsertBeforeExtension) { - const struct BinaryTestData cases[] = { - { { FPL(""), FPL("") }, FPL("") }, - { { FPL(""), FPL("txt") }, FPL("") }, - { { FPL("."), FPL("txt") }, FPL("") }, - { { FPL(".."), FPL("txt") }, FPL("") }, - { { FPL("foo.dll"), FPL("txt") }, FPL("footxt.dll") }, - { { FPL("."), FPL("") }, FPL(".") }, - { { FPL("foo.dll"), FPL(".txt") }, FPL("foo.txt.dll") }, - { { FPL("foo"), FPL("txt") }, FPL("footxt") }, - { { FPL("foo"), FPL(".txt") }, FPL("foo.txt") }, - { { FPL("foo.baz.dll"), FPL("txt") }, FPL("foo.baztxt.dll") }, - { { FPL("foo.baz.dll"), FPL(".txt") }, FPL("foo.baz.txt.dll") }, - { { FPL("foo.dll"), FPL("") }, FPL("foo.dll") }, - { { FPL("foo.dll"), FPL(".") }, FPL("foo..dll") }, - { { FPL("foo"), FPL("") }, FPL("foo") }, - { { FPL("foo"), FPL(".") }, FPL("foo.") }, - { { FPL("foo.baz.dll"), FPL("") }, FPL("foo.baz.dll") }, - { { FPL("foo.baz.dll"), FPL(".") }, FPL("foo.baz..dll") }, -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - { { FPL("\\"), FPL("") }, FPL("\\") }, - { { FPL("\\"), FPL("txt") }, FPL("\\txt") }, - { { FPL("\\."), FPL("txt") }, FPL("") }, - { { FPL("\\.."), FPL("txt") }, FPL("") }, - { { FPL("\\."), FPL("") }, FPL("\\.") }, - { { FPL("C:\\bar\\foo.dll"), FPL("txt") }, - FPL("C:\\bar\\footxt.dll") }, - { { FPL("C:\\bar.baz\\foodll"), FPL("txt") }, - FPL("C:\\bar.baz\\foodlltxt") }, - { { FPL("C:\\bar.baz\\foo.dll"), FPL("txt") }, - FPL("C:\\bar.baz\\footxt.dll") }, - { { FPL("C:\\bar.baz\\foo.dll.exe"), FPL("txt") }, - FPL("C:\\bar.baz\\foo.dlltxt.exe") }, - { { FPL("C:\\bar.baz\\foo"), FPL("") }, - FPL("C:\\bar.baz\\foo") }, - { { FPL("C:\\bar.baz\\foo.exe"), FPL("") }, - FPL("C:\\bar.baz\\foo.exe") }, - { { FPL("C:\\bar.baz\\foo.dll.exe"), FPL("") }, - FPL("C:\\bar.baz\\foo.dll.exe") }, - { { FPL("C:\\bar\\baz\\foo.exe"), FPL(" (1)") }, - FPL("C:\\bar\\baz\\foo (1).exe") }, - { { FPL("C:\\foo.baz\\\\"), FPL(" (1)") }, FPL("C:\\foo (1).baz") }, - { { FPL("C:\\foo.baz\\..\\"), FPL(" (1)") }, FPL("") }, -#endif - { { FPL("/"), FPL("") }, FPL("/") }, - { { FPL("/"), FPL("txt") }, FPL("/txt") }, - { { FPL("/."), FPL("txt") }, FPL("") }, - { { FPL("/.."), FPL("txt") }, FPL("") }, - { { FPL("/."), FPL("") }, FPL("/.") }, - { { FPL("/bar/foo.dll"), FPL("txt") }, FPL("/bar/footxt.dll") }, - { { FPL("/bar.baz/foodll"), FPL("txt") }, FPL("/bar.baz/foodlltxt") }, - { { FPL("/bar.baz/foo.dll"), FPL("txt") }, FPL("/bar.baz/footxt.dll") }, - { { FPL("/bar.baz/foo.dll.exe"), FPL("txt") }, - FPL("/bar.baz/foo.dlltxt.exe") }, - { { FPL("/bar.baz/foo"), FPL("") }, FPL("/bar.baz/foo") }, - { { FPL("/bar.baz/foo.exe"), FPL("") }, FPL("/bar.baz/foo.exe") }, - { { FPL("/bar.baz/foo.dll.exe"), FPL("") }, FPL("/bar.baz/foo.dll.exe") }, - { { FPL("/bar/baz/foo.exe"), FPL(" (1)") }, FPL("/bar/baz/foo (1).exe") }, - { { FPL("/bar/baz/..////"), FPL(" (1)") }, FPL("") }, - }; - for (unsigned int i = 0; i < arraysize(cases); ++i) { - FilePath path(cases[i].inputs[0]); - FilePath result = path.InsertBeforeExtension(cases[i].inputs[1]); - EXPECT_EQ(cases[i].expected, result.value()) << "i: " << i << - ", path: " << path.value() << ", insert: " << cases[i].inputs[1]; - } -} - -TEST_F(FilePathTest, RemoveExtension) { - const struct UnaryTestData cases[] = { - { FPL(""), FPL("") }, - { FPL("."), FPL(".") }, - { FPL(".."), FPL("..") }, - { FPL("foo.dll"), FPL("foo") }, - { FPL("./foo.dll"), FPL("./foo") }, - { FPL("foo..dll"), FPL("foo.") }, - { FPL("foo"), FPL("foo") }, - { FPL("foo."), FPL("foo") }, - { FPL("foo.."), FPL("foo.") }, - { FPL("foo.baz.dll"), FPL("foo.baz") }, -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - { FPL("C:\\foo.bar\\foo"), FPL("C:\\foo.bar\\foo") }, - { FPL("C:\\foo.bar\\..\\\\"), FPL("C:\\foo.bar\\..\\\\") }, -#endif - { FPL("/foo.bar/foo"), FPL("/foo.bar/foo") }, - { FPL("/foo.bar/..////"), FPL("/foo.bar/..////") }, - }; - for (unsigned int i = 0; i < arraysize(cases); ++i) { - FilePath path(cases[i].input); - FilePath removed = path.RemoveExtension(); - FilePath removed_final = path.RemoveFinalExtension(); - EXPECT_EQ(cases[i].expected, removed.value()) << "i: " << i << - ", path: " << path.value(); - EXPECT_EQ(cases[i].expected, removed_final.value()) << "i: " << i << - ", path: " << path.value(); - } - { - FilePath path(FPL("foo.tar.gz")); - FilePath removed = path.RemoveExtension(); - FilePath removed_final = path.RemoveFinalExtension(); - EXPECT_EQ(FPL("foo"), removed.value()) << ", path: " << path.value(); - EXPECT_EQ(FPL("foo.tar"), removed_final.value()) << ", path: " - << path.value(); - } -} - -TEST_F(FilePathTest, ReplaceExtension) { - const struct BinaryTestData cases[] = { - { { FPL(""), FPL("") }, FPL("") }, - { { FPL(""), FPL("txt") }, FPL("") }, - { { FPL("."), FPL("txt") }, FPL("") }, - { { FPL(".."), FPL("txt") }, FPL("") }, - { { FPL("."), FPL("") }, FPL("") }, - { { FPL("foo.dll"), FPL("txt") }, FPL("foo.txt") }, - { { FPL("./foo.dll"), FPL("txt") }, FPL("./foo.txt") }, - { { FPL("foo..dll"), FPL("txt") }, FPL("foo..txt") }, - { { FPL("foo.dll"), FPL(".txt") }, FPL("foo.txt") }, - { { FPL("foo"), FPL("txt") }, FPL("foo.txt") }, - { { FPL("foo."), FPL("txt") }, FPL("foo.txt") }, - { { FPL("foo.."), FPL("txt") }, FPL("foo..txt") }, - { { FPL("foo"), FPL(".txt") }, FPL("foo.txt") }, - { { FPL("foo.baz.dll"), FPL("txt") }, FPL("foo.baz.txt") }, - { { FPL("foo.baz.dll"), FPL(".txt") }, FPL("foo.baz.txt") }, - { { FPL("foo.dll"), FPL("") }, FPL("foo") }, - { { FPL("foo.dll"), FPL(".") }, FPL("foo") }, - { { FPL("foo"), FPL("") }, FPL("foo") }, - { { FPL("foo"), FPL(".") }, FPL("foo") }, - { { FPL("foo.baz.dll"), FPL("") }, FPL("foo.baz") }, - { { FPL("foo.baz.dll"), FPL(".") }, FPL("foo.baz") }, -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - { { FPL("C:\\foo.bar\\foo"), FPL("baz") }, FPL("C:\\foo.bar\\foo.baz") }, - { { FPL("C:\\foo.bar\\..\\\\"), FPL("baz") }, FPL("") }, -#endif - { { FPL("/foo.bar/foo"), FPL("baz") }, FPL("/foo.bar/foo.baz") }, - { { FPL("/foo.bar/..////"), FPL("baz") }, FPL("") }, - }; - for (unsigned int i = 0; i < arraysize(cases); ++i) { - FilePath path(cases[i].inputs[0]); - FilePath replaced = path.ReplaceExtension(cases[i].inputs[1]); - EXPECT_EQ(cases[i].expected, replaced.value()) << "i: " << i << - ", path: " << path.value() << ", replace: " << cases[i].inputs[1]; - } -} - -TEST_F(FilePathTest, AddExtension) { - const struct BinaryTestData cases[] = { - { { FPL(""), FPL("") }, FPL("") }, - { { FPL(""), FPL("txt") }, FPL("") }, - { { FPL("."), FPL("txt") }, FPL("") }, - { { FPL(".."), FPL("txt") }, FPL("") }, - { { FPL("."), FPL("") }, FPL("") }, - { { FPL("foo.dll"), FPL("txt") }, FPL("foo.dll.txt") }, - { { FPL("./foo.dll"), FPL("txt") }, FPL("./foo.dll.txt") }, - { { FPL("foo..dll"), FPL("txt") }, FPL("foo..dll.txt") }, - { { FPL("foo.dll"), FPL(".txt") }, FPL("foo.dll.txt") }, - { { FPL("foo"), FPL("txt") }, FPL("foo.txt") }, - { { FPL("foo."), FPL("txt") }, FPL("foo.txt") }, - { { FPL("foo.."), FPL("txt") }, FPL("foo..txt") }, - { { FPL("foo"), FPL(".txt") }, FPL("foo.txt") }, - { { FPL("foo.baz.dll"), FPL("txt") }, FPL("foo.baz.dll.txt") }, - { { FPL("foo.baz.dll"), FPL(".txt") }, FPL("foo.baz.dll.txt") }, - { { FPL("foo.dll"), FPL("") }, FPL("foo.dll") }, - { { FPL("foo.dll"), FPL(".") }, FPL("foo.dll") }, - { { FPL("foo"), FPL("") }, FPL("foo") }, - { { FPL("foo"), FPL(".") }, FPL("foo") }, - { { FPL("foo.baz.dll"), FPL("") }, FPL("foo.baz.dll") }, - { { FPL("foo.baz.dll"), FPL(".") }, FPL("foo.baz.dll") }, -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - { { FPL("C:\\foo.bar\\foo"), FPL("baz") }, FPL("C:\\foo.bar\\foo.baz") }, - { { FPL("C:\\foo.bar\\..\\\\"), FPL("baz") }, FPL("") }, -#endif - { { FPL("/foo.bar/foo"), FPL("baz") }, FPL("/foo.bar/foo.baz") }, - { { FPL("/foo.bar/..////"), FPL("baz") }, FPL("") }, - }; - for (unsigned int i = 0; i < arraysize(cases); ++i) { - FilePath path(cases[i].inputs[0]); - FilePath added = path.AddExtension(cases[i].inputs[1]); - EXPECT_EQ(cases[i].expected, added.value()) << "i: " << i << - ", path: " << path.value() << ", add: " << cases[i].inputs[1]; - } -} - -TEST_F(FilePathTest, MatchesExtension) { - const struct BinaryBooleanTestData cases[] = { - { { FPL("foo"), FPL("") }, true}, - { { FPL("foo"), FPL(".") }, false}, - { { FPL("foo."), FPL("") }, false}, - { { FPL("foo."), FPL(".") }, true}, - { { FPL("foo.txt"), FPL(".dll") }, false}, - { { FPL("foo.txt"), FPL(".txt") }, true}, - { { FPL("foo.txt.dll"), FPL(".txt") }, false}, - { { FPL("foo.txt.dll"), FPL(".dll") }, true}, - { { FPL("foo.TXT"), FPL(".txt") }, true}, - { { FPL("foo.txt"), FPL(".TXT") }, true}, - { { FPL("foo.tXt"), FPL(".txt") }, true}, - { { FPL("foo.txt"), FPL(".tXt") }, true}, - { { FPL("foo.tXt"), FPL(".TXT") }, true}, - { { FPL("foo.tXt"), FPL(".tXt") }, true}, -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - { { FPL("c:/foo.txt.dll"), FPL(".txt") }, false}, - { { FPL("c:/foo.txt"), FPL(".txt") }, true}, -#endif // FILE_PATH_USES_DRIVE_LETTERS -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - { { FPL("c:\\bar\\foo.txt.dll"), FPL(".txt") }, false}, - { { FPL("c:\\bar\\foo.txt"), FPL(".txt") }, true}, -#endif // FILE_PATH_USES_DRIVE_LETTERS - { { FPL("/bar/foo.txt.dll"), FPL(".txt") }, false}, - { { FPL("/bar/foo.txt"), FPL(".txt") }, true}, -#if defined(OS_WIN) || defined(OS_MACOSX) - // Umlauts A, O, U: direct comparison, and upper case vs. lower case - { { FPL("foo.\u00E4\u00F6\u00FC"), FPL(".\u00E4\u00F6\u00FC") }, true}, - { { FPL("foo.\u00C4\u00D6\u00DC"), FPL(".\u00E4\u00F6\u00FC") }, true}, - // C with circumflex: direct comparison, and upper case vs. lower case - { { FPL("foo.\u0109"), FPL(".\u0109") }, true}, - { { FPL("foo.\u0108"), FPL(".\u0109") }, true}, -#endif - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - FilePath path(cases[i].inputs[0]); - FilePath::StringType ext(cases[i].inputs[1]); - - EXPECT_EQ(cases[i].expected, path.MatchesExtension(ext)) << - "i: " << i << ", path: " << path.value() << ", ext: " << ext; - } -} - -TEST_F(FilePathTest, CompareIgnoreCase) { - const struct BinaryIntTestData cases[] = { - { { FPL("foo"), FPL("foo") }, 0}, - { { FPL("FOO"), FPL("foo") }, 0}, - { { FPL("foo.ext"), FPL("foo.ext") }, 0}, - { { FPL("FOO.EXT"), FPL("foo.ext") }, 0}, - { { FPL("Foo.Ext"), FPL("foo.ext") }, 0}, - { { FPL("foO"), FPL("foo") }, 0}, - { { FPL("foo"), FPL("foO") }, 0}, - { { FPL("fOo"), FPL("foo") }, 0}, - { { FPL("foo"), FPL("fOo") }, 0}, - { { FPL("bar"), FPL("foo") }, -1}, - { { FPL("foo"), FPL("bar") }, 1}, - { { FPL("BAR"), FPL("foo") }, -1}, - { { FPL("FOO"), FPL("bar") }, 1}, - { { FPL("bar"), FPL("FOO") }, -1}, - { { FPL("foo"), FPL("BAR") }, 1}, - { { FPL("BAR"), FPL("FOO") }, -1}, - { { FPL("FOO"), FPL("BAR") }, 1}, - // German "Eszett" (lower case and the new-fangled upper case) - // Note that uc(<lowercase eszett>) => "SS", NOT <uppercase eszett>! - // However, neither Windows nor Mac OSX converts these. - // (or even have glyphs for <uppercase eszett>) - { { FPL("\u00DF"), FPL("\u00DF") }, 0}, - { { FPL("\u1E9E"), FPL("\u1E9E") }, 0}, - { { FPL("\u00DF"), FPL("\u1E9E") }, -1}, - { { FPL("SS"), FPL("\u00DF") }, -1}, - { { FPL("SS"), FPL("\u1E9E") }, -1}, -#if defined(OS_WIN) || defined(OS_MACOSX) - // Umlauts A, O, U: direct comparison, and upper case vs. lower case - { { FPL("\u00E4\u00F6\u00FC"), FPL("\u00E4\u00F6\u00FC") }, 0}, - { { FPL("\u00C4\u00D6\u00DC"), FPL("\u00E4\u00F6\u00FC") }, 0}, - // C with circumflex: direct comparison, and upper case vs. lower case - { { FPL("\u0109"), FPL("\u0109") }, 0}, - { { FPL("\u0108"), FPL("\u0109") }, 0}, - // Cyrillic letter SHA: direct comparison, and upper case vs. lower case - { { FPL("\u0428"), FPL("\u0428") }, 0}, - { { FPL("\u0428"), FPL("\u0448") }, 0}, - // Greek letter DELTA: direct comparison, and upper case vs. lower case - { { FPL("\u0394"), FPL("\u0394") }, 0}, - { { FPL("\u0394"), FPL("\u03B4") }, 0}, - // Japanese full-width A: direct comparison, and upper case vs. lower case - // Note that full-width and standard characters are considered different. - { { FPL("\uFF21"), FPL("\uFF21") }, 0}, - { { FPL("\uFF21"), FPL("\uFF41") }, 0}, - { { FPL("A"), FPL("\uFF21") }, -1}, - { { FPL("A"), FPL("\uFF41") }, -1}, - { { FPL("a"), FPL("\uFF21") }, -1}, - { { FPL("a"), FPL("\uFF41") }, -1}, -#endif -#if defined(OS_MACOSX) - // Codepoints > 0x1000 - // Georgian letter DON: direct comparison, and upper case vs. lower case - { { FPL("\u10A3"), FPL("\u10A3") }, 0}, - { { FPL("\u10A3"), FPL("\u10D3") }, 0}, - // Combining characters vs. pre-composed characters, upper and lower case - { { FPL("k\u0301u\u032Do\u0304\u0301n"), FPL("\u1E31\u1E77\u1E53n") }, 0}, - { { FPL("k\u0301u\u032Do\u0304\u0301n"), FPL("kuon") }, 1}, - { { FPL("kuon"), FPL("k\u0301u\u032Do\u0304\u0301n") }, -1}, - { { FPL("K\u0301U\u032DO\u0304\u0301N"), FPL("KUON") }, 1}, - { { FPL("KUON"), FPL("K\u0301U\u032DO\u0304\u0301N") }, -1}, - { { FPL("k\u0301u\u032Do\u0304\u0301n"), FPL("KUON") }, 1}, - { { FPL("K\u0301U\u032DO\u0304\u0301N"), FPL("\u1E31\u1E77\u1E53n") }, 0}, - { { FPL("k\u0301u\u032Do\u0304\u0301n"), FPL("\u1E30\u1E76\u1E52n") }, 0}, - { { FPL("k\u0301u\u032Do\u0304\u0302n"), FPL("\u1E30\u1E76\u1E52n") }, 1}, -#endif - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - FilePath::StringType s1(cases[i].inputs[0]); - FilePath::StringType s2(cases[i].inputs[1]); - int result = FilePath::CompareIgnoreCase(s1, s2); - EXPECT_EQ(cases[i].expected, result) << - "i: " << i << ", s1: " << s1 << ", s2: " << s2; - } -} - -TEST_F(FilePathTest, ReferencesParent) { - const struct UnaryBooleanTestData cases[] = { - { FPL("."), false }, - { FPL(".."), true }, - { FPL(".. "), true }, - { FPL(" .."), true }, - { FPL("..."), true }, - { FPL("a.."), false }, - { FPL("..a"), false }, - { FPL("../"), true }, - { FPL("/.."), true }, - { FPL("/../"), true }, - { FPL("/a../"), false }, - { FPL("/..a/"), false }, - { FPL("//.."), true }, - { FPL("..//"), true }, - { FPL("//..//"), true }, - { FPL("a//..//c"), true }, - { FPL("../b/c"), true }, - { FPL("/../b/c"), true }, - { FPL("a/b/.."), true }, - { FPL("a/b/../"), true }, - { FPL("a/../c"), true }, - { FPL("a/b/c"), false }, - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - FilePath input(cases[i].input); - bool observed = input.ReferencesParent(); - EXPECT_EQ(cases[i].expected, observed) << - "i: " << i << ", input: " << input.value(); - } -} - -TEST_F(FilePathTest, FromUTF8Unsafe_And_AsUTF8Unsafe) { - const struct UTF8TestData cases[] = { - { FPL("foo.txt"), "foo.txt" }, - // "aeo" with accents. Use http://0xcc.net/jsescape/ to decode them. - { FPL("\u00E0\u00E8\u00F2.txt"), "\xC3\xA0\xC3\xA8\xC3\xB2.txt" }, - // Full-width "ABC". - { FPL("\uFF21\uFF22\uFF23.txt"), - "\xEF\xBC\xA1\xEF\xBC\xA2\xEF\xBC\xA3.txt" }, - }; - -#if !defined(SYSTEM_NATIVE_UTF8) && defined(OS_LINUX) - ScopedLocale locale("en_US.UTF-8"); -#endif - - for (size_t i = 0; i < arraysize(cases); ++i) { - // Test FromUTF8Unsafe() works. - FilePath from_utf8 = FilePath::FromUTF8Unsafe(cases[i].utf8); - EXPECT_EQ(cases[i].native, from_utf8.value()) - << "i: " << i << ", input: " << cases[i].native; - // Test AsUTF8Unsafe() works. - FilePath from_native = FilePath(cases[i].native); - EXPECT_EQ(cases[i].utf8, from_native.AsUTF8Unsafe()) - << "i: " << i << ", input: " << cases[i].native; - // Test the two file paths are identical. - EXPECT_EQ(from_utf8.value(), from_native.value()); - } -} - -TEST_F(FilePathTest, ConstructWithNUL) { - // Assert FPS() works. - ASSERT_EQ(3U, FPS("a\0b").length()); - - // Test constructor strips '\0' - FilePath path(FPS("a\0b")); - EXPECT_EQ(1U, path.value().length()); - EXPECT_EQ(FPL("a"), path.value()); -} - -TEST_F(FilePathTest, AppendWithNUL) { - // Assert FPS() works. - ASSERT_EQ(3U, FPS("b\0b").length()); - - // Test Append() strips '\0' - FilePath path(FPL("a")); - path = path.Append(FPS("b\0b")); - EXPECT_EQ(3U, path.value().length()); -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - EXPECT_EQ(FPL("a\\b"), path.value()); -#else - EXPECT_EQ(FPL("a/b"), path.value()); -#endif -} - -TEST_F(FilePathTest, ReferencesParentWithNUL) { - // Assert FPS() works. - ASSERT_EQ(3U, FPS("..\0").length()); - - // Test ReferencesParent() doesn't break with "..\0" - FilePath path(FPS("..\0")); - EXPECT_TRUE(path.ReferencesParent()); -} - -#if defined(FILE_PATH_USES_WIN_SEPARATORS) -TEST_F(FilePathTest, NormalizePathSeparators) { - const struct UnaryTestData cases[] = { - { FPL("foo/bar"), FPL("foo\\bar") }, - { FPL("foo/bar\\betz"), FPL("foo\\bar\\betz") }, - { FPL("foo\\bar"), FPL("foo\\bar") }, - { FPL("foo\\bar/betz"), FPL("foo\\bar\\betz") }, - { FPL("foo"), FPL("foo") }, - // Trailing slashes don't automatically get stripped. That's what - // StripTrailingSeparators() is for. - { FPL("foo\\"), FPL("foo\\") }, - { FPL("foo/"), FPL("foo\\") }, - { FPL("foo/bar\\"), FPL("foo\\bar\\") }, - { FPL("foo\\bar/"), FPL("foo\\bar\\") }, - { FPL("foo/bar/"), FPL("foo\\bar\\") }, - { FPL("foo\\bar\\"), FPL("foo\\bar\\") }, - { FPL("\\foo/bar"), FPL("\\foo\\bar") }, - { FPL("/foo\\bar"), FPL("\\foo\\bar") }, - { FPL("c:/foo/bar/"), FPL("c:\\foo\\bar\\") }, - { FPL("/foo/bar/"), FPL("\\foo\\bar\\") }, - { FPL("\\foo\\bar\\"), FPL("\\foo\\bar\\") }, - { FPL("c:\\foo/bar"), FPL("c:\\foo\\bar") }, - { FPL("//foo\\bar\\"), FPL("\\\\foo\\bar\\") }, - { FPL("\\\\foo\\bar\\"), FPL("\\\\foo\\bar\\") }, - { FPL("//foo\\bar\\"), FPL("\\\\foo\\bar\\") }, - // This method does not normalize the number of path separators. - { FPL("foo\\\\bar"), FPL("foo\\\\bar") }, - { FPL("foo//bar"), FPL("foo\\\\bar") }, - { FPL("foo/\\bar"), FPL("foo\\\\bar") }, - { FPL("foo\\/bar"), FPL("foo\\\\bar") }, - { FPL("///foo\\\\bar"), FPL("\\\\\\foo\\\\bar") }, - { FPL("foo//bar///"), FPL("foo\\\\bar\\\\\\") }, - { FPL("foo/\\bar/\\"), FPL("foo\\\\bar\\\\") }, - { FPL("/\\foo\\/bar"), FPL("\\\\foo\\\\bar") }, - }; - for (size_t i = 0; i < arraysize(cases); ++i) { - FilePath input(cases[i].input); - FilePath observed = input.NormalizePathSeparators(); - EXPECT_EQ(FilePath::StringType(cases[i].expected), observed.value()) << - "i: " << i << ", input: " << input.value(); - } -} -#endif - -TEST_F(FilePathTest, EndsWithSeparator) { - const UnaryBooleanTestData cases[] = { - { FPL(""), false }, - { FPL("/"), true }, - { FPL("foo/"), true }, - { FPL("bar"), false }, - { FPL("/foo/bar"), false }, - }; - for (size_t i = 0; i < arraysize(cases); ++i) { - FilePath input = FilePath(cases[i].input).NormalizePathSeparators(); - EXPECT_EQ(cases[i].expected, input.EndsWithSeparator()); - } -} - -TEST_F(FilePathTest, AsEndingWithSeparator) { - const UnaryTestData cases[] = { - { FPL(""), FPL("") }, - { FPL("/"), FPL("/") }, - { FPL("foo"), FPL("foo/") }, - { FPL("foo/"), FPL("foo/") } - }; - for (size_t i = 0; i < arraysize(cases); ++i) { - FilePath input = FilePath(cases[i].input).NormalizePathSeparators(); - FilePath expected = FilePath(cases[i].expected).NormalizePathSeparators(); - EXPECT_EQ(expected.value(), input.AsEndingWithSeparator().value()); - } -} - -#if defined(OS_ANDROID) -TEST_F(FilePathTest, ContentUriTest) { - const struct UnaryBooleanTestData cases[] = { - { FPL("content://foo.bar"), true }, - { FPL("content://foo.bar/"), true }, - { FPL("content://foo/bar"), true }, - { FPL("CoNTenT://foo.bar"), true }, - { FPL("content://"), true }, - { FPL("content:///foo.bar"), true }, - { FPL("content://3foo/bar"), true }, - { FPL("content://_foo/bar"), true }, - { FPL(".. "), false }, - { FPL("foo.bar"), false }, - { FPL("content:foo.bar"), false }, - { FPL("content:/foo.ba"), false }, - { FPL("content:/dir/foo.bar"), false }, - { FPL("content: //foo.bar"), false }, - { FPL("content%2a%2f%2f"), false }, - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - FilePath input(cases[i].input); - bool observed = input.IsContentUri(); - EXPECT_EQ(cases[i].expected, observed) << - "i: " << i << ", input: " << input.value(); - } -} -#endif - -// Test the operator<<(ostream, FilePath). -TEST_F(FilePathTest, PrintToOstream) { - std::stringstream ss; - FilePath fp(FPL("foo")); - ss << fp; - EXPECT_EQ("foo", ss.str()); -} - -// Test GetHFSDecomposedForm should return empty result for invalid UTF-8 -// strings. -#if defined(OS_MACOSX) -TEST_F(FilePathTest, GetHFSDecomposedFormWithInvalidInput) { - const FilePath::CharType* cases[] = { - FPL("\xc3\x28"), - FPL("\xe2\x82\x28"), - FPL("\xe2\x28\xa1"), - FPL("\xf0\x28\x8c\xbc"), - FPL("\xf0\x28\x8c\x28"), - }; - for (auto* invalid_input : cases) { - FilePath::StringType observed = FilePath::GetHFSDecomposedForm( - invalid_input); - EXPECT_TRUE(observed.empty()); - } -} -#endif - -} // namespace base
diff --git a/base/files/file_path_watcher_unittest.cc b/base/files/file_path_watcher_unittest.cc deleted file mode 100644 index 9e3d94d..0000000 --- a/base/files/file_path_watcher_unittest.cc +++ /dev/null
@@ -1,873 +0,0 @@ -// 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/files/file_path_watcher.h" - -#if defined(OS_WIN) -#include <windows.h> -#include <aclapi.h> -#elif defined(OS_POSIX) -#include <sys/stat.h> -#endif - -#include <set> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/compiler_specific.h" -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/files/scoped_temp_dir.h" -#include "base/location.h" -#include "base/macros.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "base/single_thread_task_runner.h" -#include "base/stl_util.h" -#include "base/strings/stringprintf.h" -#include "base/synchronization/waitable_event.h" -#include "base/test/test_file_util.h" -#include "base/test/test_timeouts.h" -#include "base/threading/thread_task_runner_handle.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(OS_ANDROID) -#include "base/android/path_utils.h" -#endif // defined(OS_ANDROID) - -#if defined(OS_POSIX) -#include "base/files/file_descriptor_watcher_posix.h" -#endif // defined(OS_POSIX) - -namespace base { - -namespace { - -class TestDelegate; - -// Aggregates notifications from the test delegates and breaks the message loop -// the test thread is waiting on once they all came in. -class NotificationCollector - : public base::RefCountedThreadSafe<NotificationCollector> { - public: - NotificationCollector() : task_runner_(base::ThreadTaskRunnerHandle::Get()) {} - - // Called from the file thread by the delegates. - void OnChange(TestDelegate* delegate) { - task_runner_->PostTask( - FROM_HERE, base::BindOnce(&NotificationCollector::RecordChange, this, - base::Unretained(delegate))); - } - - void Register(TestDelegate* delegate) { - delegates_.insert(delegate); - } - - void Reset() { - signaled_.clear(); - } - - bool Success() { - return signaled_ == delegates_; - } - - private: - friend class base::RefCountedThreadSafe<NotificationCollector>; - ~NotificationCollector() = default; - - void RecordChange(TestDelegate* delegate) { - // Warning: |delegate| is Unretained. Do not dereference. - ASSERT_TRUE(task_runner_->BelongsToCurrentThread()); - ASSERT_TRUE(delegates_.count(delegate)); - signaled_.insert(delegate); - - // Check whether all delegates have been signaled. - if (signaled_ == delegates_) - task_runner_->PostTask(FROM_HERE, - RunLoop::QuitCurrentWhenIdleClosureDeprecated()); - } - - // Set of registered delegates. - std::set<TestDelegate*> delegates_; - - // Set of signaled delegates. - std::set<TestDelegate*> signaled_; - - // The loop we should break after all delegates signaled. - scoped_refptr<base::SingleThreadTaskRunner> task_runner_; -}; - -class TestDelegateBase : public SupportsWeakPtr<TestDelegateBase> { - public: - TestDelegateBase() = default; - virtual ~TestDelegateBase() = default; - - virtual void OnFileChanged(const FilePath& path, bool error) = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(TestDelegateBase); -}; - -// A mock class for testing. Gmock is not appropriate because it is not -// thread-safe for setting expectations. Thus the test code cannot safely -// reset expectations while the file watcher is running. -// Instead, TestDelegate gets the notifications from FilePathWatcher and uses -// NotificationCollector to aggregate the results. -class TestDelegate : public TestDelegateBase { - public: - explicit TestDelegate(NotificationCollector* collector) - : collector_(collector) { - collector_->Register(this); - } - ~TestDelegate() override = default; - - void OnFileChanged(const FilePath& path, bool error) override { - if (error) - ADD_FAILURE() << "Error " << path.value(); - else - collector_->OnChange(this); - } - - private: - scoped_refptr<NotificationCollector> collector_; - - DISALLOW_COPY_AND_ASSIGN(TestDelegate); -}; - -class FilePathWatcherTest : public testing::Test { - public: - FilePathWatcherTest() -#if defined(OS_POSIX) - : file_descriptor_watcher_(&loop_) -#endif - { - } - - ~FilePathWatcherTest() override = default; - - protected: - void SetUp() override { -#if defined(OS_ANDROID) - // Watching files is only permitted when all parent directories are - // accessible, which is not the case for the default temp directory - // on Android which is under /data/data. Use /sdcard instead. - // TODO(pauljensen): Remove this when crbug.com/475568 is fixed. - FilePath parent_dir; - ASSERT_TRUE(android::GetExternalStorageDirectory(&parent_dir)); - ASSERT_TRUE(temp_dir_.CreateUniqueTempDirUnderPath(parent_dir)); -#else // defined(OS_ANDROID) - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); -#endif // defined(OS_ANDROID) - collector_ = new NotificationCollector(); - } - - void TearDown() override { RunLoop().RunUntilIdle(); } - - FilePath test_file() { - return temp_dir_.GetPath().AppendASCII("FilePathWatcherTest"); - } - - FilePath test_link() { - return temp_dir_.GetPath().AppendASCII("FilePathWatcherTest.lnk"); - } - - // Write |content| to |file|. Returns true on success. - bool WriteFile(const FilePath& file, const std::string& content) { - int write_size = ::base::WriteFile(file, content.c_str(), content.length()); - return write_size == static_cast<int>(content.length()); - } - - bool SetupWatch(const FilePath& target, - FilePathWatcher* watcher, - TestDelegateBase* delegate, - bool recursive_watch) WARN_UNUSED_RESULT; - - bool WaitForEvents() WARN_UNUSED_RESULT { - collector_->Reset(); - - RunLoop run_loop; - // Make sure we timeout if we don't get notified. - ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, run_loop.QuitWhenIdleClosure(), - TestTimeouts::action_timeout()); - run_loop.Run(); - return collector_->Success(); - } - - NotificationCollector* collector() { return collector_.get(); } - - MessageLoopForIO loop_; -#if defined(OS_POSIX) - FileDescriptorWatcher file_descriptor_watcher_; -#endif - - ScopedTempDir temp_dir_; - scoped_refptr<NotificationCollector> collector_; - - private: - DISALLOW_COPY_AND_ASSIGN(FilePathWatcherTest); -}; - -bool FilePathWatcherTest::SetupWatch(const FilePath& target, - FilePathWatcher* watcher, - TestDelegateBase* delegate, - bool recursive_watch) { - return watcher->Watch( - target, recursive_watch, - base::Bind(&TestDelegateBase::OnFileChanged, delegate->AsWeakPtr())); -} - -// Basic test: Create the file and verify that we notice. -TEST_F(FilePathWatcherTest, NewFile) { - FilePathWatcher watcher; - std::unique_ptr<TestDelegate> delegate(new TestDelegate(collector())); - ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false)); - - ASSERT_TRUE(WriteFile(test_file(), "content")); - ASSERT_TRUE(WaitForEvents()); -} - -// Verify that modifying the file is caught. -TEST_F(FilePathWatcherTest, ModifiedFile) { - ASSERT_TRUE(WriteFile(test_file(), "content")); - - FilePathWatcher watcher; - std::unique_ptr<TestDelegate> delegate(new TestDelegate(collector())); - ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false)); - - // Now make sure we get notified if the file is modified. - ASSERT_TRUE(WriteFile(test_file(), "new content")); - ASSERT_TRUE(WaitForEvents()); -} - -// Verify that moving the file into place is caught. -TEST_F(FilePathWatcherTest, MovedFile) { - FilePath source_file(temp_dir_.GetPath().AppendASCII("source")); - ASSERT_TRUE(WriteFile(source_file, "content")); - - FilePathWatcher watcher; - std::unique_ptr<TestDelegate> delegate(new TestDelegate(collector())); - ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false)); - - // Now make sure we get notified if the file is modified. - ASSERT_TRUE(base::Move(source_file, test_file())); - ASSERT_TRUE(WaitForEvents()); -} - -TEST_F(FilePathWatcherTest, DeletedFile) { - ASSERT_TRUE(WriteFile(test_file(), "content")); - - FilePathWatcher watcher; - std::unique_ptr<TestDelegate> delegate(new TestDelegate(collector())); - ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false)); - - // Now make sure we get notified if the file is deleted. - base::DeleteFile(test_file(), false); - ASSERT_TRUE(WaitForEvents()); -} - -// Used by the DeleteDuringNotify test below. -// Deletes the FilePathWatcher when it's notified. -class Deleter : public TestDelegateBase { - public: - Deleter(FilePathWatcher* watcher, MessageLoop* loop) - : watcher_(watcher), - loop_(loop) { - } - ~Deleter() override = default; - - void OnFileChanged(const FilePath&, bool) override { - watcher_.reset(); - loop_->task_runner()->PostTask( - FROM_HERE, RunLoop::QuitCurrentWhenIdleClosureDeprecated()); - } - - FilePathWatcher* watcher() const { return watcher_.get(); } - - private: - std::unique_ptr<FilePathWatcher> watcher_; - MessageLoop* loop_; - - DISALLOW_COPY_AND_ASSIGN(Deleter); -}; - -// Verify that deleting a watcher during the callback doesn't crash. -TEST_F(FilePathWatcherTest, DeleteDuringNotify) { - FilePathWatcher* watcher = new FilePathWatcher; - // Takes ownership of watcher. - std::unique_ptr<Deleter> deleter(new Deleter(watcher, &loop_)); - ASSERT_TRUE(SetupWatch(test_file(), watcher, deleter.get(), false)); - - ASSERT_TRUE(WriteFile(test_file(), "content")); - ASSERT_TRUE(WaitForEvents()); - - // We win if we haven't crashed yet. - // Might as well double-check it got deleted, too. - ASSERT_TRUE(deleter->watcher() == nullptr); -} - -// Verify that deleting the watcher works even if there is a pending -// notification. -// Flaky on MacOS (and ARM linux): http://crbug.com/85930 -TEST_F(FilePathWatcherTest, DISABLED_DestroyWithPendingNotification) { - std::unique_ptr<TestDelegate> delegate(new TestDelegate(collector())); - FilePathWatcher watcher; - ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false)); - ASSERT_TRUE(WriteFile(test_file(), "content")); -} - -TEST_F(FilePathWatcherTest, MultipleWatchersSingleFile) { - FilePathWatcher watcher1, watcher2; - std::unique_ptr<TestDelegate> delegate1(new TestDelegate(collector())); - std::unique_ptr<TestDelegate> delegate2(new TestDelegate(collector())); - ASSERT_TRUE(SetupWatch(test_file(), &watcher1, delegate1.get(), false)); - ASSERT_TRUE(SetupWatch(test_file(), &watcher2, delegate2.get(), false)); - - ASSERT_TRUE(WriteFile(test_file(), "content")); - ASSERT_TRUE(WaitForEvents()); -} - -// Verify that watching a file whose parent directory doesn't exist yet works if -// the directory and file are created eventually. -TEST_F(FilePathWatcherTest, NonExistentDirectory) { - FilePathWatcher watcher; - FilePath dir(temp_dir_.GetPath().AppendASCII("dir")); - FilePath file(dir.AppendASCII("file")); - std::unique_ptr<TestDelegate> delegate(new TestDelegate(collector())); - ASSERT_TRUE(SetupWatch(file, &watcher, delegate.get(), false)); - - ASSERT_TRUE(base::CreateDirectory(dir)); - - ASSERT_TRUE(WriteFile(file, "content")); - - VLOG(1) << "Waiting for file creation"; - ASSERT_TRUE(WaitForEvents()); - - ASSERT_TRUE(WriteFile(file, "content v2")); - VLOG(1) << "Waiting for file change"; - ASSERT_TRUE(WaitForEvents()); - - ASSERT_TRUE(base::DeleteFile(file, false)); - VLOG(1) << "Waiting for file deletion"; - ASSERT_TRUE(WaitForEvents()); -} - -// Exercises watch reconfiguration for the case that directories on the path -// are rapidly created. -TEST_F(FilePathWatcherTest, DirectoryChain) { - FilePath path(temp_dir_.GetPath()); - std::vector<std::string> dir_names; - for (int i = 0; i < 20; i++) { - std::string dir(base::StringPrintf("d%d", i)); - dir_names.push_back(dir); - path = path.AppendASCII(dir); - } - - FilePathWatcher watcher; - FilePath file(path.AppendASCII("file")); - std::unique_ptr<TestDelegate> delegate(new TestDelegate(collector())); - ASSERT_TRUE(SetupWatch(file, &watcher, delegate.get(), false)); - - FilePath sub_path(temp_dir_.GetPath()); - for (std::vector<std::string>::const_iterator d(dir_names.begin()); - d != dir_names.end(); ++d) { - sub_path = sub_path.AppendASCII(*d); - ASSERT_TRUE(base::CreateDirectory(sub_path)); - } - VLOG(1) << "Create File"; - ASSERT_TRUE(WriteFile(file, "content")); - VLOG(1) << "Waiting for file creation"; - ASSERT_TRUE(WaitForEvents()); - - ASSERT_TRUE(WriteFile(file, "content v2")); - VLOG(1) << "Waiting for file modification"; - ASSERT_TRUE(WaitForEvents()); -} - -#if defined(OS_MACOSX) -// http://crbug.com/85930 -#define DisappearingDirectory DISABLED_DisappearingDirectory -#endif -TEST_F(FilePathWatcherTest, DisappearingDirectory) { - FilePathWatcher watcher; - FilePath dir(temp_dir_.GetPath().AppendASCII("dir")); - FilePath file(dir.AppendASCII("file")); - ASSERT_TRUE(base::CreateDirectory(dir)); - ASSERT_TRUE(WriteFile(file, "content")); - std::unique_ptr<TestDelegate> delegate(new TestDelegate(collector())); - ASSERT_TRUE(SetupWatch(file, &watcher, delegate.get(), false)); - - ASSERT_TRUE(base::DeleteFile(dir, true)); - ASSERT_TRUE(WaitForEvents()); -} - -// Tests that a file that is deleted and reappears is tracked correctly. -TEST_F(FilePathWatcherTest, DeleteAndRecreate) { - ASSERT_TRUE(WriteFile(test_file(), "content")); - FilePathWatcher watcher; - std::unique_ptr<TestDelegate> delegate(new TestDelegate(collector())); - ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false)); - - ASSERT_TRUE(base::DeleteFile(test_file(), false)); - VLOG(1) << "Waiting for file deletion"; - ASSERT_TRUE(WaitForEvents()); - - ASSERT_TRUE(WriteFile(test_file(), "content")); - VLOG(1) << "Waiting for file creation"; - ASSERT_TRUE(WaitForEvents()); -} - -TEST_F(FilePathWatcherTest, WatchDirectory) { - FilePathWatcher watcher; - FilePath dir(temp_dir_.GetPath().AppendASCII("dir")); - FilePath file1(dir.AppendASCII("file1")); - FilePath file2(dir.AppendASCII("file2")); - std::unique_ptr<TestDelegate> delegate(new TestDelegate(collector())); - ASSERT_TRUE(SetupWatch(dir, &watcher, delegate.get(), false)); - - ASSERT_TRUE(base::CreateDirectory(dir)); - VLOG(1) << "Waiting for directory creation"; - ASSERT_TRUE(WaitForEvents()); - - ASSERT_TRUE(WriteFile(file1, "content")); - VLOG(1) << "Waiting for file1 creation"; - ASSERT_TRUE(WaitForEvents()); - -#if !defined(OS_MACOSX) - // Mac implementation does not detect files modified in a directory. - ASSERT_TRUE(WriteFile(file1, "content v2")); - VLOG(1) << "Waiting for file1 modification"; - ASSERT_TRUE(WaitForEvents()); -#endif // !OS_MACOSX - - ASSERT_TRUE(base::DeleteFile(file1, false)); - VLOG(1) << "Waiting for file1 deletion"; - ASSERT_TRUE(WaitForEvents()); - - ASSERT_TRUE(WriteFile(file2, "content")); - VLOG(1) << "Waiting for file2 creation"; - ASSERT_TRUE(WaitForEvents()); -} - -TEST_F(FilePathWatcherTest, MoveParent) { - FilePathWatcher file_watcher; - FilePathWatcher subdir_watcher; - FilePath dir(temp_dir_.GetPath().AppendASCII("dir")); - FilePath dest(temp_dir_.GetPath().AppendASCII("dest")); - FilePath subdir(dir.AppendASCII("subdir")); - FilePath file(subdir.AppendASCII("file")); - std::unique_ptr<TestDelegate> file_delegate(new TestDelegate(collector())); - ASSERT_TRUE(SetupWatch(file, &file_watcher, file_delegate.get(), false)); - std::unique_ptr<TestDelegate> subdir_delegate(new TestDelegate(collector())); - ASSERT_TRUE(SetupWatch(subdir, &subdir_watcher, subdir_delegate.get(), - false)); - - // Setup a directory hierarchy. - ASSERT_TRUE(base::CreateDirectory(subdir)); - ASSERT_TRUE(WriteFile(file, "content")); - VLOG(1) << "Waiting for file creation"; - ASSERT_TRUE(WaitForEvents()); - - // Move the parent directory. - base::Move(dir, dest); - VLOG(1) << "Waiting for directory move"; - ASSERT_TRUE(WaitForEvents()); -} - -TEST_F(FilePathWatcherTest, RecursiveWatch) { - FilePathWatcher watcher; - FilePath dir(temp_dir_.GetPath().AppendASCII("dir")); - std::unique_ptr<TestDelegate> delegate(new TestDelegate(collector())); - bool setup_result = SetupWatch(dir, &watcher, delegate.get(), true); - if (!FilePathWatcher::RecursiveWatchAvailable()) { - ASSERT_FALSE(setup_result); - return; - } - ASSERT_TRUE(setup_result); - - // Main directory("dir") creation. - ASSERT_TRUE(base::CreateDirectory(dir)); - ASSERT_TRUE(WaitForEvents()); - - // Create "$dir/file1". - FilePath file1(dir.AppendASCII("file1")); - ASSERT_TRUE(WriteFile(file1, "content")); - ASSERT_TRUE(WaitForEvents()); - - // Create "$dir/subdir". - FilePath subdir(dir.AppendASCII("subdir")); - ASSERT_TRUE(base::CreateDirectory(subdir)); - ASSERT_TRUE(WaitForEvents()); - - // Create "$dir/subdir/subdir_file1". - FilePath subdir_file1(subdir.AppendASCII("subdir_file1")); - ASSERT_TRUE(WriteFile(subdir_file1, "content")); - ASSERT_TRUE(WaitForEvents()); - - // Create "$dir/subdir/subdir_child_dir". - FilePath subdir_child_dir(subdir.AppendASCII("subdir_child_dir")); - ASSERT_TRUE(base::CreateDirectory(subdir_child_dir)); - ASSERT_TRUE(WaitForEvents()); - - // Create "$dir/subdir/subdir_child_dir/child_dir_file1". - FilePath child_dir_file1(subdir_child_dir.AppendASCII("child_dir_file1")); - ASSERT_TRUE(WriteFile(child_dir_file1, "content v2")); - ASSERT_TRUE(WaitForEvents()); - - // Write into "$dir/subdir/subdir_child_dir/child_dir_file1". - ASSERT_TRUE(WriteFile(child_dir_file1, "content")); - ASSERT_TRUE(WaitForEvents()); - -// Apps cannot change file attributes on Android in /sdcard as /sdcard uses the -// "fuse" file system, while /data uses "ext4". Running these tests in /data -// would be preferable and allow testing file attributes and symlinks. -// TODO(pauljensen): Re-enable when crbug.com/475568 is fixed and SetUp() places -// the |temp_dir_| in /data. -#if !defined(OS_ANDROID) - // Modify "$dir/subdir/subdir_child_dir/child_dir_file1" attributes. - ASSERT_TRUE(base::MakeFileUnreadable(child_dir_file1)); - ASSERT_TRUE(WaitForEvents()); -#endif - - // Delete "$dir/subdir/subdir_file1". - ASSERT_TRUE(base::DeleteFile(subdir_file1, false)); - ASSERT_TRUE(WaitForEvents()); - - // Delete "$dir/subdir/subdir_child_dir/child_dir_file1". - ASSERT_TRUE(base::DeleteFile(child_dir_file1, false)); - ASSERT_TRUE(WaitForEvents()); -} - -#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_FUCHSIA) -// Apps cannot create symlinks on Android in /sdcard as /sdcard uses the -// "fuse" file system, while /data uses "ext4". Running these tests in /data -// would be preferable and allow testing file attributes and symlinks. -// TODO(pauljensen): Re-enable when crbug.com/475568 is fixed and SetUp() places -// the |temp_dir_| in /data. -// -// This test is disabled on Fuchsia since it doesn't support symlinking. -TEST_F(FilePathWatcherTest, RecursiveWithSymLink) { - if (!FilePathWatcher::RecursiveWatchAvailable()) - return; - - FilePathWatcher watcher; - FilePath test_dir(temp_dir_.GetPath().AppendASCII("test_dir")); - ASSERT_TRUE(base::CreateDirectory(test_dir)); - FilePath symlink(test_dir.AppendASCII("symlink")); - std::unique_ptr<TestDelegate> delegate(new TestDelegate(collector())); - ASSERT_TRUE(SetupWatch(symlink, &watcher, delegate.get(), true)); - - // Link creation. - FilePath target1(temp_dir_.GetPath().AppendASCII("target1")); - ASSERT_TRUE(base::CreateSymbolicLink(target1, symlink)); - ASSERT_TRUE(WaitForEvents()); - - // Target1 creation. - ASSERT_TRUE(base::CreateDirectory(target1)); - ASSERT_TRUE(WaitForEvents()); - - // Create a file in target1. - FilePath target1_file(target1.AppendASCII("file")); - ASSERT_TRUE(WriteFile(target1_file, "content")); - ASSERT_TRUE(WaitForEvents()); - - // Link change. - FilePath target2(temp_dir_.GetPath().AppendASCII("target2")); - ASSERT_TRUE(base::CreateDirectory(target2)); - ASSERT_TRUE(base::DeleteFile(symlink, false)); - ASSERT_TRUE(base::CreateSymbolicLink(target2, symlink)); - ASSERT_TRUE(WaitForEvents()); - - // Create a file in target2. - FilePath target2_file(target2.AppendASCII("file")); - ASSERT_TRUE(WriteFile(target2_file, "content")); - ASSERT_TRUE(WaitForEvents()); -} -#endif // defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_FUCHSIA) - -TEST_F(FilePathWatcherTest, MoveChild) { - FilePathWatcher file_watcher; - FilePathWatcher subdir_watcher; - FilePath source_dir(temp_dir_.GetPath().AppendASCII("source")); - FilePath source_subdir(source_dir.AppendASCII("subdir")); - FilePath source_file(source_subdir.AppendASCII("file")); - FilePath dest_dir(temp_dir_.GetPath().AppendASCII("dest")); - FilePath dest_subdir(dest_dir.AppendASCII("subdir")); - FilePath dest_file(dest_subdir.AppendASCII("file")); - - // Setup a directory hierarchy. - ASSERT_TRUE(base::CreateDirectory(source_subdir)); - ASSERT_TRUE(WriteFile(source_file, "content")); - - std::unique_ptr<TestDelegate> file_delegate(new TestDelegate(collector())); - ASSERT_TRUE(SetupWatch(dest_file, &file_watcher, file_delegate.get(), false)); - std::unique_ptr<TestDelegate> subdir_delegate(new TestDelegate(collector())); - ASSERT_TRUE(SetupWatch(dest_subdir, &subdir_watcher, subdir_delegate.get(), - false)); - - // Move the directory into place, s.t. the watched file appears. - ASSERT_TRUE(base::Move(source_dir, dest_dir)); - ASSERT_TRUE(WaitForEvents()); -} - -// Verify that changing attributes on a file is caught -#if defined(OS_ANDROID) -// Apps cannot change file attributes on Android in /sdcard as /sdcard uses the -// "fuse" file system, while /data uses "ext4". Running these tests in /data -// would be preferable and allow testing file attributes and symlinks. -// TODO(pauljensen): Re-enable when crbug.com/475568 is fixed and SetUp() places -// the |temp_dir_| in /data. -#define FileAttributesChanged DISABLED_FileAttributesChanged -#endif // defined(OS_ANDROID -TEST_F(FilePathWatcherTest, FileAttributesChanged) { - ASSERT_TRUE(WriteFile(test_file(), "content")); - FilePathWatcher watcher; - std::unique_ptr<TestDelegate> delegate(new TestDelegate(collector())); - ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false)); - - // Now make sure we get notified if the file is modified. - ASSERT_TRUE(base::MakeFileUnreadable(test_file())); - ASSERT_TRUE(WaitForEvents()); -} - -#if defined(OS_LINUX) - -// Verify that creating a symlink is caught. -TEST_F(FilePathWatcherTest, CreateLink) { - FilePathWatcher watcher; - std::unique_ptr<TestDelegate> delegate(new TestDelegate(collector())); - // Note that we are watching the symlink - ASSERT_TRUE(SetupWatch(test_link(), &watcher, delegate.get(), false)); - - // Now make sure we get notified if the link is created. - // Note that test_file() doesn't have to exist. - ASSERT_TRUE(CreateSymbolicLink(test_file(), test_link())); - ASSERT_TRUE(WaitForEvents()); -} - -// Verify that deleting a symlink is caught. -TEST_F(FilePathWatcherTest, DeleteLink) { - // Unfortunately this test case only works if the link target exists. - // TODO(craig) fix this as part of crbug.com/91561. - ASSERT_TRUE(WriteFile(test_file(), "content")); - ASSERT_TRUE(CreateSymbolicLink(test_file(), test_link())); - FilePathWatcher watcher; - std::unique_ptr<TestDelegate> delegate(new TestDelegate(collector())); - ASSERT_TRUE(SetupWatch(test_link(), &watcher, delegate.get(), false)); - - // Now make sure we get notified if the link is deleted. - ASSERT_TRUE(base::DeleteFile(test_link(), false)); - ASSERT_TRUE(WaitForEvents()); -} - -// Verify that modifying a target file that a link is pointing to -// when we are watching the link is caught. -TEST_F(FilePathWatcherTest, ModifiedLinkedFile) { - ASSERT_TRUE(WriteFile(test_file(), "content")); - ASSERT_TRUE(CreateSymbolicLink(test_file(), test_link())); - FilePathWatcher watcher; - std::unique_ptr<TestDelegate> delegate(new TestDelegate(collector())); - // Note that we are watching the symlink. - ASSERT_TRUE(SetupWatch(test_link(), &watcher, delegate.get(), false)); - - // Now make sure we get notified if the file is modified. - ASSERT_TRUE(WriteFile(test_file(), "new content")); - ASSERT_TRUE(WaitForEvents()); -} - -// Verify that creating a target file that a link is pointing to -// when we are watching the link is caught. -TEST_F(FilePathWatcherTest, CreateTargetLinkedFile) { - ASSERT_TRUE(CreateSymbolicLink(test_file(), test_link())); - FilePathWatcher watcher; - std::unique_ptr<TestDelegate> delegate(new TestDelegate(collector())); - // Note that we are watching the symlink. - ASSERT_TRUE(SetupWatch(test_link(), &watcher, delegate.get(), false)); - - // Now make sure we get notified if the target file is created. - ASSERT_TRUE(WriteFile(test_file(), "content")); - ASSERT_TRUE(WaitForEvents()); -} - -// Verify that deleting a target file that a link is pointing to -// when we are watching the link is caught. -TEST_F(FilePathWatcherTest, DeleteTargetLinkedFile) { - ASSERT_TRUE(WriteFile(test_file(), "content")); - ASSERT_TRUE(CreateSymbolicLink(test_file(), test_link())); - FilePathWatcher watcher; - std::unique_ptr<TestDelegate> delegate(new TestDelegate(collector())); - // Note that we are watching the symlink. - ASSERT_TRUE(SetupWatch(test_link(), &watcher, delegate.get(), false)); - - // Now make sure we get notified if the target file is deleted. - ASSERT_TRUE(base::DeleteFile(test_file(), false)); - ASSERT_TRUE(WaitForEvents()); -} - -// Verify that watching a file whose parent directory is a link that -// doesn't exist yet works if the symlink is created eventually. -TEST_F(FilePathWatcherTest, LinkedDirectoryPart1) { - FilePathWatcher watcher; - FilePath dir(temp_dir_.GetPath().AppendASCII("dir")); - FilePath link_dir(temp_dir_.GetPath().AppendASCII("dir.lnk")); - FilePath file(dir.AppendASCII("file")); - FilePath linkfile(link_dir.AppendASCII("file")); - std::unique_ptr<TestDelegate> delegate(new TestDelegate(collector())); - // dir/file should exist. - ASSERT_TRUE(base::CreateDirectory(dir)); - ASSERT_TRUE(WriteFile(file, "content")); - // Note that we are watching dir.lnk/file which doesn't exist yet. - ASSERT_TRUE(SetupWatch(linkfile, &watcher, delegate.get(), false)); - - ASSERT_TRUE(CreateSymbolicLink(dir, link_dir)); - VLOG(1) << "Waiting for link creation"; - ASSERT_TRUE(WaitForEvents()); - - ASSERT_TRUE(WriteFile(file, "content v2")); - VLOG(1) << "Waiting for file change"; - ASSERT_TRUE(WaitForEvents()); - - ASSERT_TRUE(base::DeleteFile(file, false)); - VLOG(1) << "Waiting for file deletion"; - ASSERT_TRUE(WaitForEvents()); -} - -// Verify that watching a file whose parent directory is a -// dangling symlink works if the directory is created eventually. -TEST_F(FilePathWatcherTest, LinkedDirectoryPart2) { - FilePathWatcher watcher; - FilePath dir(temp_dir_.GetPath().AppendASCII("dir")); - FilePath link_dir(temp_dir_.GetPath().AppendASCII("dir.lnk")); - FilePath file(dir.AppendASCII("file")); - FilePath linkfile(link_dir.AppendASCII("file")); - std::unique_ptr<TestDelegate> delegate(new TestDelegate(collector())); - // Now create the link from dir.lnk pointing to dir but - // neither dir nor dir/file exist yet. - ASSERT_TRUE(CreateSymbolicLink(dir, link_dir)); - // Note that we are watching dir.lnk/file. - ASSERT_TRUE(SetupWatch(linkfile, &watcher, delegate.get(), false)); - - ASSERT_TRUE(base::CreateDirectory(dir)); - ASSERT_TRUE(WriteFile(file, "content")); - VLOG(1) << "Waiting for dir/file creation"; - ASSERT_TRUE(WaitForEvents()); - - ASSERT_TRUE(WriteFile(file, "content v2")); - VLOG(1) << "Waiting for file change"; - ASSERT_TRUE(WaitForEvents()); - - ASSERT_TRUE(base::DeleteFile(file, false)); - VLOG(1) << "Waiting for file deletion"; - ASSERT_TRUE(WaitForEvents()); -} - -// Verify that watching a file with a symlink on the path -// to the file works. -TEST_F(FilePathWatcherTest, LinkedDirectoryPart3) { - FilePathWatcher watcher; - FilePath dir(temp_dir_.GetPath().AppendASCII("dir")); - FilePath link_dir(temp_dir_.GetPath().AppendASCII("dir.lnk")); - FilePath file(dir.AppendASCII("file")); - FilePath linkfile(link_dir.AppendASCII("file")); - std::unique_ptr<TestDelegate> delegate(new TestDelegate(collector())); - ASSERT_TRUE(base::CreateDirectory(dir)); - ASSERT_TRUE(CreateSymbolicLink(dir, link_dir)); - // Note that we are watching dir.lnk/file but the file doesn't exist yet. - ASSERT_TRUE(SetupWatch(linkfile, &watcher, delegate.get(), false)); - - ASSERT_TRUE(WriteFile(file, "content")); - VLOG(1) << "Waiting for file creation"; - ASSERT_TRUE(WaitForEvents()); - - ASSERT_TRUE(WriteFile(file, "content v2")); - VLOG(1) << "Waiting for file change"; - ASSERT_TRUE(WaitForEvents()); - - ASSERT_TRUE(base::DeleteFile(file, false)); - VLOG(1) << "Waiting for file deletion"; - ASSERT_TRUE(WaitForEvents()); -} - -#endif // OS_LINUX - -enum Permission { - Read, - Write, - Execute -}; - -#if defined(OS_MACOSX) -bool ChangeFilePermissions(const FilePath& path, Permission perm, bool allow) { - struct stat stat_buf; - - if (stat(path.value().c_str(), &stat_buf) != 0) - return false; - - mode_t mode = 0; - switch (perm) { - case Read: - mode = S_IRUSR | S_IRGRP | S_IROTH; - break; - case Write: - mode = S_IWUSR | S_IWGRP | S_IWOTH; - break; - case Execute: - mode = S_IXUSR | S_IXGRP | S_IXOTH; - break; - default: - ADD_FAILURE() << "unknown perm " << perm; - return false; - } - if (allow) { - stat_buf.st_mode |= mode; - } else { - stat_buf.st_mode &= ~mode; - } - return chmod(path.value().c_str(), stat_buf.st_mode) == 0; -} -#endif // defined(OS_MACOSX) - -#if defined(OS_MACOSX) -// Linux implementation of FilePathWatcher doesn't catch attribute changes. -// http://crbug.com/78043 -// Windows implementation of FilePathWatcher catches attribute changes that -// don't affect the path being watched. -// http://crbug.com/78045 - -// Verify that changing attributes on a directory works. -TEST_F(FilePathWatcherTest, DirAttributesChanged) { - FilePath test_dir1( - temp_dir_.GetPath().AppendASCII("DirAttributesChangedDir1")); - FilePath test_dir2(test_dir1.AppendASCII("DirAttributesChangedDir2")); - FilePath test_file(test_dir2.AppendASCII("DirAttributesChangedFile")); - // Setup a directory hierarchy. - ASSERT_TRUE(base::CreateDirectory(test_dir1)); - ASSERT_TRUE(base::CreateDirectory(test_dir2)); - ASSERT_TRUE(WriteFile(test_file, "content")); - - FilePathWatcher watcher; - std::unique_ptr<TestDelegate> delegate(new TestDelegate(collector())); - ASSERT_TRUE(SetupWatch(test_file, &watcher, delegate.get(), false)); - - // We should not get notified in this case as it hasn't affected our ability - // to access the file. - ASSERT_TRUE(ChangeFilePermissions(test_dir1, Read, false)); - loop_.task_runner()->PostDelayedTask( - FROM_HERE, RunLoop::QuitCurrentWhenIdleClosureDeprecated(), - TestTimeouts::tiny_timeout()); - ASSERT_FALSE(WaitForEvents()); - ASSERT_TRUE(ChangeFilePermissions(test_dir1, Read, true)); - - // We should get notified in this case because filepathwatcher can no - // longer access the file - ASSERT_TRUE(ChangeFilePermissions(test_dir1, Execute, false)); - ASSERT_TRUE(WaitForEvents()); - ASSERT_TRUE(ChangeFilePermissions(test_dir1, Execute, true)); -} - -#endif // OS_MACOSX -} // namespace - -} // namespace base
diff --git a/base/files/file_proxy_unittest.cc b/base/files/file_proxy_unittest.cc deleted file mode 100644 index 73a0497..0000000 --- a/base/files/file_proxy_unittest.cc +++ /dev/null
@@ -1,399 +0,0 @@ -// 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/files/file_proxy.h" - -#include <stddef.h> -#include <stdint.h> - -#include <utility> - -#include "base/bind.h" -#include "base/files/file.h" -#include "base/files/file_util.h" -#include "base/files/scoped_temp_dir.h" -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "base/threading/thread.h" -#include "base/threading/thread_restrictions.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -class FileProxyTest : public testing::Test { - public: - FileProxyTest() - : file_thread_("FileProxyTestFileThread"), - error_(File::FILE_OK), - bytes_written_(-1), - weak_factory_(this) {} - - void SetUp() override { - ASSERT_TRUE(dir_.CreateUniqueTempDir()); - ASSERT_TRUE(file_thread_.Start()); - } - - void DidFinish(File::Error error) { - error_ = error; - RunLoop::QuitCurrentWhenIdleDeprecated(); - } - - void DidCreateOrOpen(File::Error error) { - error_ = error; - RunLoop::QuitCurrentWhenIdleDeprecated(); - } - - void DidCreateTemporary(File::Error error, - const FilePath& path) { - error_ = error; - path_ = path; - RunLoop::QuitCurrentWhenIdleDeprecated(); - } - - void DidGetFileInfo(File::Error error, - const File::Info& file_info) { - error_ = error; - file_info_ = file_info; - RunLoop::QuitCurrentWhenIdleDeprecated(); - } - - void DidRead(File::Error error, - const char* data, - int bytes_read) { - error_ = error; - buffer_.resize(bytes_read); - memcpy(&buffer_[0], data, bytes_read); - RunLoop::QuitCurrentWhenIdleDeprecated(); - } - - void DidWrite(File::Error error, - int bytes_written) { - error_ = error; - bytes_written_ = bytes_written; - RunLoop::QuitCurrentWhenIdleDeprecated(); - } - - protected: - void CreateProxy(uint32_t flags, FileProxy* proxy) { - proxy->CreateOrOpen( - TestPath(), flags, - BindOnce(&FileProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr())); - RunLoop().Run(); - EXPECT_TRUE(proxy->IsValid()); - } - - TaskRunner* file_task_runner() const { - return file_thread_.task_runner().get(); - } - const FilePath& TestDirPath() const { return dir_.GetPath(); } - const FilePath TestPath() const { return dir_.GetPath().AppendASCII("test"); } - - ScopedTempDir dir_; - MessageLoopForIO message_loop_; - Thread file_thread_; - - File::Error error_; - FilePath path_; - File::Info file_info_; - std::vector<char> buffer_; - int bytes_written_; - WeakPtrFactory<FileProxyTest> weak_factory_; -}; - -TEST_F(FileProxyTest, CreateOrOpen_Create) { - FileProxy proxy(file_task_runner()); - proxy.CreateOrOpen( - TestPath(), File::FLAG_CREATE | File::FLAG_READ, - BindOnce(&FileProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr())); - RunLoop().Run(); - - EXPECT_EQ(File::FILE_OK, error_); - EXPECT_TRUE(proxy.IsValid()); - EXPECT_TRUE(proxy.created()); - EXPECT_TRUE(PathExists(TestPath())); -} - -TEST_F(FileProxyTest, CreateOrOpen_Open) { - // Creates a file. - base::WriteFile(TestPath(), nullptr, 0); - ASSERT_TRUE(PathExists(TestPath())); - - // Opens the created file. - FileProxy proxy(file_task_runner()); - proxy.CreateOrOpen( - TestPath(), File::FLAG_OPEN | File::FLAG_READ, - BindOnce(&FileProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr())); - RunLoop().Run(); - - EXPECT_EQ(File::FILE_OK, error_); - EXPECT_TRUE(proxy.IsValid()); - EXPECT_FALSE(proxy.created()); -} - -TEST_F(FileProxyTest, CreateOrOpen_OpenNonExistent) { - FileProxy proxy(file_task_runner()); - proxy.CreateOrOpen( - TestPath(), File::FLAG_OPEN | File::FLAG_READ, - BindOnce(&FileProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr())); - RunLoop().Run(); - EXPECT_EQ(File::FILE_ERROR_NOT_FOUND, error_); - EXPECT_FALSE(proxy.IsValid()); - EXPECT_FALSE(proxy.created()); - EXPECT_FALSE(PathExists(TestPath())); -} - -TEST_F(FileProxyTest, CreateOrOpen_AbandonedCreate) { - bool prev = ThreadRestrictions::SetIOAllowed(false); - { - FileProxy proxy(file_task_runner()); - proxy.CreateOrOpen( - TestPath(), File::FLAG_CREATE | File::FLAG_READ, - BindOnce(&FileProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr())); - } - RunLoop().Run(); - ThreadRestrictions::SetIOAllowed(prev); - - EXPECT_TRUE(PathExists(TestPath())); -} - -TEST_F(FileProxyTest, Close) { - // Creates a file. - FileProxy proxy(file_task_runner()); - CreateProxy(File::FLAG_CREATE | File::FLAG_WRITE, &proxy); - -#if defined(OS_WIN) - // This fails on Windows if the file is not closed. - EXPECT_FALSE(base::Move(TestPath(), TestDirPath().AppendASCII("new"))); -#endif - - proxy.Close(BindOnce(&FileProxyTest::DidFinish, weak_factory_.GetWeakPtr())); - RunLoop().Run(); - EXPECT_EQ(File::FILE_OK, error_); - EXPECT_FALSE(proxy.IsValid()); - - // Now it should pass on all platforms. - EXPECT_TRUE(base::Move(TestPath(), TestDirPath().AppendASCII("new"))); -} - -TEST_F(FileProxyTest, CreateTemporary) { - { - FileProxy proxy(file_task_runner()); - proxy.CreateTemporary(0 /* additional_file_flags */, - BindOnce(&FileProxyTest::DidCreateTemporary, - weak_factory_.GetWeakPtr())); - RunLoop().Run(); - - EXPECT_TRUE(proxy.IsValid()); - EXPECT_EQ(File::FILE_OK, error_); - EXPECT_TRUE(PathExists(path_)); - - // The file should be writable. - proxy.Write(0, "test", 4, - BindOnce(&FileProxyTest::DidWrite, weak_factory_.GetWeakPtr())); - RunLoop().Run(); - EXPECT_EQ(File::FILE_OK, error_); - EXPECT_EQ(4, bytes_written_); - } - - // Make sure the written data can be read from the returned path. - std::string data; - EXPECT_TRUE(ReadFileToString(path_, &data)); - EXPECT_EQ("test", data); - - // Make sure we can & do delete the created file to prevent leaks on the bots. - EXPECT_TRUE(base::DeleteFile(path_, false)); -} - -TEST_F(FileProxyTest, SetAndTake) { - File file(TestPath(), File::FLAG_CREATE | File::FLAG_READ); - ASSERT_TRUE(file.IsValid()); - FileProxy proxy(file_task_runner()); - EXPECT_FALSE(proxy.IsValid()); - proxy.SetFile(std::move(file)); - EXPECT_TRUE(proxy.IsValid()); - EXPECT_FALSE(file.IsValid()); - - file = proxy.TakeFile(); - EXPECT_FALSE(proxy.IsValid()); - EXPECT_TRUE(file.IsValid()); -} - -TEST_F(FileProxyTest, DuplicateFile) { - FileProxy proxy(file_task_runner()); - CreateProxy(File::FLAG_CREATE | File::FLAG_WRITE, &proxy); - ASSERT_TRUE(proxy.IsValid()); - - base::File duplicate = proxy.DuplicateFile(); - EXPECT_TRUE(proxy.IsValid()); - EXPECT_TRUE(duplicate.IsValid()); - - FileProxy invalid_proxy(file_task_runner()); - ASSERT_FALSE(invalid_proxy.IsValid()); - - base::File invalid_duplicate = invalid_proxy.DuplicateFile(); - EXPECT_FALSE(invalid_proxy.IsValid()); - EXPECT_FALSE(invalid_duplicate.IsValid()); -} - -TEST_F(FileProxyTest, GetInfo) { - // Setup. - ASSERT_EQ(4, base::WriteFile(TestPath(), "test", 4)); - File::Info expected_info; - GetFileInfo(TestPath(), &expected_info); - - // Run. - FileProxy proxy(file_task_runner()); - CreateProxy(File::FLAG_OPEN | File::FLAG_READ, &proxy); - proxy.GetInfo( - BindOnce(&FileProxyTest::DidGetFileInfo, weak_factory_.GetWeakPtr())); - RunLoop().Run(); - - // Verify. - EXPECT_EQ(File::FILE_OK, error_); - EXPECT_EQ(expected_info.size, file_info_.size); - EXPECT_EQ(expected_info.is_directory, file_info_.is_directory); - EXPECT_EQ(expected_info.is_symbolic_link, file_info_.is_symbolic_link); - EXPECT_EQ(expected_info.last_modified, file_info_.last_modified); - EXPECT_EQ(expected_info.creation_time, file_info_.creation_time); -} - -TEST_F(FileProxyTest, Read) { - // Setup. - const char expected_data[] = "bleh"; - int expected_bytes = arraysize(expected_data); - ASSERT_EQ(expected_bytes, - base::WriteFile(TestPath(), expected_data, expected_bytes)); - - // Run. - FileProxy proxy(file_task_runner()); - CreateProxy(File::FLAG_OPEN | File::FLAG_READ, &proxy); - - proxy.Read(0, 128, - BindOnce(&FileProxyTest::DidRead, weak_factory_.GetWeakPtr())); - RunLoop().Run(); - - // Verify. - EXPECT_EQ(File::FILE_OK, error_); - EXPECT_EQ(expected_bytes, static_cast<int>(buffer_.size())); - for (size_t i = 0; i < buffer_.size(); ++i) { - EXPECT_EQ(expected_data[i], buffer_[i]); - } -} - -TEST_F(FileProxyTest, WriteAndFlush) { - FileProxy proxy(file_task_runner()); - CreateProxy(File::FLAG_CREATE | File::FLAG_WRITE, &proxy); - - const char data[] = "foo!"; - int data_bytes = arraysize(data); - proxy.Write(0, data, data_bytes, - BindOnce(&FileProxyTest::DidWrite, weak_factory_.GetWeakPtr())); - RunLoop().Run(); - EXPECT_EQ(File::FILE_OK, error_); - EXPECT_EQ(data_bytes, bytes_written_); - - // Flush the written data. (So that the following read should always - // succeed. On some platforms it may work with or without this flush.) - proxy.Flush(BindOnce(&FileProxyTest::DidFinish, weak_factory_.GetWeakPtr())); - RunLoop().Run(); - EXPECT_EQ(File::FILE_OK, error_); - - // Verify the written data. - char buffer[10]; - EXPECT_EQ(data_bytes, base::ReadFile(TestPath(), buffer, data_bytes)); - for (int i = 0; i < data_bytes; ++i) { - EXPECT_EQ(data[i], buffer[i]); - } -} - -#if defined(OS_ANDROID) -// Flaky on Android, see http://crbug.com/489602 -#define MAYBE_SetTimes DISABLED_SetTimes -#else -#define MAYBE_SetTimes SetTimes -#endif -TEST_F(FileProxyTest, MAYBE_SetTimes) { - FileProxy proxy(file_task_runner()); - CreateProxy( - File::FLAG_CREATE | File::FLAG_WRITE | File::FLAG_WRITE_ATTRIBUTES, - &proxy); - - Time last_accessed_time = Time::Now() - TimeDelta::FromDays(12345); - Time last_modified_time = Time::Now() - TimeDelta::FromHours(98765); - - proxy.SetTimes( - last_accessed_time, last_modified_time, - BindOnce(&FileProxyTest::DidFinish, weak_factory_.GetWeakPtr())); - RunLoop().Run(); - EXPECT_EQ(File::FILE_OK, error_); - - File::Info info; - GetFileInfo(TestPath(), &info); - - // The returned values may only have the seconds precision, so we cast - // the double values to int here. - EXPECT_EQ(static_cast<int>(last_modified_time.ToDoubleT()), - static_cast<int>(info.last_modified.ToDoubleT())); - EXPECT_EQ(static_cast<int>(last_accessed_time.ToDoubleT()), - static_cast<int>(info.last_accessed.ToDoubleT())); -} - -TEST_F(FileProxyTest, SetLength_Shrink) { - // Setup. - const char kTestData[] = "0123456789"; - ASSERT_EQ(10, base::WriteFile(TestPath(), kTestData, 10)); - File::Info info; - GetFileInfo(TestPath(), &info); - ASSERT_EQ(10, info.size); - - // Run. - FileProxy proxy(file_task_runner()); - CreateProxy(File::FLAG_OPEN | File::FLAG_WRITE, &proxy); - proxy.SetLength( - 7, BindOnce(&FileProxyTest::DidFinish, weak_factory_.GetWeakPtr())); - RunLoop().Run(); - - // Verify. - GetFileInfo(TestPath(), &info); - ASSERT_EQ(7, info.size); - - char buffer[7]; - EXPECT_EQ(7, base::ReadFile(TestPath(), buffer, 7)); - int i = 0; - for (; i < 7; ++i) - EXPECT_EQ(kTestData[i], buffer[i]); -} - -TEST_F(FileProxyTest, SetLength_Expand) { - // Setup. - const char kTestData[] = "9876543210"; - ASSERT_EQ(10, base::WriteFile(TestPath(), kTestData, 10)); - File::Info info; - GetFileInfo(TestPath(), &info); - ASSERT_EQ(10, info.size); - - // Run. - FileProxy proxy(file_task_runner()); - CreateProxy(File::FLAG_OPEN | File::FLAG_WRITE, &proxy); - proxy.SetLength( - 53, BindOnce(&FileProxyTest::DidFinish, weak_factory_.GetWeakPtr())); - RunLoop().Run(); - - // Verify. - GetFileInfo(TestPath(), &info); - ASSERT_EQ(53, info.size); - - char buffer[53]; - EXPECT_EQ(53, base::ReadFile(TestPath(), buffer, 53)); - int i = 0; - for (; i < 10; ++i) - EXPECT_EQ(kTestData[i], buffer[i]); - for (; i < 53; ++i) - EXPECT_EQ(0, buffer[i]); -} - -} // namespace base
diff --git a/base/files/file_unittest.cc b/base/files/file_unittest.cc deleted file mode 100644 index b9992ad..0000000 --- a/base/files/file_unittest.cc +++ /dev/null
@@ -1,721 +0,0 @@ -// 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/files/file.h" - -#include <stdint.h> - -#include <utility> - -#include "base/files/file_util.h" -#include "base/files/memory_mapped_file.h" -#include "base/files/scoped_temp_dir.h" -#include "base/time/time.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -using base::File; -using base::FilePath; - -TEST(FileTest, Create) { - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - FilePath file_path = temp_dir.GetPath().AppendASCII("create_file_1"); - - { - // Don't create a File at all. - File file; - EXPECT_FALSE(file.IsValid()); - EXPECT_EQ(base::File::FILE_ERROR_FAILED, file.error_details()); - - File file2(base::File::FILE_ERROR_TOO_MANY_OPENED); - EXPECT_FALSE(file2.IsValid()); - EXPECT_EQ(base::File::FILE_ERROR_TOO_MANY_OPENED, file2.error_details()); - } - - { - // Open a file that doesn't exist. - File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ); - EXPECT_FALSE(file.IsValid()); - EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, file.error_details()); - EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, base::File::GetLastFileError()); - } - - { - // Open or create a file. - File file(file_path, base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_READ); - EXPECT_TRUE(file.IsValid()); - EXPECT_TRUE(file.created()); - EXPECT_EQ(base::File::FILE_OK, file.error_details()); - } - - { - // Open an existing file. - File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ); - EXPECT_TRUE(file.IsValid()); - EXPECT_FALSE(file.created()); - EXPECT_EQ(base::File::FILE_OK, file.error_details()); - - // This time verify closing the file. - file.Close(); - EXPECT_FALSE(file.IsValid()); - } - - { - // Open an existing file through Initialize - File file; - file.Initialize(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ); - EXPECT_TRUE(file.IsValid()); - EXPECT_FALSE(file.created()); - EXPECT_EQ(base::File::FILE_OK, file.error_details()); - - // This time verify closing the file. - file.Close(); - EXPECT_FALSE(file.IsValid()); - } - - { - // Create a file that exists. - File file(file_path, base::File::FLAG_CREATE | base::File::FLAG_READ); - EXPECT_FALSE(file.IsValid()); - EXPECT_FALSE(file.created()); - EXPECT_EQ(base::File::FILE_ERROR_EXISTS, file.error_details()); - EXPECT_EQ(base::File::FILE_ERROR_EXISTS, base::File::GetLastFileError()); - } - - { - // Create or overwrite a file. - File file(file_path, - base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); - EXPECT_TRUE(file.IsValid()); - EXPECT_TRUE(file.created()); - EXPECT_EQ(base::File::FILE_OK, file.error_details()); - } - - { - // Create a delete-on-close file. - file_path = temp_dir.GetPath().AppendASCII("create_file_2"); - File file(file_path, - base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_READ | - base::File::FLAG_DELETE_ON_CLOSE); - EXPECT_TRUE(file.IsValid()); - EXPECT_TRUE(file.created()); - EXPECT_EQ(base::File::FILE_OK, file.error_details()); - } - - EXPECT_FALSE(base::PathExists(file_path)); -} - -TEST(FileTest, SelfSwap) { - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - FilePath file_path = temp_dir.GetPath().AppendASCII("create_file_1"); - File file(file_path, - base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_DELETE_ON_CLOSE); - std::swap(file, file); - EXPECT_TRUE(file.IsValid()); -} - -TEST(FileTest, Async) { - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - FilePath file_path = temp_dir.GetPath().AppendASCII("create_file"); - - { - File file(file_path, base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_ASYNC); - EXPECT_TRUE(file.IsValid()); - EXPECT_TRUE(file.async()); - } - - { - File file(file_path, base::File::FLAG_OPEN_ALWAYS); - EXPECT_TRUE(file.IsValid()); - EXPECT_FALSE(file.async()); - } -} - -TEST(FileTest, DeleteOpenFile) { - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - FilePath file_path = temp_dir.GetPath().AppendASCII("create_file_1"); - - // Create a file. - File file(file_path, - base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_READ | - base::File::FLAG_SHARE_DELETE); - EXPECT_TRUE(file.IsValid()); - EXPECT_TRUE(file.created()); - EXPECT_EQ(base::File::FILE_OK, file.error_details()); - - // Open an existing file and mark it as delete on close. - File same_file(file_path, - base::File::FLAG_OPEN | base::File::FLAG_DELETE_ON_CLOSE | - base::File::FLAG_READ); - EXPECT_TRUE(file.IsValid()); - EXPECT_FALSE(same_file.created()); - EXPECT_EQ(base::File::FILE_OK, same_file.error_details()); - - // Close both handles and check that the file is gone. - file.Close(); - same_file.Close(); - EXPECT_FALSE(base::PathExists(file_path)); -} - -TEST(FileTest, ReadWrite) { - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - FilePath file_path = temp_dir.GetPath().AppendASCII("read_write_file"); - File file(file_path, - base::File::FLAG_CREATE | base::File::FLAG_READ | - base::File::FLAG_WRITE); - ASSERT_TRUE(file.IsValid()); - - char data_to_write[] = "test"; - const int kTestDataSize = 4; - - // Write 0 bytes to the file. - int bytes_written = file.Write(0, data_to_write, 0); - EXPECT_EQ(0, bytes_written); - - // Write 0 bytes, with buf=nullptr. - bytes_written = file.Write(0, nullptr, 0); - EXPECT_EQ(0, bytes_written); - - // Write "test" to the file. - bytes_written = file.Write(0, data_to_write, kTestDataSize); - EXPECT_EQ(kTestDataSize, bytes_written); - - // Read from EOF. - char data_read_1[32]; - int bytes_read = file.Read(kTestDataSize, data_read_1, kTestDataSize); - EXPECT_EQ(0, bytes_read); - - // Read from somewhere in the middle of the file. - const int kPartialReadOffset = 1; - bytes_read = file.Read(kPartialReadOffset, data_read_1, kTestDataSize); - EXPECT_EQ(kTestDataSize - kPartialReadOffset, bytes_read); - for (int i = 0; i < bytes_read; i++) - EXPECT_EQ(data_to_write[i + kPartialReadOffset], data_read_1[i]); - - // Read 0 bytes. - bytes_read = file.Read(0, data_read_1, 0); - EXPECT_EQ(0, bytes_read); - - // Read the entire file. - bytes_read = file.Read(0, data_read_1, kTestDataSize); - EXPECT_EQ(kTestDataSize, bytes_read); - for (int i = 0; i < bytes_read; i++) - EXPECT_EQ(data_to_write[i], data_read_1[i]); - - // Read again, but using the trivial native wrapper. - bytes_read = file.ReadNoBestEffort(0, data_read_1, kTestDataSize); - EXPECT_LE(bytes_read, kTestDataSize); - for (int i = 0; i < bytes_read; i++) - EXPECT_EQ(data_to_write[i], data_read_1[i]); - - // Write past the end of the file. - const int kOffsetBeyondEndOfFile = 10; - const int kPartialWriteLength = 2; - bytes_written = file.Write(kOffsetBeyondEndOfFile, - data_to_write, kPartialWriteLength); - EXPECT_EQ(kPartialWriteLength, bytes_written); - - // Make sure the file was extended. - int64_t file_size = 0; - EXPECT_TRUE(GetFileSize(file_path, &file_size)); - EXPECT_EQ(kOffsetBeyondEndOfFile + kPartialWriteLength, file_size); - - // Make sure the file was zero-padded. - char data_read_2[32]; - bytes_read = file.Read(0, data_read_2, static_cast<int>(file_size)); - EXPECT_EQ(file_size, bytes_read); - for (int i = 0; i < kTestDataSize; i++) - EXPECT_EQ(data_to_write[i], data_read_2[i]); - for (int i = kTestDataSize; i < kOffsetBeyondEndOfFile; i++) - EXPECT_EQ(0, data_read_2[i]); - for (int i = kOffsetBeyondEndOfFile; i < file_size; i++) - EXPECT_EQ(data_to_write[i - kOffsetBeyondEndOfFile], data_read_2[i]); -} - -TEST(FileTest, GetLastFileError) { -#if defined(OS_WIN) - ::SetLastError(ERROR_ACCESS_DENIED); -#else - errno = EACCES; -#endif - EXPECT_EQ(File::FILE_ERROR_ACCESS_DENIED, File::GetLastFileError()); - - base::ScopedTempDir temp_dir; - EXPECT_TRUE(temp_dir.CreateUniqueTempDir()); - - FilePath nonexistent_path(temp_dir.GetPath().AppendASCII("nonexistent")); - File file(nonexistent_path, File::FLAG_OPEN | File::FLAG_READ); - File::Error last_error = File::GetLastFileError(); - EXPECT_FALSE(file.IsValid()); - EXPECT_EQ(File::FILE_ERROR_NOT_FOUND, file.error_details()); - EXPECT_EQ(File::FILE_ERROR_NOT_FOUND, last_error); -} - -TEST(FileTest, Append) { - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - FilePath file_path = temp_dir.GetPath().AppendASCII("append_file"); - File file(file_path, base::File::FLAG_CREATE | base::File::FLAG_APPEND); - ASSERT_TRUE(file.IsValid()); - - char data_to_write[] = "test"; - const int kTestDataSize = 4; - - // Write 0 bytes to the file. - int bytes_written = file.Write(0, data_to_write, 0); - EXPECT_EQ(0, bytes_written); - - // Write 0 bytes, with buf=nullptr. - bytes_written = file.Write(0, nullptr, 0); - EXPECT_EQ(0, bytes_written); - - // Write "test" to the file. - bytes_written = file.Write(0, data_to_write, kTestDataSize); - EXPECT_EQ(kTestDataSize, bytes_written); - - file.Close(); - File file2(file_path, - base::File::FLAG_OPEN | base::File::FLAG_READ | - base::File::FLAG_APPEND); - ASSERT_TRUE(file2.IsValid()); - - // Test passing the file around. - file = std::move(file2); - EXPECT_FALSE(file2.IsValid()); - ASSERT_TRUE(file.IsValid()); - - char append_data_to_write[] = "78"; - const int kAppendDataSize = 2; - - // Append "78" to the file. - bytes_written = file.Write(0, append_data_to_write, kAppendDataSize); - EXPECT_EQ(kAppendDataSize, bytes_written); - - // Read the entire file. - char data_read_1[32]; - int bytes_read = file.Read(0, data_read_1, - kTestDataSize + kAppendDataSize); - EXPECT_EQ(kTestDataSize + kAppendDataSize, bytes_read); - for (int i = 0; i < kTestDataSize; i++) - EXPECT_EQ(data_to_write[i], data_read_1[i]); - for (int i = 0; i < kAppendDataSize; i++) - EXPECT_EQ(append_data_to_write[i], data_read_1[kTestDataSize + i]); -} - - -TEST(FileTest, Length) { - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - FilePath file_path = temp_dir.GetPath().AppendASCII("truncate_file"); - File file(file_path, - base::File::FLAG_CREATE | base::File::FLAG_READ | - base::File::FLAG_WRITE); - ASSERT_TRUE(file.IsValid()); - EXPECT_EQ(0, file.GetLength()); - - // Write "test" to the file. - char data_to_write[] = "test"; - int kTestDataSize = 4; - int bytes_written = file.Write(0, data_to_write, kTestDataSize); - EXPECT_EQ(kTestDataSize, bytes_written); - - // Extend the file. - const int kExtendedFileLength = 10; - int64_t file_size = 0; - EXPECT_TRUE(file.SetLength(kExtendedFileLength)); - EXPECT_EQ(kExtendedFileLength, file.GetLength()); - EXPECT_TRUE(GetFileSize(file_path, &file_size)); - EXPECT_EQ(kExtendedFileLength, file_size); - - // Make sure the file was zero-padded. - char data_read[32]; - int bytes_read = file.Read(0, data_read, static_cast<int>(file_size)); - EXPECT_EQ(file_size, bytes_read); - for (int i = 0; i < kTestDataSize; i++) - EXPECT_EQ(data_to_write[i], data_read[i]); - for (int i = kTestDataSize; i < file_size; i++) - EXPECT_EQ(0, data_read[i]); - - // Truncate the file. - const int kTruncatedFileLength = 2; - EXPECT_TRUE(file.SetLength(kTruncatedFileLength)); - EXPECT_EQ(kTruncatedFileLength, file.GetLength()); - EXPECT_TRUE(GetFileSize(file_path, &file_size)); - EXPECT_EQ(kTruncatedFileLength, file_size); - - // Make sure the file was truncated. - bytes_read = file.Read(0, data_read, kTestDataSize); - EXPECT_EQ(file_size, bytes_read); - for (int i = 0; i < file_size; i++) - EXPECT_EQ(data_to_write[i], data_read[i]); - - // Close the file and reopen with base::File::FLAG_CREATE_ALWAYS, and make - // sure the file is empty (old file was overridden). - file.Close(); - file.Initialize(file_path, - base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); - EXPECT_EQ(0, file.GetLength()); -} - -// Flakily fails: http://crbug.com/86494 -#if defined(OS_ANDROID) -TEST(FileTest, TouchGetInfo) { -#else -TEST(FileTest, DISABLED_TouchGetInfo) { -#endif - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - File file(temp_dir.GetPath().AppendASCII("touch_get_info_file"), - base::File::FLAG_CREATE | base::File::FLAG_WRITE | - base::File::FLAG_WRITE_ATTRIBUTES); - ASSERT_TRUE(file.IsValid()); - - // Get info for a newly created file. - base::File::Info info; - EXPECT_TRUE(file.GetInfo(&info)); - - // Add 2 seconds to account for possible rounding errors on - // filesystems that use a 1s or 2s timestamp granularity. - base::Time now = base::Time::Now() + base::TimeDelta::FromSeconds(2); - EXPECT_EQ(0, info.size); - EXPECT_FALSE(info.is_directory); - EXPECT_FALSE(info.is_symbolic_link); - EXPECT_LE(info.last_accessed.ToInternalValue(), now.ToInternalValue()); - EXPECT_LE(info.last_modified.ToInternalValue(), now.ToInternalValue()); - EXPECT_LE(info.creation_time.ToInternalValue(), now.ToInternalValue()); - base::Time creation_time = info.creation_time; - - // Write "test" to the file. - char data[] = "test"; - const int kTestDataSize = 4; - int bytes_written = file.Write(0, data, kTestDataSize); - EXPECT_EQ(kTestDataSize, bytes_written); - - // Change the last_accessed and last_modified dates. - // It's best to add values that are multiples of 2 (in seconds) - // to the current last_accessed and last_modified times, because - // FATxx uses a 2s timestamp granularity. - base::Time new_last_accessed = - info.last_accessed + base::TimeDelta::FromSeconds(234); - base::Time new_last_modified = - info.last_modified + base::TimeDelta::FromMinutes(567); - - EXPECT_TRUE(file.SetTimes(new_last_accessed, new_last_modified)); - - // Make sure the file info was updated accordingly. - EXPECT_TRUE(file.GetInfo(&info)); - EXPECT_EQ(info.size, kTestDataSize); - EXPECT_FALSE(info.is_directory); - EXPECT_FALSE(info.is_symbolic_link); - - // ext2/ext3 and HPS/HPS+ seem to have a timestamp granularity of 1s. -#if defined(OS_POSIX) - EXPECT_EQ(info.last_accessed.ToTimeVal().tv_sec, - new_last_accessed.ToTimeVal().tv_sec); - EXPECT_EQ(info.last_modified.ToTimeVal().tv_sec, - new_last_modified.ToTimeVal().tv_sec); -#else - EXPECT_EQ(info.last_accessed.ToInternalValue(), - new_last_accessed.ToInternalValue()); - EXPECT_EQ(info.last_modified.ToInternalValue(), - new_last_modified.ToInternalValue()); -#endif - - EXPECT_EQ(info.creation_time.ToInternalValue(), - creation_time.ToInternalValue()); -} - -TEST(FileTest, ReadAtCurrentPosition) { - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - FilePath file_path = - temp_dir.GetPath().AppendASCII("read_at_current_position"); - File file(file_path, - base::File::FLAG_CREATE | base::File::FLAG_READ | - base::File::FLAG_WRITE); - EXPECT_TRUE(file.IsValid()); - - const char kData[] = "test"; - const int kDataSize = sizeof(kData) - 1; - EXPECT_EQ(kDataSize, file.Write(0, kData, kDataSize)); - - EXPECT_EQ(0, file.Seek(base::File::FROM_BEGIN, 0)); - - char buffer[kDataSize]; - int first_chunk_size = kDataSize / 2; - EXPECT_EQ(first_chunk_size, file.ReadAtCurrentPos(buffer, first_chunk_size)); - EXPECT_EQ(kDataSize - first_chunk_size, - file.ReadAtCurrentPos(buffer + first_chunk_size, - kDataSize - first_chunk_size)); - EXPECT_EQ(std::string(buffer, buffer + kDataSize), std::string(kData)); -} - -TEST(FileTest, WriteAtCurrentPosition) { - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - FilePath file_path = - temp_dir.GetPath().AppendASCII("write_at_current_position"); - File file(file_path, - base::File::FLAG_CREATE | base::File::FLAG_READ | - base::File::FLAG_WRITE); - EXPECT_TRUE(file.IsValid()); - - const char kData[] = "test"; - const int kDataSize = sizeof(kData) - 1; - - int first_chunk_size = kDataSize / 2; - EXPECT_EQ(first_chunk_size, file.WriteAtCurrentPos(kData, first_chunk_size)); - EXPECT_EQ(kDataSize - first_chunk_size, - file.WriteAtCurrentPos(kData + first_chunk_size, - kDataSize - first_chunk_size)); - - char buffer[kDataSize]; - EXPECT_EQ(kDataSize, file.Read(0, buffer, kDataSize)); - EXPECT_EQ(std::string(buffer, buffer + kDataSize), std::string(kData)); -} - -TEST(FileTest, Seek) { - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - FilePath file_path = temp_dir.GetPath().AppendASCII("seek_file"); - File file(file_path, - base::File::FLAG_CREATE | base::File::FLAG_READ | - base::File::FLAG_WRITE); - ASSERT_TRUE(file.IsValid()); - - const int64_t kOffset = 10; - EXPECT_EQ(kOffset, file.Seek(base::File::FROM_BEGIN, kOffset)); - EXPECT_EQ(2 * kOffset, file.Seek(base::File::FROM_CURRENT, kOffset)); - EXPECT_EQ(kOffset, file.Seek(base::File::FROM_CURRENT, -kOffset)); - EXPECT_TRUE(file.SetLength(kOffset * 2)); - EXPECT_EQ(kOffset, file.Seek(base::File::FROM_END, -kOffset)); -} - -TEST(FileTest, Duplicate) { - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - FilePath file_path = temp_dir.GetPath().AppendASCII("file"); - File file(file_path,(base::File::FLAG_CREATE | - base::File::FLAG_READ | - base::File::FLAG_WRITE)); - ASSERT_TRUE(file.IsValid()); - - File file2(file.Duplicate()); - ASSERT_TRUE(file2.IsValid()); - - // Write through one handle, close it, read through the other. - static const char kData[] = "now is a good time."; - static const int kDataLen = sizeof(kData) - 1; - - ASSERT_EQ(0, file.Seek(base::File::FROM_CURRENT, 0)); - ASSERT_EQ(0, file2.Seek(base::File::FROM_CURRENT, 0)); - ASSERT_EQ(kDataLen, file.WriteAtCurrentPos(kData, kDataLen)); - ASSERT_EQ(kDataLen, file.Seek(base::File::FROM_CURRENT, 0)); - ASSERT_EQ(kDataLen, file2.Seek(base::File::FROM_CURRENT, 0)); - file.Close(); - char buf[kDataLen]; - ASSERT_EQ(kDataLen, file2.Read(0, &buf[0], kDataLen)); - ASSERT_EQ(std::string(kData, kDataLen), std::string(&buf[0], kDataLen)); -} - -TEST(FileTest, DuplicateDeleteOnClose) { - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - FilePath file_path = temp_dir.GetPath().AppendASCII("file"); - File file(file_path,(base::File::FLAG_CREATE | - base::File::FLAG_READ | - base::File::FLAG_WRITE | - base::File::FLAG_DELETE_ON_CLOSE)); - ASSERT_TRUE(file.IsValid()); - File file2(file.Duplicate()); - ASSERT_TRUE(file2.IsValid()); - file.Close(); - file2.Close(); - ASSERT_FALSE(base::PathExists(file_path)); -} - -#if defined(OS_WIN) -TEST(FileTest, GetInfoForDirectory) { - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - FilePath empty_dir = - temp_dir.GetPath().Append(FILE_PATH_LITERAL("gpfi_test")); - ASSERT_TRUE(CreateDirectory(empty_dir)); - - base::File dir( - ::CreateFile(empty_dir.value().c_str(), - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, // Needed to open a directory. - NULL)); - ASSERT_TRUE(dir.IsValid()); - - base::File::Info info; - EXPECT_TRUE(dir.GetInfo(&info)); - EXPECT_TRUE(info.is_directory); - EXPECT_FALSE(info.is_symbolic_link); - EXPECT_EQ(0, info.size); -} - -TEST(FileTest, DeleteNoop) { - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - FilePath file_path = temp_dir.GetPath().AppendASCII("file"); - - // Creating and closing a file with DELETE perms should do nothing special. - File file(file_path, - (base::File::FLAG_CREATE | base::File::FLAG_READ | - base::File::FLAG_WRITE | base::File::FLAG_CAN_DELETE_ON_CLOSE)); - ASSERT_TRUE(file.IsValid()); - file.Close(); - ASSERT_TRUE(base::PathExists(file_path)); -} - -TEST(FileTest, Delete) { - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - FilePath file_path = temp_dir.GetPath().AppendASCII("file"); - - // Creating a file with DELETE and then marking for delete on close should - // delete it. - File file(file_path, - (base::File::FLAG_CREATE | base::File::FLAG_READ | - base::File::FLAG_WRITE | base::File::FLAG_CAN_DELETE_ON_CLOSE)); - ASSERT_TRUE(file.IsValid()); - ASSERT_TRUE(file.DeleteOnClose(true)); - file.Close(); - ASSERT_FALSE(base::PathExists(file_path)); -} - -TEST(FileTest, DeleteThenRevoke) { - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - FilePath file_path = temp_dir.GetPath().AppendASCII("file"); - - // Creating a file with DELETE, marking it for delete, then clearing delete on - // close should not delete it. - File file(file_path, - (base::File::FLAG_CREATE | base::File::FLAG_READ | - base::File::FLAG_WRITE | base::File::FLAG_CAN_DELETE_ON_CLOSE)); - ASSERT_TRUE(file.IsValid()); - ASSERT_TRUE(file.DeleteOnClose(true)); - ASSERT_TRUE(file.DeleteOnClose(false)); - file.Close(); - ASSERT_TRUE(base::PathExists(file_path)); -} - -TEST(FileTest, IrrevokableDeleteOnClose) { - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - FilePath file_path = temp_dir.GetPath().AppendASCII("file"); - - // DELETE_ON_CLOSE cannot be revoked by this opener. - File file( - file_path, - (base::File::FLAG_CREATE | base::File::FLAG_READ | - base::File::FLAG_WRITE | base::File::FLAG_DELETE_ON_CLOSE | - base::File::FLAG_SHARE_DELETE | base::File::FLAG_CAN_DELETE_ON_CLOSE)); - ASSERT_TRUE(file.IsValid()); - // https://msdn.microsoft.com/library/windows/desktop/aa364221.aspx says that - // setting the dispositon has no effect if the handle was opened with - // FLAG_DELETE_ON_CLOSE. Do not make the test's success dependent on whether - // or not SetFileInformationByHandle indicates success or failure. (It happens - // to indicate success on Windows 10.) - file.DeleteOnClose(false); - file.Close(); - ASSERT_FALSE(base::PathExists(file_path)); -} - -TEST(FileTest, IrrevokableDeleteOnCloseOther) { - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - FilePath file_path = temp_dir.GetPath().AppendASCII("file"); - - // DELETE_ON_CLOSE cannot be revoked by another opener. - File file( - file_path, - (base::File::FLAG_CREATE | base::File::FLAG_READ | - base::File::FLAG_WRITE | base::File::FLAG_DELETE_ON_CLOSE | - base::File::FLAG_SHARE_DELETE | base::File::FLAG_CAN_DELETE_ON_CLOSE)); - ASSERT_TRUE(file.IsValid()); - - File file2( - file_path, - (base::File::FLAG_OPEN | base::File::FLAG_READ | base::File::FLAG_WRITE | - base::File::FLAG_SHARE_DELETE | base::File::FLAG_CAN_DELETE_ON_CLOSE)); - ASSERT_TRUE(file2.IsValid()); - - file2.DeleteOnClose(false); - file2.Close(); - ASSERT_TRUE(base::PathExists(file_path)); - file.Close(); - ASSERT_FALSE(base::PathExists(file_path)); -} - -TEST(FileTest, DeleteWithoutPermission) { - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - FilePath file_path = temp_dir.GetPath().AppendASCII("file"); - - // It should not be possible to mark a file for deletion when it was not - // created/opened with DELETE. - File file(file_path, (base::File::FLAG_CREATE | base::File::FLAG_READ | - base::File::FLAG_WRITE)); - ASSERT_TRUE(file.IsValid()); - ASSERT_FALSE(file.DeleteOnClose(true)); - file.Close(); - ASSERT_TRUE(base::PathExists(file_path)); -} - -TEST(FileTest, UnsharedDeleteOnClose) { - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - FilePath file_path = temp_dir.GetPath().AppendASCII("file"); - - // Opening with DELETE_ON_CLOSE when a previous opener hasn't enabled sharing - // will fail. - File file(file_path, (base::File::FLAG_CREATE | base::File::FLAG_READ | - base::File::FLAG_WRITE)); - ASSERT_TRUE(file.IsValid()); - File file2( - file_path, - (base::File::FLAG_OPEN | base::File::FLAG_READ | base::File::FLAG_WRITE | - base::File::FLAG_DELETE_ON_CLOSE | base::File::FLAG_SHARE_DELETE)); - ASSERT_FALSE(file2.IsValid()); - - file.Close(); - ASSERT_TRUE(base::PathExists(file_path)); -} - -TEST(FileTest, NoDeleteOnCloseWithMappedFile) { - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - FilePath file_path = temp_dir.GetPath().AppendASCII("file"); - - // Mapping a file into memory blocks DeleteOnClose. - File file(file_path, - (base::File::FLAG_CREATE | base::File::FLAG_READ | - base::File::FLAG_WRITE | base::File::FLAG_CAN_DELETE_ON_CLOSE)); - ASSERT_TRUE(file.IsValid()); - ASSERT_EQ(5, file.WriteAtCurrentPos("12345", 5)); - - { - base::MemoryMappedFile mapping; - ASSERT_TRUE(mapping.Initialize(file.Duplicate())); - ASSERT_EQ(5U, mapping.length()); - - EXPECT_FALSE(file.DeleteOnClose(true)); - } - - file.Close(); - ASSERT_TRUE(base::PathExists(file_path)); -} -#endif // defined(OS_WIN)
diff --git a/base/files/file_util_unittest.cc b/base/files/file_util_unittest.cc deleted file mode 100644 index b4de085..0000000 --- a/base/files/file_util_unittest.cc +++ /dev/null
@@ -1,3683 +0,0 @@ -// 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 <stddef.h> -#include <stdint.h> - -#include <algorithm> -#include <fstream> -#include <initializer_list> -#include <memory> -#include <set> -#include <utility> -#include <vector> - -#include "base/base_paths.h" -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/callback_helpers.h" -#include "base/command_line.h" -#include "base/environment.h" -#include "base/files/file.h" -#include "base/files/file_enumerator.h" -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/files/scoped_file.h" -#include "base/files/scoped_temp_dir.h" -#include "base/macros.h" -#include "base/path_service.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "base/test/multiprocess_test.h" -#include "base/test/scoped_environment_variable_override.h" -#include "base/test/test_file_util.h" -#include "base/test/test_timeouts.h" -#include "base/threading/platform_thread.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/multiprocess_func_list.h" -#include "testing/platform_test.h" - -#if defined(OS_WIN) -#include <shellapi.h> -#include <shlobj.h> -#include <tchar.h> -#include <windows.h> -#include <winioctl.h> -#include "base/strings/string_number_conversions.h" -#include "base/win/scoped_handle.h" -#include "base/win/win_util.h" -#endif - -#if defined(OS_POSIX) || defined(OS_FUCHSIA) -#include <errno.h> -#include <fcntl.h> -#include <sys/ioctl.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> -#endif - -#if defined(OS_LINUX) -#include <linux/fs.h> -#endif - -#if defined(OS_ANDROID) -#include "base/android/content_uri_utils.h" -#endif - -// This macro helps avoid wrapped lines in the test structs. -#define FPL(x) FILE_PATH_LITERAL(x) - -namespace base { - -namespace { - -const size_t kLargeFileSize = (1 << 16) + 3; - -// To test that NormalizeFilePath() deals with NTFS reparse points correctly, -// we need functions to create and delete reparse points. -#if defined(OS_WIN) -typedef struct _REPARSE_DATA_BUFFER { - ULONG ReparseTag; - USHORT ReparseDataLength; - USHORT Reserved; - union { - struct { - USHORT SubstituteNameOffset; - USHORT SubstituteNameLength; - USHORT PrintNameOffset; - USHORT PrintNameLength; - ULONG Flags; - WCHAR PathBuffer[1]; - } SymbolicLinkReparseBuffer; - struct { - USHORT SubstituteNameOffset; - USHORT SubstituteNameLength; - USHORT PrintNameOffset; - USHORT PrintNameLength; - WCHAR PathBuffer[1]; - } MountPointReparseBuffer; - struct { - UCHAR DataBuffer[1]; - } GenericReparseBuffer; - }; -} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; - -// Sets a reparse point. |source| will now point to |target|. Returns true if -// the call succeeds, false otherwise. -bool SetReparsePoint(HANDLE source, const FilePath& target_path) { - std::wstring kPathPrefix = L"\\??\\"; - std::wstring target_str; - // The juction will not work if the target path does not start with \??\ . - if (kPathPrefix != target_path.value().substr(0, kPathPrefix.size())) - target_str += kPathPrefix; - target_str += target_path.value(); - const wchar_t* target = target_str.c_str(); - USHORT size_target = static_cast<USHORT>(wcslen(target)) * sizeof(target[0]); - char buffer[2000] = {0}; - DWORD returned; - - REPARSE_DATA_BUFFER* data = reinterpret_cast<REPARSE_DATA_BUFFER*>(buffer); - - data->ReparseTag = 0xa0000003; - memcpy(data->MountPointReparseBuffer.PathBuffer, target, size_target + 2); - - data->MountPointReparseBuffer.SubstituteNameLength = size_target; - data->MountPointReparseBuffer.PrintNameOffset = size_target + 2; - data->ReparseDataLength = size_target + 4 + 8; - - int data_size = data->ReparseDataLength + 8; - - if (!DeviceIoControl(source, FSCTL_SET_REPARSE_POINT, &buffer, data_size, - NULL, 0, &returned, NULL)) { - return false; - } - return true; -} - -// Delete the reparse point referenced by |source|. Returns true if the call -// succeeds, false otherwise. -bool DeleteReparsePoint(HANDLE source) { - DWORD returned; - REPARSE_DATA_BUFFER data = {0}; - data.ReparseTag = 0xa0000003; - if (!DeviceIoControl(source, FSCTL_DELETE_REPARSE_POINT, &data, 8, NULL, 0, - &returned, NULL)) { - return false; - } - return true; -} - -// Manages a reparse point for a test. -class ReparsePoint { - public: - // Creates a reparse point from |source| (an empty directory) to |target|. - ReparsePoint(const FilePath& source, const FilePath& target) { - dir_.Set( - ::CreateFile(source.value().c_str(), - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, // Needed to open a directory. - NULL)); - created_ = dir_.IsValid() && SetReparsePoint(dir_.Get(), target); - } - - ~ReparsePoint() { - if (created_) - DeleteReparsePoint(dir_.Get()); - } - - bool IsValid() { return created_; } - - private: - win::ScopedHandle dir_; - bool created_; - DISALLOW_COPY_AND_ASSIGN(ReparsePoint); -}; - -#endif - -// Fuchsia doesn't support file permissions. -#if !defined(OS_FUCHSIA) -#if defined(OS_POSIX) -// Provide a simple way to change the permissions bits on |path| in tests. -// ASSERT failures will return, but not stop the test. Caller should wrap -// calls to this function in ASSERT_NO_FATAL_FAILURE(). -void ChangePosixFilePermissions(const FilePath& path, - int mode_bits_to_set, - int mode_bits_to_clear) { - ASSERT_FALSE(mode_bits_to_set & mode_bits_to_clear) - << "Can't set and clear the same bits."; - - int mode = 0; - ASSERT_TRUE(GetPosixFilePermissions(path, &mode)); - mode |= mode_bits_to_set; - mode &= ~mode_bits_to_clear; - ASSERT_TRUE(SetPosixFilePermissions(path, mode)); -} -#endif // defined(OS_POSIX) - -// Sets the source file to read-only. -void SetReadOnly(const FilePath& path, bool read_only) { -#if defined(OS_WIN) - // On Windows, it involves setting/removing the 'readonly' bit. - DWORD attrs = GetFileAttributes(path.value().c_str()); - ASSERT_NE(INVALID_FILE_ATTRIBUTES, attrs); - ASSERT_TRUE(SetFileAttributes( - path.value().c_str(), read_only ? (attrs | FILE_ATTRIBUTE_READONLY) - : (attrs & ~FILE_ATTRIBUTE_READONLY))); - - DWORD expected = - read_only - ? ((attrs & (FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_DIRECTORY)) | - FILE_ATTRIBUTE_READONLY) - : (attrs & (FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_DIRECTORY)); - - // Ignore FILE_ATTRIBUTE_NOT_CONTENT_INDEXED if present. - attrs = GetFileAttributes(path.value().c_str()) & - ~FILE_ATTRIBUTE_NOT_CONTENT_INDEXED; - ASSERT_EQ(expected, attrs); -#else - // On all other platforms, it involves removing/setting the write bit. - mode_t mode = read_only ? S_IRUSR : (S_IRUSR | S_IWUSR); - EXPECT_TRUE(SetPosixFilePermissions( - path, DirectoryExists(path) ? (mode | S_IXUSR) : mode)); -#endif // defined(OS_WIN) -} - -bool IsReadOnly(const FilePath& path) { -#if defined(OS_WIN) - DWORD attrs = GetFileAttributes(path.value().c_str()); - EXPECT_NE(INVALID_FILE_ATTRIBUTES, attrs); - return attrs & FILE_ATTRIBUTE_READONLY; -#else - int mode = 0; - EXPECT_TRUE(GetPosixFilePermissions(path, &mode)); - return !(mode & S_IWUSR); -#endif // defined(OS_WIN) -} - -#endif // defined(OS_FUCHSIA) - -const wchar_t bogus_content[] = L"I'm cannon fodder."; - -const int FILES_AND_DIRECTORIES = - FileEnumerator::FILES | FileEnumerator::DIRECTORIES; - -// file_util winds up using autoreleased objects on the Mac, so this needs -// to be a PlatformTest -class FileUtilTest : public PlatformTest { - protected: - void SetUp() override { - PlatformTest::SetUp(); - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - } - - ScopedTempDir temp_dir_; -}; - -// Collects all the results from the given file enumerator, and provides an -// interface to query whether a given file is present. -class FindResultCollector { - public: - explicit FindResultCollector(FileEnumerator* enumerator) { - FilePath cur_file; - while (!(cur_file = enumerator->Next()).value().empty()) { - FilePath::StringType path = cur_file.value(); - // The file should not be returned twice. - EXPECT_TRUE(files_.end() == files_.find(path)) - << "Same file returned twice"; - - // Save for later. - files_.insert(path); - } - } - - // Returns true if the enumerator found the file. - bool HasFile(const FilePath& file) const { - return files_.find(file.value()) != files_.end(); - } - - int size() { - return static_cast<int>(files_.size()); - } - - private: - std::set<FilePath::StringType> files_; -}; - -// Simple function to dump some text into a new file. -void CreateTextFile(const FilePath& filename, - const std::wstring& contents) { - std::wofstream file; - file.open(filename.value().c_str()); - ASSERT_TRUE(file.is_open()); - file << contents; - file.close(); -} - -// Simple function to take out some text from a file. -std::wstring ReadTextFile(const FilePath& filename) { - wchar_t contents[64]; - std::wifstream file; - file.open(filename.value().c_str()); - EXPECT_TRUE(file.is_open()); - file.getline(contents, arraysize(contents)); - file.close(); - return std::wstring(contents); -} - -// Sets |is_inheritable| to indicate whether or not |stream| is set up to be -// inerhited into child processes (i.e., HANDLE_FLAG_INHERIT is set on the -// underlying handle on Windows, or FD_CLOEXEC is not set on the underlying file -// descriptor on POSIX). Calls to this function must be wrapped with -// ASSERT_NO_FATAL_FAILURE to properly abort tests in case of fatal failure. -void GetIsInheritable(FILE* stream, bool* is_inheritable) { -#if defined(OS_WIN) - HANDLE handle = reinterpret_cast<HANDLE>(_get_osfhandle(_fileno(stream))); - ASSERT_NE(INVALID_HANDLE_VALUE, handle); - - DWORD info = 0; - ASSERT_EQ(TRUE, ::GetHandleInformation(handle, &info)); - *is_inheritable = ((info & HANDLE_FLAG_INHERIT) != 0); -#elif defined(OS_POSIX) || defined(OS_FUCHSIA) - int fd = fileno(stream); - ASSERT_NE(-1, fd); - int flags = fcntl(fd, F_GETFD, 0); - ASSERT_NE(-1, flags); - *is_inheritable = ((flags & FD_CLOEXEC) == 0); -#else -#error Not implemented -#endif -} - -TEST_F(FileUtilTest, FileAndDirectorySize) { - // Create three files of 20, 30 and 3 chars (utf8). ComputeDirectorySize - // should return 53 bytes. - FilePath file_01 = temp_dir_.GetPath().Append(FPL("The file 01.txt")); - CreateTextFile(file_01, L"12345678901234567890"); - int64_t size_f1 = 0; - ASSERT_TRUE(GetFileSize(file_01, &size_f1)); - EXPECT_EQ(20ll, size_f1); - - FilePath subdir_path = temp_dir_.GetPath().Append(FPL("Level2")); - CreateDirectory(subdir_path); - - FilePath file_02 = subdir_path.Append(FPL("The file 02.txt")); - CreateTextFile(file_02, L"123456789012345678901234567890"); - int64_t size_f2 = 0; - ASSERT_TRUE(GetFileSize(file_02, &size_f2)); - EXPECT_EQ(30ll, size_f2); - - FilePath subsubdir_path = subdir_path.Append(FPL("Level3")); - CreateDirectory(subsubdir_path); - - FilePath file_03 = subsubdir_path.Append(FPL("The file 03.txt")); - CreateTextFile(file_03, L"123"); - - int64_t computed_size = ComputeDirectorySize(temp_dir_.GetPath()); - EXPECT_EQ(size_f1 + size_f2 + 3, computed_size); -} - -TEST_F(FileUtilTest, NormalizeFilePathBasic) { - // Create a directory under the test dir. Because we create it, - // we know it is not a link. - FilePath file_a_path = temp_dir_.GetPath().Append(FPL("file_a")); - FilePath dir_path = temp_dir_.GetPath().Append(FPL("dir")); - FilePath file_b_path = dir_path.Append(FPL("file_b")); - CreateDirectory(dir_path); - - FilePath normalized_file_a_path, normalized_file_b_path; - ASSERT_FALSE(PathExists(file_a_path)); - ASSERT_FALSE(NormalizeFilePath(file_a_path, &normalized_file_a_path)) - << "NormalizeFilePath() should fail on nonexistent paths."; - - CreateTextFile(file_a_path, bogus_content); - ASSERT_TRUE(PathExists(file_a_path)); - ASSERT_TRUE(NormalizeFilePath(file_a_path, &normalized_file_a_path)); - - CreateTextFile(file_b_path, bogus_content); - ASSERT_TRUE(PathExists(file_b_path)); - ASSERT_TRUE(NormalizeFilePath(file_b_path, &normalized_file_b_path)); - - // Beacuse this test created |dir_path|, we know it is not a link - // or junction. So, the real path of the directory holding file a - // must be the parent of the path holding file b. - ASSERT_TRUE(normalized_file_a_path.DirName() - .IsParent(normalized_file_b_path.DirName())); -} - -#if defined(OS_WIN) - -TEST_F(FileUtilTest, NormalizeFilePathReparsePoints) { - // Build the following directory structure: - // - // temp_dir - // |-> base_a - // | |-> sub_a - // | |-> file.txt - // | |-> long_name___... (Very long name.) - // | |-> sub_long - // | |-> deep.txt - // |-> base_b - // |-> to_sub_a (reparse point to temp_dir\base_a\sub_a) - // |-> to_base_b (reparse point to temp_dir\base_b) - // |-> to_sub_long (reparse point to temp_dir\sub_a\long_name_\sub_long) - - FilePath base_a = temp_dir_.GetPath().Append(FPL("base_a")); -#if defined(OS_WIN) - // TEMP can have a lower case drive letter. - string16 temp_base_a = base_a.value(); - ASSERT_FALSE(temp_base_a.empty()); - *temp_base_a.begin() = ToUpperASCII(*temp_base_a.begin()); - base_a = FilePath(temp_base_a); -#endif - ASSERT_TRUE(CreateDirectory(base_a)); - - FilePath sub_a = base_a.Append(FPL("sub_a")); - ASSERT_TRUE(CreateDirectory(sub_a)); - - FilePath file_txt = sub_a.Append(FPL("file.txt")); - CreateTextFile(file_txt, bogus_content); - - // Want a directory whose name is long enough to make the path to the file - // inside just under MAX_PATH chars. This will be used to test that when - // a junction expands to a path over MAX_PATH chars in length, - // NormalizeFilePath() fails without crashing. - FilePath sub_long_rel(FPL("sub_long")); - FilePath deep_txt(FPL("deep.txt")); - - int target_length = MAX_PATH; - target_length -= (sub_a.value().length() + 1); // +1 for the sepperator '\'. - target_length -= (sub_long_rel.Append(deep_txt).value().length() + 1); - // Without making the path a bit shorter, CreateDirectory() fails. - // the resulting path is still long enough to hit the failing case in - // NormalizePath(). - const int kCreateDirLimit = 4; - target_length -= kCreateDirLimit; - FilePath::StringType long_name_str = FPL("long_name_"); - long_name_str.resize(target_length, '_'); - - FilePath long_name = sub_a.Append(FilePath(long_name_str)); - FilePath deep_file = long_name.Append(sub_long_rel).Append(deep_txt); - ASSERT_EQ(static_cast<size_t>(MAX_PATH - kCreateDirLimit), - deep_file.value().length()); - - FilePath sub_long = deep_file.DirName(); - ASSERT_TRUE(CreateDirectory(sub_long)); - CreateTextFile(deep_file, bogus_content); - - FilePath base_b = temp_dir_.GetPath().Append(FPL("base_b")); - ASSERT_TRUE(CreateDirectory(base_b)); - - FilePath to_sub_a = base_b.Append(FPL("to_sub_a")); - ASSERT_TRUE(CreateDirectory(to_sub_a)); - FilePath normalized_path; - { - ReparsePoint reparse_to_sub_a(to_sub_a, sub_a); - ASSERT_TRUE(reparse_to_sub_a.IsValid()); - - FilePath to_base_b = base_b.Append(FPL("to_base_b")); - ASSERT_TRUE(CreateDirectory(to_base_b)); - ReparsePoint reparse_to_base_b(to_base_b, base_b); - ASSERT_TRUE(reparse_to_base_b.IsValid()); - - FilePath to_sub_long = base_b.Append(FPL("to_sub_long")); - ASSERT_TRUE(CreateDirectory(to_sub_long)); - ReparsePoint reparse_to_sub_long(to_sub_long, sub_long); - ASSERT_TRUE(reparse_to_sub_long.IsValid()); - - // Normalize a junction free path: base_a\sub_a\file.txt . - ASSERT_TRUE(NormalizeFilePath(file_txt, &normalized_path)); - ASSERT_STREQ(file_txt.value().c_str(), normalized_path.value().c_str()); - - // Check that the path base_b\to_sub_a\file.txt can be normalized to exclude - // the junction to_sub_a. - ASSERT_TRUE(NormalizeFilePath(to_sub_a.Append(FPL("file.txt")), - &normalized_path)); - ASSERT_STREQ(file_txt.value().c_str(), normalized_path.value().c_str()); - - // Check that the path base_b\to_base_b\to_base_b\to_sub_a\file.txt can be - // normalized to exclude junctions to_base_b and to_sub_a . - ASSERT_TRUE(NormalizeFilePath(base_b.Append(FPL("to_base_b")) - .Append(FPL("to_base_b")) - .Append(FPL("to_sub_a")) - .Append(FPL("file.txt")), - &normalized_path)); - ASSERT_STREQ(file_txt.value().c_str(), normalized_path.value().c_str()); - - // A long enough path will cause NormalizeFilePath() to fail. Make a long - // path using to_base_b many times, and check that paths long enough to fail - // do not cause a crash. - FilePath long_path = base_b; - const int kLengthLimit = MAX_PATH + 200; - while (long_path.value().length() <= kLengthLimit) { - long_path = long_path.Append(FPL("to_base_b")); - } - long_path = long_path.Append(FPL("to_sub_a")) - .Append(FPL("file.txt")); - - ASSERT_FALSE(NormalizeFilePath(long_path, &normalized_path)); - - // Normalizing the junction to deep.txt should fail, because the expanded - // path to deep.txt is longer than MAX_PATH. - ASSERT_FALSE(NormalizeFilePath(to_sub_long.Append(deep_txt), - &normalized_path)); - - // Delete the reparse points, and see that NormalizeFilePath() fails - // to traverse them. - } - - ASSERT_FALSE(NormalizeFilePath(to_sub_a.Append(FPL("file.txt")), - &normalized_path)); -} - -TEST_F(FileUtilTest, DevicePathToDriveLetter) { - // Get a drive letter. - string16 real_drive_letter = - ToUpperASCII(temp_dir_.GetPath().value().substr(0, 2)); - if (!isalpha(real_drive_letter[0]) || ':' != real_drive_letter[1]) { - LOG(ERROR) << "Can't get a drive letter to test with."; - return; - } - - // Get the NT style path to that drive. - wchar_t device_path[MAX_PATH] = {'\0'}; - ASSERT_TRUE( - ::QueryDosDevice(real_drive_letter.c_str(), device_path, MAX_PATH)); - FilePath actual_device_path(device_path); - FilePath win32_path; - - // Run DevicePathToDriveLetterPath() on the NT style path we got from - // QueryDosDevice(). Expect the drive letter we started with. - ASSERT_TRUE(DevicePathToDriveLetterPath(actual_device_path, &win32_path)); - ASSERT_EQ(real_drive_letter, win32_path.value()); - - // Add some directories to the path. Expect those extra path componenets - // to be preserved. - FilePath kRelativePath(FPL("dir1\\dir2\\file.txt")); - ASSERT_TRUE(DevicePathToDriveLetterPath( - actual_device_path.Append(kRelativePath), - &win32_path)); - EXPECT_EQ(FilePath(real_drive_letter + L"\\").Append(kRelativePath).value(), - win32_path.value()); - - // Deform the real path so that it is invalid by removing the last four - // characters. The way windows names devices that are hard disks - // (\Device\HardDiskVolume${NUMBER}) guarantees that the string is longer - // than three characters. The only way the truncated string could be a - // real drive is if more than 10^3 disks are mounted: - // \Device\HardDiskVolume10000 would be truncated to \Device\HardDiskVolume1 - // Check that DevicePathToDriveLetterPath fails. - int path_length = actual_device_path.value().length(); - int new_length = path_length - 4; - ASSERT_LT(0, new_length); - FilePath prefix_of_real_device_path( - actual_device_path.value().substr(0, new_length)); - ASSERT_FALSE(DevicePathToDriveLetterPath(prefix_of_real_device_path, - &win32_path)); - - ASSERT_FALSE(DevicePathToDriveLetterPath( - prefix_of_real_device_path.Append(kRelativePath), - &win32_path)); - - // Deform the real path so that it is invalid by adding some characters. For - // example, if C: maps to \Device\HardDiskVolume8, then we simulate a - // request for the drive letter whose native path is - // \Device\HardDiskVolume812345 . We assume such a device does not exist, - // because drives are numbered in order and mounting 112345 hard disks will - // never happen. - const FilePath::StringType kExtraChars = FPL("12345"); - - FilePath real_device_path_plus_numbers( - actual_device_path.value() + kExtraChars); - - ASSERT_FALSE(DevicePathToDriveLetterPath( - real_device_path_plus_numbers, - &win32_path)); - - ASSERT_FALSE(DevicePathToDriveLetterPath( - real_device_path_plus_numbers.Append(kRelativePath), - &win32_path)); -} - -TEST_F(FileUtilTest, CreateTemporaryFileInDirLongPathTest) { - // Test that CreateTemporaryFileInDir() creates a path and returns a long path - // if it is available. This test requires that: - // - the filesystem at |temp_dir_| supports long filenames. - // - the account has FILE_LIST_DIRECTORY permission for all ancestor - // directories of |temp_dir_|. - const FilePath::CharType kLongDirName[] = FPL("A long path"); - const FilePath::CharType kTestSubDirName[] = FPL("test"); - FilePath long_test_dir = temp_dir_.GetPath().Append(kLongDirName); - ASSERT_TRUE(CreateDirectory(long_test_dir)); - - // kLongDirName is not a 8.3 component. So GetShortName() should give us a - // different short name. - WCHAR path_buffer[MAX_PATH]; - DWORD path_buffer_length = GetShortPathName(long_test_dir.value().c_str(), - path_buffer, MAX_PATH); - ASSERT_LT(path_buffer_length, DWORD(MAX_PATH)); - ASSERT_NE(DWORD(0), path_buffer_length); - FilePath short_test_dir(path_buffer); - ASSERT_STRNE(kLongDirName, short_test_dir.BaseName().value().c_str()); - - FilePath temp_file; - ASSERT_TRUE(CreateTemporaryFileInDir(short_test_dir, &temp_file)); - EXPECT_STREQ(kLongDirName, temp_file.DirName().BaseName().value().c_str()); - EXPECT_TRUE(PathExists(temp_file)); - - // Create a subdirectory of |long_test_dir| and make |long_test_dir| - // unreadable. We should still be able to create a temp file in the - // subdirectory, but we won't be able to determine the long path for it. This - // mimics the environment that some users run where their user profiles reside - // in a location where the don't have full access to the higher level - // directories. (Note that this assumption is true for NTFS, but not for some - // network file systems. E.g. AFS). - FilePath access_test_dir = long_test_dir.Append(kTestSubDirName); - ASSERT_TRUE(CreateDirectory(access_test_dir)); - FilePermissionRestorer long_test_dir_restorer(long_test_dir); - ASSERT_TRUE(MakeFileUnreadable(long_test_dir)); - - // Use the short form of the directory to create a temporary filename. - ASSERT_TRUE(CreateTemporaryFileInDir( - short_test_dir.Append(kTestSubDirName), &temp_file)); - EXPECT_TRUE(PathExists(temp_file)); - EXPECT_TRUE(short_test_dir.IsParent(temp_file.DirName())); - - // Check that the long path can't be determined for |temp_file|. - path_buffer_length = GetLongPathName(temp_file.value().c_str(), - path_buffer, MAX_PATH); - EXPECT_EQ(DWORD(0), path_buffer_length); -} - -#endif // defined(OS_WIN) - -#if defined(OS_POSIX) - -TEST_F(FileUtilTest, CreateAndReadSymlinks) { - FilePath link_from = temp_dir_.GetPath().Append(FPL("from_file")); - FilePath link_to = temp_dir_.GetPath().Append(FPL("to_file")); - CreateTextFile(link_to, bogus_content); - - ASSERT_TRUE(CreateSymbolicLink(link_to, link_from)) - << "Failed to create file symlink."; - - // If we created the link properly, we should be able to read the contents - // through it. - EXPECT_EQ(bogus_content, ReadTextFile(link_from)); - - FilePath result; - ASSERT_TRUE(ReadSymbolicLink(link_from, &result)); - EXPECT_EQ(link_to.value(), result.value()); - - // Link to a directory. - link_from = temp_dir_.GetPath().Append(FPL("from_dir")); - link_to = temp_dir_.GetPath().Append(FPL("to_dir")); - ASSERT_TRUE(CreateDirectory(link_to)); - ASSERT_TRUE(CreateSymbolicLink(link_to, link_from)) - << "Failed to create directory symlink."; - - // Test failures. - EXPECT_FALSE(CreateSymbolicLink(link_to, link_to)); - EXPECT_FALSE(ReadSymbolicLink(link_to, &result)); - FilePath missing = temp_dir_.GetPath().Append(FPL("missing")); - EXPECT_FALSE(ReadSymbolicLink(missing, &result)); -} - -// The following test of NormalizeFilePath() require that we create a symlink. -// This can not be done on Windows before Vista. On Vista, creating a symlink -// requires privilege "SeCreateSymbolicLinkPrivilege". -// TODO(skerner): Investigate the possibility of giving base_unittests the -// privileges required to create a symlink. -TEST_F(FileUtilTest, NormalizeFilePathSymlinks) { - // Link one file to another. - FilePath link_from = temp_dir_.GetPath().Append(FPL("from_file")); - FilePath link_to = temp_dir_.GetPath().Append(FPL("to_file")); - CreateTextFile(link_to, bogus_content); - - ASSERT_TRUE(CreateSymbolicLink(link_to, link_from)) - << "Failed to create file symlink."; - - // Check that NormalizeFilePath sees the link. - FilePath normalized_path; - ASSERT_TRUE(NormalizeFilePath(link_from, &normalized_path)); - EXPECT_NE(link_from, link_to); - EXPECT_EQ(link_to.BaseName().value(), normalized_path.BaseName().value()); - EXPECT_EQ(link_to.BaseName().value(), normalized_path.BaseName().value()); - - // Link to a directory. - link_from = temp_dir_.GetPath().Append(FPL("from_dir")); - link_to = temp_dir_.GetPath().Append(FPL("to_dir")); - ASSERT_TRUE(CreateDirectory(link_to)); - ASSERT_TRUE(CreateSymbolicLink(link_to, link_from)) - << "Failed to create directory symlink."; - - EXPECT_FALSE(NormalizeFilePath(link_from, &normalized_path)) - << "Links to directories should return false."; - - // Test that a loop in the links causes NormalizeFilePath() to return false. - link_from = temp_dir_.GetPath().Append(FPL("link_a")); - link_to = temp_dir_.GetPath().Append(FPL("link_b")); - ASSERT_TRUE(CreateSymbolicLink(link_to, link_from)) - << "Failed to create loop symlink a."; - ASSERT_TRUE(CreateSymbolicLink(link_from, link_to)) - << "Failed to create loop symlink b."; - - // Infinite loop! - EXPECT_FALSE(NormalizeFilePath(link_from, &normalized_path)); -} - -TEST_F(FileUtilTest, DeleteSymlinkToExistentFile) { - // Create a file. - FilePath file_name = temp_dir_.GetPath().Append(FPL("Test DeleteFile 2.txt")); - CreateTextFile(file_name, bogus_content); - ASSERT_TRUE(PathExists(file_name)); - - // Create a symlink to the file. - FilePath file_link = temp_dir_.GetPath().Append("file_link_2"); - ASSERT_TRUE(CreateSymbolicLink(file_name, file_link)) - << "Failed to create symlink."; - - // Delete the symbolic link. - EXPECT_TRUE(DeleteFile(file_link, false)); - - // Make sure original file is not deleted. - EXPECT_FALSE(PathExists(file_link)); - EXPECT_TRUE(PathExists(file_name)); -} - -TEST_F(FileUtilTest, DeleteSymlinkToNonExistentFile) { - // Create a non-existent file path. - FilePath non_existent = - temp_dir_.GetPath().Append(FPL("Test DeleteFile 3.txt")); - EXPECT_FALSE(PathExists(non_existent)); - - // Create a symlink to the non-existent file. - FilePath file_link = temp_dir_.GetPath().Append("file_link_3"); - ASSERT_TRUE(CreateSymbolicLink(non_existent, file_link)) - << "Failed to create symlink."; - - // Make sure the symbolic link is exist. - EXPECT_TRUE(IsLink(file_link)); - EXPECT_FALSE(PathExists(file_link)); - - // Delete the symbolic link. - EXPECT_TRUE(DeleteFile(file_link, false)); - - // Make sure the symbolic link is deleted. - EXPECT_FALSE(IsLink(file_link)); -} - -TEST_F(FileUtilTest, CopyFileFollowsSymlinks) { - FilePath link_from = temp_dir_.GetPath().Append(FPL("from_file")); - FilePath link_to = temp_dir_.GetPath().Append(FPL("to_file")); - CreateTextFile(link_to, bogus_content); - - ASSERT_TRUE(CreateSymbolicLink(link_to, link_from)); - - // If we created the link properly, we should be able to read the contents - // through it. - EXPECT_EQ(bogus_content, ReadTextFile(link_from)); - - FilePath result; - ASSERT_TRUE(ReadSymbolicLink(link_from, &result)); - EXPECT_EQ(link_to.value(), result.value()); - - // Create another file and copy it to |link_from|. - FilePath src_file = temp_dir_.GetPath().Append(FPL("src.txt")); - const std::wstring file_contents(L"Gooooooooooooooooooooogle"); - CreateTextFile(src_file, file_contents); - ASSERT_TRUE(CopyFile(src_file, link_from)); - - // Make sure |link_from| is still a symlink, and |link_to| has been written to - // by CopyFile(). - EXPECT_TRUE(IsLink(link_from)); - EXPECT_EQ(file_contents, ReadTextFile(link_from)); - EXPECT_EQ(file_contents, ReadTextFile(link_to)); -} - -TEST_F(FileUtilTest, ChangeFilePermissionsAndRead) { - // Create a file path. - FilePath file_name = - temp_dir_.GetPath().Append(FPL("Test Readable File.txt")); - EXPECT_FALSE(PathExists(file_name)); - - static constexpr char kData[] = "hello"; - static constexpr int kDataSize = sizeof(kData) - 1; - char buffer[kDataSize]; - - // Write file. - EXPECT_EQ(kDataSize, WriteFile(file_name, kData, kDataSize)); - EXPECT_TRUE(PathExists(file_name)); - - // Make sure the file is readable. - int32_t mode = 0; - EXPECT_TRUE(GetPosixFilePermissions(file_name, &mode)); - EXPECT_TRUE(mode & FILE_PERMISSION_READ_BY_USER); - - // Get rid of the read permission. - EXPECT_TRUE(SetPosixFilePermissions(file_name, 0u)); - EXPECT_TRUE(GetPosixFilePermissions(file_name, &mode)); - EXPECT_FALSE(mode & FILE_PERMISSION_READ_BY_USER); - // Make sure the file can't be read. - EXPECT_EQ(-1, ReadFile(file_name, buffer, kDataSize)); - - // Give the read permission. - EXPECT_TRUE(SetPosixFilePermissions(file_name, FILE_PERMISSION_READ_BY_USER)); - EXPECT_TRUE(GetPosixFilePermissions(file_name, &mode)); - EXPECT_TRUE(mode & FILE_PERMISSION_READ_BY_USER); - // Make sure the file can be read. - EXPECT_EQ(kDataSize, ReadFile(file_name, buffer, kDataSize)); - - // Delete the file. - EXPECT_TRUE(DeleteFile(file_name, false)); - EXPECT_FALSE(PathExists(file_name)); -} - -TEST_F(FileUtilTest, ChangeFilePermissionsAndWrite) { - // Create a file path. - FilePath file_name = - temp_dir_.GetPath().Append(FPL("Test Readable File.txt")); - EXPECT_FALSE(PathExists(file_name)); - - const std::string kData("hello"); - - // Write file. - EXPECT_EQ(static_cast<int>(kData.length()), - WriteFile(file_name, kData.data(), kData.length())); - EXPECT_TRUE(PathExists(file_name)); - - // Make sure the file is writable. - int mode = 0; - EXPECT_TRUE(GetPosixFilePermissions(file_name, &mode)); - EXPECT_TRUE(mode & FILE_PERMISSION_WRITE_BY_USER); - EXPECT_TRUE(PathIsWritable(file_name)); - - // Get rid of the write permission. - EXPECT_TRUE(SetPosixFilePermissions(file_name, 0u)); - EXPECT_TRUE(GetPosixFilePermissions(file_name, &mode)); - EXPECT_FALSE(mode & FILE_PERMISSION_WRITE_BY_USER); - // Make sure the file can't be write. - EXPECT_EQ(-1, WriteFile(file_name, kData.data(), kData.length())); - EXPECT_FALSE(PathIsWritable(file_name)); - - // Give read permission. - EXPECT_TRUE(SetPosixFilePermissions(file_name, - FILE_PERMISSION_WRITE_BY_USER)); - EXPECT_TRUE(GetPosixFilePermissions(file_name, &mode)); - EXPECT_TRUE(mode & FILE_PERMISSION_WRITE_BY_USER); - // Make sure the file can be write. - EXPECT_EQ(static_cast<int>(kData.length()), - WriteFile(file_name, kData.data(), kData.length())); - EXPECT_TRUE(PathIsWritable(file_name)); - - // Delete the file. - EXPECT_TRUE(DeleteFile(file_name, false)); - EXPECT_FALSE(PathExists(file_name)); -} - -TEST_F(FileUtilTest, ChangeDirectoryPermissionsAndEnumerate) { - // Create a directory path. - FilePath subdir_path = temp_dir_.GetPath().Append(FPL("PermissionTest1")); - CreateDirectory(subdir_path); - ASSERT_TRUE(PathExists(subdir_path)); - - // Create a dummy file to enumerate. - FilePath file_name = subdir_path.Append(FPL("Test Readable File.txt")); - EXPECT_FALSE(PathExists(file_name)); - const std::string kData("hello"); - EXPECT_EQ(static_cast<int>(kData.length()), - WriteFile(file_name, kData.data(), kData.length())); - EXPECT_TRUE(PathExists(file_name)); - - // Make sure the directory has the all permissions. - int mode = 0; - EXPECT_TRUE(GetPosixFilePermissions(subdir_path, &mode)); - EXPECT_EQ(FILE_PERMISSION_USER_MASK, mode & FILE_PERMISSION_USER_MASK); - - // Get rid of the permissions from the directory. - EXPECT_TRUE(SetPosixFilePermissions(subdir_path, 0u)); - EXPECT_TRUE(GetPosixFilePermissions(subdir_path, &mode)); - EXPECT_FALSE(mode & FILE_PERMISSION_USER_MASK); - - // Make sure the file in the directory can't be enumerated. - FileEnumerator f1(subdir_path, true, FileEnumerator::FILES); - EXPECT_TRUE(PathExists(subdir_path)); - FindResultCollector c1(&f1); - EXPECT_EQ(0, c1.size()); - EXPECT_FALSE(GetPosixFilePermissions(file_name, &mode)); - - // Give the permissions to the directory. - EXPECT_TRUE(SetPosixFilePermissions(subdir_path, FILE_PERMISSION_USER_MASK)); - EXPECT_TRUE(GetPosixFilePermissions(subdir_path, &mode)); - EXPECT_EQ(FILE_PERMISSION_USER_MASK, mode & FILE_PERMISSION_USER_MASK); - - // Make sure the file in the directory can be enumerated. - FileEnumerator f2(subdir_path, true, FileEnumerator::FILES); - FindResultCollector c2(&f2); - EXPECT_TRUE(c2.HasFile(file_name)); - EXPECT_EQ(1, c2.size()); - - // Delete the file. - EXPECT_TRUE(DeleteFile(subdir_path, true)); - EXPECT_FALSE(PathExists(subdir_path)); -} - -TEST_F(FileUtilTest, ExecutableExistsInPath) { - // Create two directories that we will put in our PATH - const FilePath::CharType kDir1[] = FPL("dir1"); - const FilePath::CharType kDir2[] = FPL("dir2"); - - FilePath dir1 = temp_dir_.GetPath().Append(kDir1); - FilePath dir2 = temp_dir_.GetPath().Append(kDir2); - ASSERT_TRUE(CreateDirectory(dir1)); - ASSERT_TRUE(CreateDirectory(dir2)); - - test::ScopedEnvironmentVariableOverride scoped_env( - "PATH", dir1.value() + ":" + dir2.value()); - ASSERT_TRUE(scoped_env.IsOverridden()); - - const FilePath::CharType kRegularFileName[] = FPL("regular_file"); - const FilePath::CharType kExeFileName[] = FPL("exe"); - const FilePath::CharType kDneFileName[] = FPL("does_not_exist"); - - const FilePath kExePath = dir1.Append(kExeFileName); - const FilePath kRegularFilePath = dir2.Append(kRegularFileName); - - // Write file. - const std::string kData("hello"); - ASSERT_EQ(static_cast<int>(kData.length()), - WriteFile(kExePath, kData.data(), kData.length())); - ASSERT_TRUE(PathExists(kExePath)); - ASSERT_EQ(static_cast<int>(kData.length()), - WriteFile(kRegularFilePath, kData.data(), kData.length())); - ASSERT_TRUE(PathExists(kRegularFilePath)); - - ASSERT_TRUE(SetPosixFilePermissions(dir1.Append(kExeFileName), - FILE_PERMISSION_EXECUTE_BY_USER)); - - EXPECT_TRUE(ExecutableExistsInPath(scoped_env.GetEnv(), kExeFileName)); - EXPECT_FALSE(ExecutableExistsInPath(scoped_env.GetEnv(), kRegularFileName)); - EXPECT_FALSE(ExecutableExistsInPath(scoped_env.GetEnv(), kDneFileName)); -} - -TEST_F(FileUtilTest, CopyDirectoryPermissions) { - // Create a directory. - FilePath dir_name_from = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir")); - CreateDirectory(dir_name_from); - ASSERT_TRUE(PathExists(dir_name_from)); - - // Create some regular files under the directory with various permissions. - FilePath file_name_from = - dir_name_from.Append(FILE_PATH_LITERAL("Reggy-1.txt")); - CreateTextFile(file_name_from, L"Mordecai"); - ASSERT_TRUE(PathExists(file_name_from)); - ASSERT_TRUE(SetPosixFilePermissions(file_name_from, 0755)); - - FilePath file2_name_from = - dir_name_from.Append(FILE_PATH_LITERAL("Reggy-2.txt")); - CreateTextFile(file2_name_from, L"Rigby"); - ASSERT_TRUE(PathExists(file2_name_from)); - ASSERT_TRUE(SetPosixFilePermissions(file2_name_from, 0777)); - - FilePath file3_name_from = - dir_name_from.Append(FILE_PATH_LITERAL("Reggy-3.txt")); - CreateTextFile(file3_name_from, L"Benson"); - ASSERT_TRUE(PathExists(file3_name_from)); - ASSERT_TRUE(SetPosixFilePermissions(file3_name_from, 0400)); - - // Copy the directory recursively. - FilePath dir_name_to = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir")); - FilePath file_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("Reggy-1.txt")); - FilePath file2_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("Reggy-2.txt")); - FilePath file3_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("Reggy-3.txt")); - - ASSERT_FALSE(PathExists(dir_name_to)); - - EXPECT_TRUE(CopyDirectory(dir_name_from, dir_name_to, true)); - ASSERT_TRUE(PathExists(file_name_to)); - ASSERT_TRUE(PathExists(file2_name_to)); - ASSERT_TRUE(PathExists(file3_name_to)); - - int mode = 0; - int expected_mode; - ASSERT_TRUE(GetPosixFilePermissions(file_name_to, &mode)); -#if defined(OS_MACOSX) - expected_mode = 0755; -#elif defined(OS_CHROMEOS) - expected_mode = 0644; -#else - expected_mode = 0600; -#endif - EXPECT_EQ(expected_mode, mode); - - ASSERT_TRUE(GetPosixFilePermissions(file2_name_to, &mode)); -#if defined(OS_MACOSX) - expected_mode = 0755; -#elif defined(OS_CHROMEOS) - expected_mode = 0644; -#else - expected_mode = 0600; -#endif - EXPECT_EQ(expected_mode, mode); - - ASSERT_TRUE(GetPosixFilePermissions(file3_name_to, &mode)); -#if defined(OS_MACOSX) - expected_mode = 0600; -#elif defined(OS_CHROMEOS) - expected_mode = 0644; -#else - expected_mode = 0600; -#endif - EXPECT_EQ(expected_mode, mode); -} - -TEST_F(FileUtilTest, CopyDirectoryPermissionsOverExistingFile) { - // Create a directory. - FilePath dir_name_from = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir")); - CreateDirectory(dir_name_from); - ASSERT_TRUE(PathExists(dir_name_from)); - - // Create a file under the directory. - FilePath file_name_from = - dir_name_from.Append(FILE_PATH_LITERAL("Reggy-1.txt")); - CreateTextFile(file_name_from, L"Mordecai"); - ASSERT_TRUE(PathExists(file_name_from)); - ASSERT_TRUE(SetPosixFilePermissions(file_name_from, 0644)); - - // Create a directory. - FilePath dir_name_to = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir")); - CreateDirectory(dir_name_to); - ASSERT_TRUE(PathExists(dir_name_to)); - - // Create a file under the directory with wider permissions. - FilePath file_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("Reggy-1.txt")); - CreateTextFile(file_name_to, L"Rigby"); - ASSERT_TRUE(PathExists(file_name_to)); - ASSERT_TRUE(SetPosixFilePermissions(file_name_to, 0777)); - - // Ensure that when we copy the directory, the file contents are copied - // but the permissions on the destination are left alone. - EXPECT_TRUE(CopyDirectory(dir_name_from, dir_name_to, false)); - ASSERT_TRUE(PathExists(file_name_to)); - ASSERT_EQ(L"Mordecai", ReadTextFile(file_name_to)); - - int mode = 0; - ASSERT_TRUE(GetPosixFilePermissions(file_name_to, &mode)); - EXPECT_EQ(0777, mode); -} - -TEST_F(FileUtilTest, CopyDirectoryExclDoesNotOverwrite) { - // Create source directory. - FilePath dir_name_from = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir")); - CreateDirectory(dir_name_from); - ASSERT_TRUE(PathExists(dir_name_from)); - - // Create a file under the directory. - FilePath file_name_from = - dir_name_from.Append(FILE_PATH_LITERAL("Reggy-1.txt")); - CreateTextFile(file_name_from, L"Mordecai"); - ASSERT_TRUE(PathExists(file_name_from)); - - // Create destination directory. - FilePath dir_name_to = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir")); - CreateDirectory(dir_name_to); - ASSERT_TRUE(PathExists(dir_name_to)); - - // Create a file under the directory with the same name. - FilePath file_name_to = dir_name_to.Append(FILE_PATH_LITERAL("Reggy-1.txt")); - CreateTextFile(file_name_to, L"Rigby"); - ASSERT_TRUE(PathExists(file_name_to)); - - // Ensure that copying failed and the file was not overwritten. - EXPECT_FALSE(CopyDirectoryExcl(dir_name_from, dir_name_to, false)); - ASSERT_TRUE(PathExists(file_name_to)); - ASSERT_EQ(L"Rigby", ReadTextFile(file_name_to)); -} - -TEST_F(FileUtilTest, CopyDirectoryExclDirectoryOverExistingFile) { - // Create source directory. - FilePath dir_name_from = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir")); - CreateDirectory(dir_name_from); - ASSERT_TRUE(PathExists(dir_name_from)); - - // Create a subdirectory. - FilePath subdir_name_from = dir_name_from.Append(FILE_PATH_LITERAL("Subsub")); - CreateDirectory(subdir_name_from); - ASSERT_TRUE(PathExists(subdir_name_from)); - - // Create destination directory. - FilePath dir_name_to = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir")); - CreateDirectory(dir_name_to); - ASSERT_TRUE(PathExists(dir_name_to)); - - // Create a regular file under the directory with the same name. - FilePath file_name_to = dir_name_to.Append(FILE_PATH_LITERAL("Subsub")); - CreateTextFile(file_name_to, L"Rigby"); - ASSERT_TRUE(PathExists(file_name_to)); - - // Ensure that copying failed and the file was not overwritten. - EXPECT_FALSE(CopyDirectoryExcl(dir_name_from, dir_name_to, false)); - ASSERT_TRUE(PathExists(file_name_to)); - ASSERT_EQ(L"Rigby", ReadTextFile(file_name_to)); -} - -TEST_F(FileUtilTest, CopyDirectoryExclDirectoryOverExistingDirectory) { - // Create source directory. - FilePath dir_name_from = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir")); - CreateDirectory(dir_name_from); - ASSERT_TRUE(PathExists(dir_name_from)); - - // Create a subdirectory. - FilePath subdir_name_from = dir_name_from.Append(FILE_PATH_LITERAL("Subsub")); - CreateDirectory(subdir_name_from); - ASSERT_TRUE(PathExists(subdir_name_from)); - - // Create destination directory. - FilePath dir_name_to = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir")); - CreateDirectory(dir_name_to); - ASSERT_TRUE(PathExists(dir_name_to)); - - // Create a subdirectory under the directory with the same name. - FilePath subdir_name_to = dir_name_to.Append(FILE_PATH_LITERAL("Subsub")); - CreateDirectory(subdir_name_to); - ASSERT_TRUE(PathExists(subdir_name_to)); - - // Ensure that copying failed and the file was not overwritten. - EXPECT_FALSE(CopyDirectoryExcl(dir_name_from, dir_name_to, false)); -} - -TEST_F(FileUtilTest, CopyFileExecutablePermission) { - FilePath src = temp_dir_.GetPath().Append(FPL("src.txt")); - const std::wstring file_contents(L"Gooooooooooooooooooooogle"); - CreateTextFile(src, file_contents); - - ASSERT_TRUE(SetPosixFilePermissions(src, 0755)); - int mode = 0; - ASSERT_TRUE(GetPosixFilePermissions(src, &mode)); - EXPECT_EQ(0755, mode); - - FilePath dst = temp_dir_.GetPath().Append(FPL("dst.txt")); - ASSERT_TRUE(CopyFile(src, dst)); - EXPECT_EQ(file_contents, ReadTextFile(dst)); - - ASSERT_TRUE(GetPosixFilePermissions(dst, &mode)); - int expected_mode; -#if defined(OS_MACOSX) - expected_mode = 0755; -#elif defined(OS_CHROMEOS) - expected_mode = 0644; -#else - expected_mode = 0600; -#endif - EXPECT_EQ(expected_mode, mode); - ASSERT_TRUE(DeleteFile(dst, false)); - - ASSERT_TRUE(SetPosixFilePermissions(src, 0777)); - ASSERT_TRUE(GetPosixFilePermissions(src, &mode)); - EXPECT_EQ(0777, mode); - - ASSERT_TRUE(CopyFile(src, dst)); - EXPECT_EQ(file_contents, ReadTextFile(dst)); - - ASSERT_TRUE(GetPosixFilePermissions(dst, &mode)); -#if defined(OS_MACOSX) - expected_mode = 0755; -#elif defined(OS_CHROMEOS) - expected_mode = 0644; -#else - expected_mode = 0600; -#endif - EXPECT_EQ(expected_mode, mode); - ASSERT_TRUE(DeleteFile(dst, false)); - - ASSERT_TRUE(SetPosixFilePermissions(src, 0400)); - ASSERT_TRUE(GetPosixFilePermissions(src, &mode)); - EXPECT_EQ(0400, mode); - - ASSERT_TRUE(CopyFile(src, dst)); - EXPECT_EQ(file_contents, ReadTextFile(dst)); - - ASSERT_TRUE(GetPosixFilePermissions(dst, &mode)); -#if defined(OS_MACOSX) - expected_mode = 0600; -#elif defined(OS_CHROMEOS) - expected_mode = 0644; -#else - expected_mode = 0600; -#endif - EXPECT_EQ(expected_mode, mode); - - // This time, do not delete |dst|. Instead set its permissions to 0777. - ASSERT_TRUE(SetPosixFilePermissions(dst, 0777)); - ASSERT_TRUE(GetPosixFilePermissions(dst, &mode)); - EXPECT_EQ(0777, mode); - - // Overwrite it and check the permissions again. - ASSERT_TRUE(CopyFile(src, dst)); - EXPECT_EQ(file_contents, ReadTextFile(dst)); - ASSERT_TRUE(GetPosixFilePermissions(dst, &mode)); - EXPECT_EQ(0777, mode); -} - -#endif // defined(OS_POSIX) - -#if !defined(OS_FUCHSIA) - -TEST_F(FileUtilTest, CopyFileACL) { - // While FileUtilTest.CopyFile asserts the content is correctly copied over, - // this test case asserts the access control bits are meeting expectations in - // CopyFile(). - FilePath src = temp_dir_.GetPath().Append(FILE_PATH_LITERAL("src.txt")); - const std::wstring file_contents(L"Gooooooooooooooooooooogle"); - CreateTextFile(src, file_contents); - - // Set the source file to read-only. - ASSERT_FALSE(IsReadOnly(src)); - SetReadOnly(src, true); - ASSERT_TRUE(IsReadOnly(src)); - - // Copy the file. - FilePath dst = temp_dir_.GetPath().Append(FILE_PATH_LITERAL("dst.txt")); - ASSERT_TRUE(CopyFile(src, dst)); - EXPECT_EQ(file_contents, ReadTextFile(dst)); - - ASSERT_FALSE(IsReadOnly(dst)); -} - -TEST_F(FileUtilTest, CopyDirectoryACL) { - // Create source directories. - FilePath src = temp_dir_.GetPath().Append(FILE_PATH_LITERAL("src")); - FilePath src_subdir = src.Append(FILE_PATH_LITERAL("subdir")); - CreateDirectory(src_subdir); - ASSERT_TRUE(PathExists(src_subdir)); - - // Create a file under the directory. - FilePath src_file = src.Append(FILE_PATH_LITERAL("src.txt")); - CreateTextFile(src_file, L"Gooooooooooooooooooooogle"); - SetReadOnly(src_file, true); - ASSERT_TRUE(IsReadOnly(src_file)); - - // Make directory read-only. - SetReadOnly(src_subdir, true); - ASSERT_TRUE(IsReadOnly(src_subdir)); - - // Copy the directory recursively. - FilePath dst = temp_dir_.GetPath().Append(FILE_PATH_LITERAL("dst")); - FilePath dst_file = dst.Append(FILE_PATH_LITERAL("src.txt")); - EXPECT_TRUE(CopyDirectory(src, dst, true)); - - FilePath dst_subdir = dst.Append(FILE_PATH_LITERAL("subdir")); - ASSERT_FALSE(IsReadOnly(dst_subdir)); - ASSERT_FALSE(IsReadOnly(dst_file)); - - // Give write permissions to allow deletion. - SetReadOnly(src_subdir, false); - ASSERT_FALSE(IsReadOnly(src_subdir)); -} - -#endif // !defined(OS_FUCHSIA) - -TEST_F(FileUtilTest, DeleteNonExistent) { - FilePath non_existent = - temp_dir_.GetPath().AppendASCII("bogus_file_dne.foobar"); - ASSERT_FALSE(PathExists(non_existent)); - - EXPECT_TRUE(DeleteFile(non_existent, false)); - ASSERT_FALSE(PathExists(non_existent)); - EXPECT_TRUE(DeleteFile(non_existent, true)); - ASSERT_FALSE(PathExists(non_existent)); -} - -TEST_F(FileUtilTest, DeleteNonExistentWithNonExistentParent) { - FilePath non_existent = temp_dir_.GetPath().AppendASCII("bogus_topdir"); - non_existent = non_existent.AppendASCII("bogus_subdir"); - ASSERT_FALSE(PathExists(non_existent)); - - EXPECT_TRUE(DeleteFile(non_existent, false)); - ASSERT_FALSE(PathExists(non_existent)); - EXPECT_TRUE(DeleteFile(non_existent, true)); - ASSERT_FALSE(PathExists(non_existent)); -} - -TEST_F(FileUtilTest, DeleteFile) { - // Create a file - FilePath file_name = temp_dir_.GetPath().Append(FPL("Test DeleteFile 1.txt")); - CreateTextFile(file_name, bogus_content); - ASSERT_TRUE(PathExists(file_name)); - - // Make sure it's deleted - EXPECT_TRUE(DeleteFile(file_name, false)); - EXPECT_FALSE(PathExists(file_name)); - - // Test recursive case, create a new file - file_name = temp_dir_.GetPath().Append(FPL("Test DeleteFile 2.txt")); - CreateTextFile(file_name, bogus_content); - ASSERT_TRUE(PathExists(file_name)); - - // Make sure it's deleted - EXPECT_TRUE(DeleteFile(file_name, true)); - EXPECT_FALSE(PathExists(file_name)); -} - -#if defined(OS_WIN) -// Tests that the Delete function works for wild cards, especially -// with the recursion flag. Also coincidentally tests PathExists. -// TODO(erikkay): see if anyone's actually using this feature of the API -TEST_F(FileUtilTest, DeleteWildCard) { - // Create a file and a directory - FilePath file_name = - temp_dir_.GetPath().Append(FPL("Test DeleteWildCard.txt")); - CreateTextFile(file_name, bogus_content); - ASSERT_TRUE(PathExists(file_name)); - - FilePath subdir_path = temp_dir_.GetPath().Append(FPL("DeleteWildCardDir")); - CreateDirectory(subdir_path); - ASSERT_TRUE(PathExists(subdir_path)); - - // Create the wildcard path - FilePath directory_contents = temp_dir_.GetPath(); - directory_contents = directory_contents.Append(FPL("*")); - - // Delete non-recursively and check that only the file is deleted - EXPECT_TRUE(DeleteFile(directory_contents, false)); - EXPECT_FALSE(PathExists(file_name)); - EXPECT_TRUE(PathExists(subdir_path)); - - // Delete recursively and make sure all contents are deleted - EXPECT_TRUE(DeleteFile(directory_contents, true)); - EXPECT_FALSE(PathExists(file_name)); - EXPECT_FALSE(PathExists(subdir_path)); -} - -// TODO(erikkay): see if anyone's actually using this feature of the API -TEST_F(FileUtilTest, DeleteNonExistantWildCard) { - // Create a file and a directory - FilePath subdir_path = - temp_dir_.GetPath().Append(FPL("DeleteNonExistantWildCard")); - CreateDirectory(subdir_path); - ASSERT_TRUE(PathExists(subdir_path)); - - // Create the wildcard path - FilePath directory_contents = subdir_path; - directory_contents = directory_contents.Append(FPL("*")); - - // Delete non-recursively and check nothing got deleted - EXPECT_TRUE(DeleteFile(directory_contents, false)); - EXPECT_TRUE(PathExists(subdir_path)); - - // Delete recursively and check nothing got deleted - EXPECT_TRUE(DeleteFile(directory_contents, true)); - EXPECT_TRUE(PathExists(subdir_path)); -} -#endif - -// Tests non-recursive Delete() for a directory. -TEST_F(FileUtilTest, DeleteDirNonRecursive) { - // Create a subdirectory and put a file and two directories inside. - FilePath test_subdir = - temp_dir_.GetPath().Append(FPL("DeleteDirNonRecursive")); - CreateDirectory(test_subdir); - ASSERT_TRUE(PathExists(test_subdir)); - - FilePath file_name = test_subdir.Append(FPL("Test DeleteDir.txt")); - CreateTextFile(file_name, bogus_content); - ASSERT_TRUE(PathExists(file_name)); - - FilePath subdir_path1 = test_subdir.Append(FPL("TestSubDir1")); - CreateDirectory(subdir_path1); - ASSERT_TRUE(PathExists(subdir_path1)); - - FilePath subdir_path2 = test_subdir.Append(FPL("TestSubDir2")); - CreateDirectory(subdir_path2); - ASSERT_TRUE(PathExists(subdir_path2)); - - // Delete non-recursively and check that the empty dir got deleted - EXPECT_TRUE(DeleteFile(subdir_path2, false)); - EXPECT_FALSE(PathExists(subdir_path2)); - - // Delete non-recursively and check that nothing got deleted - EXPECT_FALSE(DeleteFile(test_subdir, false)); - EXPECT_TRUE(PathExists(test_subdir)); - EXPECT_TRUE(PathExists(file_name)); - EXPECT_TRUE(PathExists(subdir_path1)); -} - -// Tests recursive Delete() for a directory. -TEST_F(FileUtilTest, DeleteDirRecursive) { - // Create a subdirectory and put a file and two directories inside. - FilePath test_subdir = temp_dir_.GetPath().Append(FPL("DeleteDirRecursive")); - CreateDirectory(test_subdir); - ASSERT_TRUE(PathExists(test_subdir)); - - FilePath file_name = test_subdir.Append(FPL("Test DeleteDirRecursive.txt")); - CreateTextFile(file_name, bogus_content); - ASSERT_TRUE(PathExists(file_name)); - - FilePath subdir_path1 = test_subdir.Append(FPL("TestSubDir1")); - CreateDirectory(subdir_path1); - ASSERT_TRUE(PathExists(subdir_path1)); - - FilePath subdir_path2 = test_subdir.Append(FPL("TestSubDir2")); - CreateDirectory(subdir_path2); - ASSERT_TRUE(PathExists(subdir_path2)); - - // Delete recursively and check that the empty dir got deleted - EXPECT_TRUE(DeleteFile(subdir_path2, true)); - EXPECT_FALSE(PathExists(subdir_path2)); - - // Delete recursively and check that everything got deleted - EXPECT_TRUE(DeleteFile(test_subdir, true)); - EXPECT_FALSE(PathExists(file_name)); - EXPECT_FALSE(PathExists(subdir_path1)); - EXPECT_FALSE(PathExists(test_subdir)); -} - -// Tests recursive Delete() for a directory. -TEST_F(FileUtilTest, DeleteDirRecursiveWithOpenFile) { - // Create a subdirectory and put a file and two directories inside. - FilePath test_subdir = temp_dir_.GetPath().Append(FPL("DeleteWithOpenFile")); - CreateDirectory(test_subdir); - ASSERT_TRUE(PathExists(test_subdir)); - - FilePath file_name1 = test_subdir.Append(FPL("Undeletebable File1.txt")); - File file1(file_name1, - File::FLAG_CREATE | File::FLAG_READ | File::FLAG_WRITE); - ASSERT_TRUE(PathExists(file_name1)); - - FilePath file_name2 = test_subdir.Append(FPL("Deleteable File2.txt")); - CreateTextFile(file_name2, bogus_content); - ASSERT_TRUE(PathExists(file_name2)); - - FilePath file_name3 = test_subdir.Append(FPL("Undeletebable File3.txt")); - File file3(file_name3, - File::FLAG_CREATE | File::FLAG_READ | File::FLAG_WRITE); - ASSERT_TRUE(PathExists(file_name3)); - -#if defined(OS_LINUX) - // On Windows, holding the file open in sufficient to make it un-deletable. - // The POSIX code is verifiable on Linux by creating an "immutable" file but - // this is best-effort because it's not supported by all file systems. Both - // files will have the same flags so no need to get them individually. - int flags; - bool file_attrs_supported = - ioctl(file1.GetPlatformFile(), FS_IOC_GETFLAGS, &flags) == 0; - // Some filesystems (e.g. tmpfs) don't support file attributes. - if (file_attrs_supported) { - flags |= FS_IMMUTABLE_FL; - ioctl(file1.GetPlatformFile(), FS_IOC_SETFLAGS, &flags); - ioctl(file3.GetPlatformFile(), FS_IOC_SETFLAGS, &flags); - } -#endif - - // Delete recursively and check that at least the second file got deleted. - // This ensures that un-deletable files don't impact those that can be. - DeleteFile(test_subdir, true); - EXPECT_FALSE(PathExists(file_name2)); - -#if defined(OS_LINUX) - // Make sure that the test can clean up after itself. - if (file_attrs_supported) { - flags &= ~FS_IMMUTABLE_FL; - ioctl(file1.GetPlatformFile(), FS_IOC_SETFLAGS, &flags); - ioctl(file3.GetPlatformFile(), FS_IOC_SETFLAGS, &flags); - } -#endif -} - -TEST_F(FileUtilTest, MoveFileNew) { - // Create a file - FilePath file_name_from = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Move_Test_File.txt")); - CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(PathExists(file_name_from)); - - // The destination. - FilePath file_name_to = temp_dir_.GetPath().Append( - FILE_PATH_LITERAL("Move_Test_File_Destination.txt")); - ASSERT_FALSE(PathExists(file_name_to)); - - EXPECT_TRUE(Move(file_name_from, file_name_to)); - - // Check everything has been moved. - EXPECT_FALSE(PathExists(file_name_from)); - EXPECT_TRUE(PathExists(file_name_to)); -} - -TEST_F(FileUtilTest, MoveFileExists) { - // Create a file - FilePath file_name_from = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Move_Test_File.txt")); - CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(PathExists(file_name_from)); - - // The destination name. - FilePath file_name_to = temp_dir_.GetPath().Append( - FILE_PATH_LITERAL("Move_Test_File_Destination.txt")); - CreateTextFile(file_name_to, L"Old file content"); - ASSERT_TRUE(PathExists(file_name_to)); - - EXPECT_TRUE(Move(file_name_from, file_name_to)); - - // Check everything has been moved. - EXPECT_FALSE(PathExists(file_name_from)); - EXPECT_TRUE(PathExists(file_name_to)); - EXPECT_TRUE(L"Gooooooooooooooooooooogle" == ReadTextFile(file_name_to)); -} - -TEST_F(FileUtilTest, MoveFileDirExists) { - // Create a file - FilePath file_name_from = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Move_Test_File.txt")); - CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(PathExists(file_name_from)); - - // The destination directory - FilePath dir_name_to = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Destination")); - CreateDirectory(dir_name_to); - ASSERT_TRUE(PathExists(dir_name_to)); - - EXPECT_FALSE(Move(file_name_from, dir_name_to)); -} - - -TEST_F(FileUtilTest, MoveNew) { - // Create a directory - FilePath dir_name_from = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Move_From_Subdir")); - CreateDirectory(dir_name_from); - ASSERT_TRUE(PathExists(dir_name_from)); - - // Create a file under the directory - FilePath txt_file_name(FILE_PATH_LITERAL("Move_Test_File.txt")); - FilePath file_name_from = dir_name_from.Append(txt_file_name); - CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(PathExists(file_name_from)); - - // Move the directory. - FilePath dir_name_to = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Move_To_Subdir")); - FilePath file_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("Move_Test_File.txt")); - - ASSERT_FALSE(PathExists(dir_name_to)); - - EXPECT_TRUE(Move(dir_name_from, dir_name_to)); - - // Check everything has been moved. - EXPECT_FALSE(PathExists(dir_name_from)); - EXPECT_FALSE(PathExists(file_name_from)); - EXPECT_TRUE(PathExists(dir_name_to)); - EXPECT_TRUE(PathExists(file_name_to)); - - // Test path traversal. - file_name_from = dir_name_to.Append(txt_file_name); - file_name_to = dir_name_to.Append(FILE_PATH_LITERAL("..")); - file_name_to = file_name_to.Append(txt_file_name); - EXPECT_FALSE(Move(file_name_from, file_name_to)); - EXPECT_TRUE(PathExists(file_name_from)); - EXPECT_FALSE(PathExists(file_name_to)); - EXPECT_TRUE(internal::MoveUnsafe(file_name_from, file_name_to)); - EXPECT_FALSE(PathExists(file_name_from)); - EXPECT_TRUE(PathExists(file_name_to)); -} - -TEST_F(FileUtilTest, MoveExist) { - // Create a directory - FilePath dir_name_from = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Move_From_Subdir")); - CreateDirectory(dir_name_from); - ASSERT_TRUE(PathExists(dir_name_from)); - - // Create a file under the directory - FilePath file_name_from = - dir_name_from.Append(FILE_PATH_LITERAL("Move_Test_File.txt")); - CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(PathExists(file_name_from)); - - // Move the directory - FilePath dir_name_exists = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Destination")); - - FilePath dir_name_to = - dir_name_exists.Append(FILE_PATH_LITERAL("Move_To_Subdir")); - FilePath file_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("Move_Test_File.txt")); - - // Create the destination directory. - CreateDirectory(dir_name_exists); - ASSERT_TRUE(PathExists(dir_name_exists)); - - EXPECT_TRUE(Move(dir_name_from, dir_name_to)); - - // Check everything has been moved. - EXPECT_FALSE(PathExists(dir_name_from)); - EXPECT_FALSE(PathExists(file_name_from)); - EXPECT_TRUE(PathExists(dir_name_to)); - EXPECT_TRUE(PathExists(file_name_to)); -} - -TEST_F(FileUtilTest, CopyDirectoryRecursivelyNew) { - // Create a directory. - FilePath dir_name_from = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir")); - CreateDirectory(dir_name_from); - ASSERT_TRUE(PathExists(dir_name_from)); - - // Create a file under the directory. - FilePath file_name_from = - dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(PathExists(file_name_from)); - - // Create a subdirectory. - FilePath subdir_name_from = - dir_name_from.Append(FILE_PATH_LITERAL("Subdir")); - CreateDirectory(subdir_name_from); - ASSERT_TRUE(PathExists(subdir_name_from)); - - // Create a file under the subdirectory. - FilePath file_name2_from = - subdir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - CreateTextFile(file_name2_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(PathExists(file_name2_from)); - - // Copy the directory recursively. - FilePath dir_name_to = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir")); - FilePath file_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - FilePath subdir_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("Subdir")); - FilePath file_name2_to = - subdir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - - ASSERT_FALSE(PathExists(dir_name_to)); - - EXPECT_TRUE(CopyDirectory(dir_name_from, dir_name_to, true)); - - // Check everything has been copied. - EXPECT_TRUE(PathExists(dir_name_from)); - EXPECT_TRUE(PathExists(file_name_from)); - EXPECT_TRUE(PathExists(subdir_name_from)); - EXPECT_TRUE(PathExists(file_name2_from)); - EXPECT_TRUE(PathExists(dir_name_to)); - EXPECT_TRUE(PathExists(file_name_to)); - EXPECT_TRUE(PathExists(subdir_name_to)); - EXPECT_TRUE(PathExists(file_name2_to)); -} - -TEST_F(FileUtilTest, CopyDirectoryRecursivelyExists) { - // Create a directory. - FilePath dir_name_from = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir")); - CreateDirectory(dir_name_from); - ASSERT_TRUE(PathExists(dir_name_from)); - - // Create a file under the directory. - FilePath file_name_from = - dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(PathExists(file_name_from)); - - // Create a subdirectory. - FilePath subdir_name_from = - dir_name_from.Append(FILE_PATH_LITERAL("Subdir")); - CreateDirectory(subdir_name_from); - ASSERT_TRUE(PathExists(subdir_name_from)); - - // Create a file under the subdirectory. - FilePath file_name2_from = - subdir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - CreateTextFile(file_name2_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(PathExists(file_name2_from)); - - // Copy the directory recursively. - FilePath dir_name_exists = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Destination")); - - FilePath dir_name_to = - dir_name_exists.Append(FILE_PATH_LITERAL("Copy_From_Subdir")); - FilePath file_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - FilePath subdir_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("Subdir")); - FilePath file_name2_to = - subdir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - - // Create the destination directory. - CreateDirectory(dir_name_exists); - ASSERT_TRUE(PathExists(dir_name_exists)); - - EXPECT_TRUE(CopyDirectory(dir_name_from, dir_name_exists, true)); - - // Check everything has been copied. - EXPECT_TRUE(PathExists(dir_name_from)); - EXPECT_TRUE(PathExists(file_name_from)); - EXPECT_TRUE(PathExists(subdir_name_from)); - EXPECT_TRUE(PathExists(file_name2_from)); - EXPECT_TRUE(PathExists(dir_name_to)); - EXPECT_TRUE(PathExists(file_name_to)); - EXPECT_TRUE(PathExists(subdir_name_to)); - EXPECT_TRUE(PathExists(file_name2_to)); -} - -TEST_F(FileUtilTest, CopyDirectoryNew) { - // Create a directory. - FilePath dir_name_from = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir")); - CreateDirectory(dir_name_from); - ASSERT_TRUE(PathExists(dir_name_from)); - - // Create a file under the directory. - FilePath file_name_from = - dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(PathExists(file_name_from)); - - // Create a subdirectory. - FilePath subdir_name_from = - dir_name_from.Append(FILE_PATH_LITERAL("Subdir")); - CreateDirectory(subdir_name_from); - ASSERT_TRUE(PathExists(subdir_name_from)); - - // Create a file under the subdirectory. - FilePath file_name2_from = - subdir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - CreateTextFile(file_name2_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(PathExists(file_name2_from)); - - // Copy the directory not recursively. - FilePath dir_name_to = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir")); - FilePath file_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - FilePath subdir_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("Subdir")); - - ASSERT_FALSE(PathExists(dir_name_to)); - - EXPECT_TRUE(CopyDirectory(dir_name_from, dir_name_to, false)); - - // Check everything has been copied. - EXPECT_TRUE(PathExists(dir_name_from)); - EXPECT_TRUE(PathExists(file_name_from)); - EXPECT_TRUE(PathExists(subdir_name_from)); - EXPECT_TRUE(PathExists(file_name2_from)); - EXPECT_TRUE(PathExists(dir_name_to)); - EXPECT_TRUE(PathExists(file_name_to)); - EXPECT_FALSE(PathExists(subdir_name_to)); -} - -TEST_F(FileUtilTest, CopyDirectoryExists) { - // Create a directory. - FilePath dir_name_from = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir")); - CreateDirectory(dir_name_from); - ASSERT_TRUE(PathExists(dir_name_from)); - - // Create a file under the directory. - FilePath file_name_from = - dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(PathExists(file_name_from)); - - // Create a subdirectory. - FilePath subdir_name_from = - dir_name_from.Append(FILE_PATH_LITERAL("Subdir")); - CreateDirectory(subdir_name_from); - ASSERT_TRUE(PathExists(subdir_name_from)); - - // Create a file under the subdirectory. - FilePath file_name2_from = - subdir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - CreateTextFile(file_name2_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(PathExists(file_name2_from)); - - // Copy the directory not recursively. - FilePath dir_name_to = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir")); - FilePath file_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - FilePath subdir_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("Subdir")); - - // Create the destination directory. - CreateDirectory(dir_name_to); - ASSERT_TRUE(PathExists(dir_name_to)); - - EXPECT_TRUE(CopyDirectory(dir_name_from, dir_name_to, false)); - - // Check everything has been copied. - EXPECT_TRUE(PathExists(dir_name_from)); - EXPECT_TRUE(PathExists(file_name_from)); - EXPECT_TRUE(PathExists(subdir_name_from)); - EXPECT_TRUE(PathExists(file_name2_from)); - EXPECT_TRUE(PathExists(dir_name_to)); - EXPECT_TRUE(PathExists(file_name_to)); - EXPECT_FALSE(PathExists(subdir_name_to)); -} - -TEST_F(FileUtilTest, CopyFileWithCopyDirectoryRecursiveToNew) { - // Create a file - FilePath file_name_from = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(PathExists(file_name_from)); - - // The destination name - FilePath file_name_to = temp_dir_.GetPath().Append( - FILE_PATH_LITERAL("Copy_Test_File_Destination.txt")); - ASSERT_FALSE(PathExists(file_name_to)); - - EXPECT_TRUE(CopyDirectory(file_name_from, file_name_to, true)); - - // Check the has been copied - EXPECT_TRUE(PathExists(file_name_to)); -} - -TEST_F(FileUtilTest, CopyFileWithCopyDirectoryRecursiveToExisting) { - // Create a file - FilePath file_name_from = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(PathExists(file_name_from)); - - // The destination name - FilePath file_name_to = temp_dir_.GetPath().Append( - FILE_PATH_LITERAL("Copy_Test_File_Destination.txt")); - CreateTextFile(file_name_to, L"Old file content"); - ASSERT_TRUE(PathExists(file_name_to)); - - EXPECT_TRUE(CopyDirectory(file_name_from, file_name_to, true)); - - // Check the has been copied - EXPECT_TRUE(PathExists(file_name_to)); - EXPECT_TRUE(L"Gooooooooooooooooooooogle" == ReadTextFile(file_name_to)); -} - -TEST_F(FileUtilTest, CopyFileWithCopyDirectoryRecursiveToExistingDirectory) { - // Create a file - FilePath file_name_from = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(PathExists(file_name_from)); - - // The destination - FilePath dir_name_to = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Destination")); - CreateDirectory(dir_name_to); - ASSERT_TRUE(PathExists(dir_name_to)); - FilePath file_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - - EXPECT_TRUE(CopyDirectory(file_name_from, dir_name_to, true)); - - // Check the has been copied - EXPECT_TRUE(PathExists(file_name_to)); -} - -TEST_F(FileUtilTest, CopyFileFailureWithCopyDirectoryExcl) { - // Create a file - FilePath file_name_from = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(PathExists(file_name_from)); - - // Make a destination file. - FilePath file_name_to = temp_dir_.GetPath().Append( - FILE_PATH_LITERAL("Copy_Test_File_Destination.txt")); - CreateTextFile(file_name_to, L"Old file content"); - ASSERT_TRUE(PathExists(file_name_to)); - - // Overwriting the destination should fail. - EXPECT_FALSE(CopyDirectoryExcl(file_name_from, file_name_to, true)); - EXPECT_EQ(L"Old file content", ReadTextFile(file_name_to)); -} - -TEST_F(FileUtilTest, CopyDirectoryWithTrailingSeparators) { - // Create a directory. - FilePath dir_name_from = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir")); - CreateDirectory(dir_name_from); - ASSERT_TRUE(PathExists(dir_name_from)); - - // Create a file under the directory. - FilePath file_name_from = - dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(PathExists(file_name_from)); - - // Copy the directory recursively. - FilePath dir_name_to = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir")); - FilePath file_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - - // Create from path with trailing separators. -#if defined(OS_WIN) - FilePath from_path = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir\\\\\\")); -#elif defined(OS_POSIX) || defined(OS_FUCHSIA) - FilePath from_path = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir///")); -#endif - - EXPECT_TRUE(CopyDirectory(from_path, dir_name_to, true)); - - // Check everything has been copied. - EXPECT_TRUE(PathExists(dir_name_from)); - EXPECT_TRUE(PathExists(file_name_from)); - EXPECT_TRUE(PathExists(dir_name_to)); - EXPECT_TRUE(PathExists(file_name_to)); -} - -#if defined(OS_POSIX) -TEST_F(FileUtilTest, CopyDirectoryWithNonRegularFiles) { - // Create a directory. - FilePath dir_name_from = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir")); - ASSERT_TRUE(CreateDirectory(dir_name_from)); - ASSERT_TRUE(PathExists(dir_name_from)); - - // Create a file under the directory. - FilePath file_name_from = - dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(PathExists(file_name_from)); - - // Create a symbolic link under the directory pointing to that file. - FilePath symlink_name_from = - dir_name_from.Append(FILE_PATH_LITERAL("Symlink")); - ASSERT_TRUE(CreateSymbolicLink(file_name_from, symlink_name_from)); - ASSERT_TRUE(PathExists(symlink_name_from)); - - // Create a fifo under the directory. - FilePath fifo_name_from = - dir_name_from.Append(FILE_PATH_LITERAL("Fifo")); - ASSERT_EQ(0, mkfifo(fifo_name_from.value().c_str(), 0644)); - ASSERT_TRUE(PathExists(fifo_name_from)); - - // Copy the directory. - FilePath dir_name_to = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir")); - FilePath file_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - FilePath symlink_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("Symlink")); - FilePath fifo_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("Fifo")); - - ASSERT_FALSE(PathExists(dir_name_to)); - - EXPECT_TRUE(CopyDirectory(dir_name_from, dir_name_to, false)); - - // Check that only directories and regular files are copied. - EXPECT_TRUE(PathExists(dir_name_from)); - EXPECT_TRUE(PathExists(file_name_from)); - EXPECT_TRUE(PathExists(symlink_name_from)); - EXPECT_TRUE(PathExists(fifo_name_from)); - EXPECT_TRUE(PathExists(dir_name_to)); - EXPECT_TRUE(PathExists(file_name_to)); - EXPECT_FALSE(PathExists(symlink_name_to)); - EXPECT_FALSE(PathExists(fifo_name_to)); -} - -TEST_F(FileUtilTest, CopyDirectoryExclFileOverSymlink) { - // Create a directory. - FilePath dir_name_from = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir")); - ASSERT_TRUE(CreateDirectory(dir_name_from)); - ASSERT_TRUE(PathExists(dir_name_from)); - - // Create a file under the directory. - FilePath file_name_from = - dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(PathExists(file_name_from)); - - // Create a destination directory with a symlink of the same name. - FilePath dir_name_to = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir")); - ASSERT_TRUE(CreateDirectory(dir_name_to)); - ASSERT_TRUE(PathExists(dir_name_to)); - - FilePath symlink_target = - dir_name_to.Append(FILE_PATH_LITERAL("Symlink_Target.txt")); - CreateTextFile(symlink_target, L"asdf"); - ASSERT_TRUE(PathExists(symlink_target)); - - FilePath symlink_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - ASSERT_TRUE(CreateSymbolicLink(symlink_target, symlink_name_to)); - ASSERT_TRUE(PathExists(symlink_name_to)); - - // Check that copying fails. - EXPECT_FALSE(CopyDirectoryExcl(dir_name_from, dir_name_to, false)); -} - -TEST_F(FileUtilTest, CopyDirectoryExclDirectoryOverSymlink) { - // Create a directory. - FilePath dir_name_from = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir")); - ASSERT_TRUE(CreateDirectory(dir_name_from)); - ASSERT_TRUE(PathExists(dir_name_from)); - - // Create a subdirectory. - FilePath subdir_name_from = dir_name_from.Append(FILE_PATH_LITERAL("Subsub")); - CreateDirectory(subdir_name_from); - ASSERT_TRUE(PathExists(subdir_name_from)); - - // Create a destination directory with a symlink of the same name. - FilePath dir_name_to = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir")); - ASSERT_TRUE(CreateDirectory(dir_name_to)); - ASSERT_TRUE(PathExists(dir_name_to)); - - FilePath symlink_target = dir_name_to.Append(FILE_PATH_LITERAL("Subsub")); - CreateTextFile(symlink_target, L"asdf"); - ASSERT_TRUE(PathExists(symlink_target)); - - FilePath symlink_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - ASSERT_TRUE(CreateSymbolicLink(symlink_target, symlink_name_to)); - ASSERT_TRUE(PathExists(symlink_name_to)); - - // Check that copying fails. - EXPECT_FALSE(CopyDirectoryExcl(dir_name_from, dir_name_to, false)); -} - -TEST_F(FileUtilTest, CopyDirectoryExclFileOverDanglingSymlink) { - // Create a directory. - FilePath dir_name_from = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir")); - ASSERT_TRUE(CreateDirectory(dir_name_from)); - ASSERT_TRUE(PathExists(dir_name_from)); - - // Create a file under the directory. - FilePath file_name_from = - dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(PathExists(file_name_from)); - - // Create a destination directory with a dangling symlink of the same name. - FilePath dir_name_to = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir")); - ASSERT_TRUE(CreateDirectory(dir_name_to)); - ASSERT_TRUE(PathExists(dir_name_to)); - - FilePath symlink_target = - dir_name_to.Append(FILE_PATH_LITERAL("Symlink_Target.txt")); - CreateTextFile(symlink_target, L"asdf"); - ASSERT_TRUE(PathExists(symlink_target)); - - FilePath symlink_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - ASSERT_TRUE(CreateSymbolicLink(symlink_target, symlink_name_to)); - ASSERT_TRUE(PathExists(symlink_name_to)); - ASSERT_TRUE(DeleteFile(symlink_target, false)); - - // Check that copying fails and that no file was created for the symlink's - // referent. - EXPECT_FALSE(CopyDirectoryExcl(dir_name_from, dir_name_to, false)); - EXPECT_FALSE(PathExists(symlink_target)); -} - -TEST_F(FileUtilTest, CopyDirectoryExclDirectoryOverDanglingSymlink) { - // Create a directory. - FilePath dir_name_from = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir")); - ASSERT_TRUE(CreateDirectory(dir_name_from)); - ASSERT_TRUE(PathExists(dir_name_from)); - - // Create a subdirectory. - FilePath subdir_name_from = dir_name_from.Append(FILE_PATH_LITERAL("Subsub")); - CreateDirectory(subdir_name_from); - ASSERT_TRUE(PathExists(subdir_name_from)); - - // Create a destination directory with a dangling symlink of the same name. - FilePath dir_name_to = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir")); - ASSERT_TRUE(CreateDirectory(dir_name_to)); - ASSERT_TRUE(PathExists(dir_name_to)); - - FilePath symlink_target = - dir_name_to.Append(FILE_PATH_LITERAL("Symlink_Target.txt")); - CreateTextFile(symlink_target, L"asdf"); - ASSERT_TRUE(PathExists(symlink_target)); - - FilePath symlink_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - ASSERT_TRUE(CreateSymbolicLink(symlink_target, symlink_name_to)); - ASSERT_TRUE(PathExists(symlink_name_to)); - ASSERT_TRUE(DeleteFile(symlink_target, false)); - - // Check that copying fails and that no directory was created for the - // symlink's referent. - EXPECT_FALSE(CopyDirectoryExcl(dir_name_from, dir_name_to, false)); - EXPECT_FALSE(PathExists(symlink_target)); -} - -TEST_F(FileUtilTest, CopyDirectoryExclFileOverFifo) { - // Create a directory. - FilePath dir_name_from = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir")); - ASSERT_TRUE(CreateDirectory(dir_name_from)); - ASSERT_TRUE(PathExists(dir_name_from)); - - // Create a file under the directory. - FilePath file_name_from = - dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(PathExists(file_name_from)); - - // Create a destination directory with a fifo of the same name. - FilePath dir_name_to = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir")); - ASSERT_TRUE(CreateDirectory(dir_name_to)); - ASSERT_TRUE(PathExists(dir_name_to)); - - FilePath fifo_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - ASSERT_EQ(0, mkfifo(fifo_name_to.value().c_str(), 0644)); - ASSERT_TRUE(PathExists(fifo_name_to)); - - // Check that copying fails. - EXPECT_FALSE(CopyDirectoryExcl(dir_name_from, dir_name_to, false)); -} -#endif // defined(OS_POSIX) - -TEST_F(FileUtilTest, CopyFile) { - // Create a directory - FilePath dir_name_from = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir")); - ASSERT_TRUE(CreateDirectory(dir_name_from)); - ASSERT_TRUE(DirectoryExists(dir_name_from)); - - // Create a file under the directory - FilePath file_name_from = - dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - const std::wstring file_contents(L"Gooooooooooooooooooooogle"); - CreateTextFile(file_name_from, file_contents); - ASSERT_TRUE(PathExists(file_name_from)); - - // Copy the file. - FilePath dest_file = dir_name_from.Append(FILE_PATH_LITERAL("DestFile.txt")); - ASSERT_TRUE(CopyFile(file_name_from, dest_file)); - - // Try to copy the file to another location using '..' in the path. - FilePath dest_file2(dir_name_from); - dest_file2 = dest_file2.AppendASCII(".."); - dest_file2 = dest_file2.AppendASCII("DestFile.txt"); - ASSERT_FALSE(CopyFile(file_name_from, dest_file2)); - - FilePath dest_file2_test(dir_name_from); - dest_file2_test = dest_file2_test.DirName(); - dest_file2_test = dest_file2_test.AppendASCII("DestFile.txt"); - - // Check expected copy results. - EXPECT_TRUE(PathExists(file_name_from)); - EXPECT_TRUE(PathExists(dest_file)); - EXPECT_EQ(file_contents, ReadTextFile(dest_file)); - EXPECT_FALSE(PathExists(dest_file2_test)); - EXPECT_FALSE(PathExists(dest_file2)); - - // Change |file_name_from| contents. - const std::wstring new_file_contents(L"Moogle"); - CreateTextFile(file_name_from, new_file_contents); - ASSERT_TRUE(PathExists(file_name_from)); - EXPECT_EQ(new_file_contents, ReadTextFile(file_name_from)); - - // Overwrite |dest_file|. - ASSERT_TRUE(CopyFile(file_name_from, dest_file)); - EXPECT_TRUE(PathExists(dest_file)); - EXPECT_EQ(new_file_contents, ReadTextFile(dest_file)); - - // Create another directory. - FilePath dest_dir = temp_dir_.GetPath().Append(FPL("dest_dir")); - ASSERT_TRUE(CreateDirectory(dest_dir)); - EXPECT_TRUE(DirectoryExists(dest_dir)); - EXPECT_TRUE(IsDirectoryEmpty(dest_dir)); - - // Make sure CopyFile() cannot overwrite a directory. - ASSERT_FALSE(CopyFile(file_name_from, dest_dir)); - EXPECT_TRUE(DirectoryExists(dest_dir)); - EXPECT_TRUE(IsDirectoryEmpty(dest_dir)); -} - -// file_util winds up using autoreleased objects on the Mac, so this needs -// to be a PlatformTest. -typedef PlatformTest ReadOnlyFileUtilTest; - -TEST_F(ReadOnlyFileUtilTest, ContentsEqual) { - FilePath data_dir; - ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &data_dir)); - data_dir = data_dir.AppendASCII("file_util"); - ASSERT_TRUE(PathExists(data_dir)); - - FilePath original_file = - data_dir.Append(FILE_PATH_LITERAL("original.txt")); - FilePath same_file = - data_dir.Append(FILE_PATH_LITERAL("same.txt")); - FilePath same_length_file = - data_dir.Append(FILE_PATH_LITERAL("same_length.txt")); - FilePath different_file = - data_dir.Append(FILE_PATH_LITERAL("different.txt")); - FilePath different_first_file = - data_dir.Append(FILE_PATH_LITERAL("different_first.txt")); - FilePath different_last_file = - data_dir.Append(FILE_PATH_LITERAL("different_last.txt")); - FilePath empty1_file = - data_dir.Append(FILE_PATH_LITERAL("empty1.txt")); - FilePath empty2_file = - data_dir.Append(FILE_PATH_LITERAL("empty2.txt")); - FilePath shortened_file = - data_dir.Append(FILE_PATH_LITERAL("shortened.txt")); - FilePath binary_file = - data_dir.Append(FILE_PATH_LITERAL("binary_file.bin")); - FilePath binary_file_same = - data_dir.Append(FILE_PATH_LITERAL("binary_file_same.bin")); - FilePath binary_file_diff = - data_dir.Append(FILE_PATH_LITERAL("binary_file_diff.bin")); - - EXPECT_TRUE(ContentsEqual(original_file, original_file)); - EXPECT_TRUE(ContentsEqual(original_file, same_file)); - EXPECT_FALSE(ContentsEqual(original_file, same_length_file)); - EXPECT_FALSE(ContentsEqual(original_file, different_file)); - EXPECT_FALSE(ContentsEqual(FilePath(FILE_PATH_LITERAL("bogusname")), - FilePath(FILE_PATH_LITERAL("bogusname")))); - EXPECT_FALSE(ContentsEqual(original_file, different_first_file)); - EXPECT_FALSE(ContentsEqual(original_file, different_last_file)); - EXPECT_TRUE(ContentsEqual(empty1_file, empty2_file)); - EXPECT_FALSE(ContentsEqual(original_file, shortened_file)); - EXPECT_FALSE(ContentsEqual(shortened_file, original_file)); - EXPECT_TRUE(ContentsEqual(binary_file, binary_file_same)); - EXPECT_FALSE(ContentsEqual(binary_file, binary_file_diff)); -} - -TEST_F(ReadOnlyFileUtilTest, TextContentsEqual) { - FilePath data_dir; - ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &data_dir)); - data_dir = data_dir.AppendASCII("file_util"); - ASSERT_TRUE(PathExists(data_dir)); - - FilePath original_file = - data_dir.Append(FILE_PATH_LITERAL("original.txt")); - FilePath same_file = - data_dir.Append(FILE_PATH_LITERAL("same.txt")); - FilePath crlf_file = - data_dir.Append(FILE_PATH_LITERAL("crlf.txt")); - FilePath shortened_file = - data_dir.Append(FILE_PATH_LITERAL("shortened.txt")); - FilePath different_file = - data_dir.Append(FILE_PATH_LITERAL("different.txt")); - FilePath different_first_file = - data_dir.Append(FILE_PATH_LITERAL("different_first.txt")); - FilePath different_last_file = - data_dir.Append(FILE_PATH_LITERAL("different_last.txt")); - FilePath first1_file = - data_dir.Append(FILE_PATH_LITERAL("first1.txt")); - FilePath first2_file = - data_dir.Append(FILE_PATH_LITERAL("first2.txt")); - FilePath empty1_file = - data_dir.Append(FILE_PATH_LITERAL("empty1.txt")); - FilePath empty2_file = - data_dir.Append(FILE_PATH_LITERAL("empty2.txt")); - FilePath blank_line_file = - data_dir.Append(FILE_PATH_LITERAL("blank_line.txt")); - FilePath blank_line_crlf_file = - data_dir.Append(FILE_PATH_LITERAL("blank_line_crlf.txt")); - - EXPECT_TRUE(TextContentsEqual(original_file, same_file)); - EXPECT_TRUE(TextContentsEqual(original_file, crlf_file)); - EXPECT_FALSE(TextContentsEqual(original_file, shortened_file)); - EXPECT_FALSE(TextContentsEqual(original_file, different_file)); - EXPECT_FALSE(TextContentsEqual(original_file, different_first_file)); - EXPECT_FALSE(TextContentsEqual(original_file, different_last_file)); - EXPECT_FALSE(TextContentsEqual(first1_file, first2_file)); - EXPECT_TRUE(TextContentsEqual(empty1_file, empty2_file)); - EXPECT_FALSE(TextContentsEqual(original_file, empty1_file)); - EXPECT_TRUE(TextContentsEqual(blank_line_file, blank_line_crlf_file)); -} - -// We don't need equivalent functionality outside of Windows. -#if defined(OS_WIN) -TEST_F(FileUtilTest, CopyAndDeleteDirectoryTest) { - // Create a directory - FilePath dir_name_from = temp_dir_.GetPath().Append( - FILE_PATH_LITERAL("CopyAndDelete_From_Subdir")); - CreateDirectory(dir_name_from); - ASSERT_TRUE(PathExists(dir_name_from)); - - // Create a file under the directory - FilePath file_name_from = - dir_name_from.Append(FILE_PATH_LITERAL("CopyAndDelete_Test_File.txt")); - CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(PathExists(file_name_from)); - - // Move the directory by using CopyAndDeleteDirectory - FilePath dir_name_to = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("CopyAndDelete_To_Subdir")); - FilePath file_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("CopyAndDelete_Test_File.txt")); - - ASSERT_FALSE(PathExists(dir_name_to)); - - EXPECT_TRUE(internal::CopyAndDeleteDirectory(dir_name_from, - dir_name_to)); - - // Check everything has been moved. - EXPECT_FALSE(PathExists(dir_name_from)); - EXPECT_FALSE(PathExists(file_name_from)); - EXPECT_TRUE(PathExists(dir_name_to)); - EXPECT_TRUE(PathExists(file_name_to)); -} - -TEST_F(FileUtilTest, GetTempDirTest) { - static const TCHAR* kTmpKey = _T("TMP"); - static const TCHAR* kTmpValues[] = { - _T(""), _T("C:"), _T("C:\\"), _T("C:\\tmp"), _T("C:\\tmp\\") - }; - // Save the original $TMP. - size_t original_tmp_size; - TCHAR* original_tmp; - ASSERT_EQ(0, ::_tdupenv_s(&original_tmp, &original_tmp_size, kTmpKey)); - // original_tmp may be NULL. - - for (unsigned int i = 0; i < arraysize(kTmpValues); ++i) { - FilePath path; - ::_tputenv_s(kTmpKey, kTmpValues[i]); - GetTempDir(&path); - EXPECT_TRUE(path.IsAbsolute()) << "$TMP=" << kTmpValues[i] << - " result=" << path.value(); - } - - // Restore the original $TMP. - if (original_tmp) { - ::_tputenv_s(kTmpKey, original_tmp); - free(original_tmp); - } else { - ::_tputenv_s(kTmpKey, _T("")); - } -} -#endif // OS_WIN - -// Test that files opened by OpenFile are not set up for inheritance into child -// procs. -TEST_F(FileUtilTest, OpenFileNoInheritance) { - FilePath file_path(temp_dir_.GetPath().Append(FPL("a_file"))); - - for (const char* mode : {"wb", "r,ccs=UTF-8"}) { - SCOPED_TRACE(mode); - ASSERT_NO_FATAL_FAILURE(CreateTextFile(file_path, L"Geepers")); - FILE* file = OpenFile(file_path, mode); - ASSERT_NE(nullptr, file); - { - ScopedClosureRunner file_closer(Bind(IgnoreResult(&CloseFile), file)); - bool is_inheritable = true; - ASSERT_NO_FATAL_FAILURE(GetIsInheritable(file, &is_inheritable)); - EXPECT_FALSE(is_inheritable); - } - ASSERT_TRUE(DeleteFile(file_path, false)); - } -} - -TEST_F(FileUtilTest, CreateTemporaryFileTest) { - FilePath temp_files[3]; - for (int i = 0; i < 3; i++) { - ASSERT_TRUE(CreateTemporaryFile(&(temp_files[i]))); - EXPECT_TRUE(PathExists(temp_files[i])); - EXPECT_FALSE(DirectoryExists(temp_files[i])); - } - for (int i = 0; i < 3; i++) - EXPECT_FALSE(temp_files[i] == temp_files[(i+1)%3]); - for (int i = 0; i < 3; i++) - EXPECT_TRUE(DeleteFile(temp_files[i], false)); -} - -TEST_F(FileUtilTest, CreateAndOpenTemporaryFileTest) { - FilePath names[3]; - FILE* fps[3]; - int i; - - // Create; make sure they are open and exist. - for (i = 0; i < 3; ++i) { - fps[i] = CreateAndOpenTemporaryFile(&(names[i])); - ASSERT_TRUE(fps[i]); - EXPECT_TRUE(PathExists(names[i])); - } - - // Make sure all names are unique. - for (i = 0; i < 3; ++i) { - EXPECT_FALSE(names[i] == names[(i+1)%3]); - } - - // Close and delete. - for (i = 0; i < 3; ++i) { - EXPECT_TRUE(CloseFile(fps[i])); - EXPECT_TRUE(DeleteFile(names[i], false)); - } -} - -TEST_F(FileUtilTest, FileToFILE) { - File file; - FILE* stream = FileToFILE(std::move(file), "w"); - EXPECT_FALSE(stream); - - FilePath file_name = temp_dir_.GetPath().Append(FPL("The file.txt")); - file = File(file_name, File::FLAG_CREATE | File::FLAG_WRITE); - EXPECT_TRUE(file.IsValid()); - - stream = FileToFILE(std::move(file), "w"); - EXPECT_TRUE(stream); - EXPECT_FALSE(file.IsValid()); - EXPECT_TRUE(CloseFile(stream)); -} - -TEST_F(FileUtilTest, CreateNewTempDirectoryTest) { - FilePath temp_dir; - ASSERT_TRUE(CreateNewTempDirectory(FilePath::StringType(), &temp_dir)); - EXPECT_TRUE(PathExists(temp_dir)); - EXPECT_TRUE(DeleteFile(temp_dir, false)); -} - -TEST_F(FileUtilTest, CreateNewTemporaryDirInDirTest) { - FilePath new_dir; - ASSERT_TRUE(CreateTemporaryDirInDir( - temp_dir_.GetPath(), FILE_PATH_LITERAL("CreateNewTemporaryDirInDirTest"), - &new_dir)); - EXPECT_TRUE(PathExists(new_dir)); - EXPECT_TRUE(temp_dir_.GetPath().IsParent(new_dir)); - EXPECT_TRUE(DeleteFile(new_dir, false)); -} - -#if defined(OS_POSIX) || defined(OS_FUCHSIA) -TEST_F(FileUtilTest, GetShmemTempDirTest) { - FilePath dir; - EXPECT_TRUE(GetShmemTempDir(false, &dir)); - EXPECT_TRUE(DirectoryExists(dir)); -} -#endif - -TEST_F(FileUtilTest, GetHomeDirTest) { -#if !defined(OS_ANDROID) // Not implemented on Android. - // We don't actually know what the home directory is supposed to be without - // calling some OS functions which would just duplicate the implementation. - // So here we just test that it returns something "reasonable". - FilePath home = GetHomeDir(); - ASSERT_FALSE(home.empty()); - ASSERT_TRUE(home.IsAbsolute()); -#endif -} - -TEST_F(FileUtilTest, CreateDirectoryTest) { - FilePath test_root = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("create_directory_test")); -#if defined(OS_WIN) - FilePath test_path = - test_root.Append(FILE_PATH_LITERAL("dir\\tree\\likely\\doesnt\\exist\\")); -#elif defined(OS_POSIX) || defined(OS_FUCHSIA) - FilePath test_path = - test_root.Append(FILE_PATH_LITERAL("dir/tree/likely/doesnt/exist/")); -#endif - - EXPECT_FALSE(PathExists(test_path)); - EXPECT_TRUE(CreateDirectory(test_path)); - EXPECT_TRUE(PathExists(test_path)); - // CreateDirectory returns true if the DirectoryExists returns true. - EXPECT_TRUE(CreateDirectory(test_path)); - - // Doesn't work to create it on top of a non-dir - test_path = test_path.Append(FILE_PATH_LITERAL("foobar.txt")); - EXPECT_FALSE(PathExists(test_path)); - CreateTextFile(test_path, L"test file"); - EXPECT_TRUE(PathExists(test_path)); - EXPECT_FALSE(CreateDirectory(test_path)); - - EXPECT_TRUE(DeleteFile(test_root, true)); - EXPECT_FALSE(PathExists(test_root)); - EXPECT_FALSE(PathExists(test_path)); - - // Verify assumptions made by the Windows implementation: - // 1. The current directory always exists. - // 2. The root directory always exists. - ASSERT_TRUE(DirectoryExists(FilePath(FilePath::kCurrentDirectory))); - FilePath top_level = test_root; - while (top_level != top_level.DirName()) { - top_level = top_level.DirName(); - } - ASSERT_TRUE(DirectoryExists(top_level)); - - // Given these assumptions hold, it should be safe to - // test that "creating" these directories succeeds. - EXPECT_TRUE(CreateDirectory( - FilePath(FilePath::kCurrentDirectory))); - EXPECT_TRUE(CreateDirectory(top_level)); - -#if defined(OS_WIN) - FilePath invalid_drive(FILE_PATH_LITERAL("o:\\")); - FilePath invalid_path = - invalid_drive.Append(FILE_PATH_LITERAL("some\\inaccessible\\dir")); - if (!PathExists(invalid_drive)) { - EXPECT_FALSE(CreateDirectory(invalid_path)); - } -#endif -} - -TEST_F(FileUtilTest, DetectDirectoryTest) { - // Check a directory - FilePath test_root = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("detect_directory_test")); - EXPECT_FALSE(PathExists(test_root)); - EXPECT_TRUE(CreateDirectory(test_root)); - EXPECT_TRUE(PathExists(test_root)); - EXPECT_TRUE(DirectoryExists(test_root)); - // Check a file - FilePath test_path = - test_root.Append(FILE_PATH_LITERAL("foobar.txt")); - EXPECT_FALSE(PathExists(test_path)); - CreateTextFile(test_path, L"test file"); - EXPECT_TRUE(PathExists(test_path)); - EXPECT_FALSE(DirectoryExists(test_path)); - EXPECT_TRUE(DeleteFile(test_path, false)); - - EXPECT_TRUE(DeleteFile(test_root, true)); -} - -TEST_F(FileUtilTest, FileEnumeratorTest) { - // Test an empty directory. - FileEnumerator f0(temp_dir_.GetPath(), true, FILES_AND_DIRECTORIES); - EXPECT_EQ(FPL(""), f0.Next().value()); - EXPECT_EQ(FPL(""), f0.Next().value()); - - // Test an empty directory, non-recursively, including "..". - FileEnumerator f0_dotdot( - temp_dir_.GetPath(), false, - FILES_AND_DIRECTORIES | FileEnumerator::INCLUDE_DOT_DOT); - EXPECT_EQ(temp_dir_.GetPath().Append(FPL("..")).value(), - f0_dotdot.Next().value()); - EXPECT_EQ(FPL(""), f0_dotdot.Next().value()); - - // create the directories - FilePath dir1 = temp_dir_.GetPath().Append(FPL("dir1")); - EXPECT_TRUE(CreateDirectory(dir1)); - FilePath dir2 = temp_dir_.GetPath().Append(FPL("dir2")); - EXPECT_TRUE(CreateDirectory(dir2)); - FilePath dir2inner = dir2.Append(FPL("inner")); - EXPECT_TRUE(CreateDirectory(dir2inner)); - - // create the files - FilePath dir2file = dir2.Append(FPL("dir2file.txt")); - CreateTextFile(dir2file, std::wstring()); - FilePath dir2innerfile = dir2inner.Append(FPL("innerfile.txt")); - CreateTextFile(dir2innerfile, std::wstring()); - FilePath file1 = temp_dir_.GetPath().Append(FPL("file1.txt")); - CreateTextFile(file1, std::wstring()); - FilePath file2_rel = dir2.Append(FilePath::kParentDirectory) - .Append(FPL("file2.txt")); - CreateTextFile(file2_rel, std::wstring()); - FilePath file2_abs = temp_dir_.GetPath().Append(FPL("file2.txt")); - - // Only enumerate files. - FileEnumerator f1(temp_dir_.GetPath(), true, FileEnumerator::FILES); - FindResultCollector c1(&f1); - EXPECT_TRUE(c1.HasFile(file1)); - EXPECT_TRUE(c1.HasFile(file2_abs)); - EXPECT_TRUE(c1.HasFile(dir2file)); - EXPECT_TRUE(c1.HasFile(dir2innerfile)); - EXPECT_EQ(4, c1.size()); - - // Only enumerate directories. - FileEnumerator f2(temp_dir_.GetPath(), true, FileEnumerator::DIRECTORIES); - FindResultCollector c2(&f2); - EXPECT_TRUE(c2.HasFile(dir1)); - EXPECT_TRUE(c2.HasFile(dir2)); - EXPECT_TRUE(c2.HasFile(dir2inner)); - EXPECT_EQ(3, c2.size()); - - // Only enumerate directories non-recursively. - FileEnumerator f2_non_recursive(temp_dir_.GetPath(), false, - FileEnumerator::DIRECTORIES); - FindResultCollector c2_non_recursive(&f2_non_recursive); - EXPECT_TRUE(c2_non_recursive.HasFile(dir1)); - EXPECT_TRUE(c2_non_recursive.HasFile(dir2)); - EXPECT_EQ(2, c2_non_recursive.size()); - - // Only enumerate directories, non-recursively, including "..". - FileEnumerator f2_dotdot( - temp_dir_.GetPath(), false, - FileEnumerator::DIRECTORIES | FileEnumerator::INCLUDE_DOT_DOT); - FindResultCollector c2_dotdot(&f2_dotdot); - EXPECT_TRUE(c2_dotdot.HasFile(dir1)); - EXPECT_TRUE(c2_dotdot.HasFile(dir2)); - EXPECT_TRUE(c2_dotdot.HasFile(temp_dir_.GetPath().Append(FPL("..")))); - EXPECT_EQ(3, c2_dotdot.size()); - - // Enumerate files and directories. - FileEnumerator f3(temp_dir_.GetPath(), true, FILES_AND_DIRECTORIES); - FindResultCollector c3(&f3); - EXPECT_TRUE(c3.HasFile(dir1)); - EXPECT_TRUE(c3.HasFile(dir2)); - EXPECT_TRUE(c3.HasFile(file1)); - EXPECT_TRUE(c3.HasFile(file2_abs)); - EXPECT_TRUE(c3.HasFile(dir2file)); - EXPECT_TRUE(c3.HasFile(dir2inner)); - EXPECT_TRUE(c3.HasFile(dir2innerfile)); - EXPECT_EQ(7, c3.size()); - - // Non-recursive operation. - FileEnumerator f4(temp_dir_.GetPath(), false, FILES_AND_DIRECTORIES); - FindResultCollector c4(&f4); - EXPECT_TRUE(c4.HasFile(dir2)); - EXPECT_TRUE(c4.HasFile(dir2)); - EXPECT_TRUE(c4.HasFile(file1)); - EXPECT_TRUE(c4.HasFile(file2_abs)); - EXPECT_EQ(4, c4.size()); - - // Enumerate with a pattern. - FileEnumerator f5(temp_dir_.GetPath(), true, FILES_AND_DIRECTORIES, - FPL("dir*")); - FindResultCollector c5(&f5); - EXPECT_TRUE(c5.HasFile(dir1)); - EXPECT_TRUE(c5.HasFile(dir2)); - EXPECT_TRUE(c5.HasFile(dir2file)); - EXPECT_TRUE(c5.HasFile(dir2inner)); - EXPECT_TRUE(c5.HasFile(dir2innerfile)); - EXPECT_EQ(5, c5.size()); - -#if defined(OS_WIN) - { - // Make dir1 point to dir2. - ReparsePoint reparse_point(dir1, dir2); - EXPECT_TRUE(reparse_point.IsValid()); - - // There can be a delay for the enumeration code to see the change on - // the file system so skip this test for XP. - // Enumerate the reparse point. - FileEnumerator f6(dir1, true, FILES_AND_DIRECTORIES); - FindResultCollector c6(&f6); - FilePath inner2 = dir1.Append(FPL("inner")); - EXPECT_TRUE(c6.HasFile(inner2)); - EXPECT_TRUE(c6.HasFile(inner2.Append(FPL("innerfile.txt")))); - EXPECT_TRUE(c6.HasFile(dir1.Append(FPL("dir2file.txt")))); - EXPECT_EQ(3, c6.size()); - - // No changes for non recursive operation. - FileEnumerator f7(temp_dir_.GetPath(), false, FILES_AND_DIRECTORIES); - FindResultCollector c7(&f7); - EXPECT_TRUE(c7.HasFile(dir2)); - EXPECT_TRUE(c7.HasFile(dir2)); - EXPECT_TRUE(c7.HasFile(file1)); - EXPECT_TRUE(c7.HasFile(file2_abs)); - EXPECT_EQ(4, c7.size()); - - // Should not enumerate inside dir1 when using recursion. - FileEnumerator f8(temp_dir_.GetPath(), true, FILES_AND_DIRECTORIES); - FindResultCollector c8(&f8); - EXPECT_TRUE(c8.HasFile(dir1)); - EXPECT_TRUE(c8.HasFile(dir2)); - EXPECT_TRUE(c8.HasFile(file1)); - EXPECT_TRUE(c8.HasFile(file2_abs)); - EXPECT_TRUE(c8.HasFile(dir2file)); - EXPECT_TRUE(c8.HasFile(dir2inner)); - EXPECT_TRUE(c8.HasFile(dir2innerfile)); - EXPECT_EQ(7, c8.size()); - } -#endif - - // Make sure the destructor closes the find handle while in the middle of a - // query to allow TearDown to delete the directory. - FileEnumerator f9(temp_dir_.GetPath(), true, FILES_AND_DIRECTORIES); - EXPECT_FALSE(f9.Next().value().empty()); // Should have found something - // (we don't care what). -} - -TEST_F(FileUtilTest, AppendToFile) { - FilePath data_dir = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("FilePathTest")); - - // Create a fresh, empty copy of this directory. - if (PathExists(data_dir)) { - ASSERT_TRUE(DeleteFile(data_dir, true)); - } - ASSERT_TRUE(CreateDirectory(data_dir)); - - // Create a fresh, empty copy of this directory. - if (PathExists(data_dir)) { - ASSERT_TRUE(DeleteFile(data_dir, true)); - } - ASSERT_TRUE(CreateDirectory(data_dir)); - FilePath foobar(data_dir.Append(FILE_PATH_LITERAL("foobar.txt"))); - - std::string data("hello"); - EXPECT_FALSE(AppendToFile(foobar, data.c_str(), data.size())); - EXPECT_EQ(static_cast<int>(data.length()), - WriteFile(foobar, data.c_str(), data.length())); - EXPECT_TRUE(AppendToFile(foobar, data.c_str(), data.size())); - - const std::wstring read_content = ReadTextFile(foobar); - EXPECT_EQ(L"hellohello", read_content); -} - -TEST_F(FileUtilTest, ReadFile) { - // Create a test file to be read. - const std::string kTestData("The quick brown fox jumps over the lazy dog."); - FilePath file_path = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("ReadFileTest")); - - ASSERT_EQ(static_cast<int>(kTestData.size()), - WriteFile(file_path, kTestData.data(), kTestData.size())); - - // Make buffers with various size. - std::vector<char> small_buffer(kTestData.size() / 2); - std::vector<char> exact_buffer(kTestData.size()); - std::vector<char> large_buffer(kTestData.size() * 2); - - // Read the file with smaller buffer. - int bytes_read_small = ReadFile( - file_path, &small_buffer[0], static_cast<int>(small_buffer.size())); - EXPECT_EQ(static_cast<int>(small_buffer.size()), bytes_read_small); - EXPECT_EQ( - std::string(kTestData.begin(), kTestData.begin() + small_buffer.size()), - std::string(small_buffer.begin(), small_buffer.end())); - - // Read the file with buffer which have exactly same size. - int bytes_read_exact = ReadFile( - file_path, &exact_buffer[0], static_cast<int>(exact_buffer.size())); - EXPECT_EQ(static_cast<int>(kTestData.size()), bytes_read_exact); - EXPECT_EQ(kTestData, std::string(exact_buffer.begin(), exact_buffer.end())); - - // Read the file with larger buffer. - int bytes_read_large = ReadFile( - file_path, &large_buffer[0], static_cast<int>(large_buffer.size())); - EXPECT_EQ(static_cast<int>(kTestData.size()), bytes_read_large); - EXPECT_EQ(kTestData, std::string(large_buffer.begin(), - large_buffer.begin() + kTestData.size())); - - // Make sure the return value is -1 if the file doesn't exist. - FilePath file_path_not_exist = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("ReadFileNotExistTest")); - EXPECT_EQ(-1, - ReadFile(file_path_not_exist, - &exact_buffer[0], - static_cast<int>(exact_buffer.size()))); -} - -TEST_F(FileUtilTest, ReadFileToString) { - const char kTestData[] = "0123"; - std::string data; - - FilePath file_path = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("ReadFileToStringTest")); - FilePath file_path_dangerous = - temp_dir_.GetPath() - .Append(FILE_PATH_LITERAL("..")) - .Append(temp_dir_.GetPath().BaseName()) - .Append(FILE_PATH_LITERAL("ReadFileToStringTest")); - - // Create test file. - ASSERT_EQ(static_cast<int>(strlen(kTestData)), - WriteFile(file_path, kTestData, strlen(kTestData))); - - EXPECT_TRUE(ReadFileToString(file_path, &data)); - EXPECT_EQ(kTestData, data); - - data = "temp"; - EXPECT_FALSE(ReadFileToStringWithMaxSize(file_path, &data, 0)); - EXPECT_EQ(0u, data.length()); - - data = "temp"; - EXPECT_FALSE(ReadFileToStringWithMaxSize(file_path, &data, 2)); - EXPECT_EQ("01", data); - - data = "temp"; - EXPECT_FALSE(ReadFileToStringWithMaxSize(file_path, &data, 3)); - EXPECT_EQ("012", data); - - data = "temp"; - EXPECT_TRUE(ReadFileToStringWithMaxSize(file_path, &data, 4)); - EXPECT_EQ("0123", data); - - data = "temp"; - EXPECT_TRUE(ReadFileToStringWithMaxSize(file_path, &data, 6)); - EXPECT_EQ("0123", data); - - EXPECT_TRUE(ReadFileToStringWithMaxSize(file_path, nullptr, 6)); - - EXPECT_TRUE(ReadFileToString(file_path, nullptr)); - - data = "temp"; - EXPECT_FALSE(ReadFileToString(file_path_dangerous, &data)); - EXPECT_EQ(0u, data.length()); - - // Delete test file. - EXPECT_TRUE(DeleteFile(file_path, false)); - - data = "temp"; - EXPECT_FALSE(ReadFileToString(file_path, &data)); - EXPECT_EQ(0u, data.length()); - - data = "temp"; - EXPECT_FALSE(ReadFileToStringWithMaxSize(file_path, &data, 6)); - EXPECT_EQ(0u, data.length()); -} - -#if !defined(OS_WIN) -TEST_F(FileUtilTest, ReadFileToStringWithUnknownFileSize) { - FilePath file_path("/dev/zero"); - std::string data = "temp"; - - EXPECT_FALSE(ReadFileToStringWithMaxSize(file_path, &data, 0)); - EXPECT_EQ(0u, data.length()); - - data = "temp"; - EXPECT_FALSE(ReadFileToStringWithMaxSize(file_path, &data, 2)); - EXPECT_EQ(std::string(2, '\0'), data); - - EXPECT_FALSE(ReadFileToStringWithMaxSize(file_path, nullptr, 6)); - - // Read more than buffer size. - data = "temp"; - EXPECT_FALSE(ReadFileToStringWithMaxSize(file_path, &data, kLargeFileSize)); - EXPECT_EQ(kLargeFileSize, data.length()); - EXPECT_EQ(std::string(kLargeFileSize, '\0'), data); - - EXPECT_FALSE(ReadFileToStringWithMaxSize(file_path, nullptr, kLargeFileSize)); -} -#endif // !defined(OS_WIN) - -#if !defined(OS_WIN) && !defined(OS_NACL) && !defined(OS_FUCHSIA) && \ - !defined(OS_IOS) -#define ChildMain WriteToPipeChildMain -#define ChildMainString "WriteToPipeChildMain" - -MULTIPROCESS_TEST_MAIN(ChildMain) { - const char kTestData[] = "0123"; - base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - const FilePath pipe_path = command_line->GetSwitchValuePath("pipe-path"); - - int fd = open(pipe_path.value().c_str(), O_WRONLY); - CHECK_NE(-1, fd); - size_t written = 0; - while (written < strlen(kTestData)) { - ssize_t res = write(fd, kTestData + written, strlen(kTestData) - written); - if (res == -1) - break; - written += res; - } - CHECK_EQ(strlen(kTestData), written); - CHECK_EQ(0, close(fd)); - return 0; -} - -#define MoreThanBufferSizeChildMain WriteToPipeMoreThanBufferSizeChildMain -#define MoreThanBufferSizeChildMainString \ - "WriteToPipeMoreThanBufferSizeChildMain" - -MULTIPROCESS_TEST_MAIN(MoreThanBufferSizeChildMain) { - std::string data(kLargeFileSize, 'c'); - base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - const FilePath pipe_path = command_line->GetSwitchValuePath("pipe-path"); - - int fd = open(pipe_path.value().c_str(), O_WRONLY); - CHECK_NE(-1, fd); - - size_t written = 0; - while (written < data.size()) { - ssize_t res = write(fd, data.c_str() + written, data.size() - written); - if (res == -1) { - // We are unable to write because reading process has already read - // requested number of bytes and closed pipe. - break; - } - written += res; - } - CHECK_EQ(0, close(fd)); - return 0; -} - -TEST_F(FileUtilTest, ReadFileToStringWithNamedPipe) { - FilePath pipe_path = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("test_pipe")); - ASSERT_EQ(0, mkfifo(pipe_path.value().c_str(), 0600)); - - base::CommandLine child_command_line( - base::GetMultiProcessTestChildBaseCommandLine()); - child_command_line.AppendSwitchPath("pipe-path", pipe_path); - - { - base::Process child_process = base::SpawnMultiProcessTestChild( - ChildMainString, child_command_line, base::LaunchOptions()); - ASSERT_TRUE(child_process.IsValid()); - - std::string data = "temp"; - EXPECT_FALSE(ReadFileToStringWithMaxSize(pipe_path, &data, 2)); - EXPECT_EQ("01", data); - - int rv = -1; - ASSERT_TRUE(WaitForMultiprocessTestChildExit( - child_process, TestTimeouts::action_timeout(), &rv)); - ASSERT_EQ(0, rv); - } - { - base::Process child_process = base::SpawnMultiProcessTestChild( - ChildMainString, child_command_line, base::LaunchOptions()); - ASSERT_TRUE(child_process.IsValid()); - - std::string data = "temp"; - EXPECT_TRUE(ReadFileToStringWithMaxSize(pipe_path, &data, 6)); - EXPECT_EQ("0123", data); - - int rv = -1; - ASSERT_TRUE(WaitForMultiprocessTestChildExit( - child_process, TestTimeouts::action_timeout(), &rv)); - ASSERT_EQ(0, rv); - } - { - base::Process child_process = base::SpawnMultiProcessTestChild( - MoreThanBufferSizeChildMainString, child_command_line, - base::LaunchOptions()); - ASSERT_TRUE(child_process.IsValid()); - - std::string data = "temp"; - EXPECT_FALSE(ReadFileToStringWithMaxSize(pipe_path, &data, 6)); - EXPECT_EQ("cccccc", data); - - int rv = -1; - ASSERT_TRUE(WaitForMultiprocessTestChildExit( - child_process, TestTimeouts::action_timeout(), &rv)); - ASSERT_EQ(0, rv); - } - { - base::Process child_process = base::SpawnMultiProcessTestChild( - MoreThanBufferSizeChildMainString, child_command_line, - base::LaunchOptions()); - ASSERT_TRUE(child_process.IsValid()); - - std::string data = "temp"; - EXPECT_FALSE( - ReadFileToStringWithMaxSize(pipe_path, &data, kLargeFileSize - 1)); - EXPECT_EQ(std::string(kLargeFileSize - 1, 'c'), data); - - int rv = -1; - ASSERT_TRUE(WaitForMultiprocessTestChildExit( - child_process, TestTimeouts::action_timeout(), &rv)); - ASSERT_EQ(0, rv); - } - { - base::Process child_process = base::SpawnMultiProcessTestChild( - MoreThanBufferSizeChildMainString, child_command_line, - base::LaunchOptions()); - ASSERT_TRUE(child_process.IsValid()); - - std::string data = "temp"; - EXPECT_TRUE(ReadFileToStringWithMaxSize(pipe_path, &data, kLargeFileSize)); - EXPECT_EQ(std::string(kLargeFileSize, 'c'), data); - - int rv = -1; - ASSERT_TRUE(WaitForMultiprocessTestChildExit( - child_process, TestTimeouts::action_timeout(), &rv)); - ASSERT_EQ(0, rv); - } - { - base::Process child_process = base::SpawnMultiProcessTestChild( - MoreThanBufferSizeChildMainString, child_command_line, - base::LaunchOptions()); - ASSERT_TRUE(child_process.IsValid()); - - std::string data = "temp"; - EXPECT_TRUE( - ReadFileToStringWithMaxSize(pipe_path, &data, kLargeFileSize * 5)); - EXPECT_EQ(std::string(kLargeFileSize, 'c'), data); - - int rv = -1; - ASSERT_TRUE(WaitForMultiprocessTestChildExit( - child_process, TestTimeouts::action_timeout(), &rv)); - ASSERT_EQ(0, rv); - } - - ASSERT_EQ(0, unlink(pipe_path.value().c_str())); -} -#endif // !defined(OS_WIN) && !defined(OS_NACL) && !defined(OS_FUCHSIA) && - // !defined(OS_IOS) - -#if defined(OS_WIN) -#define ChildMain WriteToPipeChildMain -#define ChildMainString "WriteToPipeChildMain" - -MULTIPROCESS_TEST_MAIN(ChildMain) { - const char kTestData[] = "0123"; - base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - const FilePath pipe_path = command_line->GetSwitchValuePath("pipe-path"); - std::string switch_string = command_line->GetSwitchValueASCII("sync_event"); - EXPECT_FALSE(switch_string.empty()); - unsigned int switch_uint = 0; - EXPECT_TRUE(StringToUint(switch_string, &switch_uint)); - win::ScopedHandle sync_event(win::Uint32ToHandle(switch_uint)); - - HANDLE ph = CreateNamedPipe(pipe_path.value().c_str(), PIPE_ACCESS_OUTBOUND, - PIPE_WAIT, 1, 0, 0, 0, NULL); - EXPECT_NE(ph, INVALID_HANDLE_VALUE); - EXPECT_TRUE(SetEvent(sync_event.Get())); - EXPECT_TRUE(ConnectNamedPipe(ph, NULL)); - - DWORD written; - EXPECT_TRUE(::WriteFile(ph, kTestData, strlen(kTestData), &written, NULL)); - EXPECT_EQ(strlen(kTestData), written); - CloseHandle(ph); - return 0; -} - -#define MoreThanBufferSizeChildMain WriteToPipeMoreThanBufferSizeChildMain -#define MoreThanBufferSizeChildMainString \ - "WriteToPipeMoreThanBufferSizeChildMain" - -MULTIPROCESS_TEST_MAIN(MoreThanBufferSizeChildMain) { - std::string data(kLargeFileSize, 'c'); - base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - const FilePath pipe_path = command_line->GetSwitchValuePath("pipe-path"); - std::string switch_string = command_line->GetSwitchValueASCII("sync_event"); - EXPECT_FALSE(switch_string.empty()); - unsigned int switch_uint = 0; - EXPECT_TRUE(StringToUint(switch_string, &switch_uint)); - win::ScopedHandle sync_event(win::Uint32ToHandle(switch_uint)); - - HANDLE ph = CreateNamedPipe(pipe_path.value().c_str(), PIPE_ACCESS_OUTBOUND, - PIPE_WAIT, 1, data.size(), data.size(), 0, NULL); - EXPECT_NE(ph, INVALID_HANDLE_VALUE); - EXPECT_TRUE(SetEvent(sync_event.Get())); - EXPECT_TRUE(ConnectNamedPipe(ph, NULL)); - - DWORD written; - EXPECT_TRUE(::WriteFile(ph, data.c_str(), data.size(), &written, NULL)); - EXPECT_EQ(data.size(), written); - CloseHandle(ph); - return 0; -} - -TEST_F(FileUtilTest, ReadFileToStringWithNamedPipe) { - FilePath pipe_path(FILE_PATH_LITERAL("\\\\.\\pipe\\test_pipe")); - win::ScopedHandle sync_event(CreateEvent(0, false, false, nullptr)); - - base::CommandLine child_command_line( - base::GetMultiProcessTestChildBaseCommandLine()); - child_command_line.AppendSwitchPath("pipe-path", pipe_path); - child_command_line.AppendSwitchASCII( - "sync_event", UintToString(win::HandleToUint32(sync_event.Get()))); - - base::LaunchOptions options; - options.handles_to_inherit.push_back(sync_event.Get()); - - { - base::Process child_process = base::SpawnMultiProcessTestChild( - ChildMainString, child_command_line, options); - ASSERT_TRUE(child_process.IsValid()); - // Wait for pipe creation in child process. - EXPECT_EQ(WAIT_OBJECT_0, WaitForSingleObject(sync_event.Get(), INFINITE)); - - std::string data = "temp"; - EXPECT_FALSE(ReadFileToStringWithMaxSize(pipe_path, &data, 2)); - EXPECT_EQ("01", data); - - int rv = -1; - ASSERT_TRUE(WaitForMultiprocessTestChildExit( - child_process, TestTimeouts::action_timeout(), &rv)); - ASSERT_EQ(0, rv); - } - { - base::Process child_process = base::SpawnMultiProcessTestChild( - ChildMainString, child_command_line, options); - ASSERT_TRUE(child_process.IsValid()); - // Wait for pipe creation in child process. - EXPECT_EQ(WAIT_OBJECT_0, WaitForSingleObject(sync_event.Get(), INFINITE)); - - std::string data = "temp"; - EXPECT_TRUE(ReadFileToStringWithMaxSize(pipe_path, &data, 6)); - EXPECT_EQ("0123", data); - - int rv = -1; - ASSERT_TRUE(WaitForMultiprocessTestChildExit( - child_process, TestTimeouts::action_timeout(), &rv)); - ASSERT_EQ(0, rv); - } - { - base::Process child_process = base::SpawnMultiProcessTestChild( - MoreThanBufferSizeChildMainString, child_command_line, options); - ASSERT_TRUE(child_process.IsValid()); - // Wait for pipe creation in child process. - EXPECT_EQ(WAIT_OBJECT_0, WaitForSingleObject(sync_event.Get(), INFINITE)); - - std::string data = "temp"; - EXPECT_FALSE(ReadFileToStringWithMaxSize(pipe_path, &data, 6)); - EXPECT_EQ("cccccc", data); - - int rv = -1; - ASSERT_TRUE(WaitForMultiprocessTestChildExit( - child_process, TestTimeouts::action_timeout(), &rv)); - ASSERT_EQ(0, rv); - } - { - base::Process child_process = base::SpawnMultiProcessTestChild( - MoreThanBufferSizeChildMainString, child_command_line, options); - ASSERT_TRUE(child_process.IsValid()); - // Wait for pipe creation in child process. - EXPECT_EQ(WAIT_OBJECT_0, WaitForSingleObject(sync_event.Get(), INFINITE)); - - std::string data = "temp"; - EXPECT_FALSE( - ReadFileToStringWithMaxSize(pipe_path, &data, kLargeFileSize - 1)); - EXPECT_EQ(std::string(kLargeFileSize - 1, 'c'), data); - - int rv = -1; - ASSERT_TRUE(WaitForMultiprocessTestChildExit( - child_process, TestTimeouts::action_timeout(), &rv)); - ASSERT_EQ(0, rv); - } - { - base::Process child_process = base::SpawnMultiProcessTestChild( - MoreThanBufferSizeChildMainString, child_command_line, options); - ASSERT_TRUE(child_process.IsValid()); - // Wait for pipe creation in child process. - EXPECT_EQ(WAIT_OBJECT_0, WaitForSingleObject(sync_event.Get(), INFINITE)); - - std::string data = "temp"; - EXPECT_TRUE(ReadFileToStringWithMaxSize(pipe_path, &data, kLargeFileSize)); - EXPECT_EQ(std::string(kLargeFileSize, 'c'), data); - - int rv = -1; - ASSERT_TRUE(WaitForMultiprocessTestChildExit( - child_process, TestTimeouts::action_timeout(), &rv)); - ASSERT_EQ(0, rv); - } - { - base::Process child_process = base::SpawnMultiProcessTestChild( - MoreThanBufferSizeChildMainString, child_command_line, options); - ASSERT_TRUE(child_process.IsValid()); - // Wait for pipe creation in child process. - EXPECT_EQ(WAIT_OBJECT_0, WaitForSingleObject(sync_event.Get(), INFINITE)); - - std::string data = "temp"; - EXPECT_TRUE( - ReadFileToStringWithMaxSize(pipe_path, &data, kLargeFileSize * 5)); - EXPECT_EQ(std::string(kLargeFileSize, 'c'), data); - - int rv = -1; - ASSERT_TRUE(WaitForMultiprocessTestChildExit( - child_process, TestTimeouts::action_timeout(), &rv)); - ASSERT_EQ(0, rv); - } -} -#endif // defined(OS_WIN) - -#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_FUCHSIA) -TEST_F(FileUtilTest, ReadFileToStringWithProcFileSystem) { - FilePath file_path("/proc/cpuinfo"); - std::string data = "temp"; - - EXPECT_FALSE(ReadFileToStringWithMaxSize(file_path, &data, 0)); - EXPECT_EQ(0u, data.length()); - - data = "temp"; - EXPECT_FALSE(ReadFileToStringWithMaxSize(file_path, &data, 2)); -#if defined(OS_ANDROID) - EXPECT_EQ("Pr", data); -#else - EXPECT_EQ("pr", data); -#endif - - data = "temp"; - EXPECT_FALSE(ReadFileToStringWithMaxSize(file_path, &data, 4)); -#if defined(OS_ANDROID) - EXPECT_EQ("Proc", data); -#else - EXPECT_EQ("proc", data); -#endif - - EXPECT_FALSE(ReadFileToStringWithMaxSize(file_path, nullptr, 4)); -} -#endif // defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_FUCHSIA) - -TEST_F(FileUtilTest, ReadFileToStringWithLargeFile) { - std::string data(kLargeFileSize, 'c'); - - FilePath file_path = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("ReadFileToStringTest")); - - // Create test file. - ASSERT_EQ(static_cast<int>(kLargeFileSize), - WriteFile(file_path, data.c_str(), kLargeFileSize)); - - std::string actual_data = "temp"; - EXPECT_TRUE(ReadFileToString(file_path, &actual_data)); - EXPECT_EQ(data, actual_data); - - actual_data = "temp"; - EXPECT_FALSE(ReadFileToStringWithMaxSize(file_path, &actual_data, 0)); - EXPECT_EQ(0u, actual_data.length()); - - // Read more than buffer size. - actual_data = "temp"; - EXPECT_FALSE( - ReadFileToStringWithMaxSize(file_path, &actual_data, kLargeFileSize - 1)); - EXPECT_EQ(std::string(kLargeFileSize - 1, 'c'), actual_data); -} - -TEST_F(FileUtilTest, TouchFile) { - FilePath data_dir = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("FilePathTest")); - - // Create a fresh, empty copy of this directory. - if (PathExists(data_dir)) { - ASSERT_TRUE(DeleteFile(data_dir, true)); - } - ASSERT_TRUE(CreateDirectory(data_dir)); - - FilePath foobar(data_dir.Append(FILE_PATH_LITERAL("foobar.txt"))); - std::string data("hello"); - ASSERT_EQ(static_cast<int>(data.length()), - WriteFile(foobar, data.c_str(), data.length())); - - Time access_time; - // This timestamp is divisible by one day (in local timezone), - // to make it work on FAT too. - ASSERT_TRUE(Time::FromString("Wed, 16 Nov 1994, 00:00:00", - &access_time)); - - Time modification_time; - // Note that this timestamp is divisible by two (seconds) - FAT stores - // modification times with 2s resolution. - ASSERT_TRUE(Time::FromString("Tue, 15 Nov 1994, 12:45:26 GMT", - &modification_time)); - - ASSERT_TRUE(TouchFile(foobar, access_time, modification_time)); - File::Info file_info; - ASSERT_TRUE(GetFileInfo(foobar, &file_info)); -#if !defined(OS_FUCHSIA) - // Access time is not supported on Fuchsia, see https://crbug.com/735233. - EXPECT_EQ(access_time.ToInternalValue(), - file_info.last_accessed.ToInternalValue()); -#endif - EXPECT_EQ(modification_time.ToInternalValue(), - file_info.last_modified.ToInternalValue()); -} - -TEST_F(FileUtilTest, IsDirectoryEmpty) { - FilePath empty_dir = - temp_dir_.GetPath().Append(FILE_PATH_LITERAL("EmptyDir")); - - ASSERT_FALSE(PathExists(empty_dir)); - - ASSERT_TRUE(CreateDirectory(empty_dir)); - - EXPECT_TRUE(IsDirectoryEmpty(empty_dir)); - - FilePath foo(empty_dir.Append(FILE_PATH_LITERAL("foo.txt"))); - std::string bar("baz"); - ASSERT_EQ(static_cast<int>(bar.length()), - WriteFile(foo, bar.c_str(), bar.length())); - - EXPECT_FALSE(IsDirectoryEmpty(empty_dir)); -} - -#if defined(OS_POSIX) || defined(OS_FUCHSIA) - -TEST_F(FileUtilTest, SetNonBlocking) { - const int kInvalidFd = 99999; - EXPECT_FALSE(SetNonBlocking(kInvalidFd)); - - base::FilePath path; - ASSERT_TRUE(PathService::Get(base::DIR_TEST_DATA, &path)); - path = path.Append(FPL("file_util")).Append(FPL("original.txt")); - ScopedFD fd(open(path.value().c_str(), O_RDONLY)); - ASSERT_GE(fd.get(), 0); - EXPECT_TRUE(SetNonBlocking(fd.get())); -} - -TEST_F(FileUtilTest, SetCloseOnExec) { - const int kInvalidFd = 99999; - EXPECT_FALSE(SetCloseOnExec(kInvalidFd)); - - base::FilePath path; - ASSERT_TRUE(PathService::Get(base::DIR_TEST_DATA, &path)); - path = path.Append(FPL("file_util")).Append(FPL("original.txt")); - ScopedFD fd(open(path.value().c_str(), O_RDONLY)); - ASSERT_GE(fd.get(), 0); - EXPECT_TRUE(SetCloseOnExec(fd.get())); -} - -#endif - -#if defined(OS_POSIX) - -// Testing VerifyPathControlledByAdmin() is hard, because there is no -// way a test can make a file owned by root, or change file paths -// at the root of the file system. VerifyPathControlledByAdmin() -// is implemented as a call to VerifyPathControlledByUser, which gives -// us the ability to test with paths under the test's temp directory, -// using a user id we control. -// Pull tests of VerifyPathControlledByUserTest() into a separate test class -// with a common SetUp() method. -class VerifyPathControlledByUserTest : public FileUtilTest { - protected: - void SetUp() override { - FileUtilTest::SetUp(); - - // Create a basic structure used by each test. - // base_dir_ - // |-> sub_dir_ - // |-> text_file_ - - base_dir_ = temp_dir_.GetPath().AppendASCII("base_dir"); - ASSERT_TRUE(CreateDirectory(base_dir_)); - - sub_dir_ = base_dir_.AppendASCII("sub_dir"); - ASSERT_TRUE(CreateDirectory(sub_dir_)); - - text_file_ = sub_dir_.AppendASCII("file.txt"); - CreateTextFile(text_file_, L"This text file has some text in it."); - - // Get the user and group files are created with from |base_dir_|. - struct stat stat_buf; - ASSERT_EQ(0, stat(base_dir_.value().c_str(), &stat_buf)); - uid_ = stat_buf.st_uid; - ok_gids_.insert(stat_buf.st_gid); - bad_gids_.insert(stat_buf.st_gid + 1); - - ASSERT_EQ(uid_, getuid()); // This process should be the owner. - - // To ensure that umask settings do not cause the initial state - // of permissions to be different from what we expect, explicitly - // set permissions on the directories we create. - // Make all files and directories non-world-writable. - - // Users and group can read, write, traverse - int enabled_permissions = - FILE_PERMISSION_USER_MASK | FILE_PERMISSION_GROUP_MASK; - // Other users can't read, write, traverse - int disabled_permissions = FILE_PERMISSION_OTHERS_MASK; - - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions( - base_dir_, enabled_permissions, disabled_permissions)); - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions( - sub_dir_, enabled_permissions, disabled_permissions)); - } - - FilePath base_dir_; - FilePath sub_dir_; - FilePath text_file_; - uid_t uid_; - - std::set<gid_t> ok_gids_; - std::set<gid_t> bad_gids_; -}; - -TEST_F(VerifyPathControlledByUserTest, BadPaths) { - // File does not exist. - FilePath does_not_exist = base_dir_.AppendASCII("does") - .AppendASCII("not") - .AppendASCII("exist"); - EXPECT_FALSE( - VerifyPathControlledByUser(base_dir_, does_not_exist, uid_, ok_gids_)); - - // |base| not a subpath of |path|. - EXPECT_FALSE(VerifyPathControlledByUser(sub_dir_, base_dir_, uid_, ok_gids_)); - - // An empty base path will fail to be a prefix for any path. - FilePath empty; - EXPECT_FALSE(VerifyPathControlledByUser(empty, base_dir_, uid_, ok_gids_)); - - // Finding that a bad call fails proves nothing unless a good call succeeds. - EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_)); -} - -TEST_F(VerifyPathControlledByUserTest, Symlinks) { - // Symlinks in the path should cause failure. - - // Symlink to the file at the end of the path. - FilePath file_link = base_dir_.AppendASCII("file_link"); - ASSERT_TRUE(CreateSymbolicLink(text_file_, file_link)) - << "Failed to create symlink."; - - EXPECT_FALSE( - VerifyPathControlledByUser(base_dir_, file_link, uid_, ok_gids_)); - EXPECT_FALSE( - VerifyPathControlledByUser(file_link, file_link, uid_, ok_gids_)); - - // Symlink from one directory to another within the path. - FilePath link_to_sub_dir = base_dir_.AppendASCII("link_to_sub_dir"); - ASSERT_TRUE(CreateSymbolicLink(sub_dir_, link_to_sub_dir)) - << "Failed to create symlink."; - - FilePath file_path_with_link = link_to_sub_dir.AppendASCII("file.txt"); - ASSERT_TRUE(PathExists(file_path_with_link)); - - EXPECT_FALSE(VerifyPathControlledByUser(base_dir_, file_path_with_link, uid_, - ok_gids_)); - - EXPECT_FALSE(VerifyPathControlledByUser(link_to_sub_dir, file_path_with_link, - uid_, ok_gids_)); - - // Symlinks in parents of base path are allowed. - EXPECT_TRUE(VerifyPathControlledByUser(file_path_with_link, - file_path_with_link, uid_, ok_gids_)); -} - -TEST_F(VerifyPathControlledByUserTest, OwnershipChecks) { - // Get a uid that is not the uid of files we create. - uid_t bad_uid = uid_ + 1; - - // Make all files and directories non-world-writable. - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions(base_dir_, 0u, S_IWOTH)); - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions(sub_dir_, 0u, S_IWOTH)); - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions(text_file_, 0u, S_IWOTH)); - - // We control these paths. - EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_)); - EXPECT_TRUE( - VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_)); - EXPECT_TRUE(VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_)); - - // Another user does not control these paths. - EXPECT_FALSE( - VerifyPathControlledByUser(base_dir_, sub_dir_, bad_uid, ok_gids_)); - EXPECT_FALSE( - VerifyPathControlledByUser(base_dir_, text_file_, bad_uid, ok_gids_)); - EXPECT_FALSE( - VerifyPathControlledByUser(sub_dir_, text_file_, bad_uid, ok_gids_)); - - // Another group does not control the paths. - EXPECT_FALSE( - VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, bad_gids_)); - EXPECT_FALSE( - VerifyPathControlledByUser(base_dir_, text_file_, uid_, bad_gids_)); - EXPECT_FALSE( - VerifyPathControlledByUser(sub_dir_, text_file_, uid_, bad_gids_)); -} - -TEST_F(VerifyPathControlledByUserTest, GroupWriteTest) { - // Make all files and directories writable only by their owner. - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions(base_dir_, 0u, S_IWOTH|S_IWGRP)); - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions(sub_dir_, 0u, S_IWOTH|S_IWGRP)); - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions(text_file_, 0u, S_IWOTH|S_IWGRP)); - - // Any group is okay because the path is not group-writable. - EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_)); - EXPECT_TRUE( - VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_)); - EXPECT_TRUE(VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_)); - - EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, bad_gids_)); - EXPECT_TRUE( - VerifyPathControlledByUser(base_dir_, text_file_, uid_, bad_gids_)); - EXPECT_TRUE( - VerifyPathControlledByUser(sub_dir_, text_file_, uid_, bad_gids_)); - - // No group is okay, because we don't check the group - // if no group can write. - std::set<gid_t> no_gids; // Empty set of gids. - EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, no_gids)); - EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, text_file_, uid_, no_gids)); - EXPECT_TRUE(VerifyPathControlledByUser(sub_dir_, text_file_, uid_, no_gids)); - - // Make all files and directories writable by their group. - ASSERT_NO_FATAL_FAILURE(ChangePosixFilePermissions(base_dir_, S_IWGRP, 0u)); - ASSERT_NO_FATAL_FAILURE(ChangePosixFilePermissions(sub_dir_, S_IWGRP, 0u)); - ASSERT_NO_FATAL_FAILURE(ChangePosixFilePermissions(text_file_, S_IWGRP, 0u)); - - // Now |ok_gids_| works, but |bad_gids_| fails. - EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_)); - EXPECT_TRUE( - VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_)); - EXPECT_TRUE(VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_)); - - EXPECT_FALSE( - VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, bad_gids_)); - EXPECT_FALSE( - VerifyPathControlledByUser(base_dir_, text_file_, uid_, bad_gids_)); - EXPECT_FALSE( - VerifyPathControlledByUser(sub_dir_, text_file_, uid_, bad_gids_)); - - // Because any group in the group set is allowed, - // the union of good and bad gids passes. - - std::set<gid_t> multiple_gids; - std::set_union( - ok_gids_.begin(), ok_gids_.end(), - bad_gids_.begin(), bad_gids_.end(), - std::inserter(multiple_gids, multiple_gids.begin())); - - EXPECT_TRUE( - VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, multiple_gids)); - EXPECT_TRUE( - VerifyPathControlledByUser(base_dir_, text_file_, uid_, multiple_gids)); - EXPECT_TRUE( - VerifyPathControlledByUser(sub_dir_, text_file_, uid_, multiple_gids)); -} - -TEST_F(VerifyPathControlledByUserTest, WriteBitChecks) { - // Make all files and directories non-world-writable. - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions(base_dir_, 0u, S_IWOTH)); - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions(sub_dir_, 0u, S_IWOTH)); - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions(text_file_, 0u, S_IWOTH)); - - // Initialy, we control all parts of the path. - EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_)); - EXPECT_TRUE( - VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_)); - EXPECT_TRUE(VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_)); - - // Make base_dir_ world-writable. - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions(base_dir_, S_IWOTH, 0u)); - EXPECT_FALSE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_)); - EXPECT_FALSE( - VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_)); - EXPECT_TRUE(VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_)); - - // Make sub_dir_ world writable. - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions(sub_dir_, S_IWOTH, 0u)); - EXPECT_FALSE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_)); - EXPECT_FALSE( - VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_)); - EXPECT_FALSE( - VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_)); - - // Make text_file_ world writable. - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions(text_file_, S_IWOTH, 0u)); - EXPECT_FALSE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_)); - EXPECT_FALSE( - VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_)); - EXPECT_FALSE( - VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_)); - - // Make sub_dir_ non-world writable. - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions(sub_dir_, 0u, S_IWOTH)); - EXPECT_FALSE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_)); - EXPECT_FALSE( - VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_)); - EXPECT_FALSE( - VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_)); - - // Make base_dir_ non-world-writable. - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions(base_dir_, 0u, S_IWOTH)); - EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_)); - EXPECT_FALSE( - VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_)); - EXPECT_FALSE( - VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_)); - - // Back to the initial state: Nothing is writable, so every path - // should pass. - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions(text_file_, 0u, S_IWOTH)); - EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_)); - EXPECT_TRUE( - VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_)); - EXPECT_TRUE(VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_)); -} - -#endif // defined(OS_POSIX) - -#if defined(OS_ANDROID) -TEST_F(FileUtilTest, ValidContentUriTest) { - // Get the test image path. - FilePath data_dir; - ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &data_dir)); - data_dir = data_dir.AppendASCII("file_util"); - ASSERT_TRUE(PathExists(data_dir)); - FilePath image_file = data_dir.Append(FILE_PATH_LITERAL("red.png")); - int64_t image_size; - GetFileSize(image_file, &image_size); - ASSERT_GT(image_size, 0); - - // Insert the image into MediaStore. MediaStore will do some conversions, and - // return the content URI. - FilePath path = InsertImageIntoMediaStore(image_file); - EXPECT_TRUE(path.IsContentUri()); - EXPECT_TRUE(PathExists(path)); - // The file size may not equal to the input image as MediaStore may convert - // the image. - int64_t content_uri_size; - GetFileSize(path, &content_uri_size); - EXPECT_EQ(image_size, content_uri_size); - - // We should be able to read the file. - File file = OpenContentUriForRead(path); - EXPECT_TRUE(file.IsValid()); - auto buffer = std::make_unique<char[]>(image_size); - EXPECT_TRUE(file.ReadAtCurrentPos(buffer.get(), image_size)); -} - -TEST_F(FileUtilTest, NonExistentContentUriTest) { - FilePath path("content://foo.bar"); - EXPECT_TRUE(path.IsContentUri()); - EXPECT_FALSE(PathExists(path)); - // Size should be smaller than 0. - int64_t size; - EXPECT_FALSE(GetFileSize(path, &size)); - - // We should not be able to read the file. - File file = OpenContentUriForRead(path); - EXPECT_FALSE(file.IsValid()); -} -#endif - -#if defined(OS_POSIX) || defined(OS_FUCHSIA) - -TEST(ScopedFD, ScopedFDDoesClose) { - int fds[2]; - char c = 0; - ASSERT_EQ(0, pipe(fds)); - const int write_end = fds[1]; - ScopedFD read_end_closer(fds[0]); - { - ScopedFD write_end_closer(fds[1]); - } - // This is the only thread. This file descriptor should no longer be valid. - int ret = close(write_end); - EXPECT_EQ(-1, ret); - EXPECT_EQ(EBADF, errno); - // Make sure read(2) won't block. - ASSERT_EQ(0, fcntl(fds[0], F_SETFL, O_NONBLOCK)); - // Reading the pipe should EOF. - EXPECT_EQ(0, read(fds[0], &c, 1)); -} - -#if defined(GTEST_HAS_DEATH_TEST) -void CloseWithScopedFD(int fd) { - ScopedFD fd_closer(fd); -} -#endif - -TEST(ScopedFD, ScopedFDCrashesOnCloseFailure) { - int fds[2]; - ASSERT_EQ(0, pipe(fds)); - ScopedFD read_end_closer(fds[0]); - EXPECT_EQ(0, IGNORE_EINTR(close(fds[1]))); -#if defined(GTEST_HAS_DEATH_TEST) - // This is the only thread. This file descriptor should no longer be valid. - // Trying to close it should crash. This is important for security. - EXPECT_DEATH(CloseWithScopedFD(fds[1]), ""); -#endif -} - -#endif // defined(OS_POSIX) || defined(OS_FUCHSIA) - -} // namespace - -} // namespace base
diff --git a/base/files/important_file_writer_unittest.cc b/base/files/important_file_writer_unittest.cc deleted file mode 100644 index 493fb36..0000000 --- a/base/files/important_file_writer_unittest.cc +++ /dev/null
@@ -1,351 +0,0 @@ -// 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/files/important_file_writer.h" - -#include "base/bind.h" -#include "base/compiler_specific.h" -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/files/scoped_temp_dir.h" -#include "base/location.h" -#include "base/logging.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "base/single_thread_task_runner.h" -#include "base/test/histogram_tester.h" -#include "base/threading/thread.h" -#include "base/threading/thread_task_runner_handle.h" -#include "base/time/time.h" -#include "base/timer/mock_timer.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -std::string GetFileContent(const FilePath& path) { - std::string content; - if (!ReadFileToString(path, &content)) { - NOTREACHED(); - } - return content; -} - -class DataSerializer : public ImportantFileWriter::DataSerializer { - public: - explicit DataSerializer(const std::string& data) : data_(data) { - } - - bool SerializeData(std::string* output) override { - output->assign(data_); - return true; - } - - private: - const std::string data_; -}; - -class FailingDataSerializer : public ImportantFileWriter::DataSerializer { - public: - bool SerializeData(std::string* output) override { return false; } -}; - -enum WriteCallbackObservationState { - NOT_CALLED, - CALLED_WITH_ERROR, - CALLED_WITH_SUCCESS, -}; - -class WriteCallbacksObserver { - public: - WriteCallbacksObserver() = default; - - // Register OnBeforeWrite() and OnAfterWrite() to be called on the next write - // of |writer|. - void ObserveNextWriteCallbacks(ImportantFileWriter* writer); - - // Returns the |WriteCallbackObservationState| which was observed, then resets - // it to |NOT_CALLED|. - WriteCallbackObservationState GetAndResetObservationState(); - - private: - void OnBeforeWrite() { - EXPECT_FALSE(before_write_called_); - before_write_called_ = true; - } - - void OnAfterWrite(bool success) { - EXPECT_EQ(NOT_CALLED, after_write_observation_state_); - after_write_observation_state_ = - success ? CALLED_WITH_SUCCESS : CALLED_WITH_ERROR; - } - - bool before_write_called_ = false; - WriteCallbackObservationState after_write_observation_state_ = NOT_CALLED; - - DISALLOW_COPY_AND_ASSIGN(WriteCallbacksObserver); -}; - -void WriteCallbacksObserver::ObserveNextWriteCallbacks( - ImportantFileWriter* writer) { - writer->RegisterOnNextWriteCallbacks( - base::Bind(&WriteCallbacksObserver::OnBeforeWrite, - base::Unretained(this)), - base::Bind(&WriteCallbacksObserver::OnAfterWrite, - base::Unretained(this))); -} - -WriteCallbackObservationState -WriteCallbacksObserver::GetAndResetObservationState() { - EXPECT_EQ(after_write_observation_state_ != NOT_CALLED, before_write_called_) - << "The before-write callback should always be called before the " - "after-write callback"; - - WriteCallbackObservationState state = after_write_observation_state_; - before_write_called_ = false; - after_write_observation_state_ = NOT_CALLED; - return state; -} - -} // namespace - -class ImportantFileWriterTest : public testing::Test { - public: - ImportantFileWriterTest() = default; - void SetUp() override { - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - file_ = temp_dir_.GetPath().AppendASCII("test-file"); - } - - protected: - WriteCallbacksObserver write_callback_observer_; - FilePath file_; - MessageLoop loop_; - - private: - ScopedTempDir temp_dir_; -}; - -TEST_F(ImportantFileWriterTest, Basic) { - ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get()); - EXPECT_FALSE(PathExists(writer.path())); - EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState()); - writer.WriteNow(std::make_unique<std::string>("foo")); - RunLoop().RunUntilIdle(); - - EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState()); - ASSERT_TRUE(PathExists(writer.path())); - EXPECT_EQ("foo", GetFileContent(writer.path())); -} - -TEST_F(ImportantFileWriterTest, WriteWithObserver) { - ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get()); - EXPECT_FALSE(PathExists(writer.path())); - EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState()); - - // Confirm that the observer is invoked. - write_callback_observer_.ObserveNextWriteCallbacks(&writer); - writer.WriteNow(std::make_unique<std::string>("foo")); - RunLoop().RunUntilIdle(); - - EXPECT_EQ(CALLED_WITH_SUCCESS, - write_callback_observer_.GetAndResetObservationState()); - ASSERT_TRUE(PathExists(writer.path())); - EXPECT_EQ("foo", GetFileContent(writer.path())); - - // Confirm that re-installing the observer works for another write. - EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState()); - write_callback_observer_.ObserveNextWriteCallbacks(&writer); - writer.WriteNow(std::make_unique<std::string>("bar")); - RunLoop().RunUntilIdle(); - - EXPECT_EQ(CALLED_WITH_SUCCESS, - write_callback_observer_.GetAndResetObservationState()); - ASSERT_TRUE(PathExists(writer.path())); - EXPECT_EQ("bar", GetFileContent(writer.path())); - - // Confirm that writing again without re-installing the observer doesn't - // result in a notification. - EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState()); - writer.WriteNow(std::make_unique<std::string>("baz")); - RunLoop().RunUntilIdle(); - - EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState()); - ASSERT_TRUE(PathExists(writer.path())); - EXPECT_EQ("baz", GetFileContent(writer.path())); -} - -TEST_F(ImportantFileWriterTest, FailedWriteWithObserver) { - // Use an invalid file path (relative paths are invalid) to get a - // FILE_ERROR_ACCESS_DENIED error when trying to write the file. - ImportantFileWriter writer(FilePath().AppendASCII("bad/../path"), - ThreadTaskRunnerHandle::Get()); - EXPECT_FALSE(PathExists(writer.path())); - EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState()); - write_callback_observer_.ObserveNextWriteCallbacks(&writer); - writer.WriteNow(std::make_unique<std::string>("foo")); - RunLoop().RunUntilIdle(); - - // Confirm that the write observer was invoked with its boolean parameter set - // to false. - EXPECT_EQ(CALLED_WITH_ERROR, - write_callback_observer_.GetAndResetObservationState()); - EXPECT_FALSE(PathExists(writer.path())); -} - -TEST_F(ImportantFileWriterTest, CallbackRunsOnWriterThread) { - base::Thread file_writer_thread("ImportantFileWriter test thread"); - file_writer_thread.Start(); - ImportantFileWriter writer(file_, file_writer_thread.task_runner()); - EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState()); - - // Block execution on |file_writer_thread| to verify that callbacks are - // executed on it. - base::WaitableEvent wait_helper( - base::WaitableEvent::ResetPolicy::MANUAL, - base::WaitableEvent::InitialState::NOT_SIGNALED); - file_writer_thread.task_runner()->PostTask( - FROM_HERE, base::BindOnce(&base::WaitableEvent::Wait, - base::Unretained(&wait_helper))); - - write_callback_observer_.ObserveNextWriteCallbacks(&writer); - writer.WriteNow(std::make_unique<std::string>("foo")); - RunLoop().RunUntilIdle(); - - // Expect the callback to not have been executed before the - // |file_writer_thread| is unblocked. - EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState()); - - wait_helper.Signal(); - file_writer_thread.FlushForTesting(); - - EXPECT_EQ(CALLED_WITH_SUCCESS, - write_callback_observer_.GetAndResetObservationState()); - ASSERT_TRUE(PathExists(writer.path())); - EXPECT_EQ("foo", GetFileContent(writer.path())); -} - -TEST_F(ImportantFileWriterTest, ScheduleWrite) { - constexpr TimeDelta kCommitInterval = TimeDelta::FromSeconds(12345); - MockTimer timer(true, false); - ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get(), - kCommitInterval); - writer.SetTimerForTesting(&timer); - EXPECT_FALSE(writer.HasPendingWrite()); - DataSerializer serializer("foo"); - writer.ScheduleWrite(&serializer); - EXPECT_TRUE(writer.HasPendingWrite()); - ASSERT_TRUE(timer.IsRunning()); - EXPECT_EQ(kCommitInterval, timer.GetCurrentDelay()); - timer.Fire(); - EXPECT_FALSE(writer.HasPendingWrite()); - EXPECT_FALSE(timer.IsRunning()); - RunLoop().RunUntilIdle(); - ASSERT_TRUE(PathExists(writer.path())); - EXPECT_EQ("foo", GetFileContent(writer.path())); -} - -TEST_F(ImportantFileWriterTest, DoScheduledWrite) { - MockTimer timer(true, false); - ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get()); - writer.SetTimerForTesting(&timer); - EXPECT_FALSE(writer.HasPendingWrite()); - DataSerializer serializer("foo"); - writer.ScheduleWrite(&serializer); - EXPECT_TRUE(writer.HasPendingWrite()); - writer.DoScheduledWrite(); - EXPECT_FALSE(writer.HasPendingWrite()); - RunLoop().RunUntilIdle(); - ASSERT_TRUE(PathExists(writer.path())); - EXPECT_EQ("foo", GetFileContent(writer.path())); -} - -TEST_F(ImportantFileWriterTest, BatchingWrites) { - MockTimer timer(true, false); - ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get()); - writer.SetTimerForTesting(&timer); - DataSerializer foo("foo"), bar("bar"), baz("baz"); - writer.ScheduleWrite(&foo); - writer.ScheduleWrite(&bar); - writer.ScheduleWrite(&baz); - ASSERT_TRUE(timer.IsRunning()); - timer.Fire(); - RunLoop().RunUntilIdle(); - ASSERT_TRUE(PathExists(writer.path())); - EXPECT_EQ("baz", GetFileContent(writer.path())); -} - -TEST_F(ImportantFileWriterTest, ScheduleWrite_FailToSerialize) { - MockTimer timer(true, false); - ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get()); - writer.SetTimerForTesting(&timer); - EXPECT_FALSE(writer.HasPendingWrite()); - FailingDataSerializer serializer; - writer.ScheduleWrite(&serializer); - EXPECT_TRUE(writer.HasPendingWrite()); - ASSERT_TRUE(timer.IsRunning()); - timer.Fire(); - EXPECT_FALSE(writer.HasPendingWrite()); - RunLoop().RunUntilIdle(); - EXPECT_FALSE(PathExists(writer.path())); -} - -TEST_F(ImportantFileWriterTest, ScheduleWrite_WriteNow) { - MockTimer timer(true, false); - ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get()); - writer.SetTimerForTesting(&timer); - EXPECT_FALSE(writer.HasPendingWrite()); - DataSerializer serializer("foo"); - writer.ScheduleWrite(&serializer); - EXPECT_TRUE(writer.HasPendingWrite()); - writer.WriteNow(std::make_unique<std::string>("bar")); - EXPECT_FALSE(writer.HasPendingWrite()); - EXPECT_FALSE(timer.IsRunning()); - - RunLoop().RunUntilIdle(); - ASSERT_TRUE(PathExists(writer.path())); - EXPECT_EQ("bar", GetFileContent(writer.path())); -} - -TEST_F(ImportantFileWriterTest, DoScheduledWrite_FailToSerialize) { - MockTimer timer(true, false); - ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get()); - writer.SetTimerForTesting(&timer); - EXPECT_FALSE(writer.HasPendingWrite()); - FailingDataSerializer serializer; - writer.ScheduleWrite(&serializer); - EXPECT_TRUE(writer.HasPendingWrite()); - - writer.DoScheduledWrite(); - EXPECT_FALSE(timer.IsRunning()); - EXPECT_FALSE(writer.HasPendingWrite()); - RunLoop().RunUntilIdle(); - EXPECT_FALSE(PathExists(writer.path())); -} - -TEST_F(ImportantFileWriterTest, WriteFileAtomicallyHistogramSuffixTest) { - base::HistogramTester histogram_tester; - EXPECT_FALSE(PathExists(file_)); - EXPECT_TRUE(ImportantFileWriter::WriteFileAtomically(file_, "baz", "test")); - EXPECT_TRUE(PathExists(file_)); - EXPECT_EQ("baz", GetFileContent(file_)); - histogram_tester.ExpectTotalCount("ImportantFile.FileCreateError", 0); - histogram_tester.ExpectTotalCount("ImportantFile.FileCreateError.test", 0); - - FilePath invalid_file_ = FilePath().AppendASCII("bad/../non_existent/path"); - EXPECT_FALSE(PathExists(invalid_file_)); - EXPECT_FALSE( - ImportantFileWriter::WriteFileAtomically(invalid_file_, nullptr)); - histogram_tester.ExpectTotalCount("ImportantFile.FileCreateError", 1); - histogram_tester.ExpectTotalCount("ImportantFile.FileCreateError.test", 0); - EXPECT_FALSE( - ImportantFileWriter::WriteFileAtomically(invalid_file_, nullptr, "test")); - histogram_tester.ExpectTotalCount("ImportantFile.FileCreateError", 1); - histogram_tester.ExpectTotalCount("ImportantFile.FileCreateError.test", 1); -} - -} // namespace base
diff --git a/base/files/memory_mapped_file_unittest.cc b/base/files/memory_mapped_file_unittest.cc deleted file mode 100644 index b7acc61..0000000 --- a/base/files/memory_mapped_file_unittest.cc +++ /dev/null
@@ -1,243 +0,0 @@ -// 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/files/memory_mapped_file.h" - -#include <stddef.h> -#include <stdint.h> - -#include <utility> - -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/platform_test.h" - -namespace base { - -namespace { - -// Create a temporary buffer and fill it with a watermark sequence. -std::unique_ptr<uint8_t[]> CreateTestBuffer(size_t size, size_t offset) { - std::unique_ptr<uint8_t[]> buf(new uint8_t[size]); - for (size_t i = 0; i < size; ++i) - buf.get()[i] = static_cast<uint8_t>((offset + i) % 253); - return buf; -} - -// Check that the watermark sequence is consistent with the |offset| provided. -bool CheckBufferContents(const uint8_t* data, size_t size, size_t offset) { - std::unique_ptr<uint8_t[]> test_data(CreateTestBuffer(size, offset)); - return memcmp(test_data.get(), data, size) == 0; -} - -class MemoryMappedFileTest : public PlatformTest { - protected: - void SetUp() override { - PlatformTest::SetUp(); - CreateTemporaryFile(&temp_file_path_); - } - - void TearDown() override { EXPECT_TRUE(DeleteFile(temp_file_path_, false)); } - - void CreateTemporaryTestFile(size_t size) { - File file(temp_file_path_, - File::FLAG_CREATE_ALWAYS | File::FLAG_READ | File::FLAG_WRITE); - EXPECT_TRUE(file.IsValid()); - - std::unique_ptr<uint8_t[]> test_data(CreateTestBuffer(size, 0)); - size_t bytes_written = - file.Write(0, reinterpret_cast<char*>(test_data.get()), size); - EXPECT_EQ(size, bytes_written); - file.Close(); - } - - const FilePath temp_file_path() const { return temp_file_path_; } - - private: - FilePath temp_file_path_; -}; - -TEST_F(MemoryMappedFileTest, MapWholeFileByPath) { - const size_t kFileSize = 68 * 1024; - CreateTemporaryTestFile(kFileSize); - MemoryMappedFile map; - map.Initialize(temp_file_path()); - ASSERT_EQ(kFileSize, map.length()); - ASSERT_TRUE(map.data() != nullptr); - EXPECT_TRUE(map.IsValid()); - ASSERT_TRUE(CheckBufferContents(map.data(), kFileSize, 0)); -} - -TEST_F(MemoryMappedFileTest, MapWholeFileByFD) { - const size_t kFileSize = 68 * 1024; - CreateTemporaryTestFile(kFileSize); - MemoryMappedFile map; - map.Initialize(File(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ)); - ASSERT_EQ(kFileSize, map.length()); - ASSERT_TRUE(map.data() != nullptr); - EXPECT_TRUE(map.IsValid()); - ASSERT_TRUE(CheckBufferContents(map.data(), kFileSize, 0)); -} - -TEST_F(MemoryMappedFileTest, MapSmallFile) { - const size_t kFileSize = 127; - CreateTemporaryTestFile(kFileSize); - MemoryMappedFile map; - map.Initialize(temp_file_path()); - ASSERT_EQ(kFileSize, map.length()); - ASSERT_TRUE(map.data() != nullptr); - EXPECT_TRUE(map.IsValid()); - ASSERT_TRUE(CheckBufferContents(map.data(), kFileSize, 0)); -} - -TEST_F(MemoryMappedFileTest, MapWholeFileUsingRegion) { - const size_t kFileSize = 157 * 1024; - CreateTemporaryTestFile(kFileSize); - MemoryMappedFile map; - - File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ); - map.Initialize(std::move(file), MemoryMappedFile::Region::kWholeFile); - ASSERT_EQ(kFileSize, map.length()); - ASSERT_TRUE(map.data() != nullptr); - EXPECT_TRUE(map.IsValid()); - ASSERT_TRUE(CheckBufferContents(map.data(), kFileSize, 0)); -} - -TEST_F(MemoryMappedFileTest, MapPartialRegionAtBeginning) { - const size_t kFileSize = 157 * 1024; - const size_t kPartialSize = 4 * 1024 + 32; - CreateTemporaryTestFile(kFileSize); - MemoryMappedFile map; - - File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ); - MemoryMappedFile::Region region = {0, kPartialSize}; - map.Initialize(std::move(file), region); - ASSERT_EQ(kPartialSize, map.length()); - ASSERT_TRUE(map.data() != nullptr); - EXPECT_TRUE(map.IsValid()); - ASSERT_TRUE(CheckBufferContents(map.data(), kPartialSize, 0)); -} - -TEST_F(MemoryMappedFileTest, MapPartialRegionAtEnd) { - const size_t kFileSize = 157 * 1024; - const size_t kPartialSize = 5 * 1024 - 32; - const size_t kOffset = kFileSize - kPartialSize; - CreateTemporaryTestFile(kFileSize); - MemoryMappedFile map; - - File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ); - MemoryMappedFile::Region region = {kOffset, kPartialSize}; - map.Initialize(std::move(file), region); - ASSERT_EQ(kPartialSize, map.length()); - ASSERT_TRUE(map.data() != nullptr); - EXPECT_TRUE(map.IsValid()); - ASSERT_TRUE(CheckBufferContents(map.data(), kPartialSize, kOffset)); -} - -TEST_F(MemoryMappedFileTest, MapSmallPartialRegionInTheMiddle) { - const size_t kFileSize = 157 * 1024; - const size_t kOffset = 1024 * 5 + 32; - const size_t kPartialSize = 8; - - CreateTemporaryTestFile(kFileSize); - MemoryMappedFile map; - - File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ); - MemoryMappedFile::Region region = {kOffset, kPartialSize}; - map.Initialize(std::move(file), region); - ASSERT_EQ(kPartialSize, map.length()); - ASSERT_TRUE(map.data() != nullptr); - EXPECT_TRUE(map.IsValid()); - ASSERT_TRUE(CheckBufferContents(map.data(), kPartialSize, kOffset)); -} - -TEST_F(MemoryMappedFileTest, MapLargePartialRegionInTheMiddle) { - const size_t kFileSize = 157 * 1024; - const size_t kOffset = 1024 * 5 + 32; - const size_t kPartialSize = 16 * 1024 - 32; - - CreateTemporaryTestFile(kFileSize); - MemoryMappedFile map; - - File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ); - MemoryMappedFile::Region region = {kOffset, kPartialSize}; - map.Initialize(std::move(file), region); - ASSERT_EQ(kPartialSize, map.length()); - ASSERT_TRUE(map.data() != nullptr); - EXPECT_TRUE(map.IsValid()); - ASSERT_TRUE(CheckBufferContents(map.data(), kPartialSize, kOffset)); -} - -TEST_F(MemoryMappedFileTest, WriteableFile) { - const size_t kFileSize = 127; - CreateTemporaryTestFile(kFileSize); - - { - MemoryMappedFile map; - map.Initialize(temp_file_path(), MemoryMappedFile::READ_WRITE); - ASSERT_EQ(kFileSize, map.length()); - ASSERT_TRUE(map.data() != nullptr); - EXPECT_TRUE(map.IsValid()); - ASSERT_TRUE(CheckBufferContents(map.data(), kFileSize, 0)); - - uint8_t* bytes = map.data(); - bytes[0] = 'B'; - bytes[1] = 'a'; - bytes[2] = 'r'; - bytes[kFileSize - 1] = '!'; - EXPECT_FALSE(CheckBufferContents(map.data(), kFileSize, 0)); - EXPECT_TRUE(CheckBufferContents(map.data() + 3, kFileSize - 4, 3)); - } - - int64_t file_size; - ASSERT_TRUE(GetFileSize(temp_file_path(), &file_size)); - EXPECT_EQ(static_cast<int64_t>(kFileSize), file_size); - - std::string contents; - ASSERT_TRUE(ReadFileToString(temp_file_path(), &contents)); - EXPECT_EQ("Bar", contents.substr(0, 3)); - EXPECT_EQ("!", contents.substr(kFileSize - 1, 1)); -} - -TEST_F(MemoryMappedFileTest, ExtendableFile) { - const size_t kFileSize = 127; - const size_t kFileExtend = 100; - CreateTemporaryTestFile(kFileSize); - - { - File file(temp_file_path(), - File::FLAG_OPEN | File::FLAG_READ | File::FLAG_WRITE); - MemoryMappedFile::Region region = {0, kFileSize + kFileExtend}; - MemoryMappedFile map; - map.Initialize(std::move(file), region, - MemoryMappedFile::READ_WRITE_EXTEND); - EXPECT_EQ(kFileSize + kFileExtend, map.length()); - ASSERT_TRUE(map.data() != nullptr); - EXPECT_TRUE(map.IsValid()); - ASSERT_TRUE(CheckBufferContents(map.data(), kFileSize, 0)); - - uint8_t* bytes = map.data(); - EXPECT_EQ(0, bytes[kFileSize + 0]); - EXPECT_EQ(0, bytes[kFileSize + 1]); - EXPECT_EQ(0, bytes[kFileSize + 2]); - bytes[kFileSize + 0] = 'B'; - bytes[kFileSize + 1] = 'A'; - bytes[kFileSize + 2] = 'Z'; - EXPECT_TRUE(CheckBufferContents(map.data(), kFileSize, 0)); - } - - int64_t file_size; - ASSERT_TRUE(GetFileSize(temp_file_path(), &file_size)); - EXPECT_LE(static_cast<int64_t>(kFileSize + 3), file_size); - EXPECT_GE(static_cast<int64_t>(kFileSize + kFileExtend), file_size); - - std::string contents; - ASSERT_TRUE(ReadFileToString(temp_file_path(), &contents)); - EXPECT_EQ("BAZ", contents.substr(kFileSize, 3)); -} - -} // namespace - -} // namespace base
diff --git a/base/files/scoped_temp_dir_unittest.cc b/base/files/scoped_temp_dir_unittest.cc deleted file mode 100644 index 84eff6e..0000000 --- a/base/files/scoped_temp_dir_unittest.cc +++ /dev/null
@@ -1,114 +0,0 @@ -// 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 <string> - -#include "base/files/file.h" -#include "base/files/file_util.h" -#include "base/files/scoped_temp_dir.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(ScopedTempDir, FullPath) { - FilePath test_path; - base::CreateNewTempDirectory(FILE_PATH_LITERAL("scoped_temp_dir"), - &test_path); - - // Against an existing dir, it should get destroyed when leaving scope. - EXPECT_TRUE(DirectoryExists(test_path)); - { - ScopedTempDir dir; - EXPECT_TRUE(dir.Set(test_path)); - EXPECT_TRUE(dir.IsValid()); - } - EXPECT_FALSE(DirectoryExists(test_path)); - - { - ScopedTempDir dir; - EXPECT_TRUE(dir.Set(test_path)); - // Now the dir doesn't exist, so ensure that it gets created. - EXPECT_TRUE(DirectoryExists(test_path)); - // When we call Release(), it shouldn't get destroyed when leaving scope. - FilePath path = dir.Take(); - EXPECT_EQ(path.value(), test_path.value()); - EXPECT_FALSE(dir.IsValid()); - } - EXPECT_TRUE(DirectoryExists(test_path)); - - // Clean up. - { - ScopedTempDir dir; - EXPECT_TRUE(dir.Set(test_path)); - } - EXPECT_FALSE(DirectoryExists(test_path)); -} - -TEST(ScopedTempDir, TempDir) { - // In this case, just verify that a directory was created and that it's a - // child of TempDir. - FilePath test_path; - { - ScopedTempDir dir; - EXPECT_TRUE(dir.CreateUniqueTempDir()); - test_path = dir.GetPath(); - EXPECT_TRUE(DirectoryExists(test_path)); - FilePath tmp_dir; - EXPECT_TRUE(base::GetTempDir(&tmp_dir)); - EXPECT_TRUE(test_path.value().find(tmp_dir.value()) != std::string::npos); - } - EXPECT_FALSE(DirectoryExists(test_path)); -} - -TEST(ScopedTempDir, UniqueTempDirUnderPath) { - // Create a path which will contain a unique temp path. - FilePath base_path; - ASSERT_TRUE(base::CreateNewTempDirectory(FILE_PATH_LITERAL("base_dir"), - &base_path)); - - FilePath test_path; - { - ScopedTempDir dir; - EXPECT_TRUE(dir.CreateUniqueTempDirUnderPath(base_path)); - test_path = dir.GetPath(); - EXPECT_TRUE(DirectoryExists(test_path)); - EXPECT_TRUE(base_path.IsParent(test_path)); - EXPECT_TRUE(test_path.value().find(base_path.value()) != std::string::npos); - } - EXPECT_FALSE(DirectoryExists(test_path)); - base::DeleteFile(base_path, true); -} - -TEST(ScopedTempDir, MultipleInvocations) { - ScopedTempDir dir; - EXPECT_TRUE(dir.CreateUniqueTempDir()); - EXPECT_FALSE(dir.CreateUniqueTempDir()); - EXPECT_TRUE(dir.Delete()); - EXPECT_TRUE(dir.CreateUniqueTempDir()); - EXPECT_FALSE(dir.CreateUniqueTempDir()); - ScopedTempDir other_dir; - EXPECT_TRUE(other_dir.Set(dir.Take())); - EXPECT_TRUE(dir.CreateUniqueTempDir()); - EXPECT_FALSE(dir.CreateUniqueTempDir()); - EXPECT_FALSE(other_dir.CreateUniqueTempDir()); -} - -#if defined(OS_WIN) -TEST(ScopedTempDir, LockedTempDir) { - ScopedTempDir dir; - EXPECT_TRUE(dir.CreateUniqueTempDir()); - base::File file(dir.GetPath().Append(FILE_PATH_LITERAL("temp")), - base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); - EXPECT_TRUE(file.IsValid()); - EXPECT_EQ(base::File::FILE_OK, file.error_details()); - EXPECT_FALSE(dir.Delete()); // We should not be able to delete. - EXPECT_FALSE(dir.GetPath().empty()); // We should still have a valid path. - file.Close(); - // Now, we should be able to delete. - EXPECT_TRUE(dir.Delete()); -} -#endif // defined(OS_WIN) - -} // namespace base
diff --git a/base/gmock_unittest.cc b/base/gmock_unittest.cc deleted file mode 100644 index 5c16728..0000000 --- a/base/gmock_unittest.cc +++ /dev/null
@@ -1,135 +0,0 @@ -// Copyright (c) 2009 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 test is a simple sanity check to make sure gmock is able to build/link -// correctly. It just instantiates a mock object and runs through a couple of -// the basic mock features. - -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -// Gmock matchers and actions that we use below. -using testing::AnyOf; -using testing::Eq; -using testing::Return; -using testing::SetArgPointee; -using testing::WithArg; -using testing::_; - -namespace { - -// Simple class that we can mock out the behavior for. Everything is virtual -// for easy mocking. -class SampleClass { - public: - SampleClass() = default; - virtual ~SampleClass() = default; - - virtual int ReturnSomething() { - return -1; - } - - virtual void ReturnNothingConstly() const { - } - - virtual void OutputParam(int* a) { - } - - virtual int ReturnSecond(int a, int b) { - return b; - } -}; - -// Declare a mock for the class. -class MockSampleClass : public SampleClass { - public: - MOCK_METHOD0(ReturnSomething, int()); - MOCK_CONST_METHOD0(ReturnNothingConstly, void()); - MOCK_METHOD1(OutputParam, void(int* a)); - MOCK_METHOD2(ReturnSecond, int(int a, int b)); -}; - -// Create a couple of custom actions. Custom actions can be used for adding -// more complex behavior into your mock...though if you start needing these, ask -// if you're asking your mock to do too much. -ACTION(ReturnVal) { - // Return the first argument received. - return arg0; -} -ACTION(ReturnSecond) { - // Returns the second argument. This basically implemetns ReturnSecond. - return arg1; -} - -TEST(GmockTest, SimpleMatchAndActions) { - // Basic test of some simple gmock matchers, actions, and cardinality - // expectations. - MockSampleClass mock; - - EXPECT_CALL(mock, ReturnSomething()) - .WillOnce(Return(1)) - .WillOnce(Return(2)) - .WillOnce(Return(3)); - EXPECT_EQ(1, mock.ReturnSomething()); - EXPECT_EQ(2, mock.ReturnSomething()); - EXPECT_EQ(3, mock.ReturnSomething()); - - EXPECT_CALL(mock, ReturnNothingConstly()).Times(2); - mock.ReturnNothingConstly(); - mock.ReturnNothingConstly(); -} - -TEST(GmockTest, AssignArgument) { - // Capture an argument for examination. - MockSampleClass mock; - - EXPECT_CALL(mock, OutputParam(_)).WillRepeatedly(SetArgPointee<0>(5)); - - int arg = 0; - mock.OutputParam(&arg); - EXPECT_EQ(5, arg); -} - -TEST(GmockTest, SideEffects) { - // Capture an argument for examination. - MockSampleClass mock; - - EXPECT_CALL(mock, OutputParam(_)).WillRepeatedly(SetArgPointee<0>(5)); - - int arg = 0; - mock.OutputParam(&arg); - EXPECT_EQ(5, arg); -} - -TEST(GmockTest, CustomAction_ReturnSecond) { - // Test a mock of the ReturnSecond behavior using an action that provides an - // alternate implementation of the function. Danger here though, this is - // starting to add too much behavior of the mock, which means the mock - // implementation might start to have bugs itself. - MockSampleClass mock; - - EXPECT_CALL(mock, ReturnSecond(_, AnyOf(Eq(4), Eq(5)))) - .WillRepeatedly(ReturnSecond()); - EXPECT_EQ(4, mock.ReturnSecond(-1, 4)); - EXPECT_EQ(5, mock.ReturnSecond(0, 5)); - EXPECT_EQ(4, mock.ReturnSecond(0xdeadbeef, 4)); - EXPECT_EQ(4, mock.ReturnSecond(112358, 4)); - EXPECT_EQ(5, mock.ReturnSecond(1337, 5)); -} - -TEST(GmockTest, CustomAction_ReturnVal) { - // Alternate implemention of ReturnSecond using a more general custom action, - // and a WithArg adapter to bridge the interfaces. - MockSampleClass mock; - - EXPECT_CALL(mock, ReturnSecond(_, AnyOf(Eq(4), Eq(5)))) - .WillRepeatedly(WithArg<1>(ReturnVal())); - EXPECT_EQ(4, mock.ReturnSecond(-1, 4)); - EXPECT_EQ(5, mock.ReturnSecond(0, 5)); - EXPECT_EQ(4, mock.ReturnSecond(0xdeadbeef, 4)); - EXPECT_EQ(4, mock.ReturnSecond(112358, 4)); - EXPECT_EQ(5, mock.ReturnSecond(1337, 5)); -} - -} // namespace
diff --git a/base/guid_unittest.cc b/base/guid_unittest.cc deleted file mode 100644 index 8aa56ed..0000000 --- a/base/guid_unittest.cc +++ /dev/null
@@ -1,65 +0,0 @@ -// 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/guid.h" - -#include <stdint.h> - -#include <limits> - -#include "base/strings/string_util.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -bool IsGUIDv4(const std::string& guid) { - // The format of GUID version 4 must be xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx, - // where y is one of [8, 9, A, B]. - return IsValidGUID(guid) && guid[14] == '4' && - (guid[19] == '8' || guid[19] == '9' || guid[19] == 'A' || - guid[19] == 'a' || guid[19] == 'B' || guid[19] == 'b'); -} - -} // namespace - -TEST(GUIDTest, GUIDGeneratesAllZeroes) { - uint64_t bytes[] = {0, 0}; - std::string clientid = RandomDataToGUIDString(bytes); - EXPECT_EQ("00000000-0000-0000-0000-000000000000", clientid); -} - -TEST(GUIDTest, GUIDGeneratesCorrectly) { - uint64_t bytes[] = {0x0123456789ABCDEFULL, 0xFEDCBA9876543210ULL}; - std::string clientid = RandomDataToGUIDString(bytes); - EXPECT_EQ("01234567-89ab-cdef-fedc-ba9876543210", clientid); -} - -TEST(GUIDTest, GUIDCorrectlyFormatted) { - const int kIterations = 10; - for (int it = 0; it < kIterations; ++it) { - std::string guid = GenerateGUID(); - EXPECT_TRUE(IsValidGUID(guid)); - EXPECT_TRUE(IsValidGUIDOutputString(guid)); - EXPECT_TRUE(IsValidGUID(ToLowerASCII(guid))); - EXPECT_TRUE(IsValidGUID(ToUpperASCII(guid))); - } -} - -TEST(GUIDTest, GUIDBasicUniqueness) { - const int kIterations = 10; - for (int it = 0; it < kIterations; ++it) { - std::string guid1 = GenerateGUID(); - std::string guid2 = GenerateGUID(); - EXPECT_EQ(36U, guid1.length()); - EXPECT_EQ(36U, guid2.length()); - EXPECT_NE(guid1, guid2); - EXPECT_TRUE(IsGUIDv4(guid1)); - EXPECT_TRUE(IsGUIDv4(guid2)); - } -} - -} // namespace base
diff --git a/base/hash_unittest.cc b/base/hash_unittest.cc deleted file mode 100644 index fc8a751..0000000 --- a/base/hash_unittest.cc +++ /dev/null
@@ -1,82 +0,0 @@ -// 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/hash.h" - -#include <string> -#include <vector> - -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(HashTest, String) { - std::string str; - // Empty string (should hash to 0). - str = ""; - EXPECT_EQ(0u, Hash(str)); - - // Simple test. - str = "hello world"; - EXPECT_EQ(2794219650u, Hash(str)); - - // Change one bit. - str = "helmo world"; - EXPECT_EQ(1006697176u, Hash(str)); - - // Insert a null byte. - str = "hello world"; - str[5] = '\0'; - EXPECT_EQ(2319902537u, Hash(str)); - - // Test that the bytes after the null contribute to the hash. - str = "hello worle"; - str[5] = '\0'; - EXPECT_EQ(553904462u, Hash(str)); - - // Extremely long string. - // Also tests strings with high bit set, and null byte. - std::vector<char> long_string_buffer; - for (int i = 0; i < 4096; ++i) - long_string_buffer.push_back((i % 256) - 128); - str.assign(&long_string_buffer.front(), long_string_buffer.size()); - EXPECT_EQ(2797962408u, Hash(str)); - - // All possible lengths (mod 4). Tests separate code paths. Also test with - // final byte high bit set (regression test for http://crbug.com/90659). - // Note that the 1 and 3 cases have a weird bug where the final byte is - // treated as a signed char. It was decided on the above bug discussion to - // enshrine that behaviour as "correct" to avoid invalidating existing hashes. - - // Length mod 4 == 0. - str = "hello w\xab"; - EXPECT_EQ(615571198u, Hash(str)); - // Length mod 4 == 1. - str = "hello wo\xab"; - EXPECT_EQ(623474296u, Hash(str)); - // Length mod 4 == 2. - str = "hello wor\xab"; - EXPECT_EQ(4278562408u, Hash(str)); - // Length mod 4 == 3. - str = "hello worl\xab"; - EXPECT_EQ(3224633008u, Hash(str)); -} - -TEST(HashTest, CString) { - const char* str; - // Empty string (should hash to 0). - str = ""; - EXPECT_EQ(0u, Hash(str, strlen(str))); - - // Simple test. - str = "hello world"; - EXPECT_EQ(2794219650u, Hash(str, strlen(str))); - - // Ensure that it stops reading after the given length, and does not expect a - // null byte. - str = "hello world; don't read this part"; - EXPECT_EQ(2794219650u, Hash(str, strlen("hello world"))); -} - -} // namespace base
diff --git a/base/i18n/bidi_line_iterator_unittest.cc b/base/i18n/bidi_line_iterator_unittest.cc deleted file mode 100644 index d531313..0000000 --- a/base/i18n/bidi_line_iterator_unittest.cc +++ /dev/null
@@ -1,209 +0,0 @@ -// 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/i18n/bidi_line_iterator.h" - -#include "base/macros.h" -#include "base/strings/utf_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace i18n { -namespace { - -class BiDiLineIteratorTest : public testing::TestWithParam<TextDirection> { - public: - BiDiLineIteratorTest() = default; - - BiDiLineIterator* iterator() { return &iterator_; } - - private: - BiDiLineIterator iterator_; - - DISALLOW_COPY_AND_ASSIGN(BiDiLineIteratorTest); -}; - -TEST_P(BiDiLineIteratorTest, OnlyLTR) { - iterator()->Open(UTF8ToUTF16("abc 😁 测试"), GetParam(), - BiDiLineIterator::CustomBehavior::NONE); - ASSERT_EQ(1, iterator()->CountRuns()); - - int start, length; - EXPECT_EQ(UBIDI_LTR, iterator()->GetVisualRun(0, &start, &length)); - EXPECT_EQ(0, start); - EXPECT_EQ(9, length); - - int end; - UBiDiLevel level; - iterator()->GetLogicalRun(0, &end, &level); - EXPECT_EQ(9, end); - if (GetParam() == TextDirection::RIGHT_TO_LEFT) - EXPECT_EQ(2, level); - else - EXPECT_EQ(0, level); -} - -TEST_P(BiDiLineIteratorTest, OnlyRTL) { - iterator()->Open(UTF8ToUTF16("מה השעה"), GetParam(), - BiDiLineIterator::CustomBehavior::NONE); - ASSERT_EQ(1, iterator()->CountRuns()); - - int start, length; - EXPECT_EQ(UBIDI_RTL, iterator()->GetVisualRun(0, &start, &length)); - EXPECT_EQ(0, start); - EXPECT_EQ(7, length); - - int end; - UBiDiLevel level; - iterator()->GetLogicalRun(0, &end, &level); - EXPECT_EQ(7, end); - EXPECT_EQ(1, level); -} - -TEST_P(BiDiLineIteratorTest, Mixed) { - iterator()->Open(UTF8ToUTF16("אני משתמש ב- Chrome כדפדפן האינטרנט שלי"), - GetParam(), BiDiLineIterator::CustomBehavior::NONE); - ASSERT_EQ(3, iterator()->CountRuns()); - - // We'll get completely different results depending on the top-level paragraph - // direction. - if (GetParam() == TextDirection::RIGHT_TO_LEFT) { - // If para direction is RTL, expect the LTR substring "Chrome" to be nested - // within the surrounding RTL text. - int start, length; - EXPECT_EQ(UBIDI_RTL, iterator()->GetVisualRun(0, &start, &length)); - EXPECT_EQ(19, start); - EXPECT_EQ(20, length); - EXPECT_EQ(UBIDI_LTR, iterator()->GetVisualRun(1, &start, &length)); - EXPECT_EQ(13, start); - EXPECT_EQ(6, length); - EXPECT_EQ(UBIDI_RTL, iterator()->GetVisualRun(2, &start, &length)); - EXPECT_EQ(0, start); - EXPECT_EQ(13, length); - - int end; - UBiDiLevel level; - iterator()->GetLogicalRun(0, &end, &level); - EXPECT_EQ(13, end); - EXPECT_EQ(1, level); - iterator()->GetLogicalRun(13, &end, &level); - EXPECT_EQ(19, end); - EXPECT_EQ(2, level); - iterator()->GetLogicalRun(19, &end, &level); - EXPECT_EQ(39, end); - EXPECT_EQ(1, level); - } else { - // If the para direction is LTR, expect the LTR substring "- Chrome " to be - // at the top level, with two nested RTL runs on either side. - int start, length; - EXPECT_EQ(UBIDI_RTL, iterator()->GetVisualRun(0, &start, &length)); - EXPECT_EQ(0, start); - EXPECT_EQ(11, length); - EXPECT_EQ(UBIDI_LTR, iterator()->GetVisualRun(1, &start, &length)); - EXPECT_EQ(11, start); - EXPECT_EQ(9, length); - EXPECT_EQ(UBIDI_RTL, iterator()->GetVisualRun(2, &start, &length)); - EXPECT_EQ(20, start); - EXPECT_EQ(19, length); - - int end; - UBiDiLevel level; - iterator()->GetLogicalRun(0, &end, &level); - EXPECT_EQ(11, end); - EXPECT_EQ(1, level); - iterator()->GetLogicalRun(11, &end, &level); - EXPECT_EQ(20, end); - EXPECT_EQ(0, level); - iterator()->GetLogicalRun(20, &end, &level); - EXPECT_EQ(39, end); - EXPECT_EQ(1, level); - } -} - -TEST_P(BiDiLineIteratorTest, RTLPunctuationNoCustomBehavior) { - // This string features Hebrew characters interleaved with ASCII punctuation. - iterator()->Open(UTF8ToUTF16("א!ב\"ג#ד$ה%ו&ז'ח(ט)י*ך+כ,ל-ם.מ/" - "ן:נ;ס<ע=ף>פ?ץ@צ[ק\\ר]ש^ת_א`ב{ג|ד}ה~ו"), - GetParam(), BiDiLineIterator::CustomBehavior::NONE); - - // Expect a single RTL run. - ASSERT_EQ(1, iterator()->CountRuns()); - - int start, length; - EXPECT_EQ(UBIDI_RTL, iterator()->GetVisualRun(0, &start, &length)); - EXPECT_EQ(0, start); - EXPECT_EQ(65, length); - - int end; - UBiDiLevel level; - iterator()->GetLogicalRun(0, &end, &level); - EXPECT_EQ(65, end); - EXPECT_EQ(1, level); -} - -TEST_P(BiDiLineIteratorTest, RTLPunctuationAsURL) { - // This string features Hebrew characters interleaved with ASCII punctuation. - iterator()->Open(UTF8ToUTF16("א!ב\"ג#ד$ה%ו&ז'ח(ט)י*ך+כ,ל-ם.מ/" - "ן:נ;ס<ע=ף>פ?ץ@צ[ק\\ר]ש^ת_א`ב{ג|ד}ה~ו"), - GetParam(), BiDiLineIterator::CustomBehavior::AS_URL); - - const int kStringSize = 65; - - // Expect a primary RTL run, broken up by each of the 8 punctuation marks that - // are considered strong LTR (17 runs total). - struct { - int start; - UBiDiDirection dir; - } expected_runs[] = { - {0, UBIDI_RTL}, {5, UBIDI_LTR}, // '#' - {6, UBIDI_RTL}, {11, UBIDI_LTR}, // '&' - {12, UBIDI_RTL}, {27, UBIDI_LTR}, // '.' - {28, UBIDI_RTL}, {29, UBIDI_LTR}, // '/' - {30, UBIDI_RTL}, {31, UBIDI_LTR}, // ':' - {32, UBIDI_RTL}, {37, UBIDI_LTR}, // '=' - {38, UBIDI_RTL}, {41, UBIDI_LTR}, // '?' - {42, UBIDI_RTL}, {43, UBIDI_LTR}, // '@' - {44, UBIDI_RTL}, - }; - - ASSERT_EQ(arraysize(expected_runs), - static_cast<size_t>(iterator()->CountRuns())); - - for (size_t i = 0; i < arraysize(expected_runs); ++i) { - const auto& expected_run = expected_runs[i]; - int expected_run_end = i >= arraysize(expected_runs) - 1 - ? kStringSize - : expected_runs[i + 1].start; - - size_t visual_index = GetParam() == TextDirection::RIGHT_TO_LEFT - ? arraysize(expected_runs) - 1 - i - : i; - int start, length; - EXPECT_EQ(expected_run.dir, - iterator()->GetVisualRun(visual_index, &start, &length)) - << "(i = " << i << ")"; - EXPECT_EQ(expected_run.start, start) << "(i = " << i << ")"; - EXPECT_EQ(expected_run_end - expected_run.start, length) - << "(i = " << i << ")"; - - int expected_level = - expected_run.dir == UBIDI_RTL - ? 1 - : (GetParam() == TextDirection::RIGHT_TO_LEFT ? 2 : 0); - int end; - UBiDiLevel level; - iterator()->GetLogicalRun(expected_run.start, &end, &level); - EXPECT_EQ(expected_run_end, end) << "(i = " << i << ")"; - EXPECT_EQ(expected_level, level) << "(i = " << i << ")"; - } -} - -INSTANTIATE_TEST_CASE_P(, - BiDiLineIteratorTest, - ::testing::Values(TextDirection::LEFT_TO_RIGHT, - TextDirection::RIGHT_TO_LEFT)); - -} // namespace -} // namespace i18n -} // namespace base
diff --git a/base/i18n/break_iterator_unittest.cc b/base/i18n/break_iterator_unittest.cc deleted file mode 100644 index 6137e02..0000000 --- a/base/i18n/break_iterator_unittest.cc +++ /dev/null
@@ -1,461 +0,0 @@ -// 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/i18n/break_iterator.h" - -#include <stddef.h> - -#include "base/macros.h" -#include "base/strings/string_piece.h" -#include "base/strings/stringprintf.h" -#include "base/strings/utf_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace i18n { - -TEST(BreakIteratorTest, BreakWordEmpty) { - string16 empty; - BreakIterator iter(empty, BreakIterator::BREAK_WORD); - ASSERT_TRUE(iter.Init()); - EXPECT_FALSE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. - EXPECT_FALSE(iter.IsWord()); -} - -TEST(BreakIteratorTest, BreakWord) { - string16 space(UTF8ToUTF16(" ")); - string16 str(UTF8ToUTF16(" foo bar! \npouet boom")); - BreakIterator iter(str, BreakIterator::BREAK_WORD); - ASSERT_TRUE(iter.Init()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(space, iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_TRUE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("foo"), iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(space, iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_TRUE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("bar"), iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("!"), iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(space, iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("\n"), iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_TRUE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("pouet"), iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(space, iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_TRUE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("boom"), iter.GetString()); - EXPECT_FALSE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. - EXPECT_FALSE(iter.IsWord()); -} - -TEST(BreakIteratorTest, BreakWide16) { - // Two greek words separated by space. - const string16 str(WideToUTF16( - L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9" - L"\x03bf\x03c2\x0020\x0399\x03c3\x03c4\x03cc\x03c2")); - const string16 word1(str.substr(0, 10)); - const string16 word2(str.substr(11, 5)); - BreakIterator iter(str, BreakIterator::BREAK_WORD); - ASSERT_TRUE(iter.Init()); - EXPECT_TRUE(iter.Advance()); - EXPECT_TRUE(iter.IsWord()); - EXPECT_EQ(word1, iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16(" "), iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_TRUE(iter.IsWord()); - EXPECT_EQ(word2, iter.GetString()); - EXPECT_FALSE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. - EXPECT_FALSE(iter.IsWord()); -} - -TEST(BreakIteratorTest, BreakWide32) { - // U+1D49C MATHEMATICAL SCRIPT CAPITAL A - const char very_wide_char[] = "\xF0\x9D\x92\x9C"; - const string16 str( - UTF8ToUTF16(base::StringPrintf("%s a", very_wide_char))); - const string16 very_wide_word(str.substr(0, 2)); - - BreakIterator iter(str, BreakIterator::BREAK_WORD); - ASSERT_TRUE(iter.Init()); - EXPECT_TRUE(iter.Advance()); - EXPECT_TRUE(iter.IsWord()); - EXPECT_EQ(very_wide_word, iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16(" "), iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_TRUE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("a"), iter.GetString()); - EXPECT_FALSE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. - EXPECT_FALSE(iter.IsWord()); -} - -TEST(BreakIteratorTest, BreakSpaceEmpty) { - string16 empty; - BreakIterator iter(empty, BreakIterator::BREAK_SPACE); - ASSERT_TRUE(iter.Init()); - EXPECT_FALSE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. - EXPECT_FALSE(iter.IsWord()); -} - -TEST(BreakIteratorTest, BreakSpace) { - string16 str(UTF8ToUTF16(" foo bar! \npouet boom")); - BreakIterator iter(str, BreakIterator::BREAK_SPACE); - ASSERT_TRUE(iter.Init()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16(" "), iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("foo "), iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("bar! \n"), iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("pouet "), iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("boom"), iter.GetString()); - EXPECT_FALSE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. - EXPECT_FALSE(iter.IsWord()); -} - -TEST(BreakIteratorTest, BreakSpaceSP) { - string16 str(UTF8ToUTF16(" foo bar! \npouet boom ")); - BreakIterator iter(str, BreakIterator::BREAK_SPACE); - ASSERT_TRUE(iter.Init()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16(" "), iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("foo "), iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("bar! \n"), iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("pouet "), iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("boom "), iter.GetString()); - EXPECT_FALSE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. - EXPECT_FALSE(iter.IsWord()); -} - -TEST(BreakIteratorTest, BreakSpacekWide16) { - // Two Greek words. - const string16 str(WideToUTF16( - L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9" - L"\x03bf\x03c2\x0020\x0399\x03c3\x03c4\x03cc\x03c2")); - const string16 word1(str.substr(0, 11)); - const string16 word2(str.substr(11, 5)); - BreakIterator iter(str, BreakIterator::BREAK_SPACE); - ASSERT_TRUE(iter.Init()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(word1, iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(word2, iter.GetString()); - EXPECT_FALSE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. - EXPECT_FALSE(iter.IsWord()); -} - -TEST(BreakIteratorTest, BreakSpaceWide32) { - // U+1D49C MATHEMATICAL SCRIPT CAPITAL A - const char very_wide_char[] = "\xF0\x9D\x92\x9C"; - const string16 str( - UTF8ToUTF16(base::StringPrintf("%s a", very_wide_char))); - const string16 very_wide_word(str.substr(0, 3)); - - BreakIterator iter(str, BreakIterator::BREAK_SPACE); - ASSERT_TRUE(iter.Init()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(very_wide_word, iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("a"), iter.GetString()); - EXPECT_FALSE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. - EXPECT_FALSE(iter.IsWord()); -} - -TEST(BreakIteratorTest, BreakLineEmpty) { - string16 empty; - BreakIterator iter(empty, BreakIterator::BREAK_NEWLINE); - ASSERT_TRUE(iter.Init()); - EXPECT_FALSE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. - EXPECT_FALSE(iter.IsWord()); -} - -TEST(BreakIteratorTest, BreakLine) { - string16 nl(UTF8ToUTF16("\n")); - string16 str(UTF8ToUTF16("\nfoo bar!\n\npouet boom")); - BreakIterator iter(str, BreakIterator::BREAK_NEWLINE); - ASSERT_TRUE(iter.Init()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(nl, iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("foo bar!\n"), iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(nl, iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("pouet boom"), iter.GetString()); - EXPECT_FALSE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. - EXPECT_FALSE(iter.IsWord()); -} - -TEST(BreakIteratorTest, BreakLineNL) { - string16 nl(UTF8ToUTF16("\n")); - string16 str(UTF8ToUTF16("\nfoo bar!\n\npouet boom\n")); - BreakIterator iter(str, BreakIterator::BREAK_NEWLINE); - ASSERT_TRUE(iter.Init()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(nl, iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("foo bar!\n"), iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(nl, iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("pouet boom\n"), iter.GetString()); - EXPECT_FALSE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. - EXPECT_FALSE(iter.IsWord()); -} - -TEST(BreakIteratorTest, BreakLineWide16) { - // Two Greek words separated by newline. - const string16 str(WideToUTF16( - L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9" - L"\x03bf\x03c2\x000a\x0399\x03c3\x03c4\x03cc\x03c2")); - const string16 line1(str.substr(0, 11)); - const string16 line2(str.substr(11, 5)); - BreakIterator iter(str, BreakIterator::BREAK_NEWLINE); - ASSERT_TRUE(iter.Init()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(line1, iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(line2, iter.GetString()); - EXPECT_FALSE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. - EXPECT_FALSE(iter.IsWord()); -} - -TEST(BreakIteratorTest, BreakLineWide32) { - // U+1D49C MATHEMATICAL SCRIPT CAPITAL A - const char very_wide_char[] = "\xF0\x9D\x92\x9C"; - const string16 str( - UTF8ToUTF16(base::StringPrintf("%s\na", very_wide_char))); - const string16 very_wide_line(str.substr(0, 3)); - BreakIterator iter(str, BreakIterator::BREAK_NEWLINE); - ASSERT_TRUE(iter.Init()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(very_wide_line, iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("a"), iter.GetString()); - EXPECT_FALSE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. - EXPECT_FALSE(iter.IsWord()); -} - -TEST(BreakIteratorTest, BreakCharacter) { - static const wchar_t* kCharacters[] = { - // An English word consisting of four ASCII characters. - L"w", L"o", L"r", L"d", L" ", - // A Hindi word (which means "Hindi") consisting of three Devanagari - // characters. - L"\x0939\x093F", L"\x0928\x094D", L"\x0926\x0940", L" ", - // A Thai word (which means "feel") consisting of three Thai characters. - L"\x0E23\x0E39\x0E49", L"\x0E2A\x0E36", L"\x0E01", L" ", - }; - std::vector<string16> characters; - string16 text; - for (size_t i = 0; i < arraysize(kCharacters); ++i) { - characters.push_back(WideToUTF16(kCharacters[i])); - text.append(characters.back()); - } - BreakIterator iter(text, BreakIterator::BREAK_CHARACTER); - ASSERT_TRUE(iter.Init()); - for (size_t i = 0; i < arraysize(kCharacters); ++i) { - EXPECT_TRUE(iter.Advance()); - EXPECT_EQ(characters[i], iter.GetString()); - } -} - -// Test for https://code.google.com/p/chromium/issues/detail?id=411213 -// We should be able to get valid substrings with GetString() function -// after setting new content by calling SetText(). -TEST(BreakIteratorTest, GetStringAfterSetText) { - const string16 initial_string(ASCIIToUTF16("str")); - BreakIterator iter(initial_string, BreakIterator::BREAK_WORD); - ASSERT_TRUE(iter.Init()); - - const string16 long_string(ASCIIToUTF16("another,string")); - EXPECT_TRUE(iter.SetText(long_string.c_str(), long_string.size())); - EXPECT_TRUE(iter.Advance()); - EXPECT_TRUE(iter.Advance()); // Advance to ',' in |long_string| - - // Check that the current position is out of bounds of the |initial_string|. - EXPECT_LT(initial_string.size(), iter.pos()); - - // Check that we can get a valid substring of |long_string|. - EXPECT_EQ(ASCIIToUTF16(","), iter.GetString()); -} - -TEST(BreakIteratorTest, GetStringPiece) { - const string16 initial_string(ASCIIToUTF16("some string")); - BreakIterator iter(initial_string, BreakIterator::BREAK_WORD); - ASSERT_TRUE(iter.Init()); - - EXPECT_TRUE(iter.Advance()); - EXPECT_EQ(iter.GetString(), iter.GetStringPiece().as_string()); - EXPECT_EQ(StringPiece16(ASCIIToUTF16("some")), iter.GetStringPiece()); - - EXPECT_TRUE(iter.Advance()); - EXPECT_TRUE(iter.Advance()); - EXPECT_EQ(iter.GetString(), iter.GetStringPiece().as_string()); - EXPECT_EQ(StringPiece16(ASCIIToUTF16("string")), iter.GetStringPiece()); -} - -// Make sure that when not in RULE_BASED or BREAK_WORD mode we're getting -// IS_LINE_OR_CHAR_BREAK. -TEST(BreakIteratorTest, GetWordBreakStatusBreakLine) { - // A string containing the English word "foo", followed by two Khmer - // characters, the English word "Can", and then two Russian characters and - // punctuation. - base::string16 text( - base::WideToUTF16(L"foo \x1791\x17C1 \nCan \x041C\x0438...")); - BreakIterator iter(text, BreakIterator::BREAK_LINE); - ASSERT_TRUE(iter.Init()); - - EXPECT_TRUE(iter.Advance()); - // Finds "foo" and the space. - EXPECT_EQ(base::UTF8ToUTF16("foo "), iter.GetString()); - EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_LINE_OR_CHAR_BREAK); - EXPECT_TRUE(iter.Advance()); - // Finds the Khmer characters, the next space, and the newline. - EXPECT_EQ(base::WideToUTF16(L"\x1791\x17C1 \n"), iter.GetString()); - EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_LINE_OR_CHAR_BREAK); - EXPECT_TRUE(iter.Advance()); - // Finds "Can" and the space. - EXPECT_EQ(base::UTF8ToUTF16("Can "), iter.GetString()); - EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_LINE_OR_CHAR_BREAK); - EXPECT_TRUE(iter.Advance()); - // Finds the Russian characters and periods. - EXPECT_EQ(base::WideToUTF16(L"\x041C\x0438..."), iter.GetString()); - EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_LINE_OR_CHAR_BREAK); - EXPECT_FALSE(iter.Advance()); -} - -// Make sure that in BREAK_WORD mode we're getting IS_WORD_BREAK and -// IS_SKIPPABLE_WORD when we should be. IS_WORD_BREAK should be returned when we -// finish going over non-punctuation characters while IS_SKIPPABLE_WORD should -// be returned on punctuation and spaces. -TEST(BreakIteratorTest, GetWordBreakStatusBreakWord) { - // A string containing the English word "foo", followed by two Khmer - // characters, the English word "Can", and then two Russian characters and - // punctuation. - base::string16 text( - base::WideToUTF16(L"foo \x1791\x17C1 \nCan \x041C\x0438...")); - BreakIterator iter(text, BreakIterator::BREAK_WORD); - ASSERT_TRUE(iter.Init()); - - EXPECT_TRUE(iter.Advance()); - // Finds "foo". - EXPECT_EQ(base::UTF8ToUTF16("foo"), iter.GetString()); - EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_WORD_BREAK); - EXPECT_TRUE(iter.Advance()); - // Finds the space, and the Khmer characters. - EXPECT_EQ(base::UTF8ToUTF16(" "), iter.GetString()); - EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD); - EXPECT_TRUE(iter.Advance()); - EXPECT_EQ(base::WideToUTF16(L"\x1791\x17C1"), iter.GetString()); - EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_WORD_BREAK); - EXPECT_TRUE(iter.Advance()); - // Finds the space and the newline. - EXPECT_EQ(base::UTF8ToUTF16(" "), iter.GetString()); - EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD); - EXPECT_TRUE(iter.Advance()); - EXPECT_EQ(base::UTF8ToUTF16("\n"), iter.GetString()); - EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD); - EXPECT_TRUE(iter.Advance()); - // Finds "Can". - EXPECT_EQ(base::UTF8ToUTF16("Can"), iter.GetString()); - EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_WORD_BREAK); - EXPECT_TRUE(iter.Advance()); - // Finds the space and the Russian characters. - EXPECT_EQ(base::UTF8ToUTF16(" "), iter.GetString()); - EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD); - EXPECT_TRUE(iter.Advance()); - EXPECT_EQ(base::WideToUTF16(L"\x041C\x0438"), iter.GetString()); - EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_WORD_BREAK); - EXPECT_TRUE(iter.Advance()); - // Finds the trailing periods. - EXPECT_EQ(base::UTF8ToUTF16("."), iter.GetString()); - EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD); - EXPECT_TRUE(iter.Advance()); - EXPECT_EQ(base::UTF8ToUTF16("."), iter.GetString()); - EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD); - EXPECT_TRUE(iter.Advance()); - EXPECT_EQ(base::UTF8ToUTF16("."), iter.GetString()); - EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD); - EXPECT_FALSE(iter.Advance()); -} - -} // namespace i18n -} // namespace base
diff --git a/base/i18n/case_conversion_unittest.cc b/base/i18n/case_conversion_unittest.cc deleted file mode 100644 index ee795bc..0000000 --- a/base/i18n/case_conversion_unittest.cc +++ /dev/null
@@ -1,119 +0,0 @@ -// 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/i18n/case_conversion.h" -#include "base/i18n/rtl.h" -#include "base/strings/utf_string_conversions.h" -#include "base/test/icu_test_util.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/icu/source/i18n/unicode/usearch.h" - -namespace base { -namespace i18n { - -namespace { - -const wchar_t kNonASCIIMixed[] = - L"\xC4\xD6\xE4\xF6\x20\xCF\xEF\x20\xF7\x25" - L"\xA4\x23\x2A\x5E\x60\x40\xA3\x24\x2030\x201A\x7E\x20\x1F07\x1F0F" - L"\x20\x1E00\x1E01"; -const wchar_t kNonASCIILower[] = - L"\xE4\xF6\xE4\xF6\x20\xEF\xEF" - L"\x20\xF7\x25\xA4\x23\x2A\x5E\x60\x40\xA3\x24\x2030\x201A\x7E\x20\x1F07" - L"\x1F07\x20\x1E01\x1E01"; -const wchar_t kNonASCIIUpper[] = - L"\xC4\xD6\xC4\xD6\x20\xCF\xCF" - L"\x20\xF7\x25\xA4\x23\x2A\x5E\x60\x40\xA3\x24\x2030\x201A\x7E\x20\x1F0F" - L"\x1F0F\x20\x1E00\x1E00"; - -} // namespace - -// Test upper and lower case string conversion. -TEST(CaseConversionTest, UpperLower) { - const string16 mixed(ASCIIToUTF16("Text with UPPer & lowER casE.")); - const string16 expected_lower(ASCIIToUTF16("text with upper & lower case.")); - const string16 expected_upper(ASCIIToUTF16("TEXT WITH UPPER & LOWER CASE.")); - - string16 result = ToLower(mixed); - EXPECT_EQ(expected_lower, result); - - result = ToUpper(mixed); - EXPECT_EQ(expected_upper, result); -} - -TEST(CaseConversionTest, NonASCII) { - const string16 mixed(WideToUTF16(kNonASCIIMixed)); - const string16 expected_lower(WideToUTF16(kNonASCIILower)); - const string16 expected_upper(WideToUTF16(kNonASCIIUpper)); - - string16 result = ToLower(mixed); - EXPECT_EQ(expected_lower, result); - - result = ToUpper(mixed); - EXPECT_EQ(expected_upper, result); -} - -TEST(CaseConversionTest, TurkishLocaleConversion) { - const string16 mixed(WideToUTF16(L"\x49\x131")); - const string16 expected_lower(WideToUTF16(L"\x69\x131")); - const string16 expected_upper(WideToUTF16(L"\x49\x49")); - - test::ScopedRestoreICUDefaultLocale restore_locale; - i18n::SetICUDefaultLocale("en_US"); - - string16 result = ToLower(mixed); - EXPECT_EQ(expected_lower, result); - - result = ToUpper(mixed); - EXPECT_EQ(expected_upper, result); - - i18n::SetICUDefaultLocale("tr"); - - const string16 expected_lower_turkish(WideToUTF16(L"\x131\x131")); - const string16 expected_upper_turkish(WideToUTF16(L"\x49\x49")); - - result = ToLower(mixed); - EXPECT_EQ(expected_lower_turkish, result); - - result = ToUpper(mixed); - EXPECT_EQ(expected_upper_turkish, result); -} - -TEST(CaseConversionTest, FoldCase) { - // Simple ASCII, should lower-case. - EXPECT_EQ(ASCIIToUTF16("hello, world"), - FoldCase(ASCIIToUTF16("Hello, World"))); - - // Non-ASCII cases from above. They should all fold to the same result. - EXPECT_EQ(FoldCase(WideToUTF16(kNonASCIIMixed)), - FoldCase(WideToUTF16(kNonASCIILower))); - EXPECT_EQ(FoldCase(WideToUTF16(kNonASCIIMixed)), - FoldCase(WideToUTF16(kNonASCIIUpper))); - - // Turkish cases from above. This is the lower-case expected result from the - // US locale. It should be the same even when the current locale is Turkish. - const string16 turkish(WideToUTF16(L"\x49\x131")); - const string16 turkish_expected(WideToUTF16(L"\x69\x131")); - - test::ScopedRestoreICUDefaultLocale restore_locale; - i18n::SetICUDefaultLocale("en_US"); - EXPECT_EQ(turkish_expected, FoldCase(turkish)); - - i18n::SetICUDefaultLocale("tr"); - EXPECT_EQ(turkish_expected, FoldCase(turkish)); - - // Test a case that gets bigger when processed. - // U+130 = LATIN CAPITAL LETTER I WITH DOT ABOVE gets folded to a lower case - // "i" followed by U+307 COMBINING DOT ABOVE. - EXPECT_EQ(WideToUTF16(L"i\u0307j"), FoldCase(WideToUTF16(L"\u0130j"))); - - // U+00DF (SHARP S) and U+1E9E (CAPIRAL SHARP S) are both folded to "ss". - EXPECT_EQ(ASCIIToUTF16("ssss"), FoldCase(WideToUTF16(L"\u00DF\u1E9E"))); -} - -} // namespace i18n -} // namespace base - - -
diff --git a/base/i18n/char_iterator_unittest.cc b/base/i18n/char_iterator_unittest.cc deleted file mode 100644 index 0cf8e6c..0000000 --- a/base/i18n/char_iterator_unittest.cc +++ /dev/null
@@ -1,101 +0,0 @@ -// 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/i18n/char_iterator.h" - -#include "base/strings/utf_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace i18n { - -TEST(CharIteratorsTest, TestUTF8) { - std::string empty; - UTF8CharIterator empty_iter(&empty); - ASSERT_TRUE(empty_iter.end()); - ASSERT_EQ(0, empty_iter.array_pos()); - ASSERT_EQ(0, empty_iter.char_pos()); - ASSERT_FALSE(empty_iter.Advance()); - - std::string str("s\303\273r"); // [u with circumflex] - UTF8CharIterator iter(&str); - ASSERT_FALSE(iter.end()); - ASSERT_EQ(0, iter.array_pos()); - ASSERT_EQ(0, iter.char_pos()); - ASSERT_EQ('s', iter.get()); - ASSERT_TRUE(iter.Advance()); - - ASSERT_FALSE(iter.end()); - ASSERT_EQ(1, iter.array_pos()); - ASSERT_EQ(1, iter.char_pos()); - ASSERT_EQ(251, iter.get()); - ASSERT_TRUE(iter.Advance()); - - ASSERT_FALSE(iter.end()); - ASSERT_EQ(3, iter.array_pos()); - ASSERT_EQ(2, iter.char_pos()); - ASSERT_EQ('r', iter.get()); - ASSERT_TRUE(iter.Advance()); - - ASSERT_TRUE(iter.end()); - ASSERT_EQ(4, iter.array_pos()); - ASSERT_EQ(3, iter.char_pos()); - - // Don't care what it returns, but this shouldn't crash - iter.get(); - - ASSERT_FALSE(iter.Advance()); -} - -TEST(CharIteratorsTest, TestUTF16) { - string16 empty = UTF8ToUTF16(""); - UTF16CharIterator empty_iter(&empty); - ASSERT_TRUE(empty_iter.end()); - ASSERT_EQ(0, empty_iter.array_pos()); - ASSERT_EQ(0, empty_iter.char_pos()); - ASSERT_FALSE(empty_iter.Advance()); - - // This test string contains 4 characters: - // x - // u with circumflex - 2 bytes in UTF8, 1 codeword in UTF16 - // math double-struck A - 4 bytes in UTF8, 2 codewords in UTF16 - // z - string16 str = UTF8ToUTF16("x\303\273\360\235\224\270z"); - UTF16CharIterator iter(&str); - ASSERT_FALSE(iter.end()); - ASSERT_EQ(0, iter.array_pos()); - ASSERT_EQ(0, iter.char_pos()); - ASSERT_EQ('x', iter.get()); - ASSERT_TRUE(iter.Advance()); - - ASSERT_FALSE(iter.end()); - ASSERT_EQ(1, iter.array_pos()); - ASSERT_EQ(1, iter.char_pos()); - ASSERT_EQ(251, iter.get()); - ASSERT_TRUE(iter.Advance()); - - ASSERT_FALSE(iter.end()); - ASSERT_EQ(2, iter.array_pos()); - ASSERT_EQ(2, iter.char_pos()); - ASSERT_EQ(120120, iter.get()); - ASSERT_TRUE(iter.Advance()); - - ASSERT_FALSE(iter.end()); - ASSERT_EQ(4, iter.array_pos()); - ASSERT_EQ(3, iter.char_pos()); - ASSERT_EQ('z', iter.get()); - ASSERT_TRUE(iter.Advance()); - - ASSERT_TRUE(iter.end()); - ASSERT_EQ(5, iter.array_pos()); - ASSERT_EQ(4, iter.char_pos()); - - // Don't care what it returns, but this shouldn't crash - iter.get(); - - ASSERT_FALSE(iter.Advance()); -} - -} // namespace i18n -} // namespace base
diff --git a/base/i18n/character_encoding_unittest.cc b/base/i18n/character_encoding_unittest.cc deleted file mode 100644 index 3c11ba3..0000000 --- a/base/i18n/character_encoding_unittest.cc +++ /dev/null
@@ -1,23 +0,0 @@ -// 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/i18n/character_encoding.h" - -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(CharacterEncodingTest, GetCanonicalEncodingNameByAliasName) { - EXPECT_EQ("Big5", GetCanonicalEncodingNameByAliasName("Big5")); - EXPECT_EQ("windows-874", GetCanonicalEncodingNameByAliasName("windows-874")); - EXPECT_EQ("ISO-8859-8", GetCanonicalEncodingNameByAliasName("ISO-8859-8")); - - // Non-canonical alias names should be converted to a canonical one. - EXPECT_EQ("UTF-8", GetCanonicalEncodingNameByAliasName("utf8")); - EXPECT_EQ("gb18030", GetCanonicalEncodingNameByAliasName("GB18030")); - EXPECT_EQ("windows-874", GetCanonicalEncodingNameByAliasName("tis-620")); - EXPECT_EQ("EUC-KR", GetCanonicalEncodingNameByAliasName("ks_c_5601-1987")); -} - -} // namespace base
diff --git a/base/i18n/file_util_icu_unittest.cc b/base/i18n/file_util_icu_unittest.cc deleted file mode 100644 index f1c2ecc..0000000 --- a/base/i18n/file_util_icu_unittest.cc +++ /dev/null
@@ -1,140 +0,0 @@ -// 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/i18n/file_util_icu.h" - -#include <stddef.h> - -#include "base/files/file_util.h" -#include "base/macros.h" -#include "base/strings/utf_string_conversions.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/platform_test.h" - -namespace base { -namespace i18n { - -// file_util winds up using autoreleased objects on the Mac, so this needs -// to be a PlatformTest -class FileUtilICUTest : public PlatformTest { -}; - -#if defined(OS_POSIX) && !defined(OS_MACOSX) - -// On linux, file path is parsed and filtered as UTF-8. -static const struct GoodBadPairLinux { - const char* bad_name; - const char* good_name; -} kLinuxIllegalCharacterCases[] = { - {"bad*\\/file:name?.jpg", "bad---file-name-.jpg"}, - {"**********::::.txt", "--------------.txt"}, - {"\xe9\xf0zzzz.\xff", "\xe9\xf0zzzz.\xff"}, - {" _ ", "-_-"}, - {".", "-"}, - {" .( ). ", "-.( ).-"}, - {" ", "- -"}, -}; - -TEST_F(FileUtilICUTest, ReplaceIllegalCharactersInPathLinuxTest) { - for (size_t i = 0; i < arraysize(kLinuxIllegalCharacterCases); ++i) { - std::string bad_name(kLinuxIllegalCharacterCases[i].bad_name); - ReplaceIllegalCharactersInPath(&bad_name, '-'); - EXPECT_EQ(kLinuxIllegalCharacterCases[i].good_name, bad_name); - } -} - -#endif - -// For Mac & Windows, which both do Unicode validation on filenames. These -// characters are given as wide strings since its more convenient to specify -// unicode characters. For Mac they should be converted to UTF-8. -static const struct goodbad_pair { - const wchar_t* bad_name; - const wchar_t* good_name; -} kIllegalCharacterCases[] = { - {L"bad*file:name?.jpg", L"bad-file-name-.jpg"}, - {L"**********::::.txt", L"--------------.txt"}, - // We can't use UCNs (universal character names) for C0/C1 characters and - // U+007F, but \x escape is interpreted by MSVC and gcc as we intend. - {L"bad\x0003\x0091 file\u200E\u200Fname.png", L"bad-- file--name.png"}, - {L"bad*file\\?name.jpg", L"bad-file--name.jpg"}, - {L"\t bad*file\\name/.jpg", L"- bad-file-name-.jpg"}, - {L"this_file_name is okay!.mp3", L"this_file_name is okay!.mp3"}, - {L"\u4E00\uAC00.mp3", L"\u4E00\uAC00.mp3"}, - {L"\u0635\u200C\u0644.mp3", L"\u0635-\u0644.mp3"}, - {L"\U00010330\U00010331.mp3", L"\U00010330\U00010331.mp3"}, - // Unassigned codepoints are ok. - {L"\u0378\U00040001.mp3", L"\u0378\U00040001.mp3"}, - // Non-characters are not allowed. - {L"bad\uFFFFfile\U0010FFFEname.jpg", L"bad-file-name.jpg"}, - {L"bad\uFDD0file\uFDEFname.jpg", L"bad-file-name.jpg"}, - // CVE-2014-9390 - {L"(\u200C.\u200D.\u200E.\u200F.\u202A.\u202B.\u202C.\u202D.\u202E.\u206A." - L"\u206B.\u206C.\u206D.\u206F.\uFEFF)", - L"(-.-.-.-.-.-.-.-.-.-.-.-.-.-.-)"}, - {L"config~1", L"config-1"}, - {L" _ ", L"-_-"}, - {L" ", L"-"}, - {L"\u2008.(\u2007).\u3000", L"-.(\u2007).-"}, - {L" ", L"- -"}, - {L". ", L"- -"} -}; - -#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_POSIX) - -TEST_F(FileUtilICUTest, ReplaceIllegalCharactersInPathTest) { - for (size_t i = 0; i < arraysize(kIllegalCharacterCases); ++i) { -#if defined(OS_WIN) - std::wstring bad_name(kIllegalCharacterCases[i].bad_name); - ReplaceIllegalCharactersInPath(&bad_name, '-'); - EXPECT_EQ(kIllegalCharacterCases[i].good_name, bad_name); -#else - std::string bad_name(WideToUTF8(kIllegalCharacterCases[i].bad_name)); - ReplaceIllegalCharactersInPath(&bad_name, '-'); - EXPECT_EQ(WideToUTF8(kIllegalCharacterCases[i].good_name), bad_name); -#endif - } -} - -#endif - -TEST_F(FileUtilICUTest, IsFilenameLegalTest) { - EXPECT_TRUE(IsFilenameLegal(string16())); - - for (const auto& test_case : kIllegalCharacterCases) { - string16 bad_name = WideToUTF16(test_case.bad_name); - string16 good_name = WideToUTF16(test_case.good_name); - - EXPECT_TRUE(IsFilenameLegal(good_name)) << good_name; - if (good_name != bad_name) - EXPECT_FALSE(IsFilenameLegal(bad_name)) << bad_name; - } -} - -#if defined(OS_CHROMEOS) -static const struct normalize_name_encoding_test_cases { - const char* original_path; - const char* normalized_path; -} kNormalizeFileNameEncodingTestCases[] = { - { "foo_na\xcc\x88me.foo", "foo_n\xc3\xa4me.foo"}, - { "foo_dir_na\xcc\x88me/foo_na\xcc\x88me.foo", - "foo_dir_na\xcc\x88me/foo_n\xc3\xa4me.foo"}, - { "", ""}, - { "foo_dir_na\xcc\x88me/", "foo_dir_n\xc3\xa4me"} -}; - -TEST_F(FileUtilICUTest, NormalizeFileNameEncoding) { - for (size_t i = 0; i < arraysize(kNormalizeFileNameEncodingTestCases); i++) { - FilePath path(kNormalizeFileNameEncodingTestCases[i].original_path); - NormalizeFileNameEncoding(&path); - EXPECT_EQ(FilePath(kNormalizeFileNameEncodingTestCases[i].normalized_path), - path); - } -} - -#endif - -} // namespace i18n -} // namespace base
diff --git a/base/i18n/icu_string_conversions_unittest.cc b/base/i18n/icu_string_conversions_unittest.cc deleted file mode 100644 index 871f18b..0000000 --- a/base/i18n/icu_string_conversions_unittest.cc +++ /dev/null
@@ -1,235 +0,0 @@ -// 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 <math.h> -#include <stdarg.h> -#include <stddef.h> - -#include <limits> -#include <sstream> - -#include "base/format_macros.h" -#include "base/i18n/icu_string_conversions.h" -#include "base/logging.h" -#include "base/macros.h" -#include "base/strings/string_piece.h" -#include "base/strings/stringprintf.h" -#include "base/strings/utf_string_conversions.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -// Given a null-terminated string of wchar_t with each wchar_t representing -// a UTF-16 code unit, returns a string16 made up of wchar_t's in the input. -// Each wchar_t should be <= 0xFFFF and a non-BMP character (> U+FFFF) -// should be represented as a surrogate pair (two UTF-16 units) -// *even* where wchar_t is 32-bit (Linux and Mac). -// -// This is to help write tests for functions with string16 params until -// the C++ 0x UTF-16 literal is well-supported by compilers. -string16 BuildString16(const wchar_t* s) { -#if defined(WCHAR_T_IS_UTF16) - return string16(s); -#elif defined(WCHAR_T_IS_UTF32) - string16 u16; - while (*s != 0) { - DCHECK_LE(static_cast<unsigned int>(*s), 0xFFFFu); - u16.push_back(*s++); - } - return u16; -#endif -} - -} // namespace - -// kConverterCodepageCases is not comprehensive. There are a number of cases -// to add if we really want to have a comprehensive coverage of various -// codepages and their 'idiosyncrasies'. Currently, the only implementation -// for CodepageTo* and *ToCodepage uses ICU, which has a very extensive -// set of tests for the charset conversion. So, we can get away with a -// relatively small number of cases listed below. -// -// Note about |u16_wide| in the following struct. -// On Windows, the field is always identical to |wide|. On Mac and Linux, -// it's identical as long as there's no character outside the -// BMP (<= U+FFFF). When there is, it is different from |wide| and -// is not a real wide string (UTF-32 string) in that each wchar_t in -// the string is a UTF-16 code unit zero-extended to be 32-bit -// even when the code unit belongs to a surrogate pair. -// For instance, a Unicode string (U+0041 U+010000) is represented as -// L"\x0041\xD800\xDC00" instead of L"\x0041\x10000". -// To avoid the clutter, |u16_wide| will be set to NULL -// if it's identical to |wide| on *all* platforms. - -static const struct { - const char* codepage_name; - const char* encoded; - OnStringConversionError::Type on_error; - bool success; - const wchar_t* wide; - const wchar_t* u16_wide; -} kConvertCodepageCases[] = { - // Test a case where the input cannot be decoded, using SKIP, FAIL - // and SUBSTITUTE error handling rules. "A7 41" is valid, but "A6" isn't. - {"big5", "\xA7\x41\xA6", OnStringConversionError::FAIL, false, L"", - nullptr}, - {"big5", "\xA7\x41\xA6", OnStringConversionError::SKIP, true, L"\x4F60", - nullptr}, - {"big5", "\xA7\x41\xA6", OnStringConversionError::SUBSTITUTE, true, - L"\x4F60\xFFFD", nullptr}, - // Arabic (ISO-8859) - {"iso-8859-6", - "\xC7\xEE\xE4\xD3\xF1\xEE\xE4\xC7\xE5\xEF" - " " - "\xD9\xEE\xE4\xEE\xEA\xF2\xE3\xEF\xE5\xF2", - OnStringConversionError::FAIL, true, - L"\x0627\x064E\x0644\x0633\x0651\x064E\x0644\x0627\x0645\x064F" - L" " - L"\x0639\x064E\x0644\x064E\x064A\x0652\x0643\x064F\x0645\x0652", - nullptr}, - // Chinese Simplified (GB2312) - {"gb2312", "\xC4\xE3\xBA\xC3", OnStringConversionError::FAIL, true, - L"\x4F60\x597D", nullptr}, - // Chinese (GB18030) : 4 byte sequences mapped to BMP characters - {"gb18030", "\x81\x30\x84\x36\xA1\xA7", OnStringConversionError::FAIL, true, - L"\x00A5\x00A8", nullptr}, - // Chinese (GB18030) : A 4 byte sequence mapped to plane 2 (U+20000) - {"gb18030", "\x95\x32\x82\x36\xD2\xBB", OnStringConversionError::FAIL, true, -#if defined(WCHAR_T_IS_UTF16) - L"\xD840\xDC00\x4E00", -#elif defined(WCHAR_T_IS_UTF32) - L"\x20000\x4E00", -#endif - L"\xD840\xDC00\x4E00"}, - {"big5", "\xA7\x41\xA6\x6E", OnStringConversionError::FAIL, true, - L"\x4F60\x597D", nullptr}, - // Greek (ISO-8859) - {"iso-8859-7", - "\xE3\xE5\xE9\xDC" - " " - "\xF3\xEF\xF5", - OnStringConversionError::FAIL, true, - L"\x03B3\x03B5\x03B9\x03AC" - L" " - L"\x03C3\x03BF\x03C5", - nullptr}, - // Hebrew (Windows) - {"windows-1255", "\xF9\xD1\xC8\xEC\xE5\xC9\xED", - OnStringConversionError::FAIL, true, - L"\x05E9\x05C1\x05B8\x05DC\x05D5\x05B9\x05DD", nullptr}, - // Korean (EUC) - {"euc-kr", "\xBE\xC8\xB3\xE7\xC7\xCF\xBC\xBC\xBF\xE4", - OnStringConversionError::FAIL, true, L"\xC548\xB155\xD558\xC138\xC694", - nullptr}, - // Japanese (EUC) - {"euc-jp", "\xA4\xB3\xA4\xF3\xA4\xCB\xA4\xC1\xA4\xCF\xB0\xEC\x8E\xA6", - OnStringConversionError::FAIL, true, - L"\x3053\x3093\x306B\x3061\x306F\x4E00\xFF66", nullptr}, - // Japanese (ISO-2022) - {"iso-2022-jp", - "\x1B$B" - "\x24\x33\x24\x73\x24\x4B\x24\x41\x24\x4F\x30\x6C" - "\x1B(B" - "ab" - "\x1B(J" - "\x5C\x7E#$" - "\x1B(B", - OnStringConversionError::FAIL, true, - L"\x3053\x3093\x306B\x3061\x306F\x4E00" - L"ab\x00A5\x203E#$", - nullptr}, - // Japanese (Shift-JIS) - {"sjis", "\x82\xB1\x82\xF1\x82\xC9\x82\xBF\x82\xCD\x88\xEA\xA6", - OnStringConversionError::FAIL, true, - L"\x3053\x3093\x306B\x3061\x306F\x4E00\xFF66", nullptr}, - // Russian (KOI8) - {"koi8-r", "\xDA\xC4\xD2\xC1\xD7\xD3\xD4\xD7\xD5\xCA\xD4\xC5", - OnStringConversionError::FAIL, true, - L"\x0437\x0434\x0440\x0430\x0432\x0441\x0442\x0432" - L"\x0443\x0439\x0442\x0435", - nullptr}, - // Thai (windows-874) - {"windows-874", - "\xCA\xC7\xD1\xCA\xB4\xD5" - "\xA4\xC3\xD1\xBA", - OnStringConversionError::FAIL, true, - L"\x0E2A\x0E27\x0E31\x0E2A\x0E14\x0E35" - L"\x0E04\x0E23\x0e31\x0E1A", - nullptr}, -}; - -TEST(ICUStringConversionsTest, ConvertBetweenCodepageAndUTF16) { - for (size_t i = 0; i < arraysize(kConvertCodepageCases); ++i) { - SCOPED_TRACE(base::StringPrintf( - "Test[%" PRIuS "]: <encoded: %s> <codepage: %s>", i, - kConvertCodepageCases[i].encoded, - kConvertCodepageCases[i].codepage_name)); - - string16 utf16; - bool success = CodepageToUTF16(kConvertCodepageCases[i].encoded, - kConvertCodepageCases[i].codepage_name, - kConvertCodepageCases[i].on_error, - &utf16); - string16 utf16_expected; - if (kConvertCodepageCases[i].u16_wide == nullptr) - utf16_expected = BuildString16(kConvertCodepageCases[i].wide); - else - utf16_expected = BuildString16(kConvertCodepageCases[i].u16_wide); - EXPECT_EQ(kConvertCodepageCases[i].success, success); - EXPECT_EQ(utf16_expected, utf16); - - // When decoding was successful and nothing was skipped, we also check the - // reverse conversion. See also the corresponding comment in - // ConvertBetweenCodepageAndWide. - if (success && - kConvertCodepageCases[i].on_error == OnStringConversionError::FAIL) { - std::string encoded; - success = UTF16ToCodepage(utf16, kConvertCodepageCases[i].codepage_name, - kConvertCodepageCases[i].on_error, &encoded); - EXPECT_EQ(kConvertCodepageCases[i].success, success); - EXPECT_EQ(kConvertCodepageCases[i].encoded, encoded); - } - } -} - -static const struct { - const char* encoded; - const char* codepage_name; - bool expected_success; - const char* expected_value; -} kConvertAndNormalizeCases[] = { - {"foo-\xe4.html", "iso-8859-1", true, "foo-\xc3\xa4.html"}, - {"foo-\xe4.html", "iso-8859-7", true, "foo-\xce\xb4.html"}, - {"foo-\xe4.html", "foo-bar", false, ""}, - // HTML Encoding spec treats US-ASCII as synonymous with windows-1252 - {"foo-\xff.html", "ascii", true, "foo-\xc3\xbf.html"}, - {"foo.html", "ascii", true, "foo.html"}, - {"foo-a\xcc\x88.html", "utf-8", true, "foo-\xc3\xa4.html"}, - {"\x95\x32\x82\x36\xD2\xBB", "gb18030", true, "\xF0\xA0\x80\x80\xE4\xB8\x80"}, - {"\xA7\x41\xA6\x6E", "big5", true, "\xE4\xBD\xA0\xE5\xA5\xBD"}, - // Windows-1258 does have a combining character at xD2 (which is U+0309). - // The sequence of (U+00E2, U+0309) is also encoded as U+1EA9. - {"foo\xE2\xD2", "windows-1258", true, "foo\xE1\xBA\xA9"}, - {"", "iso-8859-1", true, ""}, -}; -TEST(ICUStringConversionsTest, ConvertToUtf8AndNormalize) { - std::string result; - for (size_t i = 0; i < arraysize(kConvertAndNormalizeCases); ++i) { - SCOPED_TRACE(base::StringPrintf( - "Test[%" PRIuS "]: <encoded: %s> <codepage: %s>", i, - kConvertAndNormalizeCases[i].encoded, - kConvertAndNormalizeCases[i].codepage_name)); - - bool success = ConvertToUtf8AndNormalize( - kConvertAndNormalizeCases[i].encoded, - kConvertAndNormalizeCases[i].codepage_name, &result); - EXPECT_EQ(kConvertAndNormalizeCases[i].expected_success, success); - EXPECT_EQ(kConvertAndNormalizeCases[i].expected_value, result); - } -} - -} // namespace base
diff --git a/base/i18n/message_formatter_unittest.cc b/base/i18n/message_formatter_unittest.cc deleted file mode 100644 index a6f4613..0000000 --- a/base/i18n/message_formatter_unittest.cc +++ /dev/null
@@ -1,185 +0,0 @@ -// 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/i18n/message_formatter.h" - -#include <memory> - -#include "base/i18n/rtl.h" -#include "base/strings/string_piece.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" -#include "third_party/icu/source/common/unicode/unistr.h" -#include "third_party/icu/source/i18n/unicode/datefmt.h" -#include "third_party/icu/source/i18n/unicode/msgfmt.h" - -typedef testing::Test MessageFormatterTest; - -namespace base { -namespace i18n { - -class MessageFormatterTest : public testing::Test { - protected: - MessageFormatterTest() { - original_locale_ = GetConfiguredLocale(); - SetICUDefaultLocale("en-US"); - } - ~MessageFormatterTest() override { - SetICUDefaultLocale(original_locale_); - } - - private: - std::string original_locale_; -}; - -namespace { - -void AppendFormattedDateTime(const std::unique_ptr<icu::DateFormat>& df, - const Time& now, - std::string* result) { - icu::UnicodeString formatted; - df->format(static_cast<UDate>(now.ToJsTime()), formatted). - toUTF8String(*result); -} - -} // namespace - -TEST_F(MessageFormatterTest, PluralNamedArgs) { - const string16 pattern = ASCIIToUTF16( - "{num_people, plural, " - "=0 {I met nobody in {place}.}" - "=1 {I met a person in {place}.}" - "other {I met # people in {place}.}}"); - - std::string result = UTF16ToASCII(MessageFormatter::FormatWithNamedArgs( - pattern, "num_people", 0, "place", "Paris")); - EXPECT_EQ("I met nobody in Paris.", result); - result = UTF16ToASCII(MessageFormatter::FormatWithNamedArgs( - pattern, "num_people", 1, "place", "Paris")); - EXPECT_EQ("I met a person in Paris.", result); - result = UTF16ToASCII(MessageFormatter::FormatWithNamedArgs( - pattern, "num_people", 5, "place", "Paris")); - EXPECT_EQ("I met 5 people in Paris.", result); -} - -TEST_F(MessageFormatterTest, PluralNamedArgsWithOffset) { - const string16 pattern = ASCIIToUTF16( - "{num_people, plural, offset:1 " - "=0 {I met nobody in {place}.}" - "=1 {I met {person} in {place}.}" - "=2 {I met {person} and one other person in {place}.}" - "=13 {I met {person} and a dozen other people in {place}.}" - "other {I met {person} and # other people in {place}.}}"); - - std::string result = UTF16ToASCII(MessageFormatter::FormatWithNamedArgs( - pattern, "num_people", 0, "place", "Paris")); - EXPECT_EQ("I met nobody in Paris.", result); - // {person} is ignored if {num_people} is 0. - result = UTF16ToASCII(MessageFormatter::FormatWithNamedArgs( - pattern, "num_people", 0, "place", "Paris", "person", "Peter")); - EXPECT_EQ("I met nobody in Paris.", result); - result = UTF16ToASCII(MessageFormatter::FormatWithNamedArgs( - pattern, "num_people", 1, "place", "Paris", "person", "Peter")); - EXPECT_EQ("I met Peter in Paris.", result); - result = UTF16ToASCII(MessageFormatter::FormatWithNamedArgs( - pattern, "num_people", 2, "place", "Paris", "person", "Peter")); - EXPECT_EQ("I met Peter and one other person in Paris.", result); - result = UTF16ToASCII(MessageFormatter::FormatWithNamedArgs( - pattern, "num_people", 13, "place", "Paris", "person", "Peter")); - EXPECT_EQ("I met Peter and a dozen other people in Paris.", result); - result = UTF16ToASCII(MessageFormatter::FormatWithNamedArgs( - pattern, "num_people", 50, "place", "Paris", "person", "Peter")); - EXPECT_EQ("I met Peter and 49 other people in Paris.", result); -} - -TEST_F(MessageFormatterTest, PluralNumberedArgs) { - const string16 pattern = ASCIIToUTF16( - "{1, plural, " - "=1 {The cert for {0} expired yesterday.}" - "=7 {The cert for {0} expired a week ago.}" - "other {The cert for {0} expired # days ago.}}"); - - std::string result = UTF16ToASCII(MessageFormatter::FormatWithNumberedArgs( - pattern, "example.com", 1)); - EXPECT_EQ("The cert for example.com expired yesterday.", result); - result = UTF16ToASCII(MessageFormatter::FormatWithNumberedArgs( - pattern, "example.com", 7)); - EXPECT_EQ("The cert for example.com expired a week ago.", result); - result = UTF16ToASCII(MessageFormatter::FormatWithNumberedArgs( - pattern, "example.com", 15)); - EXPECT_EQ("The cert for example.com expired 15 days ago.", result); -} - -TEST_F(MessageFormatterTest, PluralNumberedArgsWithDate) { - const string16 pattern = ASCIIToUTF16( - "{1, plural, " - "=1 {The cert for {0} expired yesterday. Today is {2,date,full}}" - "other {The cert for {0} expired # days ago. Today is {2,date,full}}}"); - - base::Time now = base::Time::Now(); - using icu::DateFormat; - std::unique_ptr<DateFormat> df( - DateFormat::createDateInstance(DateFormat::FULL)); - std::string second_sentence = " Today is "; - AppendFormattedDateTime(df, now, &second_sentence); - - std::string result = UTF16ToASCII(MessageFormatter::FormatWithNumberedArgs( - pattern, "example.com", 1, now)); - EXPECT_EQ("The cert for example.com expired yesterday." + second_sentence, - result); - result = UTF16ToASCII(MessageFormatter::FormatWithNumberedArgs( - pattern, "example.com", 15, now)); - EXPECT_EQ("The cert for example.com expired 15 days ago." + second_sentence, - result); -} - -TEST_F(MessageFormatterTest, DateTimeAndNumber) { - // Note that using 'mph' for all locales is not a good i18n practice. - const string16 pattern = ASCIIToUTF16( - "At {0,time, short} on {0,date, medium}, " - "there was {1} at building {2,number,integer}. " - "The speed of the wind was {3,number,###.#} mph."); - - using icu::DateFormat; - std::unique_ptr<DateFormat> tf( - DateFormat::createTimeInstance(DateFormat::SHORT)); - std::unique_ptr<DateFormat> df( - DateFormat::createDateInstance(DateFormat::MEDIUM)); - - base::Time now = base::Time::Now(); - std::string expected = "At "; - AppendFormattedDateTime(tf, now, &expected); - expected.append(" on "); - AppendFormattedDateTime(df, now, &expected); - expected.append(", there was an explosion at building 3. " - "The speed of the wind was 37.4 mph."); - - EXPECT_EQ(expected, UTF16ToASCII(MessageFormatter::FormatWithNumberedArgs( - pattern, now, "an explosion", 3, 37.413))); -} - -TEST_F(MessageFormatterTest, SelectorSingleOrMultiple) { - const string16 pattern = ASCIIToUTF16( - "{0, select," - "single {Select a file to upload.}" - "multiple {Select files to upload.}" - "other {UNUSED}}"); - - std::string result = UTF16ToASCII(MessageFormatter::FormatWithNumberedArgs( - pattern, "single")); - EXPECT_EQ("Select a file to upload.", result); - result = UTF16ToASCII(MessageFormatter::FormatWithNumberedArgs( - pattern, "multiple")); - EXPECT_EQ("Select files to upload.", result); - - // fallback if a parameter is not selectors specified in the message pattern. - result = UTF16ToASCII(MessageFormatter::FormatWithNumberedArgs( - pattern, "foobar")); - EXPECT_EQ("UNUSED", result); -} - -} // namespace i18n -} // namespace base
diff --git a/base/i18n/number_formatting_unittest.cc b/base/i18n/number_formatting_unittest.cc deleted file mode 100644 index 71b15a5..0000000 --- a/base/i18n/number_formatting_unittest.cc +++ /dev/null
@@ -1,135 +0,0 @@ -// 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 <stddef.h> -#include <stdint.h> - -#include <limits> - -#include "base/i18n/number_formatting.h" -#include "base/i18n/rtl.h" -#include "base/macros.h" -#include "base/strings/utf_string_conversions.h" -#include "base/test/icu_test_util.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/icu/source/i18n/unicode/usearch.h" - -namespace base { -namespace { - -TEST(NumberFormattingTest, FormatNumber) { - static const struct { - int64_t number; - const char* expected_english; - const char* expected_german; - } cases[] = { - {0, "0", "0"}, - {1024, "1,024", "1.024"}, - {std::numeric_limits<int64_t>::max(), - "9,223,372,036,854,775,807", "9.223.372.036.854.775.807"}, - {std::numeric_limits<int64_t>::min(), - "-9,223,372,036,854,775,808", "-9.223.372.036.854.775.808"}, - {-42, "-42", "-42"}, - }; - - test::ScopedRestoreICUDefaultLocale restore_locale; - - for (size_t i = 0; i < arraysize(cases); ++i) { - i18n::SetICUDefaultLocale("en"); - testing::ResetFormatters(); - EXPECT_EQ(cases[i].expected_english, - UTF16ToUTF8(FormatNumber(cases[i].number))); - i18n::SetICUDefaultLocale("de"); - testing::ResetFormatters(); - EXPECT_EQ(cases[i].expected_german, - UTF16ToUTF8(FormatNumber(cases[i].number))); - } -} - -TEST(NumberFormattingTest, FormatDouble) { - static const struct { - double number; - int frac_digits; - const char* expected_english; - const char* expected_german; - } cases[] = { - {0.0, 0, "0", "0"}, -#if !defined(OS_ANDROID) - // Bionic can't printf negative zero correctly. - {-0.0, 4, "-0.0000", "-0,0000"}, -#endif - {1024.2, 0, "1,024", "1.024"}, - {-1024.223, 2, "-1,024.22", "-1.024,22"}, - {std::numeric_limits<double>::max(), 6, - "179,769,313,486,231,570,000,000,000,000,000,000,000,000,000,000,000," - "000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000," - "000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000," - "000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000," - "000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000," - "000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000," - "000.000000", - "179.769.313.486.231.570.000.000.000.000.000.000.000.000.000.000.000." - "000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000." - "000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000." - "000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000." - "000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000." - "000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000." - "000,000000"}, - {std::numeric_limits<double>::min(), 2, "0.00", "0,00"}, - {-42.7, 3, "-42.700", "-42,700"}, - }; - - test::ScopedRestoreICUDefaultLocale restore_locale; - for (size_t i = 0; i < arraysize(cases); ++i) { - i18n::SetICUDefaultLocale("en"); - testing::ResetFormatters(); - EXPECT_EQ(cases[i].expected_english, - UTF16ToUTF8(FormatDouble(cases[i].number, cases[i].frac_digits))); - i18n::SetICUDefaultLocale("de"); - testing::ResetFormatters(); - EXPECT_EQ(cases[i].expected_german, - UTF16ToUTF8(FormatDouble(cases[i].number, cases[i].frac_digits))); - } -} - -TEST(NumberFormattingTest, FormatPercent) { - static const struct { - int64_t number; - const char* expected_english; - const wchar_t* expected_german; // Note: Space before % isn't \x20. - // Note: Eastern Arabic-Indic digits (U+06Fx) for Persian and - // Arabic-Indic digits (U+066x) for Arabic. - // See https://unicode.org/cldr/trac/ticket/9040 for details. - // See also https://unicode.org/cldr/trac/ticket/10176 . - // For now, take what CLDR 32 has (percent sign to the right of - // a number in Persian). - const wchar_t* expected_persian; - const wchar_t* expected_arabic; - } cases[] = { - {0, "0%", L"0\xa0%", L"\x6f0\x66a", L"\x660\x66a\x61c"}, - {42, "42%", L"42\xa0%", L"\x6f4\x6f2\x66a", L"\x664\x662\x66a\x61c"}, - {1024, "1,024%", L"1.024\xa0%", L"\x6f1\x66c\x6f0\x6f2\x6f4\x66a", - L"\x661\x66c\x660\x662\x664\x66a\x61c"}, - }; - - test::ScopedRestoreICUDefaultLocale restore_locale; - for (size_t i = 0; i < arraysize(cases); ++i) { - i18n::SetICUDefaultLocale("en"); - EXPECT_EQ(ASCIIToUTF16(cases[i].expected_english), - FormatPercent(cases[i].number)); - i18n::SetICUDefaultLocale("de"); - EXPECT_EQ(WideToUTF16(cases[i].expected_german), - FormatPercent(cases[i].number)); - i18n::SetICUDefaultLocale("fa"); - EXPECT_EQ(WideToUTF16(cases[i].expected_persian), - FormatPercent(cases[i].number)); - i18n::SetICUDefaultLocale("ar"); - EXPECT_EQ(WideToUTF16(cases[i].expected_arabic), - FormatPercent(cases[i].number)); - } -} - -} // namespace -} // namespace base
diff --git a/base/i18n/rtl_unittest.cc b/base/i18n/rtl_unittest.cc deleted file mode 100644 index 88ae36a..0000000 --- a/base/i18n/rtl_unittest.cc +++ /dev/null
@@ -1,567 +0,0 @@ -// 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/i18n/rtl.h" - -#include <stddef.h> - -#include <algorithm> - -#include "base/files/file_path.h" -#include "base/macros.h" -#include "base/strings/string_util.h" -#include "base/strings/sys_string_conversions.h" -#include "base/strings/utf_string_conversions.h" -#include "base/test/icu_test_util.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/platform_test.h" -#include "third_party/icu/source/common/unicode/locid.h" -#include "third_party/icu/source/i18n/unicode/usearch.h" - -namespace base { -namespace i18n { - -namespace { - -// A test utility function to set the application default text direction. -void SetRTL(bool rtl) { - // Override the current locale/direction. - SetICUDefaultLocale(rtl ? "he" : "en"); - EXPECT_EQ(rtl, IsRTL()); -} - -} // namespace - -class RTLTest : public PlatformTest { -}; - -TEST_F(RTLTest, GetFirstStrongCharacterDirection) { - struct { - const wchar_t* text; - TextDirection direction; - } cases[] = { - // Test pure LTR string. - { L"foo bar", LEFT_TO_RIGHT }, - // Test pure RTL string. - { L"\x05d0\x05d1\x05d2 \x05d3\x0d4\x05d5", RIGHT_TO_LEFT}, - // Test bidi string in which the first character with strong directionality - // is a character with type L. - { L"foo \x05d0 bar", LEFT_TO_RIGHT }, - // Test bidi string in which the first character with strong directionality - // is a character with type R. - { L"\x05d0 foo bar", RIGHT_TO_LEFT }, - // Test bidi string which starts with a character with weak directionality - // and in which the first character with strong directionality is a - // character with type L. - { L"!foo \x05d0 bar", LEFT_TO_RIGHT }, - // Test bidi string which starts with a character with weak directionality - // and in which the first character with strong directionality is a - // character with type R. - { L",\x05d0 foo bar", RIGHT_TO_LEFT }, - // Test bidi string in which the first character with strong directionality - // is a character with type LRE. - { L"\x202a \x05d0 foo bar", LEFT_TO_RIGHT }, - // Test bidi string in which the first character with strong directionality - // is a character with type LRO. - { L"\x202d \x05d0 foo bar", LEFT_TO_RIGHT }, - // Test bidi string in which the first character with strong directionality - // is a character with type RLE. - { L"\x202b foo \x05d0 bar", RIGHT_TO_LEFT }, - // Test bidi string in which the first character with strong directionality - // is a character with type RLO. - { L"\x202e foo \x05d0 bar", RIGHT_TO_LEFT }, - // Test bidi string in which the first character with strong directionality - // is a character with type AL. - { L"\x0622 foo \x05d0 bar", RIGHT_TO_LEFT }, - // Test a string without strong directionality characters. - { L",!.{}", LEFT_TO_RIGHT }, - // Test empty string. - { L"", LEFT_TO_RIGHT }, - // Test characters in non-BMP (e.g. Phoenician letters. Please refer to - // http://demo.icu-project.org/icu-bin/ubrowse?scr=151&b=10910 for more - // information). - { -#if defined(WCHAR_T_IS_UTF32) - L" ! \x10910" L"abc 123", -#elif defined(WCHAR_T_IS_UTF16) - L" ! \xd802\xdd10" L"abc 123", -#else -#error wchar_t should be either UTF-16 or UTF-32 -#endif - RIGHT_TO_LEFT }, - { -#if defined(WCHAR_T_IS_UTF32) - L" ! \x10401" L"abc 123", -#elif defined(WCHAR_T_IS_UTF16) - L" ! \xd801\xdc01" L"abc 123", -#else -#error wchar_t should be either UTF-16 or UTF-32 -#endif - LEFT_TO_RIGHT }, - }; - - for (size_t i = 0; i < arraysize(cases); ++i) - EXPECT_EQ(cases[i].direction, - GetFirstStrongCharacterDirection(WideToUTF16(cases[i].text))); -} - - -// Note that the cases with LRE, LRO, RLE and RLO are invalid for -// GetLastStrongCharacterDirection because they should be followed by PDF -// character. -TEST_F(RTLTest, GetLastStrongCharacterDirection) { - struct { - const wchar_t* text; - TextDirection direction; - } cases[] = { - // Test pure LTR string. - { L"foo bar", LEFT_TO_RIGHT }, - // Test pure RTL string. - { L"\x05d0\x05d1\x05d2 \x05d3\x0d4\x05d5", RIGHT_TO_LEFT}, - // Test bidi string in which the last character with strong directionality - // is a character with type L. - { L"foo \x05d0 bar", LEFT_TO_RIGHT }, - // Test bidi string in which the last character with strong directionality - // is a character with type R. - { L"\x05d0 foo bar \x05d3", RIGHT_TO_LEFT }, - // Test bidi string which ends with a character with weak directionality - // and in which the last character with strong directionality is a - // character with type L. - { L"!foo \x05d0 bar!", LEFT_TO_RIGHT }, - // Test bidi string which ends with a character with weak directionality - // and in which the last character with strong directionality is a - // character with type R. - { L",\x05d0 foo bar \x05d1,", RIGHT_TO_LEFT }, - // Test bidi string in which the last character with strong directionality - // is a character with type AL. - { L"\x0622 foo \x05d0 bar \x0622", RIGHT_TO_LEFT }, - // Test a string without strong directionality characters. - { L",!.{}", LEFT_TO_RIGHT }, - // Test empty string. - { L"", LEFT_TO_RIGHT }, - // Test characters in non-BMP (e.g. Phoenician letters. Please refer to - // http://demo.icu-project.org/icu-bin/ubrowse?scr=151&b=10910 for more - // information). - { -#if defined(WCHAR_T_IS_UTF32) - L"abc 123" L" ! \x10910 !", -#elif defined(WCHAR_T_IS_UTF16) - L"abc 123" L" ! \xd802\xdd10 !", -#else -#error wchar_t should be either UTF-16 or UTF-32 -#endif - RIGHT_TO_LEFT }, - { -#if defined(WCHAR_T_IS_UTF32) - L"abc 123" L" ! \x10401 !", -#elif defined(WCHAR_T_IS_UTF16) - L"abc 123" L" ! \xd801\xdc01 !", -#else -#error wchar_t should be either UTF-16 or UTF-32 -#endif - LEFT_TO_RIGHT }, - }; - - for (size_t i = 0; i < arraysize(cases); ++i) - EXPECT_EQ(cases[i].direction, - GetLastStrongCharacterDirection(WideToUTF16(cases[i].text))); -} - -TEST_F(RTLTest, GetStringDirection) { - struct { - const wchar_t* text; - TextDirection direction; - } cases[] = { - // Test pure LTR string. - { L"foobar", LEFT_TO_RIGHT }, - { L".foobar", LEFT_TO_RIGHT }, - { L"foo, bar", LEFT_TO_RIGHT }, - // Test pure LTR with strong directionality characters of type LRE. - { L"\x202a\x202a", LEFT_TO_RIGHT }, - { L".\x202a\x202a", LEFT_TO_RIGHT }, - { L"\x202a, \x202a", LEFT_TO_RIGHT }, - // Test pure LTR with strong directionality characters of type LRO. - { L"\x202d\x202d", LEFT_TO_RIGHT }, - { L".\x202d\x202d", LEFT_TO_RIGHT }, - { L"\x202d, \x202d", LEFT_TO_RIGHT }, - // Test pure LTR with various types of strong directionality characters. - { L"foo \x202a\x202d", LEFT_TO_RIGHT }, - { L".\x202d foo \x202a", LEFT_TO_RIGHT }, - { L"\x202a, \x202d foo", LEFT_TO_RIGHT }, - // Test pure RTL with strong directionality characters of type R. - { L"\x05d0\x05d0", RIGHT_TO_LEFT }, - { L".\x05d0\x05d0", RIGHT_TO_LEFT }, - { L"\x05d0, \x05d0", RIGHT_TO_LEFT }, - // Test pure RTL with strong directionality characters of type RLE. - { L"\x202b\x202b", RIGHT_TO_LEFT }, - { L".\x202b\x202b", RIGHT_TO_LEFT }, - { L"\x202b, \x202b", RIGHT_TO_LEFT }, - // Test pure RTL with strong directionality characters of type RLO. - { L"\x202e\x202e", RIGHT_TO_LEFT }, - { L".\x202e\x202e", RIGHT_TO_LEFT }, - { L"\x202e, \x202e", RIGHT_TO_LEFT }, - // Test pure RTL with strong directionality characters of type AL. - { L"\x0622\x0622", RIGHT_TO_LEFT }, - { L".\x0622\x0622", RIGHT_TO_LEFT }, - { L"\x0622, \x0622", RIGHT_TO_LEFT }, - // Test pure RTL with various types of strong directionality characters. - { L"\x05d0\x202b\x202e\x0622", RIGHT_TO_LEFT }, - { L".\x202b\x202e\x0622\x05d0", RIGHT_TO_LEFT }, - { L"\x0622\x202e, \x202b\x05d0", RIGHT_TO_LEFT }, - // Test bidi strings. - { L"foo \x05d0 bar", UNKNOWN_DIRECTION }, - { L"\x202b foo bar", UNKNOWN_DIRECTION }, - { L"!foo \x0622 bar", UNKNOWN_DIRECTION }, - { L"\x202a\x202b", UNKNOWN_DIRECTION }, - { L"\x202e\x202d", UNKNOWN_DIRECTION }, - { L"\x0622\x202a", UNKNOWN_DIRECTION }, - { L"\x202d\x05d0", UNKNOWN_DIRECTION }, - // Test a string without strong directionality characters. - { L",!.{}", LEFT_TO_RIGHT }, - // Test empty string. - { L"", LEFT_TO_RIGHT }, - { -#if defined(WCHAR_T_IS_UTF32) - L" ! \x10910" L"abc 123", -#elif defined(WCHAR_T_IS_UTF16) - L" ! \xd802\xdd10" L"abc 123", -#else -#error wchar_t should be either UTF-16 or UTF-32 -#endif - UNKNOWN_DIRECTION }, - { -#if defined(WCHAR_T_IS_UTF32) - L" ! \x10401" L"abc 123", -#elif defined(WCHAR_T_IS_UTF16) - L" ! \xd801\xdc01" L"abc 123", -#else -#error wchar_t should be either UTF-16 or UTF-32 -#endif - LEFT_TO_RIGHT }, - }; - - for (size_t i = 0; i < arraysize(cases); ++i) - EXPECT_EQ(cases[i].direction, - GetStringDirection(WideToUTF16(cases[i].text))); -} - -TEST_F(RTLTest, WrapPathWithLTRFormatting) { - const wchar_t* cases[] = { - // Test common path, such as "c:\foo\bar". - L"c:/foo/bar", - // Test path with file name, such as "c:\foo\bar\test.jpg". - L"c:/foo/bar/test.jpg", - // Test path ending with punctuation, such as "c:\(foo)\bar.". - L"c:/(foo)/bar.", - // Test path ending with separator, such as "c:\foo\bar\". - L"c:/foo/bar/", - // Test path with RTL character. - L"c:/\x05d0", - // Test path with 2 level RTL directory names. - L"c:/\x05d0/\x0622", - // Test path with mixed RTL/LTR directory names and ending with punctuation. - L"c:/\x05d0/\x0622/(foo)/b.a.r.", - // Test path without driver name, such as "/foo/bar/test/jpg". - L"/foo/bar/test.jpg", - // Test path start with current directory, such as "./foo". - L"./foo", - // Test path start with parent directory, such as "../foo/bar.jpg". - L"../foo/bar.jpg", - // Test absolute path, such as "//foo/bar.jpg". - L"//foo/bar.jpg", - // Test path with mixed RTL/LTR directory names. - L"c:/foo/\x05d0/\x0622/\x05d1.jpg", - // Test empty path. - L"" - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - FilePath path; -#if defined(OS_WIN) - std::wstring win_path(cases[i]); - std::replace(win_path.begin(), win_path.end(), '/', '\\'); - path = FilePath(win_path); - std::wstring wrapped_expected = - std::wstring(L"\x202a") + win_path + L"\x202c"; -#else - path = FilePath(base::SysWideToNativeMB(cases[i])); - std::wstring wrapped_expected = - std::wstring(L"\x202a") + cases[i] + L"\x202c"; -#endif - string16 localized_file_path_string; - WrapPathWithLTRFormatting(path, &localized_file_path_string); - - std::wstring wrapped_actual = UTF16ToWide(localized_file_path_string); - EXPECT_EQ(wrapped_expected, wrapped_actual); - } -} - -TEST_F(RTLTest, WrapString) { - const wchar_t* cases[] = { - L" . ", - L"abc", - L"a" L"\x5d0\x5d1", - L"a" L"\x5d1" L"b", - L"\x5d0\x5d1\x5d2", - L"\x5d0\x5d1" L"a", - L"\x5d0" L"a" L"\x5d1", - }; - - const bool was_rtl = IsRTL(); - - test::ScopedRestoreICUDefaultLocale restore_locale; - for (size_t i = 0; i < 2; ++i) { - // Toggle the application default text direction (to try each direction). - SetRTL(!IsRTL()); - - string16 empty; - WrapStringWithLTRFormatting(&empty); - EXPECT_TRUE(empty.empty()); - WrapStringWithRTLFormatting(&empty); - EXPECT_TRUE(empty.empty()); - - for (size_t i = 0; i < arraysize(cases); ++i) { - string16 input = WideToUTF16(cases[i]); - string16 ltr_wrap = input; - WrapStringWithLTRFormatting(<r_wrap); - EXPECT_EQ(ltr_wrap[0], kLeftToRightEmbeddingMark); - EXPECT_EQ(ltr_wrap.substr(1, ltr_wrap.length() - 2), input); - EXPECT_EQ(ltr_wrap[ltr_wrap.length() -1], kPopDirectionalFormatting); - - string16 rtl_wrap = input; - WrapStringWithRTLFormatting(&rtl_wrap); - EXPECT_EQ(rtl_wrap[0], kRightToLeftEmbeddingMark); - EXPECT_EQ(rtl_wrap.substr(1, rtl_wrap.length() - 2), input); - EXPECT_EQ(rtl_wrap[rtl_wrap.length() -1], kPopDirectionalFormatting); - } - } - - EXPECT_EQ(was_rtl, IsRTL()); -} - -TEST_F(RTLTest, GetDisplayStringInLTRDirectionality) { - struct { - const wchar_t* path; - bool wrap_ltr; - bool wrap_rtl; - } cases[] = { - { L"test", false, true }, - { L"test.html", false, true }, - { L"\x05d0\x05d1\x05d2", true, true }, - { L"\x05d0\x05d1\x05d2.txt", true, true }, - { L"\x05d0" L"abc", true, true }, - { L"\x05d0" L"abc.txt", true, true }, - { L"abc\x05d0\x05d1", false, true }, - { L"abc\x05d0\x05d1.jpg", false, true }, - }; - - const bool was_rtl = IsRTL(); - - test::ScopedRestoreICUDefaultLocale restore_locale; - for (size_t i = 0; i < 2; ++i) { - // Toggle the application default text direction (to try each direction). - SetRTL(!IsRTL()); - for (size_t i = 0; i < arraysize(cases); ++i) { - string16 input = WideToUTF16(cases[i].path); - string16 output = GetDisplayStringInLTRDirectionality(input); - // Test the expected wrapping behavior for the current UI directionality. - if (IsRTL() ? cases[i].wrap_rtl : cases[i].wrap_ltr) - EXPECT_NE(output, input); - else - EXPECT_EQ(output, input); - } - } - - EXPECT_EQ(was_rtl, IsRTL()); -} - -TEST_F(RTLTest, GetTextDirection) { - EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("ar")); - EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("ar_EG")); - EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("he")); - EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("he_IL")); - // iw is an obsolete code for Hebrew. - EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("iw")); - // Although we're not yet localized to Farsi and Urdu, we - // do have the text layout direction information for them. - EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("fa")); - EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("ur")); -#if 0 - // Enable these when we include the minimal locale data for Azerbaijani - // written in Arabic and Dhivehi. At the moment, our copy of - // ICU data does not have entries for them. - EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("az_Arab")); - // Dhivehi that uses Thaana script. - EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("dv")); -#endif - EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocale("en")); - // Chinese in China with '-'. - EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocale("zh-CN")); - // Filipino : 3-letter code - EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocale("fil")); - // Russian - EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocale("ru")); - // Japanese that uses multiple scripts - EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocale("ja")); -} - -TEST_F(RTLTest, GetTextDirectionForLocaleInStartUp) { - EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocaleInStartUp("ar")); - EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocaleInStartUp("ar_EG")); - EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocaleInStartUp("he")); - EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocaleInStartUp("he_IL")); - // iw is an obsolete code for Hebrew. - EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocaleInStartUp("iw")); - // Although we're not yet localized to Farsi and Urdu, we - // do have the text layout direction information for them. - EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocaleInStartUp("fa")); - EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocaleInStartUp("ur")); - EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocaleInStartUp("en")); - // Chinese in China with '-'. - EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocaleInStartUp("zh-CN")); - // Filipino : 3-letter code - EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocaleInStartUp("fil")); - // Russian - EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocaleInStartUp("ru")); - // Japanese that uses multiple scripts - EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocaleInStartUp("ja")); -} - -TEST_F(RTLTest, UnadjustStringForLocaleDirection) { - // These test strings are borrowed from WrapPathWithLTRFormatting - const wchar_t* cases[] = { - L"foo bar", - L"foo \x05d0 bar", - L"\x05d0 foo bar", - L"!foo \x05d0 bar", - L",\x05d0 foo bar", - L"\x202a \x05d0 foo bar", - L"\x202d \x05d0 foo bar", - L"\x202b foo \x05d0 bar", - L"\x202e foo \x05d0 bar", - L"\x0622 foo \x05d0 bar", - }; - - const bool was_rtl = IsRTL(); - - test::ScopedRestoreICUDefaultLocale restore_locale; - for (size_t i = 0; i < 2; ++i) { - // Toggle the application default text direction (to try each direction). - SetRTL(!IsRTL()); - - for (size_t i = 0; i < arraysize(cases); ++i) { - string16 test_case = WideToUTF16(cases[i]); - string16 adjusted_string = test_case; - - if (!AdjustStringForLocaleDirection(&adjusted_string)) - continue; - - EXPECT_NE(test_case, adjusted_string); - EXPECT_TRUE(UnadjustStringForLocaleDirection(&adjusted_string)); - EXPECT_EQ(test_case, adjusted_string) << " for test case [" << test_case - << "] with IsRTL() == " << IsRTL(); - } - } - - EXPECT_EQ(was_rtl, IsRTL()); -} - -TEST_F(RTLTest, EnsureTerminatedDirectionalFormatting) { - struct { - const wchar_t* unformated_text; - const wchar_t* formatted_text; - } cases[] = { - // Tests string without any dir-formatting characters. - {L"google.com", L"google.com"}, - // Tests string with properly terminated dir-formatting character. - {L"\x202egoogle.com\x202c", L"\x202egoogle.com\x202c"}, - // Tests string with over-terminated dir-formatting characters. - {L"\x202egoogle\x202c.com\x202c", L"\x202egoogle\x202c.com\x202c"}, - // Tests string beginning with a dir-formatting character. - {L"\x202emoc.elgoog", L"\x202emoc.elgoog\x202c"}, - // Tests string that over-terminates then re-opens. - {L"\x202egoogle\x202c\x202c.\x202eom", - L"\x202egoogle\x202c\x202c.\x202eom\x202c"}, - // Tests string containing a dir-formatting character in the middle. - {L"google\x202e.com", L"google\x202e.com\x202c"}, - // Tests string with multiple dir-formatting characters. - {L"\x202egoogle\x202e.com/\x202eguest", - L"\x202egoogle\x202e.com/\x202eguest\x202c\x202c\x202c"}, - // Test the other dir-formatting characters (U+202A, U+202B, and U+202D). - {L"\x202agoogle.com", L"\x202agoogle.com\x202c"}, - {L"\x202bgoogle.com", L"\x202bgoogle.com\x202c"}, - {L"\x202dgoogle.com", L"\x202dgoogle.com\x202c"}, - }; - - const bool was_rtl = IsRTL(); - - test::ScopedRestoreICUDefaultLocale restore_locale; - for (size_t i = 0; i < 2; ++i) { - // Toggle the application default text direction (to try each direction). - SetRTL(!IsRTL()); - for (size_t i = 0; i < arraysize(cases); ++i) { - string16 unsanitized_text = WideToUTF16(cases[i].unformated_text); - string16 sanitized_text = WideToUTF16(cases[i].formatted_text); - EnsureTerminatedDirectionalFormatting(&unsanitized_text); - EXPECT_EQ(sanitized_text, unsanitized_text); - } - } - EXPECT_EQ(was_rtl, IsRTL()); -} - -TEST_F(RTLTest, SanitizeUserSuppliedString) { - struct { - const wchar_t* unformatted_text; - const wchar_t* formatted_text; - } cases[] = { - // Tests RTL string with properly terminated dir-formatting character. - {L"\x202eكبير Google التطبيق\x202c", L"\x202eكبير Google التطبيق\x202c"}, - // Tests RTL string with over-terminated dir-formatting characters. - {L"\x202eكبير Google\x202cالتطبيق\x202c", - L"\x202eكبير Google\x202cالتطبيق\x202c"}, - // Tests RTL string that over-terminates then re-opens. - {L"\x202eكبير Google\x202c\x202cالتطبيق\x202e", - L"\x202eكبير Google\x202c\x202cالتطبيق\x202e\x202c"}, - // Tests RTL string with multiple dir-formatting characters. - {L"\x202eك\x202eبير Google الت\x202eطبيق", - L"\x202eك\x202eبير Google الت\x202eطبيق\x202c\x202c\x202c"}, - // Test the other dir-formatting characters (U+202A, U+202B, and U+202D). - {L"\x202aكبير Google التطبيق", L"\x202aكبير Google التطبيق\x202c"}, - {L"\x202bكبير Google التطبيق", L"\x202bكبير Google التطبيق\x202c"}, - {L"\x202dكبير Google التطبيق", L"\x202dكبير Google التطبيق\x202c"}, - - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - // On Windows for an LTR locale, no changes to the string are made. - string16 prefix, suffix = WideToUTF16(L""); -#if !defined(OS_WIN) - prefix = WideToUTF16(L"\x200e\x202b"); - suffix = WideToUTF16(L"\x202c\x200e"); -#endif // !OS_WIN - string16 unsanitized_text = WideToUTF16(cases[i].unformatted_text); - string16 sanitized_text = - prefix + WideToUTF16(cases[i].formatted_text) + suffix; - SanitizeUserSuppliedString(&unsanitized_text); - EXPECT_EQ(sanitized_text, unsanitized_text); - } -} - -class SetICULocaleTest : public PlatformTest {}; - -TEST_F(SetICULocaleTest, OverlongLocaleId) { - test::ScopedRestoreICUDefaultLocale restore_locale; - std::string id("fr-ca-x-foo"); - while (id.length() < 152) - id.append("-x-foo"); - SetICUDefaultLocale(id); - EXPECT_STRNE("en_US", icu::Locale::getDefault().getName()); - id.append("zzz"); - SetICUDefaultLocale(id); - EXPECT_STREQ("en_US", icu::Locale::getDefault().getName()); -} - -} // namespace i18n -} // namespace base
diff --git a/base/i18n/streaming_utf8_validator_unittest.cc b/base/i18n/streaming_utf8_validator_unittest.cc deleted file mode 100644 index f9772d0..0000000 --- a/base/i18n/streaming_utf8_validator_unittest.cc +++ /dev/null
@@ -1,412 +0,0 @@ -// 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/i18n/streaming_utf8_validator.h" - -#include <stddef.h> -#include <stdint.h> -#include <stdio.h> -#include <string.h> - -#include <string> - -#include "base/macros.h" -#include "base/strings/string_piece.h" -#include "testing/gtest/include/gtest/gtest.h" - -// Define BASE_I18N_UTF8_VALIDATOR_THOROUGH_TEST to verify that this class -// accepts exactly the same set of 4-byte strings as ICU-based validation. This -// tests every possible 4-byte string, so it is too slow to run routinely on -// low-powered machines. -// -// #define BASE_I18N_UTF8_VALIDATOR_THOROUGH_TEST - -#ifdef BASE_I18N_UTF8_VALIDATOR_THOROUGH_TEST - -#include "base/bind.h" -#include "base/location.h" -#include "base/logging.h" -#include "base/memory/ref_counted.h" -#include "base/strings/string_util.h" -#include "base/strings/stringprintf.h" -#include "base/strings/utf_string_conversion_utils.h" -#include "base/synchronization/lock.h" -#include "base/task_scheduler/post_task.h" -#include "base/task_scheduler/task_scheduler.h" -#include "third_party/icu/source/common/unicode/utf8.h" - -#endif // BASE_I18N_UTF8_VALIDATOR_THOROUGH_TEST - -namespace base { -namespace { - -// Avoid having to qualify the enum values in the tests. -const StreamingUtf8Validator::State VALID_ENDPOINT = - StreamingUtf8Validator::VALID_ENDPOINT; -const StreamingUtf8Validator::State VALID_MIDPOINT = - StreamingUtf8Validator::VALID_MIDPOINT; -const StreamingUtf8Validator::State INVALID = StreamingUtf8Validator::INVALID; - -#ifdef BASE_I18N_UTF8_VALIDATOR_THOROUGH_TEST - -const uint32_t kThoroughTestChunkSize = 1 << 24; - -class StreamingUtf8ValidatorThoroughTest : public ::testing::Test { - protected: - StreamingUtf8ValidatorThoroughTest() - : tasks_dispatched_(0), tasks_finished_(0) {} - - // This uses the same logic as base::IsStringUTF8 except it considers - // non-characters valid (and doesn't require a string as input). - static bool IsStringUtf8(const char* src, int32_t src_len) { - int32_t char_index = 0; - - while (char_index < src_len) { - int32_t code_point; - U8_NEXT(src, char_index, src_len, code_point); - if (!base::IsValidCodepoint(code_point)) - return false; - } - return true; - } - - // Converts the passed-in integer to a 4 byte string and then - // verifies that IsStringUtf8 and StreamingUtf8Validator agree on - // whether it is valid UTF-8 or not. - void TestNumber(uint32_t n) const { - char test[sizeof n]; - memcpy(test, &n, sizeof n); - StreamingUtf8Validator validator; - EXPECT_EQ(IsStringUtf8(test, sizeof n), - validator.AddBytes(test, sizeof n) == VALID_ENDPOINT) - << "Difference of opinion for \"" - << base::StringPrintf("\\x%02X\\x%02X\\x%02X\\x%02X", - test[0] & 0xFF, - test[1] & 0xFF, - test[2] & 0xFF, - test[3] & 0xFF) << "\""; - } - - public: - // Tests the 4-byte sequences corresponding to the |size| integers - // starting at |begin|. This is intended to be run from a worker - // pool. Signals |all_done_| at the end if it thinks all tasks are - // finished. - void TestRange(uint32_t begin, uint32_t size) { - for (uint32_t i = 0; i < size; ++i) { - TestNumber(begin + i); - } - base::AutoLock al(lock_); - ++tasks_finished_; - LOG(INFO) << tasks_finished_ << " / " << tasks_dispatched_ - << " tasks done\n"; - } - - protected: - base::Lock lock_; - int tasks_dispatched_; - int tasks_finished_; -}; - -TEST_F(StreamingUtf8ValidatorThoroughTest, TestEverything) { - base::TaskScheduler::CreateAndStartWithDefaultParams( - "StreamingUtf8ValidatorThoroughTest"); - { - base::AutoLock al(lock_); - uint32_t begin = 0; - do { - base::PostTaskWithTraits( - FROM_HERE, {base::TaskShutdownBehavior::BLOCK_SHUTDOWN}, - base::BindOnce(&StreamingUtf8ValidatorThoroughTest::TestRange, - base::Unretained(this), begin, - kThoroughTestChunkSize)); - ++tasks_dispatched_; - begin += kThoroughTestChunkSize; - } while (begin != 0); - } - base::TaskScheduler::GetInstance()->Shutdown(); - base::TaskScheduler::GetInstance()->JoinForTesting(); - base::TaskScheduler::SetInstance(nullptr); -} - -#endif // BASE_I18N_UTF8_VALIDATOR_THOROUGH_TEST - -// These valid and invalid UTF-8 sequences are based on the tests from -// base/strings/string_util_unittest.cc - -// All of the strings in |valid| must represent a single codepoint, because -// partial sequences are constructed by taking non-empty prefixes of these -// strings. -const char* const valid[] = {"\r", "\n", "a", - "\xc2\x81", "\xe1\x80\xbf", "\xf1\x80\xa0\xbf", - "\xef\xbb\xbf", // UTF-8 BOM -}; - -const char* const* const valid_end = valid + arraysize(valid); - -const char* const invalid[] = { - // always invalid bytes - "\xc0", "\xc1", - "\xf5", "\xf6", "\xf7", - "\xf8", "\xf9", "\xfa", "\xfb", "\xfc", "\xfd", "\xfe", "\xff", - // surrogate code points - "\xed\xa0\x80", "\xed\x0a\x8f", "\xed\xbf\xbf", - // - // overlong sequences - "\xc0\x80", // U+0000 - "\xc1\x80", // "A" - "\xc1\x81", // "B" - "\xe0\x80\x80", // U+0000 - "\xe0\x82\x80", // U+0080 - "\xe0\x9f\xbf", // U+07ff - "\xf0\x80\x80\x8D", // U+000D - "\xf0\x80\x82\x91", // U+0091 - "\xf0\x80\xa0\x80", // U+0800 - "\xf0\x8f\xbb\xbf", // U+FEFF (BOM) - "\xf8\x80\x80\x80\xbf", // U+003F - "\xfc\x80\x80\x80\xa0\xa5", - // - // Beyond U+10FFFF - "\xf4\x90\x80\x80", // U+110000 - "\xf8\xa0\xbf\x80\xbf", // 5 bytes - "\xfc\x9c\xbf\x80\xbf\x80", // 6 bytes - // - // BOMs in UTF-16(BE|LE) - "\xfe\xff", "\xff\xfe", -}; - -const char* const* const invalid_end = invalid + arraysize(invalid); - -// A ForwardIterator which returns all the non-empty prefixes of the elements of -// "valid". -class PartialIterator { - public: - // The constructor returns the first iterator, ie. it is equivalent to - // begin(). - PartialIterator() : index_(0), prefix_length_(0) { Advance(); } - // The trivial destructor left intentionally undefined. - // This is a value type; the default copy constructor and assignment operator - // generated by the compiler are used. - - static PartialIterator end() { return PartialIterator(arraysize(valid), 1); } - - PartialIterator& operator++() { - Advance(); - return *this; - } - - base::StringPiece operator*() const { - return base::StringPiece(valid[index_], prefix_length_); - } - - bool operator==(const PartialIterator& rhs) const { - return index_ == rhs.index_ && prefix_length_ == rhs.prefix_length_; - } - - bool operator!=(const PartialIterator& rhs) const { return !(rhs == *this); } - - private: - // This constructor is used by the end() method. - PartialIterator(size_t index, size_t prefix_length) - : index_(index), prefix_length_(prefix_length) {} - - void Advance() { - if (index_ < arraysize(valid) && prefix_length_ < strlen(valid[index_])) - ++prefix_length_; - while (index_ < arraysize(valid) && - prefix_length_ == strlen(valid[index_])) { - ++index_; - prefix_length_ = 1; - } - } - - // The UTF-8 sequence, as an offset into the |valid| array. - size_t index_; - size_t prefix_length_; -}; - -// A test fixture for tests which test one UTF-8 sequence (or invalid -// byte sequence) at a time. -class StreamingUtf8ValidatorSingleSequenceTest : public ::testing::Test { - protected: - // Iterator must be convertible when de-referenced to StringPiece. - template <typename Iterator> - void CheckRange(Iterator begin, - Iterator end, - StreamingUtf8Validator::State expected) { - for (Iterator it = begin; it != end; ++it) { - StreamingUtf8Validator validator; - base::StringPiece sequence = *it; - EXPECT_EQ(expected, - validator.AddBytes(sequence.data(), sequence.size())) - << "Failed for \"" << sequence << "\""; - } - } - - // Adding input a byte at a time should make absolutely no difference. - template <typename Iterator> - void CheckRangeByteAtATime(Iterator begin, - Iterator end, - StreamingUtf8Validator::State expected) { - for (Iterator it = begin; it != end; ++it) { - StreamingUtf8Validator validator; - base::StringPiece sequence = *it; - StreamingUtf8Validator::State state = VALID_ENDPOINT; - for (base::StringPiece::const_iterator cit = sequence.begin(); - cit != sequence.end(); - ++cit) { - state = validator.AddBytes(&*cit, 1); - } - EXPECT_EQ(expected, state) << "Failed for \"" << sequence << "\""; - } - } -}; - -// A test fixture for tests which test the concatenation of byte sequences. -class StreamingUtf8ValidatorDoubleSequenceTest : public ::testing::Test { - protected: - // Check every possible concatenation of byte sequences from two - // ranges, and verify that the combination matches the expected - // state. - template <typename Iterator1, typename Iterator2> - void CheckCombinations(Iterator1 begin1, - Iterator1 end1, - Iterator2 begin2, - Iterator2 end2, - StreamingUtf8Validator::State expected) { - StreamingUtf8Validator validator; - for (Iterator1 it1 = begin1; it1 != end1; ++it1) { - base::StringPiece c1 = *it1; - for (Iterator2 it2 = begin2; it2 != end2; ++it2) { - base::StringPiece c2 = *it2; - validator.AddBytes(c1.data(), c1.size()); - EXPECT_EQ(expected, validator.AddBytes(c2.data(), c2.size())) - << "Failed for \"" << c1 << c2 << "\""; - validator.Reset(); - } - } - } -}; - -TEST(StreamingUtf8ValidatorTest, NothingIsValid) { - static const char kNothing[] = ""; - EXPECT_EQ(VALID_ENDPOINT, StreamingUtf8Validator().AddBytes(kNothing, 0)); -} - -// Because the members of the |valid| array need to be non-zero length -// sequences and are measured with strlen(), |valid| cannot be used it -// to test the NUL character '\0', so the NUL character gets its own -// test. -TEST(StreamingUtf8ValidatorTest, NulIsValid) { - static const char kNul[] = "\x00"; - EXPECT_EQ(VALID_ENDPOINT, StreamingUtf8Validator().AddBytes(kNul, 1)); -} - -// Just a basic sanity test before we start getting fancy. -TEST(StreamingUtf8ValidatorTest, HelloWorld) { - static const char kHelloWorld[] = "Hello, World!"; - EXPECT_EQ( - VALID_ENDPOINT, - StreamingUtf8Validator().AddBytes(kHelloWorld, strlen(kHelloWorld))); -} - -// Check that the Reset() method works. -TEST(StreamingUtf8ValidatorTest, ResetWorks) { - StreamingUtf8Validator validator; - EXPECT_EQ(INVALID, validator.AddBytes("\xC0", 1)); - EXPECT_EQ(INVALID, validator.AddBytes("a", 1)); - validator.Reset(); - EXPECT_EQ(VALID_ENDPOINT, validator.AddBytes("a", 1)); -} - -TEST_F(StreamingUtf8ValidatorSingleSequenceTest, Valid) { - CheckRange(valid, valid_end, VALID_ENDPOINT); -} - -TEST_F(StreamingUtf8ValidatorSingleSequenceTest, Partial) { - CheckRange(PartialIterator(), PartialIterator::end(), VALID_MIDPOINT); -} - -TEST_F(StreamingUtf8ValidatorSingleSequenceTest, Invalid) { - CheckRange(invalid, invalid_end, INVALID); -} - -TEST_F(StreamingUtf8ValidatorSingleSequenceTest, ValidByByte) { - CheckRangeByteAtATime(valid, valid_end, VALID_ENDPOINT); -} - -TEST_F(StreamingUtf8ValidatorSingleSequenceTest, PartialByByte) { - CheckRangeByteAtATime( - PartialIterator(), PartialIterator::end(), VALID_MIDPOINT); -} - -TEST_F(StreamingUtf8ValidatorSingleSequenceTest, InvalidByByte) { - CheckRangeByteAtATime(invalid, invalid_end, INVALID); -} - -TEST_F(StreamingUtf8ValidatorDoubleSequenceTest, ValidPlusValidIsValid) { - CheckCombinations(valid, valid_end, valid, valid_end, VALID_ENDPOINT); -} - -TEST_F(StreamingUtf8ValidatorDoubleSequenceTest, ValidPlusPartialIsPartial) { - CheckCombinations(valid, - valid_end, - PartialIterator(), - PartialIterator::end(), - VALID_MIDPOINT); -} - -TEST_F(StreamingUtf8ValidatorDoubleSequenceTest, PartialPlusValidIsInvalid) { - CheckCombinations( - PartialIterator(), PartialIterator::end(), valid, valid_end, INVALID); -} - -TEST_F(StreamingUtf8ValidatorDoubleSequenceTest, PartialPlusPartialIsInvalid) { - CheckCombinations(PartialIterator(), - PartialIterator::end(), - PartialIterator(), - PartialIterator::end(), - INVALID); -} - -TEST_F(StreamingUtf8ValidatorDoubleSequenceTest, ValidPlusInvalidIsInvalid) { - CheckCombinations(valid, valid_end, invalid, invalid_end, INVALID); -} - -TEST_F(StreamingUtf8ValidatorDoubleSequenceTest, InvalidPlusValidIsInvalid) { - CheckCombinations(invalid, invalid_end, valid, valid_end, INVALID); -} - -TEST_F(StreamingUtf8ValidatorDoubleSequenceTest, InvalidPlusInvalidIsInvalid) { - CheckCombinations(invalid, invalid_end, invalid, invalid_end, INVALID); -} - -TEST_F(StreamingUtf8ValidatorDoubleSequenceTest, InvalidPlusPartialIsInvalid) { - CheckCombinations( - invalid, invalid_end, PartialIterator(), PartialIterator::end(), INVALID); -} - -TEST_F(StreamingUtf8ValidatorDoubleSequenceTest, PartialPlusInvalidIsInvalid) { - CheckCombinations( - PartialIterator(), PartialIterator::end(), invalid, invalid_end, INVALID); -} - -TEST(StreamingUtf8ValidatorValidateTest, EmptyIsValid) { - EXPECT_TRUE(StreamingUtf8Validator::Validate(std::string())); -} - -TEST(StreamingUtf8ValidatorValidateTest, SimpleValidCase) { - EXPECT_TRUE(StreamingUtf8Validator::Validate("\xc2\x81")); -} - -TEST(StreamingUtf8ValidatorValidateTest, SimpleInvalidCase) { - EXPECT_FALSE(StreamingUtf8Validator::Validate("\xc0\x80")); -} - -TEST(StreamingUtf8ValidatorValidateTest, TruncatedIsInvalid) { - EXPECT_FALSE(StreamingUtf8Validator::Validate("\xc2")); -} - -} // namespace -} // namespace base
diff --git a/base/i18n/string_search_unittest.cc b/base/i18n/string_search_unittest.cc deleted file mode 100644 index 69501d6..0000000 --- a/base/i18n/string_search_unittest.cc +++ /dev/null
@@ -1,228 +0,0 @@ -// 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 <stddef.h> - -#include <string> - -#include "base/i18n/rtl.h" -#include "base/i18n/string_search.h" -#include "base/strings/string16.h" -#include "base/strings/utf_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/icu/source/i18n/unicode/usearch.h" - -namespace base { -namespace i18n { - -// Note on setting default locale for testing: The current default locale on -// the Mac trybot is en_US_POSIX, with which primary-level collation strength -// string search is case-sensitive, when normally it should be -// case-insensitive. In other locales (including en_US which English speakers -// in the U.S. use), this search would be case-insensitive as expected. - -TEST(StringSearchTest, ASCII) { - std::string default_locale(uloc_getDefault()); - bool locale_is_posix = (default_locale == "en_US_POSIX"); - if (locale_is_posix) - SetICUDefaultLocale("en_US"); - - size_t index = 0; - size_t length = 0; - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - ASCIIToUTF16("hello"), ASCIIToUTF16("hello world"), &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(5U, length); - - EXPECT_FALSE(StringSearchIgnoringCaseAndAccents( - ASCIIToUTF16("h e l l o"), ASCIIToUTF16("h e l l o"), - &index, &length)); - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - ASCIIToUTF16("aabaaa"), ASCIIToUTF16("aaabaabaaa"), &index, &length)); - EXPECT_EQ(4U, index); - EXPECT_EQ(6U, length); - - EXPECT_FALSE(StringSearchIgnoringCaseAndAccents( - ASCIIToUTF16("searching within empty string"), string16(), - &index, &length)); - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - string16(), ASCIIToUTF16("searching for empty string"), &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(0U, length); - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - ASCIIToUTF16("case insensitivity"), ASCIIToUTF16("CaSe InSeNsItIvItY"), - &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(18U, length); - - if (locale_is_posix) - SetICUDefaultLocale(default_locale.data()); -} - -TEST(StringSearchTest, UnicodeLocaleIndependent) { - // Base characters - const string16 e_base = WideToUTF16(L"e"); - const string16 E_base = WideToUTF16(L"E"); - const string16 a_base = WideToUTF16(L"a"); - - // Composed characters - const string16 e_with_acute_accent = WideToUTF16(L"\u00e9"); - const string16 E_with_acute_accent = WideToUTF16(L"\u00c9"); - const string16 e_with_grave_accent = WideToUTF16(L"\u00e8"); - const string16 E_with_grave_accent = WideToUTF16(L"\u00c8"); - const string16 a_with_acute_accent = WideToUTF16(L"\u00e1"); - - // Decomposed characters - const string16 e_with_acute_combining_mark = WideToUTF16(L"e\u0301"); - const string16 E_with_acute_combining_mark = WideToUTF16(L"E\u0301"); - const string16 e_with_grave_combining_mark = WideToUTF16(L"e\u0300"); - const string16 E_with_grave_combining_mark = WideToUTF16(L"E\u0300"); - const string16 a_with_acute_combining_mark = WideToUTF16(L"a\u0301"); - - std::string default_locale(uloc_getDefault()); - bool locale_is_posix = (default_locale == "en_US_POSIX"); - if (locale_is_posix) - SetICUDefaultLocale("en_US"); - - size_t index = 0; - size_t length = 0; - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - e_base, e_with_acute_accent, &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(e_with_acute_accent.size(), length); - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - e_with_acute_accent, e_base, &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(e_base.size(), length); - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - e_base, e_with_acute_combining_mark, &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(e_with_acute_combining_mark.size(), length); - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - e_with_acute_combining_mark, e_base, &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(e_base.size(), length); - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - e_with_acute_combining_mark, e_with_acute_accent, - &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(e_with_acute_accent.size(), length); - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - e_with_acute_accent, e_with_acute_combining_mark, - &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(e_with_acute_combining_mark.size(), length); - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - e_with_acute_combining_mark, e_with_grave_combining_mark, - &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(e_with_grave_combining_mark.size(), length); - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - e_with_grave_combining_mark, e_with_acute_combining_mark, - &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(e_with_acute_combining_mark.size(), length); - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - e_with_acute_combining_mark, e_with_grave_accent, &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(e_with_grave_accent.size(), length); - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - e_with_grave_accent, e_with_acute_combining_mark, &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(e_with_acute_combining_mark.size(), length); - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - E_with_acute_accent, e_with_acute_accent, &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(e_with_acute_accent.size(), length); - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - E_with_grave_accent, e_with_acute_accent, &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(e_with_acute_accent.size(), length); - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - E_with_acute_combining_mark, e_with_grave_accent, &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(e_with_grave_accent.size(), length); - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - E_with_grave_combining_mark, e_with_acute_accent, &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(e_with_acute_accent.size(), length); - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - E_base, e_with_grave_accent, &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(e_with_grave_accent.size(), length); - - EXPECT_FALSE(StringSearchIgnoringCaseAndAccents( - a_with_acute_accent, e_with_acute_accent, &index, &length)); - - EXPECT_FALSE(StringSearchIgnoringCaseAndAccents( - a_with_acute_combining_mark, e_with_acute_combining_mark, - &index, &length)); - - if (locale_is_posix) - SetICUDefaultLocale(default_locale.data()); -} - -TEST(StringSearchTest, UnicodeLocaleDependent) { - // Base characters - const string16 a_base = WideToUTF16(L"a"); - - // Composed characters - const string16 a_with_ring = WideToUTF16(L"\u00e5"); - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(a_base, a_with_ring, nullptr, - nullptr)); - - const char* default_locale = uloc_getDefault(); - SetICUDefaultLocale("da"); - - EXPECT_FALSE(StringSearchIgnoringCaseAndAccents(a_base, a_with_ring, nullptr, - nullptr)); - - SetICUDefaultLocale(default_locale); -} - -TEST(StringSearchTest, FixedPatternMultipleSearch) { - std::string default_locale(uloc_getDefault()); - bool locale_is_posix = (default_locale == "en_US_POSIX"); - if (locale_is_posix) - SetICUDefaultLocale("en_US"); - - size_t index = 0; - size_t length = 0; - - // Search "hello" over multiple texts. - FixedPatternStringSearchIgnoringCaseAndAccents query(ASCIIToUTF16("hello")); - EXPECT_TRUE(query.Search(ASCIIToUTF16("12hello34"), &index, &length)); - EXPECT_EQ(2U, index); - EXPECT_EQ(5U, length); - EXPECT_FALSE(query.Search(ASCIIToUTF16("bye"), &index, &length)); - EXPECT_TRUE(query.Search(ASCIIToUTF16("hELLo"), &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(5U, length); - - if (locale_is_posix) - SetICUDefaultLocale(default_locale.data()); -} - -} // namespace i18n -} // namespace base
diff --git a/base/i18n/time_formatting_unittest.cc b/base/i18n/time_formatting_unittest.cc deleted file mode 100644 index 027b7c9..0000000 --- a/base/i18n/time_formatting_unittest.cc +++ /dev/null
@@ -1,434 +0,0 @@ -// 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/i18n/time_formatting.h" - -#include <memory> - -#include "base/i18n/rtl.h" -#include "base/i18n/unicodestring.h" -#include "base/strings/utf_string_conversions.h" -#include "base/test/icu_test_util.h" -#include "base/time/time.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/icu/source/common/unicode/uversion.h" -#include "third_party/icu/source/i18n/unicode/calendar.h" -#include "third_party/icu/source/i18n/unicode/timezone.h" -#include "third_party/icu/source/i18n/unicode/tzfmt.h" - -namespace base { -namespace { - -const Time::Exploded kTestDateTimeExploded = { - 2011, 4, 6, 30, // Sat, Apr 30, 2011 - 22, 42, 7, 0 // 22:42:07.000 in UTC = 15:42:07 in US PDT. -}; - -// Returns difference between the local time and GMT formatted as string. -// This function gets |time| because the difference depends on time, -// see https://en.wikipedia.org/wiki/Daylight_saving_time for details. -string16 GetShortTimeZone(const Time& time) { - UErrorCode status = U_ZERO_ERROR; - std::unique_ptr<icu::TimeZone> zone(icu::TimeZone::createDefault()); - std::unique_ptr<icu::TimeZoneFormat> zone_formatter( - icu::TimeZoneFormat::createInstance(icu::Locale::getDefault(), status)); - EXPECT_TRUE(U_SUCCESS(status)); - icu::UnicodeString name; - zone_formatter->format(UTZFMT_STYLE_SPECIFIC_SHORT, *zone, - static_cast<UDate>(time.ToDoubleT() * 1000), - name, nullptr); - return i18n::UnicodeStringToString16(name); -} - -// Calls TimeDurationFormat() with |delta| and |width| and returns the resulting -// string. On failure, adds a failed expectation and returns an empty string. -string16 TimeDurationFormatString(const TimeDelta& delta, - DurationFormatWidth width) { - string16 str; - EXPECT_TRUE(TimeDurationFormat(delta, width, &str)) - << "Failed to format " << delta.ToInternalValue() << " with width " - << width; - return str; -} - -// Calls TimeDurationFormatWithSeconds() with |delta| and |width| and returns -// the resulting string. On failure, adds a failed expectation and returns an -// empty string. -string16 TimeDurationFormatWithSecondsString(const TimeDelta& delta, - DurationFormatWidth width) { - string16 str; - EXPECT_TRUE(TimeDurationFormatWithSeconds(delta, width, &str)) - << "Failed to format " << delta.ToInternalValue() << " with width " - << width; - return str; -} - -class ScopedRestoreDefaultTimezone { - public: - ScopedRestoreDefaultTimezone(const char* zoneid) { - original_zone_.reset(icu::TimeZone::createDefault()); - icu::TimeZone::adoptDefault(icu::TimeZone::createTimeZone(zoneid)); - } - ~ScopedRestoreDefaultTimezone() { - icu::TimeZone::adoptDefault(original_zone_.release()); - } - - ScopedRestoreDefaultTimezone(const ScopedRestoreDefaultTimezone&) = delete; - ScopedRestoreDefaultTimezone& operator=(const ScopedRestoreDefaultTimezone&) = - delete; - - private: - std::unique_ptr<icu::TimeZone> original_zone_; -}; - -TEST(TimeFormattingTest, TimeFormatTimeOfDayDefault12h) { - // Test for a locale defaulted to 12h clock. - // As an instance, we use third_party/icu/source/data/locales/en.txt. - test::ScopedRestoreICUDefaultLocale restore_locale; - i18n::SetICUDefaultLocale("en_US"); - ScopedRestoreDefaultTimezone la_time("America/Los_Angeles"); - - Time time; - EXPECT_TRUE(Time::FromUTCExploded(kTestDateTimeExploded, &time)); - string16 clock24h(ASCIIToUTF16("15:42")); - string16 clock12h_pm(ASCIIToUTF16("3:42 PM")); - string16 clock12h(ASCIIToUTF16("3:42")); - string16 clock24h_millis(ASCIIToUTF16("15:42:07.000")); - - // The default is 12h clock. - EXPECT_EQ(clock12h_pm, TimeFormatTimeOfDay(time)); - EXPECT_EQ(clock24h_millis, TimeFormatTimeOfDayWithMilliseconds(time)); - EXPECT_EQ(k12HourClock, GetHourClockType()); - // k{Keep,Drop}AmPm should not affect for 24h clock. - EXPECT_EQ(clock24h, - TimeFormatTimeOfDayWithHourClockType(time, - k24HourClock, - kKeepAmPm)); - EXPECT_EQ(clock24h, - TimeFormatTimeOfDayWithHourClockType(time, - k24HourClock, - kDropAmPm)); - // k{Keep,Drop}AmPm affects for 12h clock. - EXPECT_EQ(clock12h_pm, - TimeFormatTimeOfDayWithHourClockType(time, - k12HourClock, - kKeepAmPm)); - EXPECT_EQ(clock12h, - TimeFormatTimeOfDayWithHourClockType(time, - k12HourClock, - kDropAmPm)); -} - -TEST(TimeFormattingTest, TimeFormatTimeOfDayDefault24h) { - // Test for a locale defaulted to 24h clock. - // As an instance, we use third_party/icu/source/data/locales/en_GB.txt. - test::ScopedRestoreICUDefaultLocale restore_locale; - i18n::SetICUDefaultLocale("en_GB"); - ScopedRestoreDefaultTimezone la_time("America/Los_Angeles"); - - Time time; - EXPECT_TRUE(Time::FromUTCExploded(kTestDateTimeExploded, &time)); - string16 clock24h(ASCIIToUTF16("15:42")); - string16 clock12h_pm(ASCIIToUTF16("3:42 pm")); - string16 clock12h(ASCIIToUTF16("3:42")); - string16 clock24h_millis(ASCIIToUTF16("15:42:07.000")); - - // The default is 24h clock. - EXPECT_EQ(clock24h, TimeFormatTimeOfDay(time)); - EXPECT_EQ(clock24h_millis, TimeFormatTimeOfDayWithMilliseconds(time)); - EXPECT_EQ(k24HourClock, GetHourClockType()); - // k{Keep,Drop}AmPm should not affect for 24h clock. - EXPECT_EQ(clock24h, - TimeFormatTimeOfDayWithHourClockType(time, - k24HourClock, - kKeepAmPm)); - EXPECT_EQ(clock24h, - TimeFormatTimeOfDayWithHourClockType(time, - k24HourClock, - kDropAmPm)); - // k{Keep,Drop}AmPm affects for 12h clock. - EXPECT_EQ(clock12h_pm, - TimeFormatTimeOfDayWithHourClockType(time, - k12HourClock, - kKeepAmPm)); - EXPECT_EQ(clock12h, - TimeFormatTimeOfDayWithHourClockType(time, - k12HourClock, - kDropAmPm)); -} - -TEST(TimeFormattingTest, TimeFormatTimeOfDayJP) { - // Test for a locale that uses different mark than "AM" and "PM". - // As an instance, we use third_party/icu/source/data/locales/ja.txt. - test::ScopedRestoreICUDefaultLocale restore_locale; - i18n::SetICUDefaultLocale("ja_JP"); - ScopedRestoreDefaultTimezone la_time("America/Los_Angeles"); - - Time time; - EXPECT_TRUE(Time::FromUTCExploded(kTestDateTimeExploded, &time)); - string16 clock24h(ASCIIToUTF16("15:42")); - string16 clock12h_pm(UTF8ToUTF16(u8"午後3:42")); - string16 clock12h(ASCIIToUTF16("3:42")); - - // The default is 24h clock. - EXPECT_EQ(clock24h, TimeFormatTimeOfDay(time)); - EXPECT_EQ(k24HourClock, GetHourClockType()); - // k{Keep,Drop}AmPm should not affect for 24h clock. - EXPECT_EQ(clock24h, TimeFormatTimeOfDayWithHourClockType(time, k24HourClock, - kKeepAmPm)); - EXPECT_EQ(clock24h, TimeFormatTimeOfDayWithHourClockType(time, k24HourClock, - kDropAmPm)); - // k{Keep,Drop}AmPm affects for 12h clock. - EXPECT_EQ(clock12h_pm, TimeFormatTimeOfDayWithHourClockType( - time, k12HourClock, kKeepAmPm)); - EXPECT_EQ(clock12h, TimeFormatTimeOfDayWithHourClockType(time, k12HourClock, - kDropAmPm)); -} - -TEST(TimeFormattingTest, TimeFormatTimeOfDayDE) { - // Test for a locale that uses different mark than "AM" and "PM". - // As an instance, we use third_party/icu/source/data/locales/de.txt. - test::ScopedRestoreICUDefaultLocale restore_locale; - i18n::SetICUDefaultLocale("de"); - ScopedRestoreDefaultTimezone la_time("America/Los_Angeles"); - - Time time; - EXPECT_TRUE(Time::FromUTCExploded(kTestDateTimeExploded, &time)); - string16 clock24h(ASCIIToUTF16("15:42")); - string16 clock12h_pm(UTF8ToUTF16("3:42 nachm.")); - string16 clock12h(ASCIIToUTF16("3:42")); - - // The default is 24h clock. - EXPECT_EQ(clock24h, TimeFormatTimeOfDay(time)); - EXPECT_EQ(k24HourClock, GetHourClockType()); - // k{Keep,Drop}AmPm should not affect for 24h clock. - EXPECT_EQ(clock24h, - TimeFormatTimeOfDayWithHourClockType(time, - k24HourClock, - kKeepAmPm)); - EXPECT_EQ(clock24h, - TimeFormatTimeOfDayWithHourClockType(time, - k24HourClock, - kDropAmPm)); - // k{Keep,Drop}AmPm affects for 12h clock. - EXPECT_EQ(clock12h_pm, - TimeFormatTimeOfDayWithHourClockType(time, - k12HourClock, - kKeepAmPm)); - EXPECT_EQ(clock12h, - TimeFormatTimeOfDayWithHourClockType(time, - k12HourClock, - kDropAmPm)); -} - -TEST(TimeFormattingTest, TimeFormatDateUS) { - // See third_party/icu/source/data/locales/en.txt. - // The date patterns are "EEEE, MMMM d, y", "MMM d, y", and "M/d/yy". - test::ScopedRestoreICUDefaultLocale restore_locale; - i18n::SetICUDefaultLocale("en_US"); - ScopedRestoreDefaultTimezone la_time("America/Los_Angeles"); - - Time time; - EXPECT_TRUE(Time::FromUTCExploded(kTestDateTimeExploded, &time)); - - EXPECT_EQ(ASCIIToUTF16("Apr 30, 2011"), TimeFormatShortDate(time)); - EXPECT_EQ(ASCIIToUTF16("4/30/11"), TimeFormatShortDateNumeric(time)); - - EXPECT_EQ(ASCIIToUTF16("4/30/11, 3:42:07 PM"), - TimeFormatShortDateAndTime(time)); - EXPECT_EQ(ASCIIToUTF16("4/30/11, 3:42:07 PM ") + GetShortTimeZone(time), - TimeFormatShortDateAndTimeWithTimeZone(time)); - - EXPECT_EQ(ASCIIToUTF16("April 2011"), TimeFormatMonthAndYear(time)); - - EXPECT_EQ(ASCIIToUTF16("Saturday, April 30, 2011 at 3:42:07 PM"), - TimeFormatFriendlyDateAndTime(time)); - - EXPECT_EQ(ASCIIToUTF16("Saturday, April 30, 2011"), - TimeFormatFriendlyDate(time)); -} - -TEST(TimeFormattingTest, TimeFormatDateGB) { - // See third_party/icu/source/data/locales/en_GB.txt. - // The date patterns are "EEEE, d MMMM y", "d MMM y", and "dd/MM/yyyy". - test::ScopedRestoreICUDefaultLocale restore_locale; - i18n::SetICUDefaultLocale("en_GB"); - ScopedRestoreDefaultTimezone la_time("America/Los_Angeles"); - - Time time; - EXPECT_TRUE(Time::FromUTCExploded(kTestDateTimeExploded, &time)); - - EXPECT_EQ(ASCIIToUTF16("30 Apr 2011"), TimeFormatShortDate(time)); - EXPECT_EQ(ASCIIToUTF16("30/04/2011"), TimeFormatShortDateNumeric(time)); - EXPECT_EQ(ASCIIToUTF16("30/04/2011, 15:42:07"), - TimeFormatShortDateAndTime(time)); - EXPECT_EQ(ASCIIToUTF16("30/04/2011, 15:42:07 ") + GetShortTimeZone(time), - TimeFormatShortDateAndTimeWithTimeZone(time)); - EXPECT_EQ(ASCIIToUTF16("April 2011"), TimeFormatMonthAndYear(time)); - EXPECT_EQ(ASCIIToUTF16("Saturday, 30 April 2011 at 15:42:07"), - TimeFormatFriendlyDateAndTime(time)); - EXPECT_EQ(ASCIIToUTF16("Saturday, 30 April 2011"), - TimeFormatFriendlyDate(time)); -} - -TEST(TimeFormattingTest, TimeFormatWithPattern) { - test::ScopedRestoreICUDefaultLocale restore_locale; - ScopedRestoreDefaultTimezone la_time("America/Los_Angeles"); - - Time time; - EXPECT_TRUE(Time::FromUTCExploded(kTestDateTimeExploded, &time)); - - i18n::SetICUDefaultLocale("en_US"); - EXPECT_EQ(ASCIIToUTF16("Apr 30, 2011"), TimeFormatWithPattern(time, "yMMMd")); - EXPECT_EQ(ASCIIToUTF16("April 30, 3:42:07 PM"), - TimeFormatWithPattern(time, "MMMMdjmmss")); - - i18n::SetICUDefaultLocale("en_GB"); - EXPECT_EQ(ASCIIToUTF16("30 Apr 2011"), TimeFormatWithPattern(time, "yMMMd")); - EXPECT_EQ(ASCIIToUTF16("30 April, 15:42:07"), - TimeFormatWithPattern(time, "MMMMdjmmss")); - - i18n::SetICUDefaultLocale("ja_JP"); - EXPECT_EQ(UTF8ToUTF16(u8"2011年4月30日"), - TimeFormatWithPattern(time, "yMMMd")); - EXPECT_EQ(UTF8ToUTF16(u8"4月30日 15:42:07"), - TimeFormatWithPattern(time, "MMMMdjmmss")); -} - -TEST(TimeFormattingTest, TimeDurationFormat) { - test::ScopedRestoreICUDefaultLocale restore_locale; - TimeDelta delta = TimeDelta::FromMinutes(15 * 60 + 42); - - // US English. - i18n::SetICUDefaultLocale("en_US"); - EXPECT_EQ(ASCIIToUTF16("15 hours, 42 minutes"), - TimeDurationFormatString(delta, DURATION_WIDTH_WIDE)); - EXPECT_EQ(ASCIIToUTF16("15 hr, 42 min"), - TimeDurationFormatString(delta, DURATION_WIDTH_SHORT)); - EXPECT_EQ(ASCIIToUTF16("15h 42m"), - TimeDurationFormatString(delta, DURATION_WIDTH_NARROW)); - EXPECT_EQ(ASCIIToUTF16("15:42"), - TimeDurationFormatString(delta, DURATION_WIDTH_NUMERIC)); - - // Danish, with Latin alphabet but different abbreviations and punctuation. - i18n::SetICUDefaultLocale("da"); - EXPECT_EQ(ASCIIToUTF16("15 timer og 42 minutter"), - TimeDurationFormatString(delta, DURATION_WIDTH_WIDE)); - EXPECT_EQ(ASCIIToUTF16("15 t og 42 min."), - TimeDurationFormatString(delta, DURATION_WIDTH_SHORT)); - EXPECT_EQ(ASCIIToUTF16("15 t og 42 min"), - TimeDurationFormatString(delta, DURATION_WIDTH_NARROW)); - EXPECT_EQ(ASCIIToUTF16("15.42"), - TimeDurationFormatString(delta, DURATION_WIDTH_NUMERIC)); - - // Persian, with non-Arabic numbers. - i18n::SetICUDefaultLocale("fa"); - string16 fa_wide = UTF8ToUTF16( - u8"\u06f1\u06f5 \u0633\u0627\u0639\u062a \u0648 \u06f4\u06f2 \u062f\u0642" - u8"\u06cc\u0642\u0647"); - string16 fa_short = UTF8ToUTF16( - u8"\u06f1\u06f5 \u0633\u0627\u0639\u062a\u060c\u200f \u06f4\u06f2 \u062f" - u8"\u0642\u06cc\u0642\u0647"); - string16 fa_narrow = UTF8ToUTF16( - u8"\u06f1\u06f5 \u0633\u0627\u0639\u062a \u06f4\u06f2 \u062f\u0642\u06cc" - u8"\u0642\u0647"); - string16 fa_numeric = UTF8ToUTF16(u8"\u06f1\u06f5:\u06f4\u06f2"); - EXPECT_EQ(fa_wide, TimeDurationFormatString(delta, DURATION_WIDTH_WIDE)); - EXPECT_EQ(fa_short, TimeDurationFormatString(delta, DURATION_WIDTH_SHORT)); - EXPECT_EQ(fa_narrow, TimeDurationFormatString(delta, DURATION_WIDTH_NARROW)); - EXPECT_EQ(fa_numeric, - TimeDurationFormatString(delta, DURATION_WIDTH_NUMERIC)); -} - -TEST(TimeFormattingTest, TimeDurationFormatWithSeconds) { - test::ScopedRestoreICUDefaultLocale restore_locale; - - // US English. - i18n::SetICUDefaultLocale("en_US"); - - // Test different formats. - TimeDelta delta = TimeDelta::FromSeconds(15 * 3600 + 42 * 60 + 30); - EXPECT_EQ(ASCIIToUTF16("15 hours, 42 minutes, 30 seconds"), - TimeDurationFormatWithSecondsString(delta, DURATION_WIDTH_WIDE)); - EXPECT_EQ(ASCIIToUTF16("15 hr, 42 min, 30 sec"), - TimeDurationFormatWithSecondsString(delta, DURATION_WIDTH_SHORT)); - EXPECT_EQ(ASCIIToUTF16("15h 42m 30s"), - TimeDurationFormatWithSecondsString(delta, DURATION_WIDTH_NARROW)); - EXPECT_EQ(ASCIIToUTF16("15:42:30"), - TimeDurationFormatWithSecondsString(delta, DURATION_WIDTH_NUMERIC)); - - // Test edge case when hour >= 100. - delta = TimeDelta::FromSeconds(125 * 3600 + 42 * 60 + 30); - EXPECT_EQ(ASCIIToUTF16("125 hours, 42 minutes, 30 seconds"), - TimeDurationFormatWithSecondsString(delta, DURATION_WIDTH_WIDE)); - EXPECT_EQ(ASCIIToUTF16("125 hr, 42 min, 30 sec"), - TimeDurationFormatWithSecondsString(delta, DURATION_WIDTH_SHORT)); - EXPECT_EQ(ASCIIToUTF16("125h 42m 30s"), - TimeDurationFormatWithSecondsString(delta, DURATION_WIDTH_NARROW)); - - // Test edge case when minute = 0. - delta = TimeDelta::FromSeconds(15 * 3600 + 0 * 60 + 30); - EXPECT_EQ(ASCIIToUTF16("15 hours, 0 minutes, 30 seconds"), - TimeDurationFormatWithSecondsString(delta, DURATION_WIDTH_WIDE)); - EXPECT_EQ(ASCIIToUTF16("15 hr, 0 min, 30 sec"), - TimeDurationFormatWithSecondsString(delta, DURATION_WIDTH_SHORT)); - EXPECT_EQ(ASCIIToUTF16("15h 0m 30s"), - TimeDurationFormatWithSecondsString(delta, DURATION_WIDTH_NARROW)); - EXPECT_EQ(ASCIIToUTF16("15:00:30"), - TimeDurationFormatWithSecondsString(delta, DURATION_WIDTH_NUMERIC)); - - // Test edge case when second = 0. - delta = TimeDelta::FromSeconds(15 * 3600 + 42 * 60 + 0); - EXPECT_EQ(ASCIIToUTF16("15 hours, 42 minutes, 0 seconds"), - TimeDurationFormatWithSecondsString(delta, DURATION_WIDTH_WIDE)); - EXPECT_EQ(ASCIIToUTF16("15 hr, 42 min, 0 sec"), - TimeDurationFormatWithSecondsString(delta, DURATION_WIDTH_SHORT)); - EXPECT_EQ(ASCIIToUTF16("15h 42m 0s"), - TimeDurationFormatWithSecondsString(delta, DURATION_WIDTH_NARROW)); - EXPECT_EQ(ASCIIToUTF16("15:42:00"), - TimeDurationFormatWithSecondsString(delta, DURATION_WIDTH_NUMERIC)); -} - -TEST(TimeFormattingTest, TimeIntervalFormat) { - test::ScopedRestoreICUDefaultLocale restore_locale; - i18n::SetICUDefaultLocale("en_US"); - ScopedRestoreDefaultTimezone la_time("America/Los_Angeles"); - - const Time::Exploded kTestIntervalEndTimeExploded = { - 2011, 5, 6, 28, // Sat, May 28, 2012 - 22, 42, 7, 0 // 22:42:07.000 - }; - - Time begin_time; - EXPECT_TRUE(Time::FromUTCExploded(kTestDateTimeExploded, &begin_time)); - Time end_time; - EXPECT_TRUE(Time::FromUTCExploded(kTestIntervalEndTimeExploded, &end_time)); - - EXPECT_EQ( - UTF8ToUTF16(u8"Saturday, April 30 – Saturday, May 28"), - DateIntervalFormat(begin_time, end_time, DATE_FORMAT_MONTH_WEEKDAY_DAY)); - - const Time::Exploded kTestIntervalBeginTimeExploded = { - 2011, 5, 1, 16, // Mon, May 16, 2012 - 22, 42, 7, 0 // 22:42:07.000 - }; - EXPECT_TRUE( - Time::FromUTCExploded(kTestIntervalBeginTimeExploded, &begin_time)); - EXPECT_EQ( - UTF8ToUTF16(u8"Monday, May 16 – Saturday, May 28"), - DateIntervalFormat(begin_time, end_time, DATE_FORMAT_MONTH_WEEKDAY_DAY)); - - i18n::SetICUDefaultLocale("en_GB"); - EXPECT_EQ( - UTF8ToUTF16(u8"Monday 16 – Saturday 28 May"), - DateIntervalFormat(begin_time, end_time, DATE_FORMAT_MONTH_WEEKDAY_DAY)); - - i18n::SetICUDefaultLocale("ja"); - EXPECT_EQ( - UTF8ToUTF16(u8"5月16日(月曜日)~28日(土曜日)"), - DateIntervalFormat(begin_time, end_time, DATE_FORMAT_MONTH_WEEKDAY_DAY)); -} - -} // namespace -} // namespace base
diff --git a/base/i18n/timezone_unittest.cc b/base/i18n/timezone_unittest.cc deleted file mode 100644 index 57467dc..0000000 --- a/base/i18n/timezone_unittest.cc +++ /dev/null
@@ -1,27 +0,0 @@ -// 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/i18n/timezone.h" - -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -TEST(TimezoneTest, CountryCodeForCurrentTimezone) { - std::string country_code = CountryCodeForCurrentTimezone(); - // On some systems (such as Android or some flavors of Linux), ICU may come up - // empty. With https://chromium-review.googlesource.com/c/512282/ , ICU will - // not fail any more. See also http://bugs.icu-project.org/trac/ticket/13208 . - // Even with that, ICU returns '001' (world) for region-agnostic timezones - // such as Etc/UTC and |CountryCodeForCurrentTimezone| returns an empty - // string so that the next fallback can be tried by a customer. - // TODO(jshin): Revise this to test for actual timezones using - // use ScopedRestoreICUDefaultTimezone. - if (!country_code.empty()) - EXPECT_EQ(2U, country_code.size()) << "country_code = " << country_code; -} - -} // namespace -} // namespace base
diff --git a/base/json/json_parser_unittest.cc b/base/json/json_parser_unittest.cc deleted file mode 100644 index 0da3db8..0000000 --- a/base/json/json_parser_unittest.cc +++ /dev/null
@@ -1,462 +0,0 @@ -// 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/json/json_parser.h" - -#include <stddef.h> - -#include <memory> - -#include "base/json/json_reader.h" -#include "base/memory/ptr_util.h" -#include "base/optional.h" -#include "base/strings/stringprintf.h" -#include "base/values.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace internal { - -class JSONParserTest : public testing::Test { - public: - JSONParser* NewTestParser(const std::string& input, - int options = JSON_PARSE_RFC) { - JSONParser* parser = new JSONParser(options); - parser->input_ = input; - parser->index_ = 0; - return parser; - } - - // MSan will do a better job detecting over-read errors if the input is - // not nul-terminated on the heap. This will copy |input| to a new buffer - // owned by |owner|, returning a StringPiece to |owner|. - StringPiece MakeNotNullTerminatedInput(const char* input, - std::unique_ptr<char[]>* owner) { - size_t str_len = strlen(input); - owner->reset(new char[str_len]); - memcpy(owner->get(), input, str_len); - return StringPiece(owner->get(), str_len); - } - - void TestLastThree(JSONParser* parser) { - EXPECT_EQ(',', *parser->PeekChar()); - parser->ConsumeChar(); - EXPECT_EQ('|', *parser->PeekChar()); - parser->ConsumeChar(); - EXPECT_EQ('\0', *parser->pos()); - EXPECT_EQ(static_cast<size_t>(parser->index_), parser->input_.length()); - } -}; - -TEST_F(JSONParserTest, NextChar) { - std::string input("Hello world"); - std::unique_ptr<JSONParser> parser(NewTestParser(input)); - - EXPECT_EQ('H', *parser->pos()); - for (size_t i = 1; i < input.length(); ++i) { - parser->ConsumeChar(); - EXPECT_EQ(input[i], *parser->PeekChar()); - } - parser->ConsumeChar(); - EXPECT_EQ('\0', *parser->pos()); - EXPECT_EQ(static_cast<size_t>(parser->index_), parser->input_.length()); -} - -TEST_F(JSONParserTest, ConsumeString) { - std::string input("\"test\",|"); - std::unique_ptr<JSONParser> parser(NewTestParser(input)); - Optional<Value> value(parser->ConsumeString()); - EXPECT_EQ(',', *parser->pos()); - - TestLastThree(parser.get()); - - ASSERT_TRUE(value); - std::string str; - EXPECT_TRUE(value->GetAsString(&str)); - EXPECT_EQ("test", str); -} - -TEST_F(JSONParserTest, ConsumeList) { - std::string input("[true, false],|"); - std::unique_ptr<JSONParser> parser(NewTestParser(input)); - Optional<Value> value(parser->ConsumeList()); - EXPECT_EQ(',', *parser->pos()); - - TestLastThree(parser.get()); - - ASSERT_TRUE(value); - base::ListValue* list; - EXPECT_TRUE(value->GetAsList(&list)); - EXPECT_EQ(2u, list->GetSize()); -} - -TEST_F(JSONParserTest, ConsumeDictionary) { - std::string input("{\"abc\":\"def\"},|"); - std::unique_ptr<JSONParser> parser(NewTestParser(input)); - Optional<Value> value(parser->ConsumeDictionary()); - EXPECT_EQ(',', *parser->pos()); - - TestLastThree(parser.get()); - - ASSERT_TRUE(value); - base::DictionaryValue* dict; - EXPECT_TRUE(value->GetAsDictionary(&dict)); - std::string str; - EXPECT_TRUE(dict->GetString("abc", &str)); - EXPECT_EQ("def", str); -} - -TEST_F(JSONParserTest, ConsumeLiterals) { - // Literal |true|. - std::string input("true,|"); - std::unique_ptr<JSONParser> parser(NewTestParser(input)); - Optional<Value> value(parser->ConsumeLiteral()); - EXPECT_EQ(',', *parser->pos()); - - TestLastThree(parser.get()); - - ASSERT_TRUE(value); - bool bool_value = false; - EXPECT_TRUE(value->GetAsBoolean(&bool_value)); - EXPECT_TRUE(bool_value); - - // Literal |false|. - input = "false,|"; - parser.reset(NewTestParser(input)); - value = parser->ConsumeLiteral(); - EXPECT_EQ(',', *parser->pos()); - - TestLastThree(parser.get()); - - ASSERT_TRUE(value); - EXPECT_TRUE(value->GetAsBoolean(&bool_value)); - EXPECT_FALSE(bool_value); - - // Literal |null|. - input = "null,|"; - parser.reset(NewTestParser(input)); - value = parser->ConsumeLiteral(); - EXPECT_EQ(',', *parser->pos()); - - TestLastThree(parser.get()); - - ASSERT_TRUE(value); - EXPECT_TRUE(value->is_none()); -} - -TEST_F(JSONParserTest, ConsumeNumbers) { - // Integer. - std::string input("1234,|"); - std::unique_ptr<JSONParser> parser(NewTestParser(input)); - Optional<Value> value(parser->ConsumeNumber()); - EXPECT_EQ(',', *parser->pos()); - - TestLastThree(parser.get()); - - ASSERT_TRUE(value); - int number_i; - EXPECT_TRUE(value->GetAsInteger(&number_i)); - EXPECT_EQ(1234, number_i); - - // Negative integer. - input = "-1234,|"; - parser.reset(NewTestParser(input)); - value = parser->ConsumeNumber(); - EXPECT_EQ(',', *parser->pos()); - - TestLastThree(parser.get()); - - ASSERT_TRUE(value); - EXPECT_TRUE(value->GetAsInteger(&number_i)); - EXPECT_EQ(-1234, number_i); - - // Double. - input = "12.34,|"; - parser.reset(NewTestParser(input)); - value = parser->ConsumeNumber(); - EXPECT_EQ(',', *parser->pos()); - - TestLastThree(parser.get()); - - ASSERT_TRUE(value); - double number_d; - EXPECT_TRUE(value->GetAsDouble(&number_d)); - EXPECT_EQ(12.34, number_d); - - // Scientific. - input = "42e3,|"; - parser.reset(NewTestParser(input)); - value = parser->ConsumeNumber(); - EXPECT_EQ(',', *parser->pos()); - - TestLastThree(parser.get()); - - ASSERT_TRUE(value); - EXPECT_TRUE(value->GetAsDouble(&number_d)); - EXPECT_EQ(42000, number_d); - - // Negative scientific. - input = "314159e-5,|"; - parser.reset(NewTestParser(input)); - value = parser->ConsumeNumber(); - EXPECT_EQ(',', *parser->pos()); - - TestLastThree(parser.get()); - - ASSERT_TRUE(value); - EXPECT_TRUE(value->GetAsDouble(&number_d)); - EXPECT_EQ(3.14159, number_d); - - // Positive scientific. - input = "0.42e+3,|"; - parser.reset(NewTestParser(input)); - value = parser->ConsumeNumber(); - EXPECT_EQ(',', *parser->pos()); - - TestLastThree(parser.get()); - - ASSERT_TRUE(value); - EXPECT_TRUE(value->GetAsDouble(&number_d)); - EXPECT_EQ(420, number_d); -} - -TEST_F(JSONParserTest, ErrorMessages) { - // Error strings should not be modified in case of success. - std::string error_message; - int error_code = 0; - std::unique_ptr<Value> root = JSONReader::ReadAndReturnError( - "[42]", JSON_PARSE_RFC, &error_code, &error_message); - EXPECT_TRUE(error_message.empty()); - EXPECT_EQ(0, error_code); - - // Test line and column counting - const char big_json[] = "[\n0,\n1,\n2,\n3,4,5,6 7,\n8,\n9\n]"; - // error here ----------------------------------^ - root = JSONReader::ReadAndReturnError(big_json, JSON_PARSE_RFC, &error_code, - &error_message); - EXPECT_FALSE(root.get()); - EXPECT_EQ(JSONParser::FormatErrorMessage(5, 10, JSONReader::kSyntaxError), - error_message); - EXPECT_EQ(JSONReader::JSON_SYNTAX_ERROR, error_code); - - error_code = 0; - error_message = ""; - // Test line and column counting with "\r\n" line ending - const char big_json_crlf[] = - "[\r\n0,\r\n1,\r\n2,\r\n3,4,5,6 7,\r\n8,\r\n9\r\n]"; - // error here ----------------------^ - root = JSONReader::ReadAndReturnError(big_json_crlf, JSON_PARSE_RFC, - &error_code, &error_message); - EXPECT_FALSE(root.get()); - EXPECT_EQ(JSONParser::FormatErrorMessage(5, 10, JSONReader::kSyntaxError), - error_message); - EXPECT_EQ(JSONReader::JSON_SYNTAX_ERROR, error_code); - - // Test each of the error conditions - root = JSONReader::ReadAndReturnError("{},{}", JSON_PARSE_RFC, &error_code, - &error_message); - EXPECT_FALSE(root.get()); - EXPECT_EQ(JSONParser::FormatErrorMessage(1, 3, - JSONReader::kUnexpectedDataAfterRoot), error_message); - EXPECT_EQ(JSONReader::JSON_UNEXPECTED_DATA_AFTER_ROOT, error_code); - - std::string nested_json; - for (int i = 0; i < 201; ++i) { - nested_json.insert(nested_json.begin(), '['); - nested_json.append(1, ']'); - } - root = JSONReader::ReadAndReturnError(nested_json, JSON_PARSE_RFC, - &error_code, &error_message); - EXPECT_FALSE(root.get()); - EXPECT_EQ(JSONParser::FormatErrorMessage(1, 200, JSONReader::kTooMuchNesting), - error_message); - EXPECT_EQ(JSONReader::JSON_TOO_MUCH_NESTING, error_code); - - root = JSONReader::ReadAndReturnError("[1,]", JSON_PARSE_RFC, &error_code, - &error_message); - EXPECT_FALSE(root.get()); - EXPECT_EQ(JSONParser::FormatErrorMessage(1, 4, JSONReader::kTrailingComma), - error_message); - EXPECT_EQ(JSONReader::JSON_TRAILING_COMMA, error_code); - - root = JSONReader::ReadAndReturnError("{foo:\"bar\"}", JSON_PARSE_RFC, - &error_code, &error_message); - EXPECT_FALSE(root.get()); - EXPECT_EQ(JSONParser::FormatErrorMessage(1, 2, - JSONReader::kUnquotedDictionaryKey), error_message); - EXPECT_EQ(JSONReader::JSON_UNQUOTED_DICTIONARY_KEY, error_code); - - root = JSONReader::ReadAndReturnError("{\"foo\":\"bar\",}", JSON_PARSE_RFC, - &error_code, &error_message); - EXPECT_FALSE(root.get()); - EXPECT_EQ(JSONParser::FormatErrorMessage(1, 14, JSONReader::kTrailingComma), - error_message); - - root = JSONReader::ReadAndReturnError("[nu]", JSON_PARSE_RFC, &error_code, - &error_message); - EXPECT_FALSE(root.get()); - EXPECT_EQ(JSONParser::FormatErrorMessage(1, 2, JSONReader::kSyntaxError), - error_message); - EXPECT_EQ(JSONReader::JSON_SYNTAX_ERROR, error_code); - - root = JSONReader::ReadAndReturnError("[\"xxx\\xq\"]", JSON_PARSE_RFC, - &error_code, &error_message); - EXPECT_FALSE(root.get()); - EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONReader::kInvalidEscape), - error_message); - EXPECT_EQ(JSONReader::JSON_INVALID_ESCAPE, error_code); - - root = JSONReader::ReadAndReturnError("[\"xxx\\uq\"]", JSON_PARSE_RFC, - &error_code, &error_message); - EXPECT_FALSE(root.get()); - EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONReader::kInvalidEscape), - error_message); - EXPECT_EQ(JSONReader::JSON_INVALID_ESCAPE, error_code); - - root = JSONReader::ReadAndReturnError("[\"xxx\\q\"]", JSON_PARSE_RFC, - &error_code, &error_message); - EXPECT_FALSE(root.get()); - EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONReader::kInvalidEscape), - error_message); - EXPECT_EQ(JSONReader::JSON_INVALID_ESCAPE, error_code); - - root = JSONReader::ReadAndReturnError(("[\"\\ufffe\"]"), JSON_PARSE_RFC, - &error_code, &error_message); - EXPECT_EQ(JSONParser::FormatErrorMessage(1, 8, JSONReader::kInvalidEscape), - error_message); - EXPECT_EQ(JSONReader::JSON_INVALID_ESCAPE, error_code); -} - -TEST_F(JSONParserTest, Decode4ByteUtf8Char) { - // This test strings contains a 4 byte unicode character (a smiley!) that the - // reader should be able to handle (the character is \xf0\x9f\x98\x87). - const char kUtf8Data[] = - "[\"😇\",[],[],[],{\"google:suggesttype\":[]}]"; - std::string error_message; - int error_code = 0; - std::unique_ptr<Value> root = JSONReader::ReadAndReturnError( - kUtf8Data, JSON_PARSE_RFC, &error_code, &error_message); - EXPECT_TRUE(root.get()) << error_message; -} - -TEST_F(JSONParserTest, DecodeUnicodeNonCharacter) { - // Tests Unicode code points (encoded as escaped UTF-16) that are not valid - // characters. - EXPECT_FALSE(JSONReader::Read("[\"\\ufdd0\"]")); - EXPECT_FALSE(JSONReader::Read("[\"\\ufffe\"]")); - EXPECT_FALSE(JSONReader::Read("[\"\\ud83f\\udffe\"]")); - - EXPECT_TRUE( - JSONReader::Read("[\"\\ufdd0\"]", JSON_REPLACE_INVALID_CHARACTERS)); - EXPECT_TRUE( - JSONReader::Read("[\"\\ufffe\"]", JSON_REPLACE_INVALID_CHARACTERS)); -} - -TEST_F(JSONParserTest, DecodeNegativeEscapeSequence) { - EXPECT_FALSE(JSONReader::Read("[\"\\x-A\"]")); - EXPECT_FALSE(JSONReader::Read("[\"\\u-00A\"]")); -} - -// Verifies invalid utf-8 characters are replaced. -TEST_F(JSONParserTest, ReplaceInvalidCharacters) { - const std::string bogus_char = ""; - const std::string quoted_bogus_char = "\"" + bogus_char + "\""; - std::unique_ptr<JSONParser> parser( - NewTestParser(quoted_bogus_char, JSON_REPLACE_INVALID_CHARACTERS)); - Optional<Value> value(parser->ConsumeString()); - ASSERT_TRUE(value); - std::string str; - EXPECT_TRUE(value->GetAsString(&str)); - EXPECT_EQ(kUnicodeReplacementString, str); -} - -TEST_F(JSONParserTest, ReplaceInvalidUTF16EscapeSequence) { - const std::string invalid = "\"\\ufffe\""; - std::unique_ptr<JSONParser> parser( - NewTestParser(invalid, JSON_REPLACE_INVALID_CHARACTERS)); - Optional<Value> value(parser->ConsumeString()); - ASSERT_TRUE(value); - std::string str; - EXPECT_TRUE(value->GetAsString(&str)); - EXPECT_EQ(kUnicodeReplacementString, str); -} - -TEST_F(JSONParserTest, ParseNumberErrors) { - const struct { - const char* input; - bool parse_success; - double value; - } kCases[] = { - // clang-format off - {"1", true, 1}, - {"2.", false, 0}, - {"42", true, 42}, - {"6e", false, 0}, - {"43e2", true, 4300}, - {"43e-", false, 0}, - {"9e-3", true, 0.009}, - {"2e+", false, 0}, - {"2e+2", true, 200}, - // clang-format on - }; - - for (unsigned int i = 0; i < arraysize(kCases); ++i) { - auto test_case = kCases[i]; - SCOPED_TRACE(StringPrintf("case %u: \"%s\"", i, test_case.input)); - - std::unique_ptr<char[]> input_owner; - StringPiece input = - MakeNotNullTerminatedInput(test_case.input, &input_owner); - - std::unique_ptr<Value> result = JSONReader::Read(input); - if (test_case.parse_success) { - EXPECT_TRUE(result); - } else { - EXPECT_FALSE(result); - } - - if (!result) - continue; - - double double_value = 0; - EXPECT_TRUE(result->GetAsDouble(&double_value)); - EXPECT_EQ(test_case.value, double_value); - } -} - -TEST_F(JSONParserTest, UnterminatedInputs) { - const char* kCases[] = { - // clang-format off - "/", - "//", - "/*", - "\"xxxxxx", - "\"", - "{ ", - "[\t", - "tru", - "fals", - "nul", - "\"\\x", - "\"\\x2", - "\"\\u123", - "\"\\uD803\\u", - "\"\\", - "\"\\/", - // clang-format on - }; - - for (unsigned int i = 0; i < arraysize(kCases); ++i) { - auto* test_case = kCases[i]; - SCOPED_TRACE(StringPrintf("case %u: \"%s\"", i, test_case)); - - std::unique_ptr<char[]> input_owner; - StringPiece input = MakeNotNullTerminatedInput(test_case, &input_owner); - - EXPECT_FALSE(JSONReader::Read(input)); - } -} - -} // namespace internal -} // namespace base
diff --git a/base/json/json_reader_unittest.cc b/base/json/json_reader_unittest.cc deleted file mode 100644 index 828fba0..0000000 --- a/base/json/json_reader_unittest.cc +++ /dev/null
@@ -1,665 +0,0 @@ -// 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/json/json_reader.h" - -#include <stddef.h> - -#include <memory> - -#include "base/base_paths.h" -#include "base/files/file_util.h" -#include "base/logging.h" -#include "base/macros.h" -#include "base/path_service.h" -#include "base/strings/string_piece.h" -#include "base/strings/utf_string_conversions.h" -#include "base/values.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(JSONReaderTest, Whitespace) { - std::unique_ptr<Value> root = JSONReader().ReadToValue(" null "); - ASSERT_TRUE(root); - EXPECT_TRUE(root->is_none()); -} - -TEST(JSONReaderTest, InvalidString) { - EXPECT_FALSE(JSONReader().ReadToValue("nu")); -} - -TEST(JSONReaderTest, SimpleBool) { - std::unique_ptr<Value> root = JSONReader().ReadToValue("true "); - ASSERT_TRUE(root); - EXPECT_TRUE(root->is_bool()); -} - -TEST(JSONReaderTest, EmbeddedComments) { - std::unique_ptr<Value> root = JSONReader().ReadToValue("/* comment */null"); - ASSERT_TRUE(root); - EXPECT_TRUE(root->is_none()); - root = JSONReader().ReadToValue("40 /* comment */"); - ASSERT_TRUE(root); - EXPECT_TRUE(root->is_int()); - root = JSONReader().ReadToValue("true // comment"); - ASSERT_TRUE(root); - EXPECT_TRUE(root->is_bool()); - root = JSONReader().ReadToValue("/* comment */\"sample string\""); - ASSERT_TRUE(root); - EXPECT_TRUE(root->is_string()); - std::string value; - EXPECT_TRUE(root->GetAsString(&value)); - EXPECT_EQ("sample string", value); - std::unique_ptr<ListValue> list = - ListValue::From(JSONReader().ReadToValue("[1, /* comment, 2 ] */ \n 3]")); - ASSERT_TRUE(list); - EXPECT_EQ(2u, list->GetSize()); - int int_val = 0; - EXPECT_TRUE(list->GetInteger(0, &int_val)); - EXPECT_EQ(1, int_val); - EXPECT_TRUE(list->GetInteger(1, &int_val)); - EXPECT_EQ(3, int_val); - list = ListValue::From(JSONReader().ReadToValue("[1, /*a*/2, 3]")); - ASSERT_TRUE(list); - EXPECT_EQ(3u, list->GetSize()); - root = JSONReader().ReadToValue("/* comment **/42"); - ASSERT_TRUE(root); - EXPECT_TRUE(root->is_int()); - EXPECT_TRUE(root->GetAsInteger(&int_val)); - EXPECT_EQ(42, int_val); - root = JSONReader().ReadToValue( - "/* comment **/\n" - "// */ 43\n" - "44"); - ASSERT_TRUE(root); - EXPECT_TRUE(root->is_int()); - EXPECT_TRUE(root->GetAsInteger(&int_val)); - EXPECT_EQ(44, int_val); -} - -TEST(JSONReaderTest, Ints) { - std::unique_ptr<Value> root = JSONReader().ReadToValue("43"); - ASSERT_TRUE(root); - EXPECT_TRUE(root->is_int()); - int int_val = 0; - EXPECT_TRUE(root->GetAsInteger(&int_val)); - EXPECT_EQ(43, int_val); -} - -TEST(JSONReaderTest, NonDecimalNumbers) { - // According to RFC4627, oct, hex, and leading zeros are invalid JSON. - EXPECT_FALSE(JSONReader().ReadToValue("043")); - EXPECT_FALSE(JSONReader().ReadToValue("0x43")); - EXPECT_FALSE(JSONReader().ReadToValue("00")); -} - -TEST(JSONReaderTest, NumberZero) { - // Test 0 (which needs to be special cased because of the leading zero - // clause). - std::unique_ptr<Value> root = JSONReader().ReadToValue("0"); - ASSERT_TRUE(root); - EXPECT_TRUE(root->is_int()); - int int_val = 1; - EXPECT_TRUE(root->GetAsInteger(&int_val)); - EXPECT_EQ(0, int_val); -} - -TEST(JSONReaderTest, LargeIntPromotion) { - // Numbers that overflow ints should succeed, being internally promoted to - // storage as doubles - std::unique_ptr<Value> root = JSONReader().ReadToValue("2147483648"); - ASSERT_TRUE(root); - double double_val; - EXPECT_TRUE(root->is_double()); - double_val = 0.0; - EXPECT_TRUE(root->GetAsDouble(&double_val)); - EXPECT_DOUBLE_EQ(2147483648.0, double_val); - root = JSONReader().ReadToValue("-2147483649"); - ASSERT_TRUE(root); - EXPECT_TRUE(root->is_double()); - double_val = 0.0; - EXPECT_TRUE(root->GetAsDouble(&double_val)); - EXPECT_DOUBLE_EQ(-2147483649.0, double_val); -} - -TEST(JSONReaderTest, Doubles) { - std::unique_ptr<Value> root = JSONReader().ReadToValue("43.1"); - ASSERT_TRUE(root); - EXPECT_TRUE(root->is_double()); - double double_val = 0.0; - EXPECT_TRUE(root->GetAsDouble(&double_val)); - EXPECT_DOUBLE_EQ(43.1, double_val); - - root = JSONReader().ReadToValue("4.3e-1"); - ASSERT_TRUE(root); - EXPECT_TRUE(root->is_double()); - double_val = 0.0; - EXPECT_TRUE(root->GetAsDouble(&double_val)); - EXPECT_DOUBLE_EQ(.43, double_val); - - root = JSONReader().ReadToValue("2.1e0"); - ASSERT_TRUE(root); - EXPECT_TRUE(root->is_double()); - double_val = 0.0; - EXPECT_TRUE(root->GetAsDouble(&double_val)); - EXPECT_DOUBLE_EQ(2.1, double_val); - - root = JSONReader().ReadToValue("2.1e+0001"); - ASSERT_TRUE(root); - EXPECT_TRUE(root->is_double()); - double_val = 0.0; - EXPECT_TRUE(root->GetAsDouble(&double_val)); - EXPECT_DOUBLE_EQ(21.0, double_val); - - root = JSONReader().ReadToValue("0.01"); - ASSERT_TRUE(root); - EXPECT_TRUE(root->is_double()); - double_val = 0.0; - EXPECT_TRUE(root->GetAsDouble(&double_val)); - EXPECT_DOUBLE_EQ(0.01, double_val); - - root = JSONReader().ReadToValue("1.00"); - ASSERT_TRUE(root); - EXPECT_TRUE(root->is_double()); - double_val = 0.0; - EXPECT_TRUE(root->GetAsDouble(&double_val)); - EXPECT_DOUBLE_EQ(1.0, double_val); -} - -TEST(JSONReaderTest, FractionalNumbers) { - // Fractional parts must have a digit before and after the decimal point. - EXPECT_FALSE(JSONReader().ReadToValue("1.")); - EXPECT_FALSE(JSONReader().ReadToValue(".1")); - EXPECT_FALSE(JSONReader().ReadToValue("1.e10")); -} - -TEST(JSONReaderTest, ExponentialNumbers) { - // Exponent must have a digit following the 'e'. - EXPECT_FALSE(JSONReader().ReadToValue("1e")); - EXPECT_FALSE(JSONReader().ReadToValue("1E")); - EXPECT_FALSE(JSONReader().ReadToValue("1e1.")); - EXPECT_FALSE(JSONReader().ReadToValue("1e1.0")); -} - -TEST(JSONReaderTest, InvalidNAN) { - EXPECT_FALSE(JSONReader().ReadToValue("1e1000")); - EXPECT_FALSE(JSONReader().ReadToValue("-1e1000")); - EXPECT_FALSE(JSONReader().ReadToValue("NaN")); - EXPECT_FALSE(JSONReader().ReadToValue("nan")); - EXPECT_FALSE(JSONReader().ReadToValue("inf")); -} - -TEST(JSONReaderTest, InvalidNumbers) { - EXPECT_FALSE(JSONReader().ReadToValue("4.3.1")); - EXPECT_FALSE(JSONReader().ReadToValue("4e3.1")); - EXPECT_FALSE(JSONReader().ReadToValue("4.a")); -} - -TEST(JSONReader, SimpleString) { - std::unique_ptr<Value> root = JSONReader().ReadToValue("\"hello world\""); - ASSERT_TRUE(root); - EXPECT_TRUE(root->is_string()); - std::string str_val; - EXPECT_TRUE(root->GetAsString(&str_val)); - EXPECT_EQ("hello world", str_val); -} - -TEST(JSONReaderTest, EmptyString) { - std::unique_ptr<Value> root = JSONReader().ReadToValue("\"\""); - ASSERT_TRUE(root); - EXPECT_TRUE(root->is_string()); - std::string str_val; - EXPECT_TRUE(root->GetAsString(&str_val)); - EXPECT_EQ("", str_val); -} - -TEST(JSONReaderTest, BasicStringEscapes) { - std::unique_ptr<Value> root = - JSONReader().ReadToValue("\" \\\"\\\\\\/\\b\\f\\n\\r\\t\\v\""); - ASSERT_TRUE(root); - EXPECT_TRUE(root->is_string()); - std::string str_val; - EXPECT_TRUE(root->GetAsString(&str_val)); - EXPECT_EQ(" \"\\/\b\f\n\r\t\v", str_val); -} - -TEST(JSONReaderTest, UnicodeEscapes) { - // Test hex and unicode escapes including the null character. - std::unique_ptr<Value> root = - JSONReader().ReadToValue("\"\\x41\\x00\\u1234\\u0000\""); - ASSERT_TRUE(root); - EXPECT_TRUE(root->is_string()); - std::string str_val; - EXPECT_TRUE(root->GetAsString(&str_val)); - EXPECT_EQ(std::wstring(L"A\0\x1234\0", 4), UTF8ToWide(str_val)); -} - -TEST(JSONReaderTest, InvalidStrings) { - EXPECT_FALSE(JSONReader().ReadToValue("\"no closing quote")); - EXPECT_FALSE(JSONReader().ReadToValue("\"\\z invalid escape char\"")); - EXPECT_FALSE(JSONReader().ReadToValue("\"\\xAQ invalid hex code\"")); - EXPECT_FALSE(JSONReader().ReadToValue("not enough hex chars\\x1\"")); - EXPECT_FALSE(JSONReader().ReadToValue("\"not enough escape chars\\u123\"")); - EXPECT_FALSE( - JSONReader().ReadToValue("\"extra backslash at end of input\\\"")); -} - -TEST(JSONReaderTest, BasicArray) { - std::unique_ptr<ListValue> list = - ListValue::From(JSONReader::Read("[true, false, null]")); - ASSERT_TRUE(list); - EXPECT_EQ(3U, list->GetSize()); - - // Test with trailing comma. Should be parsed the same as above. - std::unique_ptr<Value> root2 = - JSONReader::Read("[true, false, null, ]", JSON_ALLOW_TRAILING_COMMAS); - EXPECT_TRUE(list->Equals(root2.get())); -} - -TEST(JSONReaderTest, EmptyArray) { - std::unique_ptr<ListValue> list = ListValue::From(JSONReader::Read("[]")); - ASSERT_TRUE(list); - EXPECT_EQ(0U, list->GetSize()); -} - -TEST(JSONReaderTest, NestedArrays) { - std::unique_ptr<ListValue> list = ListValue::From( - JSONReader::Read("[[true], [], [false, [], [null]], null]")); - ASSERT_TRUE(list); - EXPECT_EQ(4U, list->GetSize()); - - // Lots of trailing commas. - std::unique_ptr<Value> root2 = - JSONReader::Read("[[true], [], [false, [], [null, ] , ], null,]", - JSON_ALLOW_TRAILING_COMMAS); - EXPECT_TRUE(list->Equals(root2.get())); -} - -TEST(JSONReaderTest, InvalidArrays) { - // Missing close brace. - EXPECT_FALSE(JSONReader::Read("[[true], [], [false, [], [null]], null")); - - // Too many commas. - EXPECT_FALSE(JSONReader::Read("[true,, null]")); - EXPECT_FALSE(JSONReader::Read("[true,, null]", JSON_ALLOW_TRAILING_COMMAS)); - - // No commas. - EXPECT_FALSE(JSONReader::Read("[true null]")); - - // Trailing comma. - EXPECT_FALSE(JSONReader::Read("[true,]")); -} - -TEST(JSONReaderTest, ArrayTrailingComma) { - // Valid if we set |allow_trailing_comma| to true. - std::unique_ptr<ListValue> list = - ListValue::From(JSONReader::Read("[true,]", JSON_ALLOW_TRAILING_COMMAS)); - ASSERT_TRUE(list); - EXPECT_EQ(1U, list->GetSize()); - Value* tmp_value = nullptr; - ASSERT_TRUE(list->Get(0, &tmp_value)); - EXPECT_TRUE(tmp_value->is_bool()); - bool bool_value = false; - EXPECT_TRUE(tmp_value->GetAsBoolean(&bool_value)); - EXPECT_TRUE(bool_value); -} - -TEST(JSONReaderTest, ArrayTrailingCommaNoEmptyElements) { - // Don't allow empty elements, even if |allow_trailing_comma| is - // true. - EXPECT_FALSE(JSONReader::Read("[,]", JSON_ALLOW_TRAILING_COMMAS)); - EXPECT_FALSE(JSONReader::Read("[true,,]", JSON_ALLOW_TRAILING_COMMAS)); - EXPECT_FALSE(JSONReader::Read("[,true,]", JSON_ALLOW_TRAILING_COMMAS)); - EXPECT_FALSE(JSONReader::Read("[true,,false]", JSON_ALLOW_TRAILING_COMMAS)); -} - -TEST(JSONReaderTest, EmptyDictionary) { - std::unique_ptr<DictionaryValue> dict_val = - DictionaryValue::From(JSONReader::Read("{}")); - ASSERT_TRUE(dict_val); -} - -TEST(JSONReaderTest, CompleteDictionary) { - auto dict_val = DictionaryValue::From(JSONReader::Read( - "{\"number\":9.87654321, \"null\":null , \"\\x53\" : \"str\" }")); - ASSERT_TRUE(dict_val); - double double_val = 0.0; - EXPECT_TRUE(dict_val->GetDouble("number", &double_val)); - EXPECT_DOUBLE_EQ(9.87654321, double_val); - Value* null_val = nullptr; - ASSERT_TRUE(dict_val->Get("null", &null_val)); - EXPECT_TRUE(null_val->is_none()); - std::string str_val; - EXPECT_TRUE(dict_val->GetString("S", &str_val)); - EXPECT_EQ("str", str_val); - - std::unique_ptr<Value> root2 = JSONReader::Read( - "{\"number\":9.87654321, \"null\":null , \"\\x53\" : \"str\", }", - JSON_ALLOW_TRAILING_COMMAS); - ASSERT_TRUE(root2); - EXPECT_TRUE(dict_val->Equals(root2.get())); - - // Test newline equivalence. - root2 = JSONReader::Read( - "{\n" - " \"number\":9.87654321,\n" - " \"null\":null,\n" - " \"\\x53\":\"str\",\n" - "}\n", - JSON_ALLOW_TRAILING_COMMAS); - ASSERT_TRUE(root2); - EXPECT_TRUE(dict_val->Equals(root2.get())); - - root2 = JSONReader::Read( - "{\r\n" - " \"number\":9.87654321,\r\n" - " \"null\":null,\r\n" - " \"\\x53\":\"str\",\r\n" - "}\r\n", - JSON_ALLOW_TRAILING_COMMAS); - ASSERT_TRUE(root2); - EXPECT_TRUE(dict_val->Equals(root2.get())); -} - -TEST(JSONReaderTest, NestedDictionaries) { - std::unique_ptr<DictionaryValue> dict_val = - DictionaryValue::From(JSONReader::Read( - "{\"inner\":{\"array\":[true]},\"false\":false,\"d\":{}}")); - ASSERT_TRUE(dict_val); - DictionaryValue* inner_dict = nullptr; - ASSERT_TRUE(dict_val->GetDictionary("inner", &inner_dict)); - ListValue* inner_array = nullptr; - ASSERT_TRUE(inner_dict->GetList("array", &inner_array)); - EXPECT_EQ(1U, inner_array->GetSize()); - bool bool_value = true; - EXPECT_TRUE(dict_val->GetBoolean("false", &bool_value)); - EXPECT_FALSE(bool_value); - inner_dict = nullptr; - EXPECT_TRUE(dict_val->GetDictionary("d", &inner_dict)); - - std::unique_ptr<Value> root2 = JSONReader::Read( - "{\"inner\": {\"array\":[true] , },\"false\":false,\"d\":{},}", - JSON_ALLOW_TRAILING_COMMAS); - EXPECT_TRUE(dict_val->Equals(root2.get())); -} - -TEST(JSONReaderTest, DictionaryKeysWithPeriods) { - std::unique_ptr<DictionaryValue> dict_val = DictionaryValue::From( - JSONReader::Read("{\"a.b\":3,\"c\":2,\"d.e.f\":{\"g.h.i.j\":1}}")); - ASSERT_TRUE(dict_val); - int integer_value = 0; - EXPECT_TRUE(dict_val->GetIntegerWithoutPathExpansion("a.b", &integer_value)); - EXPECT_EQ(3, integer_value); - EXPECT_TRUE(dict_val->GetIntegerWithoutPathExpansion("c", &integer_value)); - EXPECT_EQ(2, integer_value); - DictionaryValue* inner_dict = nullptr; - ASSERT_TRUE( - dict_val->GetDictionaryWithoutPathExpansion("d.e.f", &inner_dict)); - EXPECT_EQ(1U, inner_dict->size()); - EXPECT_TRUE( - inner_dict->GetIntegerWithoutPathExpansion("g.h.i.j", &integer_value)); - EXPECT_EQ(1, integer_value); - - dict_val = - DictionaryValue::From(JSONReader::Read("{\"a\":{\"b\":2},\"a.b\":1}")); - ASSERT_TRUE(dict_val); - EXPECT_TRUE(dict_val->GetInteger("a.b", &integer_value)); - EXPECT_EQ(2, integer_value); - EXPECT_TRUE(dict_val->GetIntegerWithoutPathExpansion("a.b", &integer_value)); - EXPECT_EQ(1, integer_value); -} - -TEST(JSONReaderTest, InvalidDictionaries) { - // No closing brace. - EXPECT_FALSE(JSONReader::Read("{\"a\": true")); - - // Keys must be quoted strings. - EXPECT_FALSE(JSONReader::Read("{foo:true}")); - EXPECT_FALSE(JSONReader::Read("{1234: false}")); - EXPECT_FALSE(JSONReader::Read("{:false}")); - - // Trailing comma. - EXPECT_FALSE(JSONReader::Read("{\"a\":true,}")); - - // Too many commas. - EXPECT_FALSE(JSONReader::Read("{\"a\":true,,\"b\":false}")); - EXPECT_FALSE(JSONReader::Read("{\"a\":true,,\"b\":false}", - JSON_ALLOW_TRAILING_COMMAS)); - - // No separator. - EXPECT_FALSE(JSONReader::Read("{\"a\" \"b\"}")); - - // Lone comma. - EXPECT_FALSE(JSONReader::Read("{,}")); - EXPECT_FALSE(JSONReader::Read("{,}", JSON_ALLOW_TRAILING_COMMAS)); - EXPECT_FALSE(JSONReader::Read("{\"a\":true,,}", JSON_ALLOW_TRAILING_COMMAS)); - EXPECT_FALSE(JSONReader::Read("{,\"a\":true}", JSON_ALLOW_TRAILING_COMMAS)); - EXPECT_FALSE(JSONReader::Read("{\"a\":true,,\"b\":false}", - JSON_ALLOW_TRAILING_COMMAS)); -} - -TEST(JSONReaderTest, StackOverflow) { - std::string evil(1000000, '['); - evil.append(std::string(1000000, ']')); - EXPECT_FALSE(JSONReader::Read(evil)); - - // A few thousand adjacent lists is fine. - std::string not_evil("["); - not_evil.reserve(15010); - for (int i = 0; i < 5000; ++i) - not_evil.append("[],"); - not_evil.append("[]]"); - std::unique_ptr<ListValue> list = ListValue::From(JSONReader::Read(not_evil)); - ASSERT_TRUE(list); - EXPECT_EQ(5001U, list->GetSize()); -} - -TEST(JSONReaderTest, UTF8Input) { - std::unique_ptr<Value> root = - JSONReader().ReadToValue("\"\xe7\xbd\x91\xe9\xa1\xb5\""); - ASSERT_TRUE(root); - EXPECT_TRUE(root->is_string()); - std::string str_val; - EXPECT_TRUE(root->GetAsString(&str_val)); - EXPECT_EQ(L"\x7f51\x9875", UTF8ToWide(str_val)); - - std::unique_ptr<DictionaryValue> dict_val = - DictionaryValue::From(JSONReader().ReadToValue( - "{\"path\": \"/tmp/\xc3\xa0\xc3\xa8\xc3\xb2.png\"}")); - ASSERT_TRUE(dict_val); - EXPECT_TRUE(dict_val->GetString("path", &str_val)); - EXPECT_EQ("/tmp/\xC3\xA0\xC3\xA8\xC3\xB2.png", str_val); -} - -TEST(JSONReaderTest, InvalidUTF8Input) { - EXPECT_FALSE(JSONReader().ReadToValue("\"345\xb0\xa1\xb0\xa2\"")); - EXPECT_FALSE(JSONReader().ReadToValue("\"123\xc0\x81\"")); - EXPECT_FALSE(JSONReader().ReadToValue("\"abc\xc0\xae\"")); -} - -TEST(JSONReaderTest, UTF16Escapes) { - std::unique_ptr<Value> root = JSONReader().ReadToValue("\"\\u20ac3,14\""); - ASSERT_TRUE(root); - EXPECT_TRUE(root->is_string()); - std::string str_val; - EXPECT_TRUE(root->GetAsString(&str_val)); - EXPECT_EQ( - "\xe2\x82\xac" - "3,14", - str_val); - - root = JSONReader().ReadToValue("\"\\ud83d\\udca9\\ud83d\\udc6c\""); - ASSERT_TRUE(root); - EXPECT_TRUE(root->is_string()); - str_val.clear(); - EXPECT_TRUE(root->GetAsString(&str_val)); - EXPECT_EQ("\xf0\x9f\x92\xa9\xf0\x9f\x91\xac", str_val); -} - -TEST(JSONReaderTest, InvalidUTF16Escapes) { - const char* const cases[] = { - "\"\\u123\"", // Invalid scalar. - "\"\\ud83d\"", // Invalid scalar. - "\"\\u$%@!\"", // Invalid scalar. - "\"\\uzz89\"", // Invalid scalar. - "\"\\ud83d\\udca\"", // Invalid lower surrogate. - "\"\\ud83d\\ud83d\"", // Invalid lower surrogate. - "\"\\ud83d\\uaaaZ\"" // Invalid lower surrogate. - "\"\\ud83foo\"", // No lower surrogate. - "\"\\ud83d\\foo\"" // No lower surrogate. - "\"\\ud83\\foo\"" // Invalid upper surrogate. - "\"\\ud83d\\u1\"" // No lower surrogate. - "\"\\ud83\\u1\"" // Invalid upper surrogate. - }; - std::unique_ptr<Value> root; - for (size_t i = 0; i < arraysize(cases); ++i) { - root = JSONReader().ReadToValue(cases[i]); - EXPECT_FALSE(root) << cases[i]; - } -} - -TEST(JSONReaderTest, LiteralRoots) { - std::unique_ptr<Value> root = JSONReader::Read("null"); - ASSERT_TRUE(root); - EXPECT_TRUE(root->is_none()); - - root = JSONReader::Read("true"); - ASSERT_TRUE(root); - bool bool_value; - EXPECT_TRUE(root->GetAsBoolean(&bool_value)); - EXPECT_TRUE(bool_value); - - root = JSONReader::Read("10"); - ASSERT_TRUE(root); - int integer_value; - EXPECT_TRUE(root->GetAsInteger(&integer_value)); - EXPECT_EQ(10, integer_value); - - root = JSONReader::Read("\"root\""); - ASSERT_TRUE(root); - std::string str_val; - EXPECT_TRUE(root->GetAsString(&str_val)); - EXPECT_EQ("root", str_val); -} - -TEST(JSONReaderTest, ReadFromFile) { - FilePath path; - ASSERT_TRUE(PathService::Get(base::DIR_TEST_DATA, &path)); - path = path.AppendASCII("json"); - ASSERT_TRUE(base::PathExists(path)); - - std::string input; - ASSERT_TRUE(ReadFileToString(path.AppendASCII("bom_feff.json"), &input)); - - JSONReader reader; - std::unique_ptr<Value> root(reader.ReadToValue(input)); - ASSERT_TRUE(root) << reader.GetErrorMessage(); - EXPECT_TRUE(root->is_dict()); -} - -// Tests that the root of a JSON object can be deleted safely while its -// children outlive it. -TEST(JSONReaderTest, StringOptimizations) { - std::unique_ptr<Value> dict_literal_0; - std::unique_ptr<Value> dict_literal_1; - std::unique_ptr<Value> dict_string_0; - std::unique_ptr<Value> dict_string_1; - std::unique_ptr<Value> list_value_0; - std::unique_ptr<Value> list_value_1; - - { - std::unique_ptr<Value> root = JSONReader::Read( - "{" - " \"test\": {" - " \"foo\": true," - " \"bar\": 3.14," - " \"baz\": \"bat\"," - " \"moo\": \"cow\"" - " }," - " \"list\": [" - " \"a\"," - " \"b\"" - " ]" - "}", - JSON_PARSE_RFC); - ASSERT_TRUE(root); - - DictionaryValue* root_dict = nullptr; - ASSERT_TRUE(root->GetAsDictionary(&root_dict)); - - DictionaryValue* dict = nullptr; - ListValue* list = nullptr; - - ASSERT_TRUE(root_dict->GetDictionary("test", &dict)); - ASSERT_TRUE(root_dict->GetList("list", &list)); - - ASSERT_TRUE(dict->Remove("foo", &dict_literal_0)); - ASSERT_TRUE(dict->Remove("bar", &dict_literal_1)); - ASSERT_TRUE(dict->Remove("baz", &dict_string_0)); - ASSERT_TRUE(dict->Remove("moo", &dict_string_1)); - - ASSERT_EQ(2u, list->GetSize()); - ASSERT_TRUE(list->Remove(0, &list_value_0)); - ASSERT_TRUE(list->Remove(0, &list_value_1)); - } - - bool b = false; - double d = 0; - std::string s; - - EXPECT_TRUE(dict_literal_0->GetAsBoolean(&b)); - EXPECT_TRUE(b); - - EXPECT_TRUE(dict_literal_1->GetAsDouble(&d)); - EXPECT_EQ(3.14, d); - - EXPECT_TRUE(dict_string_0->GetAsString(&s)); - EXPECT_EQ("bat", s); - - EXPECT_TRUE(dict_string_1->GetAsString(&s)); - EXPECT_EQ("cow", s); - - EXPECT_TRUE(list_value_0->GetAsString(&s)); - EXPECT_EQ("a", s); - EXPECT_TRUE(list_value_1->GetAsString(&s)); - EXPECT_EQ("b", s); -} - -// A smattering of invalid JSON designed to test specific portions of the -// parser implementation against buffer overflow. Best run with DCHECKs so -// that the one in NextChar fires. -TEST(JSONReaderTest, InvalidSanity) { - const char* const kInvalidJson[] = { - "/* test *", "{\"foo\"", "{\"foo\":", " [", "\"\\u123g\"", "{\n\"eh:\n}", - }; - - for (size_t i = 0; i < arraysize(kInvalidJson); ++i) { - JSONReader reader; - LOG(INFO) << "Sanity test " << i << ": <" << kInvalidJson[i] << ">"; - EXPECT_FALSE(reader.ReadToValue(kInvalidJson[i])); - EXPECT_NE(JSONReader::JSON_NO_ERROR, reader.error_code()); - EXPECT_NE("", reader.GetErrorMessage()); - } -} - -TEST(JSONReaderTest, IllegalTrailingNull) { - const char json[] = { '"', 'n', 'u', 'l', 'l', '"', '\0' }; - std::string json_string(json, sizeof(json)); - JSONReader reader; - EXPECT_FALSE(reader.ReadToValue(json_string)); - EXPECT_EQ(JSONReader::JSON_UNEXPECTED_DATA_AFTER_ROOT, reader.error_code()); -} - -TEST(JSONReaderTest, MaxNesting) { - std::string json(R"({"outer": { "inner": {"foo": true}}})"); - std::unique_ptr<Value> root; - root = JSONReader::Read(json, JSON_PARSE_RFC, 3); - ASSERT_FALSE(root); - root = JSONReader::Read(json, JSON_PARSE_RFC, 4); - ASSERT_TRUE(root); -} - -} // namespace base
diff --git a/base/json/json_value_converter_unittest.cc b/base/json/json_value_converter_unittest.cc deleted file mode 100644 index 322f5f0..0000000 --- a/base/json/json_value_converter_unittest.cc +++ /dev/null
@@ -1,255 +0,0 @@ -// 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/json/json_value_converter.h" - -#include <memory> -#include <string> -#include <vector> - -#include "base/json/json_reader.h" -#include "base/strings/string_piece.h" -#include "base/values.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -// Very simple messages. -struct SimpleMessage { - enum SimpleEnum { - FOO, BAR, - }; - int foo; - std::string bar; - bool baz; - bool bstruct; - SimpleEnum simple_enum; - std::vector<std::unique_ptr<int>> ints; - std::vector<std::unique_ptr<std::string>> string_values; - SimpleMessage() : foo(0), baz(false), bstruct(false), simple_enum(FOO) {} - - static bool ParseSimpleEnum(StringPiece value, SimpleEnum* field) { - if (value == "foo") { - *field = FOO; - return true; - } else if (value == "bar") { - *field = BAR; - return true; - } - return false; - } - - static bool HasFieldPresent(const base::Value* value, bool* result) { - *result = value != nullptr; - return true; - } - - static bool GetValueString(const base::Value* value, std::string* result) { - const base::DictionaryValue* dict = nullptr; - if (!value->GetAsDictionary(&dict)) - return false; - - if (!dict->GetString("val", result)) - return false; - - return true; - } - - static void RegisterJSONConverter( - base::JSONValueConverter<SimpleMessage>* converter) { - converter->RegisterIntField("foo", &SimpleMessage::foo); - converter->RegisterStringField("bar", &SimpleMessage::bar); - converter->RegisterBoolField("baz", &SimpleMessage::baz); - converter->RegisterCustomField<SimpleEnum>( - "simple_enum", &SimpleMessage::simple_enum, &ParseSimpleEnum); - converter->RegisterRepeatedInt("ints", &SimpleMessage::ints); - converter->RegisterCustomValueField<bool>("bstruct", - &SimpleMessage::bstruct, - &HasFieldPresent); - converter->RegisterRepeatedCustomValue<std::string>( - "string_values", - &SimpleMessage::string_values, - &GetValueString); - } -}; - -// For nested messages. -struct NestedMessage { - double foo; - SimpleMessage child; - std::vector<std::unique_ptr<SimpleMessage>> children; - - NestedMessage() : foo(0) {} - - static void RegisterJSONConverter( - base::JSONValueConverter<NestedMessage>* converter) { - converter->RegisterDoubleField("foo", &NestedMessage::foo); - converter->RegisterNestedField("child", &NestedMessage::child); - converter->RegisterRepeatedMessage("children", &NestedMessage::children); - } -}; - -} // namespace - -TEST(JSONValueConverterTest, ParseSimpleMessage) { - const char normal_data[] = - "{\n" - " \"foo\": 1,\n" - " \"bar\": \"bar\",\n" - " \"baz\": true,\n" - " \"bstruct\": {},\n" - " \"string_values\": [{\"val\": \"value_1\"}, {\"val\": \"value_2\"}]," - " \"simple_enum\": \"foo\"," - " \"ints\": [1, 2]" - "}\n"; - - std::unique_ptr<Value> value = base::JSONReader::Read(normal_data); - SimpleMessage message; - base::JSONValueConverter<SimpleMessage> converter; - EXPECT_TRUE(converter.Convert(*value.get(), &message)); - - EXPECT_EQ(1, message.foo); - EXPECT_EQ("bar", message.bar); - EXPECT_TRUE(message.baz); - EXPECT_EQ(SimpleMessage::FOO, message.simple_enum); - EXPECT_EQ(2, static_cast<int>(message.ints.size())); - ASSERT_EQ(2U, message.string_values.size()); - EXPECT_EQ("value_1", *message.string_values[0]); - EXPECT_EQ("value_2", *message.string_values[1]); - EXPECT_EQ(1, *(message.ints[0])); - EXPECT_EQ(2, *(message.ints[1])); -} - -TEST(JSONValueConverterTest, ParseNestedMessage) { - const char normal_data[] = - "{\n" - " \"foo\": 1.0,\n" - " \"child\": {\n" - " \"foo\": 1,\n" - " \"bar\": \"bar\",\n" - " \"bstruct\": {},\n" - " \"string_values\": [{\"val\": \"value_1\"}, {\"val\": \"value_2\"}]," - " \"baz\": true\n" - " },\n" - " \"children\": [{\n" - " \"foo\": 2,\n" - " \"bar\": \"foobar\",\n" - " \"bstruct\": \"\",\n" - " \"string_values\": [{\"val\": \"value_1\"}]," - " \"baz\": true\n" - " },\n" - " {\n" - " \"foo\": 3,\n" - " \"bar\": \"barbaz\",\n" - " \"baz\": false\n" - " }]\n" - "}\n"; - - std::unique_ptr<Value> value = base::JSONReader::Read(normal_data); - NestedMessage message; - base::JSONValueConverter<NestedMessage> converter; - EXPECT_TRUE(converter.Convert(*value.get(), &message)); - - EXPECT_EQ(1.0, message.foo); - EXPECT_EQ(1, message.child.foo); - EXPECT_EQ("bar", message.child.bar); - EXPECT_TRUE(message.child.baz); - EXPECT_TRUE(message.child.bstruct); - ASSERT_EQ(2U, message.child.string_values.size()); - EXPECT_EQ("value_1", *message.child.string_values[0]); - EXPECT_EQ("value_2", *message.child.string_values[1]); - - EXPECT_EQ(2, static_cast<int>(message.children.size())); - const SimpleMessage* first_child = message.children[0].get(); - ASSERT_TRUE(first_child); - EXPECT_EQ(2, first_child->foo); - EXPECT_EQ("foobar", first_child->bar); - EXPECT_TRUE(first_child->baz); - EXPECT_TRUE(first_child->bstruct); - ASSERT_EQ(1U, first_child->string_values.size()); - EXPECT_EQ("value_1", *first_child->string_values[0]); - - const SimpleMessage* second_child = message.children[1].get(); - ASSERT_TRUE(second_child); - EXPECT_EQ(3, second_child->foo); - EXPECT_EQ("barbaz", second_child->bar); - EXPECT_FALSE(second_child->baz); - EXPECT_FALSE(second_child->bstruct); - EXPECT_EQ(0U, second_child->string_values.size()); -} - -TEST(JSONValueConverterTest, ParseFailures) { - const char normal_data[] = - "{\n" - " \"foo\": 1,\n" - " \"bar\": 2,\n" // "bar" is an integer here. - " \"baz\": true,\n" - " \"ints\": [1, 2]" - "}\n"; - - std::unique_ptr<Value> value = base::JSONReader::Read(normal_data); - SimpleMessage message; - base::JSONValueConverter<SimpleMessage> converter; - EXPECT_FALSE(converter.Convert(*value.get(), &message)); - // Do not check the values below. |message| may be modified during - // Convert() even it fails. -} - -TEST(JSONValueConverterTest, ParseWithMissingFields) { - const char normal_data[] = - "{\n" - " \"foo\": 1,\n" - " \"baz\": true,\n" - " \"ints\": [1, 2]" - "}\n"; - - std::unique_ptr<Value> value = base::JSONReader::Read(normal_data); - SimpleMessage message; - base::JSONValueConverter<SimpleMessage> converter; - // Convert() still succeeds even if the input doesn't have "bar" field. - EXPECT_TRUE(converter.Convert(*value.get(), &message)); - - EXPECT_EQ(1, message.foo); - EXPECT_TRUE(message.baz); - EXPECT_EQ(2, static_cast<int>(message.ints.size())); - EXPECT_EQ(1, *(message.ints[0])); - EXPECT_EQ(2, *(message.ints[1])); -} - -TEST(JSONValueConverterTest, EnumParserFails) { - const char normal_data[] = - "{\n" - " \"foo\": 1,\n" - " \"bar\": \"bar\",\n" - " \"baz\": true,\n" - " \"simple_enum\": \"baz\"," - " \"ints\": [1, 2]" - "}\n"; - - std::unique_ptr<Value> value = base::JSONReader::Read(normal_data); - SimpleMessage message; - base::JSONValueConverter<SimpleMessage> converter; - EXPECT_FALSE(converter.Convert(*value.get(), &message)); - // No check the values as mentioned above. -} - -TEST(JSONValueConverterTest, RepeatedValueErrorInTheMiddle) { - const char normal_data[] = - "{\n" - " \"foo\": 1,\n" - " \"bar\": \"bar\",\n" - " \"baz\": true,\n" - " \"simple_enum\": \"baz\"," - " \"ints\": [1, false]" - "}\n"; - - std::unique_ptr<Value> value = base::JSONReader::Read(normal_data); - SimpleMessage message; - base::JSONValueConverter<SimpleMessage> converter; - EXPECT_FALSE(converter.Convert(*value.get(), &message)); - // No check the values as mentioned above. -} - -} // namespace base
diff --git a/base/json/json_value_serializer_unittest.cc b/base/json/json_value_serializer_unittest.cc deleted file mode 100644 index b358dec..0000000 --- a/base/json/json_value_serializer_unittest.cc +++ /dev/null
@@ -1,487 +0,0 @@ -// 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 <memory> -#include <string> - -#include "base/files/file_util.h" -#include "base/files/scoped_temp_dir.h" -#include "base/json/json_file_value_serializer.h" -#include "base/json/json_reader.h" -#include "base/json/json_string_value_serializer.h" -#include "base/json/json_writer.h" -#include "base/path_service.h" -#include "base/strings/string_piece.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "base/values.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -// Some proper JSON to test with: -const char kProperJSON[] = - "{\n" - " \"compound\": {\n" - " \"a\": 1,\n" - " \"b\": 2\n" - " },\n" - " \"some_String\": \"1337\",\n" - " \"some_int\": 42,\n" - " \"the_list\": [ \"val1\", \"val2\" ]\n" - "}\n"; - -// Some proper JSON with trailing commas: -const char kProperJSONWithCommas[] = - "{\n" - "\t\"some_int\": 42,\n" - "\t\"some_String\": \"1337\",\n" - "\t\"the_list\": [\"val1\", \"val2\", ],\n" - "\t\"compound\": { \"a\": 1, \"b\": 2, },\n" - "}\n"; - -// kProperJSON with a few misc characters at the begin and end. -const char kProperJSONPadded[] = - ")]}'\n" - "{\n" - " \"compound\": {\n" - " \"a\": 1,\n" - " \"b\": 2\n" - " },\n" - " \"some_String\": \"1337\",\n" - " \"some_int\": 42,\n" - " \"the_list\": [ \"val1\", \"val2\" ]\n" - "}\n" - "?!ab\n"; - -const char kWinLineEnds[] = "\r\n"; -const char kLinuxLineEnds[] = "\n"; - -// Verifies the generated JSON against the expected output. -void CheckJSONIsStillTheSame(const Value& value) { - // Serialize back the output. - std::string serialized_json; - JSONStringValueSerializer str_serializer(&serialized_json); - str_serializer.set_pretty_print(true); - ASSERT_TRUE(str_serializer.Serialize(value)); - // Unify line endings between platforms. - ReplaceSubstringsAfterOffset(&serialized_json, 0, - kWinLineEnds, kLinuxLineEnds); - // Now compare the input with the output. - ASSERT_EQ(kProperJSON, serialized_json); -} - -void ValidateJsonList(const std::string& json) { - std::unique_ptr<ListValue> list = ListValue::From(JSONReader::Read(json)); - ASSERT_TRUE(list); - ASSERT_EQ(1U, list->GetSize()); - Value* elt = nullptr; - ASSERT_TRUE(list->Get(0, &elt)); - int value = 0; - ASSERT_TRUE(elt && elt->GetAsInteger(&value)); - ASSERT_EQ(1, value); -} - -// Test proper JSON deserialization from string is working. -TEST(JSONValueDeserializerTest, ReadProperJSONFromString) { - // Try to deserialize it through the serializer. - JSONStringValueDeserializer str_deserializer(kProperJSON); - - int error_code = 0; - std::string error_message; - std::unique_ptr<Value> value = - str_deserializer.Deserialize(&error_code, &error_message); - ASSERT_TRUE(value); - ASSERT_EQ(0, error_code); - ASSERT_TRUE(error_message.empty()); - // Verify if the same JSON is still there. - CheckJSONIsStillTheSame(*value); -} - -// Test proper JSON deserialization from a StringPiece substring. -TEST(JSONValueDeserializerTest, ReadProperJSONFromStringPiece) { - // Create a StringPiece for the substring of kProperJSONPadded that matches - // kProperJSON. - StringPiece proper_json(kProperJSONPadded); - proper_json = proper_json.substr(5, proper_json.length() - 10); - JSONStringValueDeserializer str_deserializer(proper_json); - - int error_code = 0; - std::string error_message; - std::unique_ptr<Value> value = - str_deserializer.Deserialize(&error_code, &error_message); - ASSERT_TRUE(value); - ASSERT_EQ(0, error_code); - ASSERT_TRUE(error_message.empty()); - // Verify if the same JSON is still there. - CheckJSONIsStillTheSame(*value); -} - -// Test that trialing commas are only properly deserialized from string when -// the proper flag for that is set. -TEST(JSONValueDeserializerTest, ReadJSONWithTrailingCommasFromString) { - // Try to deserialize it through the serializer. - JSONStringValueDeserializer str_deserializer(kProperJSONWithCommas); - - int error_code = 0; - std::string error_message; - std::unique_ptr<Value> value = - str_deserializer.Deserialize(&error_code, &error_message); - ASSERT_FALSE(value); - ASSERT_NE(0, error_code); - ASSERT_FALSE(error_message.empty()); - // Repeat with commas allowed. - JSONStringValueDeserializer str_deserializer2(kProperJSONWithCommas, - JSON_ALLOW_TRAILING_COMMAS); - value = str_deserializer2.Deserialize(&error_code, &error_message); - ASSERT_TRUE(value); - ASSERT_EQ(JSONReader::JSON_TRAILING_COMMA, error_code); - // Verify if the same JSON is still there. - CheckJSONIsStillTheSame(*value); -} - -// Test proper JSON deserialization from file is working. -TEST(JSONValueDeserializerTest, ReadProperJSONFromFile) { - ScopedTempDir tempdir; - ASSERT_TRUE(tempdir.CreateUniqueTempDir()); - // Write it down in the file. - FilePath temp_file(tempdir.GetPath().AppendASCII("test.json")); - ASSERT_EQ(static_cast<int>(strlen(kProperJSON)), - WriteFile(temp_file, kProperJSON, strlen(kProperJSON))); - - // Try to deserialize it through the serializer. - JSONFileValueDeserializer file_deserializer(temp_file); - - int error_code = 0; - std::string error_message; - std::unique_ptr<Value> value = - file_deserializer.Deserialize(&error_code, &error_message); - ASSERT_TRUE(value); - ASSERT_EQ(0, error_code); - ASSERT_TRUE(error_message.empty()); - // Verify if the same JSON is still there. - CheckJSONIsStillTheSame(*value); -} - -// Test that trialing commas are only properly deserialized from file when -// the proper flag for that is set. -TEST(JSONValueDeserializerTest, ReadJSONWithCommasFromFile) { - ScopedTempDir tempdir; - ASSERT_TRUE(tempdir.CreateUniqueTempDir()); - // Write it down in the file. - FilePath temp_file(tempdir.GetPath().AppendASCII("test.json")); - ASSERT_EQ(static_cast<int>(strlen(kProperJSONWithCommas)), - WriteFile(temp_file, kProperJSONWithCommas, - strlen(kProperJSONWithCommas))); - - // Try to deserialize it through the serializer. - JSONFileValueDeserializer file_deserializer(temp_file); - // This must fail without the proper flag. - int error_code = 0; - std::string error_message; - std::unique_ptr<Value> value = - file_deserializer.Deserialize(&error_code, &error_message); - ASSERT_FALSE(value); - ASSERT_NE(0, error_code); - ASSERT_FALSE(error_message.empty()); - // Repeat with commas allowed. - JSONFileValueDeserializer file_deserializer2(temp_file, - JSON_ALLOW_TRAILING_COMMAS); - value = file_deserializer2.Deserialize(&error_code, &error_message); - ASSERT_TRUE(value); - ASSERT_EQ(JSONReader::JSON_TRAILING_COMMA, error_code); - // Verify if the same JSON is still there. - CheckJSONIsStillTheSame(*value); -} - -TEST(JSONValueDeserializerTest, AllowTrailingComma) { - static const char kTestWithCommas[] = "{\"key\": [true,],}"; - static const char kTestNoCommas[] = "{\"key\": [true]}"; - - JSONStringValueDeserializer deserializer(kTestWithCommas, - JSON_ALLOW_TRAILING_COMMAS); - JSONStringValueDeserializer deserializer_expected(kTestNoCommas); - std::unique_ptr<Value> root = deserializer.Deserialize(nullptr, nullptr); - ASSERT_TRUE(root); - std::unique_ptr<Value> root_expected; - root_expected = deserializer_expected.Deserialize(nullptr, nullptr); - ASSERT_TRUE(root_expected); - ASSERT_TRUE(root->Equals(root_expected.get())); -} - -TEST(JSONValueSerializerTest, Roundtrip) { - static const char kOriginalSerialization[] = - "{\"bool\":true,\"double\":3.14,\"int\":42,\"list\":[1,2],\"null\":null}"; - JSONStringValueDeserializer deserializer(kOriginalSerialization); - std::unique_ptr<DictionaryValue> root_dict = - DictionaryValue::From(deserializer.Deserialize(nullptr, nullptr)); - ASSERT_TRUE(root_dict); - - Value* null_value = nullptr; - ASSERT_TRUE(root_dict->Get("null", &null_value)); - ASSERT_TRUE(null_value); - ASSERT_TRUE(null_value->is_none()); - - bool bool_value = false; - ASSERT_TRUE(root_dict->GetBoolean("bool", &bool_value)); - ASSERT_TRUE(bool_value); - - int int_value = 0; - ASSERT_TRUE(root_dict->GetInteger("int", &int_value)); - ASSERT_EQ(42, int_value); - - double double_value = 0.0; - ASSERT_TRUE(root_dict->GetDouble("double", &double_value)); - ASSERT_DOUBLE_EQ(3.14, double_value); - - std::string test_serialization; - JSONStringValueSerializer mutable_serializer(&test_serialization); - ASSERT_TRUE(mutable_serializer.Serialize(*root_dict)); - ASSERT_EQ(kOriginalSerialization, test_serialization); - - mutable_serializer.set_pretty_print(true); - ASSERT_TRUE(mutable_serializer.Serialize(*root_dict)); - // JSON output uses a different newline style on Windows than on other - // platforms. -#if defined(OS_WIN) -#define JSON_NEWLINE "\r\n" -#else -#define JSON_NEWLINE "\n" -#endif - const std::string pretty_serialization = - "{" JSON_NEWLINE - " \"bool\": true," JSON_NEWLINE - " \"double\": 3.14," JSON_NEWLINE - " \"int\": 42," JSON_NEWLINE - " \"list\": [ 1, 2 ]," JSON_NEWLINE - " \"null\": null" JSON_NEWLINE - "}" JSON_NEWLINE; -#undef JSON_NEWLINE - ASSERT_EQ(pretty_serialization, test_serialization); -} - -TEST(JSONValueSerializerTest, StringEscape) { - string16 all_chars; - for (int i = 1; i < 256; ++i) { - all_chars += static_cast<char16>(i); - } - // Generated in in Firefox using the following js (with an extra backslash for - // double quote): - // var s = ''; - // for (var i = 1; i < 256; ++i) { s += String.fromCharCode(i); } - // uneval(s).replace(/\\/g, "\\\\"); - std::string all_chars_expected = - "\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000B\\f\\r" - "\\u000E\\u000F\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017" - "\\u0018\\u0019\\u001A\\u001B\\u001C\\u001D\\u001E\\u001F !\\\"#$%&'()*+," - "-./0123456789:;\\u003C=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcde" - "fghijklmnopqrstuvwxyz{|}~\x7F\xC2\x80\xC2\x81\xC2\x82\xC2\x83\xC2\x84" - "\xC2\x85\xC2\x86\xC2\x87\xC2\x88\xC2\x89\xC2\x8A\xC2\x8B\xC2\x8C\xC2\x8D" - "\xC2\x8E\xC2\x8F\xC2\x90\xC2\x91\xC2\x92\xC2\x93\xC2\x94\xC2\x95\xC2\x96" - "\xC2\x97\xC2\x98\xC2\x99\xC2\x9A\xC2\x9B\xC2\x9C\xC2\x9D\xC2\x9E\xC2\x9F" - "\xC2\xA0\xC2\xA1\xC2\xA2\xC2\xA3\xC2\xA4\xC2\xA5\xC2\xA6\xC2\xA7\xC2\xA8" - "\xC2\xA9\xC2\xAA\xC2\xAB\xC2\xAC\xC2\xAD\xC2\xAE\xC2\xAF\xC2\xB0\xC2\xB1" - "\xC2\xB2\xC2\xB3\xC2\xB4\xC2\xB5\xC2\xB6\xC2\xB7\xC2\xB8\xC2\xB9\xC2\xBA" - "\xC2\xBB\xC2\xBC\xC2\xBD\xC2\xBE\xC2\xBF\xC3\x80\xC3\x81\xC3\x82\xC3\x83" - "\xC3\x84\xC3\x85\xC3\x86\xC3\x87\xC3\x88\xC3\x89\xC3\x8A\xC3\x8B\xC3\x8C" - "\xC3\x8D\xC3\x8E\xC3\x8F\xC3\x90\xC3\x91\xC3\x92\xC3\x93\xC3\x94\xC3\x95" - "\xC3\x96\xC3\x97\xC3\x98\xC3\x99\xC3\x9A\xC3\x9B\xC3\x9C\xC3\x9D\xC3\x9E" - "\xC3\x9F\xC3\xA0\xC3\xA1\xC3\xA2\xC3\xA3\xC3\xA4\xC3\xA5\xC3\xA6\xC3\xA7" - "\xC3\xA8\xC3\xA9\xC3\xAA\xC3\xAB\xC3\xAC\xC3\xAD\xC3\xAE\xC3\xAF\xC3\xB0" - "\xC3\xB1\xC3\xB2\xC3\xB3\xC3\xB4\xC3\xB5\xC3\xB6\xC3\xB7\xC3\xB8\xC3\xB9" - "\xC3\xBA\xC3\xBB\xC3\xBC\xC3\xBD\xC3\xBE\xC3\xBF"; - - std::string expected_output = "{\"all_chars\":\"" + all_chars_expected + - "\"}"; - // Test JSONWriter interface - std::string output_js; - DictionaryValue valueRoot; - valueRoot.SetString("all_chars", all_chars); - JSONWriter::Write(valueRoot, &output_js); - ASSERT_EQ(expected_output, output_js); - - // Test JSONValueSerializer interface (uses JSONWriter). - JSONStringValueSerializer serializer(&output_js); - ASSERT_TRUE(serializer.Serialize(valueRoot)); - ASSERT_EQ(expected_output, output_js); -} - -TEST(JSONValueSerializerTest, UnicodeStrings) { - // unicode string json -> escaped ascii text - DictionaryValue root; - string16 test(WideToUTF16(L"\x7F51\x9875")); - root.SetString("web", test); - - static const char kExpected[] = "{\"web\":\"\xE7\xBD\x91\xE9\xA1\xB5\"}"; - - std::string actual; - JSONStringValueSerializer serializer(&actual); - ASSERT_TRUE(serializer.Serialize(root)); - ASSERT_EQ(kExpected, actual); - - // escaped ascii text -> json - JSONStringValueDeserializer deserializer(kExpected); - std::unique_ptr<Value> deserial_root = - deserializer.Deserialize(nullptr, nullptr); - ASSERT_TRUE(deserial_root); - DictionaryValue* dict_root = - static_cast<DictionaryValue*>(deserial_root.get()); - string16 web_value; - ASSERT_TRUE(dict_root->GetString("web", &web_value)); - ASSERT_EQ(test, web_value); -} - -TEST(JSONValueSerializerTest, HexStrings) { - // hex string json -> escaped ascii text - DictionaryValue root; - string16 test(WideToUTF16(L"\x01\x02")); - root.SetString("test", test); - - static const char kExpected[] = "{\"test\":\"\\u0001\\u0002\"}"; - - std::string actual; - JSONStringValueSerializer serializer(&actual); - ASSERT_TRUE(serializer.Serialize(root)); - ASSERT_EQ(kExpected, actual); - - // escaped ascii text -> json - JSONStringValueDeserializer deserializer(kExpected); - std::unique_ptr<Value> deserial_root = - deserializer.Deserialize(nullptr, nullptr); - ASSERT_TRUE(deserial_root); - DictionaryValue* dict_root = - static_cast<DictionaryValue*>(deserial_root.get()); - string16 test_value; - ASSERT_TRUE(dict_root->GetString("test", &test_value)); - ASSERT_EQ(test, test_value); - - // Test converting escaped regular chars - static const char kEscapedChars[] = "{\"test\":\"\\u0067\\u006f\"}"; - JSONStringValueDeserializer deserializer2(kEscapedChars); - deserial_root = deserializer2.Deserialize(nullptr, nullptr); - ASSERT_TRUE(deserial_root); - dict_root = static_cast<DictionaryValue*>(deserial_root.get()); - ASSERT_TRUE(dict_root->GetString("test", &test_value)); - ASSERT_EQ(ASCIIToUTF16("go"), test_value); -} - -TEST(JSONValueSerializerTest, JSONReaderComments) { - ValidateJsonList("[ // 2, 3, ignore me ] \n1 ]"); - ValidateJsonList("[ /* 2, \n3, ignore me ]*/ \n1 ]"); - ValidateJsonList("//header\n[ // 2, \n// 3, \n1 ]// footer"); - ValidateJsonList("/*\n[ // 2, \n// 3, \n1 ]*/[1]"); - ValidateJsonList("[ 1 /* one */ ] /* end */"); - ValidateJsonList("[ 1 //// ,2\r\n ]"); - - // It's ok to have a comment in a string. - std::unique_ptr<ListValue> list = - ListValue::From(JSONReader::Read("[\"// ok\\n /* foo */ \"]")); - ASSERT_TRUE(list); - ASSERT_EQ(1U, list->GetSize()); - Value* elt = nullptr; - ASSERT_TRUE(list->Get(0, &elt)); - std::string value; - ASSERT_TRUE(elt && elt->GetAsString(&value)); - ASSERT_EQ("// ok\n /* foo */ ", value); - - // You can't nest comments. - ASSERT_FALSE(JSONReader::Read("/* /* inner */ outer */ [ 1 ]")); - - // Not a open comment token. - ASSERT_FALSE(JSONReader::Read("/ * * / [1]")); -} - -class JSONFileValueSerializerTest : public testing::Test { - protected: - void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); } - - ScopedTempDir temp_dir_; -}; - -TEST_F(JSONFileValueSerializerTest, Roundtrip) { - FilePath original_file_path; - ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &original_file_path)); - original_file_path = original_file_path.AppendASCII("serializer_test.json"); - - ASSERT_TRUE(PathExists(original_file_path)); - - JSONFileValueDeserializer deserializer(original_file_path); - std::unique_ptr<DictionaryValue> root_dict = - DictionaryValue::From(deserializer.Deserialize(nullptr, nullptr)); - ASSERT_TRUE(root_dict); - - Value* null_value = nullptr; - ASSERT_TRUE(root_dict->Get("null", &null_value)); - ASSERT_TRUE(null_value); - ASSERT_TRUE(null_value->is_none()); - - bool bool_value = false; - ASSERT_TRUE(root_dict->GetBoolean("bool", &bool_value)); - ASSERT_TRUE(bool_value); - - int int_value = 0; - ASSERT_TRUE(root_dict->GetInteger("int", &int_value)); - ASSERT_EQ(42, int_value); - - std::string string_value; - ASSERT_TRUE(root_dict->GetString("string", &string_value)); - ASSERT_EQ("hello", string_value); - - // Now try writing. - const FilePath written_file_path = - temp_dir_.GetPath().AppendASCII("test_output.js"); - - ASSERT_FALSE(PathExists(written_file_path)); - JSONFileValueSerializer serializer(written_file_path); - ASSERT_TRUE(serializer.Serialize(*root_dict)); - ASSERT_TRUE(PathExists(written_file_path)); - - // Now compare file contents. - EXPECT_TRUE(TextContentsEqual(original_file_path, written_file_path)); - EXPECT_TRUE(DeleteFile(written_file_path, false)); -} - -TEST_F(JSONFileValueSerializerTest, RoundtripNested) { - FilePath original_file_path; - ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &original_file_path)); - original_file_path = - original_file_path.AppendASCII("serializer_nested_test.json"); - - ASSERT_TRUE(PathExists(original_file_path)); - - JSONFileValueDeserializer deserializer(original_file_path); - std::unique_ptr<Value> root = deserializer.Deserialize(nullptr, nullptr); - ASSERT_TRUE(root); - - // Now try writing. - FilePath written_file_path = - temp_dir_.GetPath().AppendASCII("test_output.json"); - - ASSERT_FALSE(PathExists(written_file_path)); - JSONFileValueSerializer serializer(written_file_path); - ASSERT_TRUE(serializer.Serialize(*root)); - ASSERT_TRUE(PathExists(written_file_path)); - - // Now compare file contents. - EXPECT_TRUE(TextContentsEqual(original_file_path, written_file_path)); - EXPECT_TRUE(DeleteFile(written_file_path, false)); -} - -TEST_F(JSONFileValueSerializerTest, NoWhitespace) { - FilePath source_file_path; - ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &source_file_path)); - source_file_path = - source_file_path.AppendASCII("serializer_test_nowhitespace.json"); - ASSERT_TRUE(PathExists(source_file_path)); - JSONFileValueDeserializer deserializer(source_file_path); - std::unique_ptr<Value> root = deserializer.Deserialize(nullptr, nullptr); - ASSERT_TRUE(root); -} - -} // namespace - -} // namespace base
diff --git a/base/json/json_writer_unittest.cc b/base/json/json_writer_unittest.cc deleted file mode 100644 index b90c3ea..0000000 --- a/base/json/json_writer_unittest.cc +++ /dev/null
@@ -1,154 +0,0 @@ -// 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/json/json_writer.h" - -#include "base/memory/ptr_util.h" -#include "base/values.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(JSONWriterTest, BasicTypes) { - std::string output_js; - - // Test null. - EXPECT_TRUE(JSONWriter::Write(Value(), &output_js)); - EXPECT_EQ("null", output_js); - - // Test empty dict. - EXPECT_TRUE(JSONWriter::Write(DictionaryValue(), &output_js)); - EXPECT_EQ("{}", output_js); - - // Test empty list. - EXPECT_TRUE(JSONWriter::Write(ListValue(), &output_js)); - EXPECT_EQ("[]", output_js); - - // Test integer values. - EXPECT_TRUE(JSONWriter::Write(Value(42), &output_js)); - EXPECT_EQ("42", output_js); - - // Test boolean values. - EXPECT_TRUE(JSONWriter::Write(Value(true), &output_js)); - EXPECT_EQ("true", output_js); - - // Test Real values should always have a decimal or an 'e'. - EXPECT_TRUE(JSONWriter::Write(Value(1.0), &output_js)); - EXPECT_EQ("1.0", output_js); - - // Test Real values in the the range (-1, 1) must have leading zeros - EXPECT_TRUE(JSONWriter::Write(Value(0.2), &output_js)); - EXPECT_EQ("0.2", output_js); - - // Test Real values in the the range (-1, 1) must have leading zeros - EXPECT_TRUE(JSONWriter::Write(Value(-0.8), &output_js)); - EXPECT_EQ("-0.8", output_js); - - // Test String values. - EXPECT_TRUE(JSONWriter::Write(Value("foo"), &output_js)); - EXPECT_EQ("\"foo\"", output_js); -} - -TEST(JSONWriterTest, NestedTypes) { - std::string output_js; - - // Writer unittests like empty list/dict nesting, - // list list nesting, etc. - DictionaryValue root_dict; - std::unique_ptr<ListValue> list(new ListValue()); - std::unique_ptr<DictionaryValue> inner_dict(new DictionaryValue()); - inner_dict->SetInteger("inner int", 10); - list->Append(std::move(inner_dict)); - list->Append(std::make_unique<ListValue>()); - list->AppendBoolean(true); - root_dict.Set("list", std::move(list)); - - // Test the pretty-printer. - EXPECT_TRUE(JSONWriter::Write(root_dict, &output_js)); - EXPECT_EQ("{\"list\":[{\"inner int\":10},[],true]}", output_js); - EXPECT_TRUE(JSONWriter::WriteWithOptions( - root_dict, JSONWriter::OPTIONS_PRETTY_PRINT, &output_js)); - - // The pretty-printer uses a different newline style on Windows than on - // other platforms. -#if defined(OS_WIN) -#define JSON_NEWLINE "\r\n" -#else -#define JSON_NEWLINE "\n" -#endif - EXPECT_EQ("{" JSON_NEWLINE - " \"list\": [ {" JSON_NEWLINE - " \"inner int\": 10" JSON_NEWLINE - " }, [ ], true ]" JSON_NEWLINE - "}" JSON_NEWLINE, - output_js); -#undef JSON_NEWLINE -} - -TEST(JSONWriterTest, KeysWithPeriods) { - std::string output_js; - - DictionaryValue period_dict; - period_dict.SetKey("a.b", base::Value(3)); - period_dict.SetKey("c", base::Value(2)); - std::unique_ptr<DictionaryValue> period_dict2(new DictionaryValue()); - period_dict2->SetKey("g.h.i.j", base::Value(1)); - period_dict.SetWithoutPathExpansion("d.e.f", std::move(period_dict2)); - EXPECT_TRUE(JSONWriter::Write(period_dict, &output_js)); - EXPECT_EQ("{\"a.b\":3,\"c\":2,\"d.e.f\":{\"g.h.i.j\":1}}", output_js); - - DictionaryValue period_dict3; - period_dict3.SetInteger("a.b", 2); - period_dict3.SetKey("a.b", base::Value(1)); - EXPECT_TRUE(JSONWriter::Write(period_dict3, &output_js)); - EXPECT_EQ("{\"a\":{\"b\":2},\"a.b\":1}", output_js); -} - -TEST(JSONWriterTest, BinaryValues) { - std::string output_js; - - // Binary values should return errors unless suppressed via the - // OPTIONS_OMIT_BINARY_VALUES flag. - std::unique_ptr<Value> root(Value::CreateWithCopiedBuffer("asdf", 4)); - EXPECT_FALSE(JSONWriter::Write(*root, &output_js)); - EXPECT_TRUE(JSONWriter::WriteWithOptions( - *root, JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js)); - EXPECT_TRUE(output_js.empty()); - - ListValue binary_list; - binary_list.Append(Value::CreateWithCopiedBuffer("asdf", 4)); - binary_list.Append(std::make_unique<Value>(5)); - binary_list.Append(Value::CreateWithCopiedBuffer("asdf", 4)); - binary_list.Append(std::make_unique<Value>(2)); - binary_list.Append(Value::CreateWithCopiedBuffer("asdf", 4)); - EXPECT_FALSE(JSONWriter::Write(binary_list, &output_js)); - EXPECT_TRUE(JSONWriter::WriteWithOptions( - binary_list, JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js)); - EXPECT_EQ("[5,2]", output_js); - - DictionaryValue binary_dict; - binary_dict.Set("a", Value::CreateWithCopiedBuffer("asdf", 4)); - binary_dict.SetInteger("b", 5); - binary_dict.Set("c", Value::CreateWithCopiedBuffer("asdf", 4)); - binary_dict.SetInteger("d", 2); - binary_dict.Set("e", Value::CreateWithCopiedBuffer("asdf", 4)); - EXPECT_FALSE(JSONWriter::Write(binary_dict, &output_js)); - EXPECT_TRUE(JSONWriter::WriteWithOptions( - binary_dict, JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js)); - EXPECT_EQ("{\"b\":5,\"d\":2}", output_js); -} - -TEST(JSONWriterTest, DoublesAsInts) { - std::string output_js; - - // Test allowing a double with no fractional part to be written as an integer. - Value double_value(1e10); - EXPECT_TRUE(JSONWriter::WriteWithOptions( - double_value, JSONWriter::OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION, - &output_js)); - EXPECT_EQ("10000000000", output_js); -} - -} // namespace base
diff --git a/base/json/string_escape_unittest.cc b/base/json/string_escape_unittest.cc deleted file mode 100644 index 1e962c6..0000000 --- a/base/json/string_escape_unittest.cc +++ /dev/null
@@ -1,189 +0,0 @@ -// 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/json/string_escape.h" - -#include <stddef.h> - -#include "base/macros.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(JSONStringEscapeTest, EscapeUTF8) { - const struct { - const char* to_escape; - const char* escaped; - } cases[] = { - {"\b\001aZ\"\\wee", "\\b\\u0001aZ\\\"\\\\wee"}, - {"a\b\f\n\r\t\v\1\\.\"z", "a\\b\\f\\n\\r\\t\\u000B\\u0001\\\\.\\\"z"}, - {"b\x0f\x7f\xf0\xff!", // \xf0\xff is not a valid UTF-8 unit. - "b\\u000F\x7F\xEF\xBF\xBD\xEF\xBF\xBD!"}, - {"c<>d", "c\\u003C>d"}, - {"Hello\xe2\x80\xa8world", "Hello\\u2028world"}, - {"\xe2\x80\xa9purple", "\\u2029purple"}, - {"\xF3\xBF\xBF\xBF", "\xEF\xBF\xBD"}, - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - const char* in_ptr = cases[i].to_escape; - std::string in_str = in_ptr; - - std::string out; - EscapeJSONString(in_ptr, false, &out); - EXPECT_EQ(std::string(cases[i].escaped), out); - EXPECT_TRUE(IsStringUTF8(out)); - - out.erase(); - bool convert_ok = EscapeJSONString(in_str, false, &out); - EXPECT_EQ(std::string(cases[i].escaped), out); - EXPECT_TRUE(IsStringUTF8(out)); - - if (convert_ok) { - std::string fooout = GetQuotedJSONString(in_str); - EXPECT_EQ("\"" + std::string(cases[i].escaped) + "\"", fooout); - EXPECT_TRUE(IsStringUTF8(out)); - } - } - - std::string in = cases[0].to_escape; - std::string out; - EscapeJSONString(in, false, &out); - EXPECT_TRUE(IsStringUTF8(out)); - - // test quoting - std::string out_quoted; - EscapeJSONString(in, true, &out_quoted); - EXPECT_EQ(out.length() + 2, out_quoted.length()); - EXPECT_EQ(out_quoted.find(out), 1U); - EXPECT_TRUE(IsStringUTF8(out_quoted)); - - // now try with a NULL in the string - std::string null_prepend = "test"; - null_prepend.push_back(0); - in = null_prepend + in; - std::string expected = "test\\u0000"; - expected += cases[0].escaped; - out.clear(); - EscapeJSONString(in, false, &out); - EXPECT_EQ(expected, out); - EXPECT_TRUE(IsStringUTF8(out)); -} - -TEST(JSONStringEscapeTest, EscapeUTF16) { - const struct { - const wchar_t* to_escape; - const char* escaped; - } cases[] = { - {L"b\uffb1\u00ff", "b\xEF\xBE\xB1\xC3\xBF"}, - {L"\b\001aZ\"\\wee", "\\b\\u0001aZ\\\"\\\\wee"}, - {L"a\b\f\n\r\t\v\1\\.\"z", - "a\\b\\f\\n\\r\\t\\u000B\\u0001\\\\.\\\"z"}, - {L"b\x0f\x7f\xf0\xff!", "b\\u000F\x7F\xC3\xB0\xC3\xBF!"}, - {L"c<>d", "c\\u003C>d"}, - {L"Hello\u2028world", "Hello\\u2028world"}, - {L"\u2029purple", "\\u2029purple"}, - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - string16 in = WideToUTF16(cases[i].to_escape); - - std::string out; - EscapeJSONString(in, false, &out); - EXPECT_EQ(std::string(cases[i].escaped), out); - EXPECT_TRUE(IsStringUTF8(out)); - - out = GetQuotedJSONString(in); - EXPECT_EQ("\"" + std::string(cases[i].escaped) + "\"", out); - EXPECT_TRUE(IsStringUTF8(out)); - } - - string16 in = WideToUTF16(cases[0].to_escape); - std::string out; - EscapeJSONString(in, false, &out); - EXPECT_TRUE(IsStringUTF8(out)); - - // test quoting - std::string out_quoted; - EscapeJSONString(in, true, &out_quoted); - EXPECT_EQ(out.length() + 2, out_quoted.length()); - EXPECT_EQ(out_quoted.find(out), 1U); - EXPECT_TRUE(IsStringUTF8(out)); - - // now try with a NULL in the string - string16 null_prepend = WideToUTF16(L"test"); - null_prepend.push_back(0); - in = null_prepend + in; - std::string expected = "test\\u0000"; - expected += cases[0].escaped; - out.clear(); - EscapeJSONString(in, false, &out); - EXPECT_EQ(expected, out); - EXPECT_TRUE(IsStringUTF8(out)); -} - -TEST(JSONStringEscapeTest, EscapeUTF16OutsideBMP) { - { - // {a, U+10300, !}, SMP. - string16 test; - test.push_back('a'); - test.push_back(0xD800); - test.push_back(0xDF00); - test.push_back('!'); - std::string actual; - EXPECT_TRUE(EscapeJSONString(test, false, &actual)); - EXPECT_EQ("a\xF0\x90\x8C\x80!", actual); - } - { - // {U+20021, U+2002B}, SIP. - string16 test; - test.push_back(0xD840); - test.push_back(0xDC21); - test.push_back(0xD840); - test.push_back(0xDC2B); - std::string actual; - EXPECT_TRUE(EscapeJSONString(test, false, &actual)); - EXPECT_EQ("\xF0\xA0\x80\xA1\xF0\xA0\x80\xAB", actual); - } - { - // {?, U+D800, @}, lone surrogate. - string16 test; - test.push_back('?'); - test.push_back(0xD800); - test.push_back('@'); - std::string actual; - EXPECT_FALSE(EscapeJSONString(test, false, &actual)); - EXPECT_EQ("?\xEF\xBF\xBD@", actual); - } -} - -TEST(JSONStringEscapeTest, EscapeBytes) { - const struct { - const char* to_escape; - const char* escaped; - } cases[] = { - {"b\x0f\x7f\xf0\xff!", "b\\u000F\\u007F\\u00F0\\u00FF!"}, - {"\xe5\xc4\x4f\x05\xb6\xfd", "\\u00E5\\u00C4O\\u0005\\u00B6\\u00FD"}, - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - std::string in = std::string(cases[i].to_escape); - EXPECT_FALSE(IsStringUTF8(in)); - - EXPECT_EQ(std::string(cases[i].escaped), - EscapeBytesAsInvalidJSONString(in, false)); - EXPECT_EQ("\"" + std::string(cases[i].escaped) + "\"", - EscapeBytesAsInvalidJSONString(in, true)); - } - - const char kEmbedNull[] = { '\xab', '\x39', '\0', '\x9f', '\xab' }; - std::string in(kEmbedNull, arraysize(kEmbedNull)); - EXPECT_FALSE(IsStringUTF8(in)); - EXPECT_EQ(std::string("\\u00AB9\\u0000\\u009F\\u00AB"), - EscapeBytesAsInvalidJSONString(in, false)); -} - -} // namespace base
diff --git a/base/lazy_instance_unittest.cc b/base/lazy_instance_unittest.cc deleted file mode 100644 index 242e8b5..0000000 --- a/base/lazy_instance_unittest.cc +++ /dev/null
@@ -1,322 +0,0 @@ -// 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 <stddef.h> - -#include <memory> -#include <vector> - -#include "base/at_exit.h" -#include "base/atomic_sequence_num.h" -#include "base/atomicops.h" -#include "base/barrier_closure.h" -#include "base/bind.h" -#include "base/lazy_instance.h" -#include "base/sys_info.h" -#include "base/threading/platform_thread.h" -#include "base/threading/simple_thread.h" -#include "base/time/time.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -base::AtomicSequenceNumber constructed_seq_; -base::AtomicSequenceNumber destructed_seq_; - -class ConstructAndDestructLogger { - public: - ConstructAndDestructLogger() { - constructed_seq_.GetNext(); - } - ~ConstructAndDestructLogger() { - destructed_seq_.GetNext(); - } - - private: - DISALLOW_COPY_AND_ASSIGN(ConstructAndDestructLogger); -}; - -class SlowConstructor { - public: - SlowConstructor() : some_int_(0) { - // Sleep for 1 second to try to cause a race. - base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1)); - ++constructed; - some_int_ = 12; - } - int some_int() const { return some_int_; } - - static int constructed; - private: - int some_int_; - - DISALLOW_COPY_AND_ASSIGN(SlowConstructor); -}; - -// static -int SlowConstructor::constructed = 0; - -class SlowDelegate : public base::DelegateSimpleThread::Delegate { - public: - explicit SlowDelegate( - base::LazyInstance<SlowConstructor>::DestructorAtExit* lazy) - : lazy_(lazy) {} - - void Run() override { - EXPECT_EQ(12, lazy_->Get().some_int()); - EXPECT_EQ(12, lazy_->Pointer()->some_int()); - } - - private: - base::LazyInstance<SlowConstructor>::DestructorAtExit* lazy_; - - DISALLOW_COPY_AND_ASSIGN(SlowDelegate); -}; - -} // namespace - -base::LazyInstance<ConstructAndDestructLogger>::DestructorAtExit lazy_logger = - LAZY_INSTANCE_INITIALIZER; - -TEST(LazyInstanceTest, Basic) { - { - base::ShadowingAtExitManager shadow; - - EXPECT_FALSE(lazy_logger.IsCreated()); - EXPECT_EQ(0, constructed_seq_.GetNext()); - EXPECT_EQ(0, destructed_seq_.GetNext()); - - lazy_logger.Get(); - EXPECT_TRUE(lazy_logger.IsCreated()); - EXPECT_EQ(2, constructed_seq_.GetNext()); - EXPECT_EQ(1, destructed_seq_.GetNext()); - - lazy_logger.Pointer(); - EXPECT_TRUE(lazy_logger.IsCreated()); - EXPECT_EQ(3, constructed_seq_.GetNext()); - EXPECT_EQ(2, destructed_seq_.GetNext()); - } - EXPECT_FALSE(lazy_logger.IsCreated()); - EXPECT_EQ(4, constructed_seq_.GetNext()); - EXPECT_EQ(4, destructed_seq_.GetNext()); -} - -base::LazyInstance<SlowConstructor>::DestructorAtExit lazy_slow = - LAZY_INSTANCE_INITIALIZER; - -TEST(LazyInstanceTest, ConstructorThreadSafety) { - { - base::ShadowingAtExitManager shadow; - - SlowDelegate delegate(&lazy_slow); - EXPECT_EQ(0, SlowConstructor::constructed); - - base::DelegateSimpleThreadPool pool("lazy_instance_cons", 5); - pool.AddWork(&delegate, 20); - EXPECT_EQ(0, SlowConstructor::constructed); - - pool.Start(); - pool.JoinAll(); - EXPECT_EQ(1, SlowConstructor::constructed); - } -} - -namespace { - -// DeleteLogger is an object which sets a flag when it's destroyed. -// It accepts a bool* and sets the bool to true when the dtor runs. -class DeleteLogger { - public: - DeleteLogger() : deleted_(nullptr) {} - ~DeleteLogger() { *deleted_ = true; } - - void SetDeletedPtr(bool* deleted) { - deleted_ = deleted; - } - - private: - bool* deleted_; -}; - -} // anonymous namespace - -TEST(LazyInstanceTest, LeakyLazyInstance) { - // Check that using a plain LazyInstance causes the dtor to run - // when the AtExitManager finishes. - bool deleted1 = false; - { - base::ShadowingAtExitManager shadow; - static base::LazyInstance<DeleteLogger>::DestructorAtExit test = - LAZY_INSTANCE_INITIALIZER; - test.Get().SetDeletedPtr(&deleted1); - } - EXPECT_TRUE(deleted1); - - // Check that using a *leaky* LazyInstance makes the dtor not run - // when the AtExitManager finishes. - bool deleted2 = false; - { - base::ShadowingAtExitManager shadow; - static base::LazyInstance<DeleteLogger>::Leaky - test = LAZY_INSTANCE_INITIALIZER; - test.Get().SetDeletedPtr(&deleted2); - } - EXPECT_FALSE(deleted2); -} - -namespace { - -template <size_t alignment> -class AlignedData { - public: - AlignedData() = default; - ~AlignedData() = default; - alignas(alignment) char data_[alignment]; -}; - -} // namespace - -#define EXPECT_ALIGNED(ptr, align) \ - EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1)) - -TEST(LazyInstanceTest, Alignment) { - using base::LazyInstance; - - // Create some static instances with increasing sizes and alignment - // requirements. By ordering this way, the linker will need to do some work to - // ensure proper alignment of the static data. - static LazyInstance<AlignedData<4>>::DestructorAtExit align4 = - LAZY_INSTANCE_INITIALIZER; - static LazyInstance<AlignedData<32>>::DestructorAtExit align32 = - LAZY_INSTANCE_INITIALIZER; - static LazyInstance<AlignedData<4096>>::DestructorAtExit align4096 = - LAZY_INSTANCE_INITIALIZER; - - EXPECT_ALIGNED(align4.Pointer(), 4); - EXPECT_ALIGNED(align32.Pointer(), 32); - EXPECT_ALIGNED(align4096.Pointer(), 4096); -} - -namespace { - -// A class whose constructor busy-loops until it is told to complete -// construction. -class BlockingConstructor { - public: - BlockingConstructor() { - EXPECT_FALSE(WasConstructorCalled()); - base::subtle::NoBarrier_Store(&constructor_called_, 1); - EXPECT_TRUE(WasConstructorCalled()); - while (!base::subtle::NoBarrier_Load(&complete_construction_)) - base::PlatformThread::YieldCurrentThread(); - done_construction_ = true; - } - - ~BlockingConstructor() { - // Restore static state for the next test. - base::subtle::NoBarrier_Store(&constructor_called_, 0); - base::subtle::NoBarrier_Store(&complete_construction_, 0); - } - - // Returns true if BlockingConstructor() was entered. - static bool WasConstructorCalled() { - return base::subtle::NoBarrier_Load(&constructor_called_); - } - - // Instructs BlockingConstructor() that it may now unblock its construction. - static void CompleteConstructionNow() { - base::subtle::NoBarrier_Store(&complete_construction_, 1); - } - - bool done_construction() { return done_construction_; } - - private: - // Use Atomic32 instead of AtomicFlag for them to be trivially initialized. - static base::subtle::Atomic32 constructor_called_; - static base::subtle::Atomic32 complete_construction_; - - bool done_construction_ = false; - - DISALLOW_COPY_AND_ASSIGN(BlockingConstructor); -}; - -// A SimpleThread running at |thread_priority| which invokes |before_get| -// (optional) and then invokes Get() on the LazyInstance it's assigned. -class BlockingConstructorThread : public base::SimpleThread { - public: - BlockingConstructorThread( - base::ThreadPriority thread_priority, - base::LazyInstance<BlockingConstructor>::DestructorAtExit* lazy, - base::OnceClosure before_get) - : SimpleThread("BlockingConstructorThread", Options(thread_priority)), - lazy_(lazy), - before_get_(std::move(before_get)) {} - - void Run() override { - if (before_get_) - std::move(before_get_).Run(); - EXPECT_TRUE(lazy_->Get().done_construction()); - } - - private: - base::LazyInstance<BlockingConstructor>::DestructorAtExit* lazy_; - base::OnceClosure before_get_; - - DISALLOW_COPY_AND_ASSIGN(BlockingConstructorThread); -}; - -// static -base::subtle::Atomic32 BlockingConstructor::constructor_called_ = 0; -// static -base::subtle::Atomic32 BlockingConstructor::complete_construction_ = 0; - -base::LazyInstance<BlockingConstructor>::DestructorAtExit lazy_blocking = - LAZY_INSTANCE_INITIALIZER; - -} // namespace - -// Tests that if the thread assigned to construct the LazyInstance runs at -// background priority : the foreground threads will yield to it enough for it -// to eventually complete construction. -// This is a regression test for https://crbug.com/797129. -TEST(LazyInstanceTest, PriorityInversionAtInitializationResolves) { - base::TimeTicks test_begin = base::TimeTicks::Now(); - - // Construct BlockingConstructor from a background thread. - BlockingConstructorThread background_getter( - base::ThreadPriority::BACKGROUND, &lazy_blocking, base::OnceClosure()); - background_getter.Start(); - - while (!BlockingConstructor::WasConstructorCalled()) - base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1)); - - // Spin 4 foreground thread per core contending to get the already under - // construction LazyInstance. When they are all running and poking at it : - // allow the background thread to complete its work. - const int kNumForegroundThreads = 4 * base::SysInfo::NumberOfProcessors(); - std::vector<std::unique_ptr<base::SimpleThread>> foreground_threads; - base::RepeatingClosure foreground_thread_ready_callback = - base::BarrierClosure( - kNumForegroundThreads, - base::BindOnce(&BlockingConstructor::CompleteConstructionNow)); - for (int i = 0; i < kNumForegroundThreads; ++i) { - foreground_threads.push_back(std::make_unique<BlockingConstructorThread>( - base::ThreadPriority::NORMAL, &lazy_blocking, - foreground_thread_ready_callback)); - foreground_threads.back()->Start(); - } - - // This test will hang if the foreground threads become stuck in - // LazyInstance::Get() per the background thread never being scheduled to - // complete construction. - for (auto& foreground_thread : foreground_threads) - foreground_thread->Join(); - background_getter.Join(); - - // Fail if this test takes more than 5 seconds (it takes 5-10 seconds on a - // Z840 without r527445 but is expected to be fast (~30ms) with the fix). - EXPECT_LT(base::TimeTicks::Now() - test_begin, - base::TimeDelta::FromSeconds(5)); -}
diff --git a/base/logging_unittest.cc b/base/logging_unittest.cc deleted file mode 100644 index 0264012..0000000 --- a/base/logging_unittest.cc +++ /dev/null
@@ -1,676 +0,0 @@ -// 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/logging.h" -#include "base/bind.h" -#include "base/callback.h" -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "base/strings/string_piece.h" -#include "base/test/scoped_feature_list.h" -#include "build_config.h" - -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(OS_POSIX) -#include <signal.h> -#include <unistd.h> -#include "base/posix/eintr_wrapper.h" -#endif // OS_POSIX - -#if defined(OS_LINUX) || defined(OS_ANDROID) -#include <ucontext.h> -#endif - -#if defined(OS_WIN) -#include <excpt.h> -#include <windows.h> -#endif // OS_WIN - -#if defined(OS_FUCHSIA) -#include "base/fuchsia/fuchsia_logging.h" -#endif - -namespace logging { - -namespace { - -using ::testing::Return; -using ::testing::_; - -// Needs to be global since log assert handlers can't maintain state. -int g_log_sink_call_count = 0; - -#if !defined(OFFICIAL_BUILD) || defined(DCHECK_ALWAYS_ON) || !defined(NDEBUG) -void LogSink(const char* file, - int line, - const base::StringPiece message, - const base::StringPiece stack_trace) { - ++g_log_sink_call_count; -} -#endif - -// Class to make sure any manipulations we do to the min log level are -// contained (i.e., do not affect other unit tests). -class LogStateSaver { - public: - LogStateSaver() : old_min_log_level_(GetMinLogLevel()) {} - - ~LogStateSaver() { - SetMinLogLevel(old_min_log_level_); - g_log_sink_call_count = 0; - } - - private: - int old_min_log_level_; - - DISALLOW_COPY_AND_ASSIGN(LogStateSaver); -}; - -class LoggingTest : public testing::Test { - private: - LogStateSaver log_state_saver_; -}; - -class MockLogSource { - public: - MOCK_METHOD0(Log, const char*()); -}; - -class MockLogAssertHandler { - public: - MOCK_METHOD4( - HandleLogAssert, - void(const char*, int, const base::StringPiece, const base::StringPiece)); -}; - -TEST_F(LoggingTest, BasicLogging) { - MockLogSource mock_log_source; - EXPECT_CALL(mock_log_source, Log()) - .Times(DCHECK_IS_ON() ? 16 : 8) - .WillRepeatedly(Return("log message")); - - SetMinLogLevel(LOG_INFO); - - EXPECT_TRUE(LOG_IS_ON(INFO)); - EXPECT_TRUE((DCHECK_IS_ON() != 0) == DLOG_IS_ON(INFO)); - EXPECT_TRUE(VLOG_IS_ON(0)); - - LOG(INFO) << mock_log_source.Log(); - LOG_IF(INFO, true) << mock_log_source.Log(); - PLOG(INFO) << mock_log_source.Log(); - PLOG_IF(INFO, true) << mock_log_source.Log(); - VLOG(0) << mock_log_source.Log(); - VLOG_IF(0, true) << mock_log_source.Log(); - VPLOG(0) << mock_log_source.Log(); - VPLOG_IF(0, true) << mock_log_source.Log(); - - DLOG(INFO) << mock_log_source.Log(); - DLOG_IF(INFO, true) << mock_log_source.Log(); - DPLOG(INFO) << mock_log_source.Log(); - DPLOG_IF(INFO, true) << mock_log_source.Log(); - DVLOG(0) << mock_log_source.Log(); - DVLOG_IF(0, true) << mock_log_source.Log(); - DVPLOG(0) << mock_log_source.Log(); - DVPLOG_IF(0, true) << mock_log_source.Log(); -} - -TEST_F(LoggingTest, LogIsOn) { -#if defined(NDEBUG) - const bool kDfatalIsFatal = false; -#else // defined(NDEBUG) - const bool kDfatalIsFatal = true; -#endif // defined(NDEBUG) - - SetMinLogLevel(LOG_INFO); - EXPECT_TRUE(LOG_IS_ON(INFO)); - EXPECT_TRUE(LOG_IS_ON(WARNING)); - EXPECT_TRUE(LOG_IS_ON(ERROR)); - EXPECT_TRUE(LOG_IS_ON(FATAL)); - EXPECT_TRUE(LOG_IS_ON(DFATAL)); - - SetMinLogLevel(LOG_WARNING); - EXPECT_FALSE(LOG_IS_ON(INFO)); - EXPECT_TRUE(LOG_IS_ON(WARNING)); - EXPECT_TRUE(LOG_IS_ON(ERROR)); - EXPECT_TRUE(LOG_IS_ON(FATAL)); - EXPECT_TRUE(LOG_IS_ON(DFATAL)); - - SetMinLogLevel(LOG_ERROR); - EXPECT_FALSE(LOG_IS_ON(INFO)); - EXPECT_FALSE(LOG_IS_ON(WARNING)); - EXPECT_TRUE(LOG_IS_ON(ERROR)); - EXPECT_TRUE(LOG_IS_ON(FATAL)); - EXPECT_TRUE(LOG_IS_ON(DFATAL)); - - // LOG_IS_ON(FATAL) should always be true. - SetMinLogLevel(LOG_FATAL + 1); - EXPECT_FALSE(LOG_IS_ON(INFO)); - EXPECT_FALSE(LOG_IS_ON(WARNING)); - EXPECT_FALSE(LOG_IS_ON(ERROR)); - EXPECT_TRUE(LOG_IS_ON(FATAL)); - EXPECT_EQ(kDfatalIsFatal, LOG_IS_ON(DFATAL)); -} - -TEST_F(LoggingTest, LoggingIsLazyBySeverity) { - MockLogSource mock_log_source; - EXPECT_CALL(mock_log_source, Log()).Times(0); - - SetMinLogLevel(LOG_WARNING); - - EXPECT_FALSE(LOG_IS_ON(INFO)); - EXPECT_FALSE(DLOG_IS_ON(INFO)); - EXPECT_FALSE(VLOG_IS_ON(1)); - - LOG(INFO) << mock_log_source.Log(); - LOG_IF(INFO, false) << mock_log_source.Log(); - PLOG(INFO) << mock_log_source.Log(); - PLOG_IF(INFO, false) << mock_log_source.Log(); - VLOG(1) << mock_log_source.Log(); - VLOG_IF(1, true) << mock_log_source.Log(); - VPLOG(1) << mock_log_source.Log(); - VPLOG_IF(1, true) << mock_log_source.Log(); - - DLOG(INFO) << mock_log_source.Log(); - DLOG_IF(INFO, true) << mock_log_source.Log(); - DPLOG(INFO) << mock_log_source.Log(); - DPLOG_IF(INFO, true) << mock_log_source.Log(); - DVLOG(1) << mock_log_source.Log(); - DVLOG_IF(1, true) << mock_log_source.Log(); - DVPLOG(1) << mock_log_source.Log(); - DVPLOG_IF(1, true) << mock_log_source.Log(); -} - -TEST_F(LoggingTest, LoggingIsLazyByDestination) { - MockLogSource mock_log_source; - MockLogSource mock_log_source_error; - EXPECT_CALL(mock_log_source, Log()).Times(0); - - // Severity >= ERROR is always printed to stderr. - EXPECT_CALL(mock_log_source_error, Log()).Times(1). - WillRepeatedly(Return("log message")); - - LoggingSettings settings; - settings.logging_dest = LOG_NONE; - InitLogging(settings); - - LOG(INFO) << mock_log_source.Log(); - LOG(WARNING) << mock_log_source.Log(); - LOG(ERROR) << mock_log_source_error.Log(); -} - -// Official builds have CHECKs directly call BreakDebugger. -#if !defined(OFFICIAL_BUILD) - -// https://crbug.com/709067 tracks test flakiness on iOS. -#if defined(OS_IOS) -#define MAYBE_CheckStreamsAreLazy DISABLED_CheckStreamsAreLazy -#else -#define MAYBE_CheckStreamsAreLazy CheckStreamsAreLazy -#endif -TEST_F(LoggingTest, MAYBE_CheckStreamsAreLazy) { - MockLogSource mock_log_source, uncalled_mock_log_source; - EXPECT_CALL(mock_log_source, Log()).Times(8). - WillRepeatedly(Return("check message")); - EXPECT_CALL(uncalled_mock_log_source, Log()).Times(0); - - ScopedLogAssertHandler scoped_assert_handler(base::Bind(LogSink)); - - CHECK(mock_log_source.Log()) << uncalled_mock_log_source.Log(); - PCHECK(!mock_log_source.Log()) << mock_log_source.Log(); - CHECK_EQ(mock_log_source.Log(), mock_log_source.Log()) - << uncalled_mock_log_source.Log(); - CHECK_NE(mock_log_source.Log(), mock_log_source.Log()) - << mock_log_source.Log(); -} - -#endif - -#if defined(OFFICIAL_BUILD) && defined(OS_WIN) -NOINLINE void CheckContainingFunc(int death_location) { - CHECK(death_location != 1); - CHECK(death_location != 2); - CHECK(death_location != 3); -} - -int GetCheckExceptionData(EXCEPTION_POINTERS* p, DWORD* code, void** addr) { - *code = p->ExceptionRecord->ExceptionCode; - *addr = p->ExceptionRecord->ExceptionAddress; - return EXCEPTION_EXECUTE_HANDLER; -} - -TEST_F(LoggingTest, CheckCausesDistinctBreakpoints) { - DWORD code1 = 0; - DWORD code2 = 0; - DWORD code3 = 0; - void* addr1 = nullptr; - void* addr2 = nullptr; - void* addr3 = nullptr; - - // Record the exception code and addresses. - __try { - CheckContainingFunc(1); - } __except ( - GetCheckExceptionData(GetExceptionInformation(), &code1, &addr1)) { - } - - __try { - CheckContainingFunc(2); - } __except ( - GetCheckExceptionData(GetExceptionInformation(), &code2, &addr2)) { - } - - __try { - CheckContainingFunc(3); - } __except ( - GetCheckExceptionData(GetExceptionInformation(), &code3, &addr3)) { - } - - // Ensure that the exception codes are correct (in particular, breakpoints, - // not access violations). - EXPECT_EQ(STATUS_BREAKPOINT, code1); - EXPECT_EQ(STATUS_BREAKPOINT, code2); - EXPECT_EQ(STATUS_BREAKPOINT, code3); - - // Ensure that none of the CHECKs are colocated. - EXPECT_NE(addr1, addr2); - EXPECT_NE(addr1, addr3); - EXPECT_NE(addr2, addr3); -} - -#elif defined(OS_POSIX) && !defined(OS_NACL) && !defined(OS_IOS) && \ - !defined(OS_FUCHSIA) && \ - (defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM_FAMILY)) - -int g_child_crash_pipe; - -void CheckCrashTestSighandler(int, siginfo_t* info, void* context_ptr) { - // Conversely to what clearly stated in "man 2 sigaction", some Linux kernels - // do NOT populate the |info->si_addr| in the case of a SIGTRAP. Hence we - // need the arch-specific boilerplate below, which is inspired by breakpad. - // At the same time, on OSX, ucontext.h is deprecated but si_addr works fine. - uintptr_t crash_addr = 0; -#if defined(OS_MACOSX) - crash_addr = reinterpret_cast<uintptr_t>(info->si_addr); -#else // OS_POSIX && !OS_MACOSX - ucontext_t* context = reinterpret_cast<ucontext_t*>(context_ptr); -#if defined(ARCH_CPU_X86) - crash_addr = static_cast<uintptr_t>(context->uc_mcontext.gregs[REG_EIP]); -#elif defined(ARCH_CPU_X86_64) - crash_addr = static_cast<uintptr_t>(context->uc_mcontext.gregs[REG_RIP]); -#elif defined(ARCH_CPU_ARMEL) - crash_addr = static_cast<uintptr_t>(context->uc_mcontext.arm_pc); -#elif defined(ARCH_CPU_ARM64) - crash_addr = static_cast<uintptr_t>(context->uc_mcontext.pc); -#endif // ARCH_* -#endif // OS_POSIX && !OS_MACOSX - HANDLE_EINTR(write(g_child_crash_pipe, &crash_addr, sizeof(uintptr_t))); - _exit(0); -} - -// CHECK causes a direct crash (without jumping to another function) only in -// official builds. Unfortunately, continuous test coverage on official builds -// is lower. DO_CHECK here falls back on a home-brewed implementation in -// non-official builds, to catch regressions earlier in the CQ. -#if defined(OFFICIAL_BUILD) -#define DO_CHECK CHECK -#else -#define DO_CHECK(cond) \ - if (!(cond)) \ - IMMEDIATE_CRASH() -#endif - -void CrashChildMain(int death_location) { - struct sigaction act = {}; - act.sa_sigaction = CheckCrashTestSighandler; - act.sa_flags = SA_SIGINFO; - ASSERT_EQ(0, sigaction(SIGTRAP, &act, nullptr)); - ASSERT_EQ(0, sigaction(SIGBUS, &act, nullptr)); - ASSERT_EQ(0, sigaction(SIGILL, &act, nullptr)); - DO_CHECK(death_location != 1); - DO_CHECK(death_location != 2); - printf("\n"); - DO_CHECK(death_location != 3); - - // Should never reach this point. - const uintptr_t failed = 0; - HANDLE_EINTR(write(g_child_crash_pipe, &failed, sizeof(uintptr_t))); -}; - -void SpawnChildAndCrash(int death_location, uintptr_t* child_crash_addr) { - int pipefd[2]; - ASSERT_EQ(0, pipe(pipefd)); - - int pid = fork(); - ASSERT_GE(pid, 0); - - if (pid == 0) { // child process. - close(pipefd[0]); // Close reader (parent) end. - g_child_crash_pipe = pipefd[1]; - CrashChildMain(death_location); - FAIL() << "The child process was supposed to crash. It didn't."; - } - - close(pipefd[1]); // Close writer (child) end. - DCHECK(child_crash_addr); - int res = HANDLE_EINTR(read(pipefd[0], child_crash_addr, sizeof(uintptr_t))); - ASSERT_EQ(static_cast<int>(sizeof(uintptr_t)), res); -} - -TEST_F(LoggingTest, CheckCausesDistinctBreakpoints) { - uintptr_t child_crash_addr_1 = 0; - uintptr_t child_crash_addr_2 = 0; - uintptr_t child_crash_addr_3 = 0; - - SpawnChildAndCrash(1, &child_crash_addr_1); - SpawnChildAndCrash(2, &child_crash_addr_2); - SpawnChildAndCrash(3, &child_crash_addr_3); - - ASSERT_NE(0u, child_crash_addr_1); - ASSERT_NE(0u, child_crash_addr_2); - ASSERT_NE(0u, child_crash_addr_3); - ASSERT_NE(child_crash_addr_1, child_crash_addr_2); - ASSERT_NE(child_crash_addr_1, child_crash_addr_3); - ASSERT_NE(child_crash_addr_2, child_crash_addr_3); -} -#endif // OS_POSIX - -TEST_F(LoggingTest, DebugLoggingReleaseBehavior) { -#if DCHECK_IS_ON() - int debug_only_variable = 1; -#endif - // These should avoid emitting references to |debug_only_variable| - // in release mode. - DLOG_IF(INFO, debug_only_variable) << "test"; - DLOG_ASSERT(debug_only_variable) << "test"; - DPLOG_IF(INFO, debug_only_variable) << "test"; - DVLOG_IF(1, debug_only_variable) << "test"; -} - -TEST_F(LoggingTest, DcheckStreamsAreLazy) { - MockLogSource mock_log_source; - EXPECT_CALL(mock_log_source, Log()).Times(0); -#if DCHECK_IS_ON() - DCHECK(true) << mock_log_source.Log(); - DCHECK_EQ(0, 0) << mock_log_source.Log(); -#else - DCHECK(mock_log_source.Log()) << mock_log_source.Log(); - DPCHECK(mock_log_source.Log()) << mock_log_source.Log(); - DCHECK_EQ(0, 0) << mock_log_source.Log(); - DCHECK_EQ(mock_log_source.Log(), static_cast<const char*>(nullptr)) - << mock_log_source.Log(); -#endif -} - -void DcheckEmptyFunction1() { - // Provide a body so that Release builds do not cause the compiler to - // optimize DcheckEmptyFunction1 and DcheckEmptyFunction2 as a single - // function, which breaks the Dcheck tests below. - LOG(INFO) << "DcheckEmptyFunction1"; -} -void DcheckEmptyFunction2() {} - -#if DCHECK_IS_CONFIGURABLE -class ScopedDcheckSeverity { - public: - ScopedDcheckSeverity(LogSeverity new_severity) : old_severity_(LOG_DCHECK) { - LOG_DCHECK = new_severity; - } - - ~ScopedDcheckSeverity() { LOG_DCHECK = old_severity_; } - - private: - LogSeverity old_severity_; -}; -#endif // DCHECK_IS_CONFIGURABLE - -// https://crbug.com/709067 tracks test flakiness on iOS. -#if defined(OS_IOS) -#define MAYBE_Dcheck DISABLED_Dcheck -#else -#define MAYBE_Dcheck Dcheck -#endif -TEST_F(LoggingTest, MAYBE_Dcheck) { -#if DCHECK_IS_CONFIGURABLE - // DCHECKs are enabled, and LOG_DCHECK is mutable, but defaults to non-fatal. - // Set it to LOG_FATAL to get the expected behavior from the rest of this - // test. - ScopedDcheckSeverity dcheck_severity(LOG_FATAL); -#endif // DCHECK_IS_CONFIGURABLE - -#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON) - // Release build. - EXPECT_FALSE(DCHECK_IS_ON()); - EXPECT_FALSE(DLOG_IS_ON(DCHECK)); -#elif defined(NDEBUG) && defined(DCHECK_ALWAYS_ON) - // Release build with real DCHECKS. - ScopedLogAssertHandler scoped_assert_handler(base::Bind(LogSink)); - EXPECT_TRUE(DCHECK_IS_ON()); - EXPECT_TRUE(DLOG_IS_ON(DCHECK)); -#else - // Debug build. - ScopedLogAssertHandler scoped_assert_handler(base::Bind(LogSink)); - EXPECT_TRUE(DCHECK_IS_ON()); - EXPECT_TRUE(DLOG_IS_ON(DCHECK)); -#endif - - // DCHECKs are fatal iff they're compiled in DCHECK_IS_ON() and the DCHECK - // log level is set to fatal. - const bool dchecks_are_fatal = DCHECK_IS_ON() && LOG_DCHECK == LOG_FATAL; - EXPECT_EQ(0, g_log_sink_call_count); - DCHECK(false); - EXPECT_EQ(dchecks_are_fatal ? 1 : 0, g_log_sink_call_count); - DPCHECK(false); - EXPECT_EQ(dchecks_are_fatal ? 2 : 0, g_log_sink_call_count); - DCHECK_EQ(0, 1); - EXPECT_EQ(dchecks_are_fatal ? 3 : 0, g_log_sink_call_count); - - // Test DCHECK on std::nullptr_t - g_log_sink_call_count = 0; - const void* p_null = nullptr; - const void* p_not_null = &p_null; - DCHECK_EQ(p_null, nullptr); - DCHECK_EQ(nullptr, p_null); - DCHECK_NE(p_not_null, nullptr); - DCHECK_NE(nullptr, p_not_null); - EXPECT_EQ(0, g_log_sink_call_count); - - // Test DCHECK on a scoped enum. - enum class Animal { DOG, CAT }; - DCHECK_EQ(Animal::DOG, Animal::DOG); - EXPECT_EQ(0, g_log_sink_call_count); - DCHECK_EQ(Animal::DOG, Animal::CAT); - EXPECT_EQ(dchecks_are_fatal ? 1 : 0, g_log_sink_call_count); - - // Test DCHECK on functions and function pointers. - g_log_sink_call_count = 0; - struct MemberFunctions { - void MemberFunction1() { - // See the comment in DcheckEmptyFunction1(). - LOG(INFO) << "Do not merge with MemberFunction2."; - } - void MemberFunction2() {} - }; - void (MemberFunctions::*mp1)() = &MemberFunctions::MemberFunction1; - void (MemberFunctions::*mp2)() = &MemberFunctions::MemberFunction2; - void (*fp1)() = DcheckEmptyFunction1; - void (*fp2)() = DcheckEmptyFunction2; - void (*fp3)() = DcheckEmptyFunction1; - DCHECK_EQ(fp1, fp3); - EXPECT_EQ(0, g_log_sink_call_count); - DCHECK_EQ(mp1, &MemberFunctions::MemberFunction1); - EXPECT_EQ(0, g_log_sink_call_count); - DCHECK_EQ(mp2, &MemberFunctions::MemberFunction2); - EXPECT_EQ(0, g_log_sink_call_count); - DCHECK_EQ(fp1, fp2); - EXPECT_EQ(dchecks_are_fatal ? 1 : 0, g_log_sink_call_count); - DCHECK_EQ(mp2, &MemberFunctions::MemberFunction1); - EXPECT_EQ(dchecks_are_fatal ? 2 : 0, g_log_sink_call_count); -} - -TEST_F(LoggingTest, DcheckReleaseBehavior) { - int some_variable = 1; - // These should still reference |some_variable| so we don't get - // unused variable warnings. - DCHECK(some_variable) << "test"; - DPCHECK(some_variable) << "test"; - DCHECK_EQ(some_variable, 1) << "test"; -} - -TEST_F(LoggingTest, DCheckEqStatements) { - bool reached = false; - if (false) - DCHECK_EQ(false, true); // Unreached. - else - DCHECK_EQ(true, reached = true); // Reached, passed. - ASSERT_EQ(DCHECK_IS_ON() ? true : false, reached); - - if (false) - DCHECK_EQ(false, true); // Unreached. -} - -TEST_F(LoggingTest, CheckEqStatements) { - bool reached = false; - if (false) - CHECK_EQ(false, true); // Unreached. - else - CHECK_EQ(true, reached = true); // Reached, passed. - ASSERT_TRUE(reached); - - if (false) - CHECK_EQ(false, true); // Unreached. -} - -TEST_F(LoggingTest, NestedLogAssertHandlers) { - ::testing::InSequence dummy; - ::testing::StrictMock<MockLogAssertHandler> handler_a, handler_b; - - EXPECT_CALL( - handler_a, - HandleLogAssert( - _, _, base::StringPiece("First assert must be caught by handler_a"), - _)); - EXPECT_CALL( - handler_b, - HandleLogAssert( - _, _, base::StringPiece("Second assert must be caught by handler_b"), - _)); - EXPECT_CALL( - handler_a, - HandleLogAssert( - _, _, - base::StringPiece("Last assert must be caught by handler_a again"), - _)); - - logging::ScopedLogAssertHandler scoped_handler_a(base::Bind( - &MockLogAssertHandler::HandleLogAssert, base::Unretained(&handler_a))); - - // Using LOG(FATAL) rather than CHECK(false) here since log messages aren't - // preserved for CHECKs in official builds. - LOG(FATAL) << "First assert must be caught by handler_a"; - - { - logging::ScopedLogAssertHandler scoped_handler_b(base::Bind( - &MockLogAssertHandler::HandleLogAssert, base::Unretained(&handler_b))); - LOG(FATAL) << "Second assert must be caught by handler_b"; - } - - LOG(FATAL) << "Last assert must be caught by handler_a again"; -} - -// Test that defining an operator<< for a type in a namespace doesn't prevent -// other code in that namespace from calling the operator<<(ostream, wstring) -// defined by logging.h. This can fail if operator<<(ostream, wstring) can't be -// found by ADL, since defining another operator<< prevents name lookup from -// looking in the global namespace. -namespace nested_test { - class Streamable {}; - ALLOW_UNUSED_TYPE std::ostream& operator<<(std::ostream& out, - const Streamable&) { - return out << "Streamable"; - } - TEST_F(LoggingTest, StreamingWstringFindsCorrectOperator) { - std::wstring wstr = L"Hello World"; - std::ostringstream ostr; - ostr << wstr; - EXPECT_EQ("Hello World", ostr.str()); - } -} // namespace nested_test - -#if DCHECK_IS_CONFIGURABLE -TEST_F(LoggingTest, ConfigurableDCheck) { - // Verify that DCHECKs default to non-fatal in configurable-DCHECK builds. - // Note that we require only that DCHECK is non-fatal by default, rather - // than requiring that it be exactly INFO, ERROR, etc level. - EXPECT_LT(LOG_DCHECK, LOG_FATAL); - DCHECK(false); - - // Verify that DCHECK* aren't hard-wired to crash on failure. - LOG_DCHECK = LOG_INFO; - DCHECK(false); - DCHECK_EQ(1, 2); - - // Verify that DCHECK does crash if LOG_DCHECK is set to LOG_FATAL. - LOG_DCHECK = LOG_FATAL; - - ::testing::StrictMock<MockLogAssertHandler> handler; - EXPECT_CALL(handler, HandleLogAssert(_, _, _, _)).Times(2); - { - logging::ScopedLogAssertHandler scoped_handler_b(base::Bind( - &MockLogAssertHandler::HandleLogAssert, base::Unretained(&handler))); - DCHECK(false); - DCHECK_EQ(1, 2); - } -} - -TEST_F(LoggingTest, ConfigurableDCheckFeature) { - // Initialize FeatureList with and without DcheckIsFatal, and verify the - // value of LOG_DCHECK. Note that we don't require that DCHECK take a - // specific value when the feature is off, only that it is non-fatal. - - { - base::test::ScopedFeatureList feature_list; - feature_list.InitFromCommandLine("DcheckIsFatal", ""); - EXPECT_EQ(LOG_DCHECK, LOG_FATAL); - } - - { - base::test::ScopedFeatureList feature_list; - feature_list.InitFromCommandLine("", "DcheckIsFatal"); - EXPECT_LT(LOG_DCHECK, LOG_FATAL); - } - - // The default case is last, so we leave LOG_DCHECK in the default state. - { - base::test::ScopedFeatureList feature_list; - feature_list.InitFromCommandLine("", ""); - EXPECT_LT(LOG_DCHECK, LOG_FATAL); - } -} -#endif // DCHECK_IS_CONFIGURABLE - -#if defined(OS_FUCHSIA) -TEST_F(LoggingTest, FuchsiaLogging) { - MockLogSource mock_log_source; - EXPECT_CALL(mock_log_source, Log()) - .Times(DCHECK_IS_ON() ? 2 : 1) - .WillRepeatedly(Return("log message")); - - SetMinLogLevel(LOG_INFO); - - EXPECT_TRUE(LOG_IS_ON(INFO)); - EXPECT_TRUE((DCHECK_IS_ON() != 0) == DLOG_IS_ON(INFO)); - - ZX_LOG(INFO, ZX_ERR_INTERNAL) << mock_log_source.Log(); - ZX_DLOG(INFO, ZX_ERR_INTERNAL) << mock_log_source.Log(); - - ZX_CHECK(true, ZX_ERR_INTERNAL); - ZX_DCHECK(true, ZX_ERR_INTERNAL); -} -#endif // defined(OS_FUCHSIA) - -} // namespace - -} // namespace logging
diff --git a/base/mac/dispatch_source_mach_unittest.cc b/base/mac/dispatch_source_mach_unittest.cc deleted file mode 100644 index 738a137..0000000 --- a/base/mac/dispatch_source_mach_unittest.cc +++ /dev/null
@@ -1,125 +0,0 @@ -// 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/mac/dispatch_source_mach.h" - -#include <mach/mach.h> - -#include <memory> - -#include "base/logging.h" -#include "base/mac/scoped_mach_port.h" -#include "base/test/test_timeouts.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -class DispatchSourceMachTest : public testing::Test { - public: - void SetUp() override { - mach_port_t port = MACH_PORT_NULL; - ASSERT_EQ(KERN_SUCCESS, mach_port_allocate(mach_task_self(), - MACH_PORT_RIGHT_RECEIVE, &port)); - receive_right_.reset(port); - - ASSERT_EQ(KERN_SUCCESS, mach_port_insert_right(mach_task_self(), port, - port, MACH_MSG_TYPE_MAKE_SEND)); - send_right_.reset(port); - } - - mach_port_t GetPort() { return receive_right_.get(); } - - void WaitForSemaphore(dispatch_semaphore_t semaphore) { - dispatch_semaphore_wait(semaphore, dispatch_time( - DISPATCH_TIME_NOW, - TestTimeouts::action_timeout().InSeconds() * NSEC_PER_SEC)); - } - - private: - base::mac::ScopedMachReceiveRight receive_right_; - base::mac::ScopedMachSendRight send_right_; -}; - -TEST_F(DispatchSourceMachTest, ReceiveAfterResume) { - dispatch_semaphore_t signal = dispatch_semaphore_create(0); - mach_port_t port = GetPort(); - - bool __block did_receive = false; - DispatchSourceMach source("org.chromium.base.test.ReceiveAfterResume", - port, ^{ - mach_msg_empty_rcv_t msg = {{0}}; - msg.header.msgh_size = sizeof(msg); - msg.header.msgh_local_port = port; - mach_msg_receive(&msg.header); - did_receive = true; - - dispatch_semaphore_signal(signal); - }); - - mach_msg_empty_send_t msg = {{0}}; - msg.header.msgh_size = sizeof(msg); - msg.header.msgh_remote_port = port; - msg.header.msgh_bits = MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_COPY_SEND); - ASSERT_EQ(KERN_SUCCESS, mach_msg_send(&msg.header)); - - EXPECT_FALSE(did_receive); - - source.Resume(); - - WaitForSemaphore(signal); - dispatch_release(signal); - - EXPECT_TRUE(did_receive); -} - -TEST_F(DispatchSourceMachTest, NoMessagesAfterDestruction) { - mach_port_t port = GetPort(); - - std::unique_ptr<int> count(new int(0)); - int* __block count_ptr = count.get(); - - std::unique_ptr<DispatchSourceMach> source(new DispatchSourceMach( - "org.chromium.base.test.NoMessagesAfterDestruction", port, ^{ - mach_msg_empty_rcv_t msg = {{0}}; - msg.header.msgh_size = sizeof(msg); - msg.header.msgh_local_port = port; - mach_msg_receive(&msg.header); - LOG(INFO) << "Receieve " << *count_ptr; - ++(*count_ptr); - })); - source->Resume(); - - dispatch_queue_t queue = - dispatch_queue_create("org.chromium.base.test.MessageSend", NULL); - dispatch_semaphore_t signal = dispatch_semaphore_create(0); - for (int i = 0; i < 30; ++i) { - dispatch_async(queue, ^{ - mach_msg_empty_send_t msg = {{0}}; - msg.header.msgh_size = sizeof(msg); - msg.header.msgh_remote_port = port; - msg.header.msgh_bits = - MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_COPY_SEND); - mach_msg_send(&msg.header); - }); - - // After sending five messages, shut down the source and taint the - // pointer the handler dereferences. The test will crash if |count_ptr| - // is being used after "free". - if (i == 5) { - std::unique_ptr<DispatchSourceMach>* source_ptr = &source; - dispatch_async(queue, ^{ - source_ptr->reset(); - count_ptr = reinterpret_cast<int*>(0xdeaddead); - dispatch_semaphore_signal(signal); - }); - } - } - - WaitForSemaphore(signal); - dispatch_release(signal); - - dispatch_release(queue); -} - -} // namespace base
diff --git a/base/mac/mach_port_broker_unittest.cc b/base/mac/mach_port_broker_unittest.cc deleted file mode 100644 index bff8eb6..0000000 --- a/base/mac/mach_port_broker_unittest.cc +++ /dev/null
@@ -1,133 +0,0 @@ -// 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/mac/mach_port_broker.h" - -#include "base/command_line.h" -#include "base/synchronization/lock.h" -#include "base/synchronization/waitable_event.h" -#include "base/test/multiprocess_test.h" -#include "base/test/test_timeouts.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/multiprocess_func_list.h" - -namespace base { - -namespace { -const char kBootstrapPortName[] = "thisisatest"; -} - -class MachPortBrokerTest : public testing::Test, - public base::PortProvider::Observer { - public: - MachPortBrokerTest() - : broker_(kBootstrapPortName), - event_(base::WaitableEvent::ResetPolicy::MANUAL, - base::WaitableEvent::InitialState::NOT_SIGNALED), - received_process_(kNullProcessHandle) { - broker_.AddObserver(this); - } - ~MachPortBrokerTest() override { - broker_.RemoveObserver(this); - } - - // Helper function to acquire/release locks and call |PlaceholderForPid()|. - void AddPlaceholderForPid(base::ProcessHandle pid) { - base::AutoLock lock(broker_.GetLock()); - broker_.AddPlaceholderForPid(pid); - } - - // Helper function to acquire/release locks and call |FinalizePid()|. - void FinalizePid(base::ProcessHandle pid, - mach_port_t task_port) { - base::AutoLock lock(broker_.GetLock()); - broker_.FinalizePid(pid, task_port); - } - - void WaitForTaskPort() { - event_.Wait(); - } - - // base::PortProvider::Observer: - void OnReceivedTaskPort(ProcessHandle process) override { - received_process_ = process; - event_.Signal(); - } - - protected: - MachPortBroker broker_; - WaitableEvent event_; - ProcessHandle received_process_; -}; - -TEST_F(MachPortBrokerTest, Locks) { - // Acquire and release the locks. Nothing bad should happen. - base::AutoLock lock(broker_.GetLock()); -} - -TEST_F(MachPortBrokerTest, AddPlaceholderAndFinalize) { - // Add a placeholder for PID 1. - AddPlaceholderForPid(1); - EXPECT_EQ(0u, broker_.TaskForPid(1)); - - // Finalize PID 1. - FinalizePid(1, 100u); - EXPECT_EQ(100u, broker_.TaskForPid(1)); - - // Should be no entry for PID 2. - EXPECT_EQ(0u, broker_.TaskForPid(2)); -} - -TEST_F(MachPortBrokerTest, FinalizeUnknownPid) { - // Finalizing an entry for an unknown pid should not add it to the map. - FinalizePid(1u, 100u); - EXPECT_EQ(0u, broker_.TaskForPid(1u)); -} - -MULTIPROCESS_TEST_MAIN(MachPortBrokerTestChild) { - CHECK(base::MachPortBroker::ChildSendTaskPortToParent(kBootstrapPortName)); - return 0; -} - -TEST_F(MachPortBrokerTest, ReceivePortFromChild) { - ASSERT_TRUE(broker_.Init()); - CommandLine command_line( - base::GetMultiProcessTestChildBaseCommandLine()); - broker_.GetLock().Acquire(); - base::Process test_child_process = base::SpawnMultiProcessTestChild( - "MachPortBrokerTestChild", command_line, LaunchOptions()); - broker_.AddPlaceholderForPid(test_child_process.Handle()); - broker_.GetLock().Release(); - - WaitForTaskPort(); - EXPECT_EQ(test_child_process.Handle(), received_process_); - - int rv = -1; - ASSERT_TRUE(test_child_process.WaitForExitWithTimeout( - TestTimeouts::action_timeout(), &rv)); - EXPECT_EQ(0, rv); - - EXPECT_NE(static_cast<mach_port_t>(MACH_PORT_NULL), - broker_.TaskForPid(test_child_process.Handle())); -} - -TEST_F(MachPortBrokerTest, ReceivePortFromChildWithoutAdding) { - ASSERT_TRUE(broker_.Init()); - CommandLine command_line( - base::GetMultiProcessTestChildBaseCommandLine()); - broker_.GetLock().Acquire(); - base::Process test_child_process = base::SpawnMultiProcessTestChild( - "MachPortBrokerTestChild", command_line, LaunchOptions()); - broker_.GetLock().Release(); - - int rv = -1; - ASSERT_TRUE(test_child_process.WaitForExitWithTimeout( - TestTimeouts::action_timeout(), &rv)); - EXPECT_EQ(0, rv); - - EXPECT_EQ(static_cast<mach_port_t>(MACH_PORT_NULL), - broker_.TaskForPid(test_child_process.Handle())); -} - -} // namespace base
diff --git a/base/md5_unittest.cc b/base/md5_unittest.cc deleted file mode 100644 index b27efe9..0000000 --- a/base/md5_unittest.cc +++ /dev/null
@@ -1,253 +0,0 @@ -// 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/md5.h" - -#include <string.h> - -#include <memory> -#include <string> - -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(MD5, DigestToBase16) { - MD5Digest digest; - - int data[] = { - 0xd4, 0x1d, 0x8c, 0xd9, - 0x8f, 0x00, 0xb2, 0x04, - 0xe9, 0x80, 0x09, 0x98, - 0xec, 0xf8, 0x42, 0x7e - }; - - for (int i = 0; i < 16; ++i) - digest.a[i] = data[i] & 0xff; - - std::string actual = MD5DigestToBase16(digest); - std::string expected = "d41d8cd98f00b204e9800998ecf8427e"; - - EXPECT_EQ(expected, actual); -} - -TEST(MD5, MD5SumEmtpyData) { - MD5Digest digest; - const char data[] = ""; - - MD5Sum(data, strlen(data), &digest); - - int expected[] = { - 0xd4, 0x1d, 0x8c, 0xd9, - 0x8f, 0x00, 0xb2, 0x04, - 0xe9, 0x80, 0x09, 0x98, - 0xec, 0xf8, 0x42, 0x7e - }; - - for (int i = 0; i < 16; ++i) - EXPECT_EQ(expected[i], digest.a[i] & 0xFF); -} - -TEST(MD5, MD5SumOneByteData) { - MD5Digest digest; - const char data[] = "a"; - - MD5Sum(data, strlen(data), &digest); - - int expected[] = { - 0x0c, 0xc1, 0x75, 0xb9, - 0xc0, 0xf1, 0xb6, 0xa8, - 0x31, 0xc3, 0x99, 0xe2, - 0x69, 0x77, 0x26, 0x61 - }; - - for (int i = 0; i < 16; ++i) - EXPECT_EQ(expected[i], digest.a[i] & 0xFF); -} - -TEST(MD5, MD5SumLongData) { - const int length = 10 * 1024 * 1024 + 1; - std::unique_ptr<char[]> data(new char[length]); - - for (int i = 0; i < length; ++i) - data[i] = i & 0xFF; - - MD5Digest digest; - MD5Sum(data.get(), length, &digest); - - int expected[] = { - 0x90, 0xbd, 0x6a, 0xd9, - 0x0a, 0xce, 0xf5, 0xad, - 0xaa, 0x92, 0x20, 0x3e, - 0x21, 0xc7, 0xa1, 0x3e - }; - - for (int i = 0; i < 16; ++i) - EXPECT_EQ(expected[i], digest.a[i] & 0xFF); -} - -TEST(MD5, ContextWithEmptyData) { - MD5Context ctx; - MD5Init(&ctx); - - MD5Digest digest; - MD5Final(&digest, &ctx); - - int expected[] = { - 0xd4, 0x1d, 0x8c, 0xd9, - 0x8f, 0x00, 0xb2, 0x04, - 0xe9, 0x80, 0x09, 0x98, - 0xec, 0xf8, 0x42, 0x7e - }; - - for (int i = 0; i < 16; ++i) - EXPECT_EQ(expected[i], digest.a[i] & 0xFF); -} - -TEST(MD5, ContextWithLongData) { - MD5Context ctx; - MD5Init(&ctx); - - const int length = 10 * 1024 * 1024 + 1; - std::unique_ptr<char[]> data(new char[length]); - - for (int i = 0; i < length; ++i) - data[i] = i & 0xFF; - - int total = 0; - while (total < length) { - int len = 4097; // intentionally not 2^k. - if (len > length - total) - len = length - total; - - MD5Update(&ctx, - StringPiece(reinterpret_cast<char*>(data.get() + total), len)); - total += len; - } - - EXPECT_EQ(length, total); - - MD5Digest digest; - MD5Final(&digest, &ctx); - - int expected[] = { - 0x90, 0xbd, 0x6a, 0xd9, - 0x0a, 0xce, 0xf5, 0xad, - 0xaa, 0x92, 0x20, 0x3e, - 0x21, 0xc7, 0xa1, 0x3e - }; - - for (int i = 0; i < 16; ++i) - EXPECT_EQ(expected[i], digest.a[i] & 0xFF); -} - -// Example data from http://www.ietf.org/rfc/rfc1321.txt A.5 Test Suite -TEST(MD5, MD5StringTestSuite1) { - std::string actual = MD5String(""); - std::string expected = "d41d8cd98f00b204e9800998ecf8427e"; - EXPECT_EQ(expected, actual); -} - -TEST(MD5, MD5StringTestSuite2) { - std::string actual = MD5String("a"); - std::string expected = "0cc175b9c0f1b6a831c399e269772661"; - EXPECT_EQ(expected, actual); -} - -TEST(MD5, MD5StringTestSuite3) { - std::string actual = MD5String("abc"); - std::string expected = "900150983cd24fb0d6963f7d28e17f72"; - EXPECT_EQ(expected, actual); -} - -TEST(MD5, MD5StringTestSuite4) { - std::string actual = MD5String("message digest"); - std::string expected = "f96b697d7cb7938d525a2f31aaf161d0"; - EXPECT_EQ(expected, actual); -} - -TEST(MD5, MD5StringTestSuite5) { - std::string actual = MD5String("abcdefghijklmnopqrstuvwxyz"); - std::string expected = "c3fcd3d76192e4007dfb496cca67e13b"; - EXPECT_EQ(expected, actual); -} - -TEST(MD5, MD5StringTestSuite6) { - std::string actual = MD5String("ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789"); - std::string expected = "d174ab98d277d9f5a5611c2c9f419d9f"; - EXPECT_EQ(expected, actual); -} - -TEST(MD5, MD5StringTestSuite7) { - std::string actual = MD5String("12345678901234567890" - "12345678901234567890" - "12345678901234567890" - "12345678901234567890"); - std::string expected = "57edf4a22be3c955ac49da2e2107b67a"; - EXPECT_EQ(expected, actual); -} - -TEST(MD5, ContextWithStringData) { - MD5Context ctx; - MD5Init(&ctx); - - MD5Update(&ctx, "abc"); - - MD5Digest digest; - MD5Final(&digest, &ctx); - - std::string actual = MD5DigestToBase16(digest); - std::string expected = "900150983cd24fb0d6963f7d28e17f72"; - - EXPECT_EQ(expected, actual); -} - -// Test that a digest generated by MD5IntermediateFinal() gives the same results -// as an independently-calculated digest, and also does not modify the context. -TEST(MD5, IntermediateFinal) { - // Independent context over the header. - MD5Context check_header_context; - MD5Init(&check_header_context); - - // Independent context over entire input. - MD5Context check_full_context; - MD5Init(&check_full_context); - - // Context intermediate digest will be calculated from. - MD5Context context; - MD5Init(&context); - - static const char kHeader[] = "header data"; - static const char kBody[] = "payload data"; - - MD5Update(&context, kHeader); - MD5Update(&check_header_context, kHeader); - MD5Update(&check_full_context, kHeader); - - MD5Digest check_header_digest; - MD5Final(&check_header_digest, &check_header_context); - - MD5Digest header_digest; - MD5IntermediateFinal(&header_digest, &context); - - MD5Update(&context, kBody); - MD5Update(&check_full_context, kBody); - - MD5Digest check_full_digest; - MD5Final(&check_full_digest, &check_full_context); - - MD5Digest digest; - MD5Final(&digest, &context); - - // The header and full digest pairs are the same, and they aren't the same as - // each other. - EXPECT_TRUE(!memcmp(&header_digest, &check_header_digest, - sizeof(header_digest))); - EXPECT_TRUE(!memcmp(&digest, &check_full_digest, sizeof(digest))); - EXPECT_TRUE(memcmp(&digest, &header_digest, sizeof(digest))); -} - -} // namespace base
diff --git a/base/memory/aligned_memory_unittest.cc b/base/memory/aligned_memory_unittest.cc deleted file mode 100644 index 29ed706..0000000 --- a/base/memory/aligned_memory_unittest.cc +++ /dev/null
@@ -1,46 +0,0 @@ -// 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/memory/aligned_memory.h" - -#include <memory> - -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -#define EXPECT_ALIGNED(ptr, align) \ - EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1)) - -namespace base { - -TEST(AlignedMemoryTest, DynamicAllocation) { - void* p = AlignedAlloc(8, 8); - EXPECT_TRUE(p); - EXPECT_ALIGNED(p, 8); - AlignedFree(p); - - p = AlignedAlloc(8, 16); - EXPECT_TRUE(p); - EXPECT_ALIGNED(p, 16); - AlignedFree(p); - - p = AlignedAlloc(8, 256); - EXPECT_TRUE(p); - EXPECT_ALIGNED(p, 256); - AlignedFree(p); - - p = AlignedAlloc(8, 4096); - EXPECT_TRUE(p); - EXPECT_ALIGNED(p, 4096); - AlignedFree(p); -} - -TEST(AlignedMemoryTest, ScopedDynamicAllocation) { - std::unique_ptr<float, AlignedFreeDeleter> p( - static_cast<float*>(AlignedAlloc(8, 8))); - EXPECT_TRUE(p.get()); - EXPECT_ALIGNED(p.get(), 8); -} - -} // namespace base
diff --git a/base/memory/discardable_shared_memory_unittest.cc b/base/memory/discardable_shared_memory_unittest.cc deleted file mode 100644 index bda37f6..0000000 --- a/base/memory/discardable_shared_memory_unittest.cc +++ /dev/null
@@ -1,456 +0,0 @@ -// 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 <fcntl.h> -#include <stdint.h> - -#include "base/files/scoped_file.h" -#include "base/memory/discardable_shared_memory.h" -#include "base/memory/shared_memory_tracker.h" -#include "base/process/process_metrics.h" -#include "base/trace_event/memory_allocator_dump.h" -#include "base/trace_event/process_memory_dump.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -class TestDiscardableSharedMemory : public DiscardableSharedMemory { - public: - TestDiscardableSharedMemory() = default; - - explicit TestDiscardableSharedMemory(UnsafeSharedMemoryRegion region) - : DiscardableSharedMemory(std::move(region)) {} - - void SetNow(Time now) { now_ = now; } - - private: - // Overriden from DiscardableSharedMemory: - Time Now() const override { return now_; } - - Time now_; -}; - -TEST(DiscardableSharedMemoryTest, CreateAndMap) { - const uint32_t kDataSize = 1024; - - TestDiscardableSharedMemory memory; - bool rv = memory.CreateAndMap(kDataSize); - ASSERT_TRUE(rv); - EXPECT_GE(memory.mapped_size(), kDataSize); - EXPECT_TRUE(memory.IsMemoryLocked()); -} - -TEST(DiscardableSharedMemoryTest, CreateFromHandle) { - const uint32_t kDataSize = 1024; - - TestDiscardableSharedMemory memory1; - bool rv = memory1.CreateAndMap(kDataSize); - ASSERT_TRUE(rv); - - UnsafeSharedMemoryRegion shared_region = memory1.DuplicateRegion(); - ASSERT_TRUE(shared_region.IsValid()); - - TestDiscardableSharedMemory memory2(std::move(shared_region)); - rv = memory2.Map(kDataSize); - ASSERT_TRUE(rv); - EXPECT_TRUE(memory2.IsMemoryLocked()); -} - -TEST(DiscardableSharedMemoryTest, LockAndUnlock) { - const uint32_t kDataSize = 1024; - - TestDiscardableSharedMemory memory1; - bool rv = memory1.CreateAndMap(kDataSize); - ASSERT_TRUE(rv); - - // Memory is initially locked. Unlock it. - memory1.SetNow(Time::FromDoubleT(1)); - memory1.Unlock(0, 0); - EXPECT_FALSE(memory1.IsMemoryLocked()); - - // Lock and unlock memory. - DiscardableSharedMemory::LockResult lock_rv = memory1.Lock(0, 0); - EXPECT_EQ(DiscardableSharedMemory::SUCCESS, lock_rv); - memory1.SetNow(Time::FromDoubleT(2)); - memory1.Unlock(0, 0); - - // Lock again before duplicating and passing ownership to new instance. - lock_rv = memory1.Lock(0, 0); - EXPECT_EQ(DiscardableSharedMemory::SUCCESS, lock_rv); - EXPECT_TRUE(memory1.IsMemoryLocked()); - - UnsafeSharedMemoryRegion shared_region = memory1.DuplicateRegion(); - ASSERT_TRUE(shared_region.IsValid()); - - TestDiscardableSharedMemory memory2(std::move(shared_region)); - rv = memory2.Map(kDataSize); - ASSERT_TRUE(rv); - - // Unlock second instance. - memory2.SetNow(Time::FromDoubleT(3)); - memory2.Unlock(0, 0); - - // Both memory instances should be unlocked now. - EXPECT_FALSE(memory2.IsMemoryLocked()); - EXPECT_FALSE(memory1.IsMemoryLocked()); - - // Lock second instance before passing ownership back to first instance. - lock_rv = memory2.Lock(0, 0); - EXPECT_EQ(DiscardableSharedMemory::SUCCESS, lock_rv); - - // Memory should still be resident and locked. - rv = memory1.IsMemoryResident(); - EXPECT_TRUE(rv); - EXPECT_TRUE(memory1.IsMemoryLocked()); - - // Unlock first instance. - memory1.SetNow(Time::FromDoubleT(4)); - memory1.Unlock(0, 0); -} - -TEST(DiscardableSharedMemoryTest, Purge) { - const uint32_t kDataSize = 1024; - - TestDiscardableSharedMemory memory1; - bool rv = memory1.CreateAndMap(kDataSize); - ASSERT_TRUE(rv); - - UnsafeSharedMemoryRegion shared_region = memory1.DuplicateRegion(); - ASSERT_TRUE(shared_region.IsValid()); - - TestDiscardableSharedMemory memory2(std::move(shared_region)); - rv = memory2.Map(kDataSize); - ASSERT_TRUE(rv); - - // This should fail as memory is locked. - rv = memory1.Purge(Time::FromDoubleT(1)); - EXPECT_FALSE(rv); - - memory2.SetNow(Time::FromDoubleT(2)); - memory2.Unlock(0, 0); - - ASSERT_TRUE(memory2.IsMemoryResident()); - - // Memory is unlocked, but our usage timestamp is incorrect. - rv = memory1.Purge(Time::FromDoubleT(3)); - EXPECT_FALSE(rv); - - ASSERT_TRUE(memory2.IsMemoryResident()); - - // Memory is unlocked and our usage timestamp should be correct. - rv = memory1.Purge(Time::FromDoubleT(4)); - EXPECT_TRUE(rv); - - // Lock should fail as memory has been purged. - DiscardableSharedMemory::LockResult lock_rv = memory2.Lock(0, 0); - EXPECT_EQ(DiscardableSharedMemory::FAILED, lock_rv); - - ASSERT_FALSE(memory2.IsMemoryResident()); -} - -TEST(DiscardableSharedMemoryTest, LastUsed) { - const uint32_t kDataSize = 1024; - - TestDiscardableSharedMemory memory1; - bool rv = memory1.CreateAndMap(kDataSize); - ASSERT_TRUE(rv); - - UnsafeSharedMemoryRegion shared_region = memory1.DuplicateRegion(); - ASSERT_TRUE(shared_region.IsValid()); - - TestDiscardableSharedMemory memory2(std::move(shared_region)); - rv = memory2.Map(kDataSize); - ASSERT_TRUE(rv); - - memory2.SetNow(Time::FromDoubleT(1)); - memory2.Unlock(0, 0); - - EXPECT_EQ(memory2.last_known_usage(), Time::FromDoubleT(1)); - - DiscardableSharedMemory::LockResult lock_rv = memory2.Lock(0, 0); - EXPECT_EQ(DiscardableSharedMemory::SUCCESS, lock_rv); - - // This should fail as memory is locked. - rv = memory1.Purge(Time::FromDoubleT(2)); - ASSERT_FALSE(rv); - - // Last usage should have been updated to timestamp passed to Purge above. - EXPECT_EQ(memory1.last_known_usage(), Time::FromDoubleT(2)); - - memory2.SetNow(Time::FromDoubleT(3)); - memory2.Unlock(0, 0); - - // Usage time should be correct for |memory2| instance. - EXPECT_EQ(memory2.last_known_usage(), Time::FromDoubleT(3)); - - // However, usage time has not changed as far as |memory1| instance knows. - EXPECT_EQ(memory1.last_known_usage(), Time::FromDoubleT(2)); - - // Memory is unlocked, but our usage timestamp is incorrect. - rv = memory1.Purge(Time::FromDoubleT(4)); - EXPECT_FALSE(rv); - - // The failed purge attempt should have updated usage time to the correct - // value. - EXPECT_EQ(memory1.last_known_usage(), Time::FromDoubleT(3)); - - // Purge memory through |memory2| instance. The last usage time should be - // set to 0 as a result of this. - rv = memory2.Purge(Time::FromDoubleT(5)); - EXPECT_TRUE(rv); - EXPECT_TRUE(memory2.last_known_usage().is_null()); - - // This should fail as memory has already been purged and |memory1|'s usage - // time is incorrect as a result. - rv = memory1.Purge(Time::FromDoubleT(6)); - EXPECT_FALSE(rv); - - // The failed purge attempt should have updated usage time to the correct - // value. - EXPECT_TRUE(memory1.last_known_usage().is_null()); - - // Purge should succeed now that usage time is correct. - rv = memory1.Purge(Time::FromDoubleT(7)); - EXPECT_TRUE(rv); -} - -TEST(DiscardableSharedMemoryTest, LockShouldAlwaysFailAfterSuccessfulPurge) { - const uint32_t kDataSize = 1024; - - TestDiscardableSharedMemory memory1; - bool rv = memory1.CreateAndMap(kDataSize); - ASSERT_TRUE(rv); - - UnsafeSharedMemoryRegion shared_region = memory1.DuplicateRegion(); - ASSERT_TRUE(shared_region.IsValid()); - - TestDiscardableSharedMemory memory2(std::move(shared_region)); - rv = memory2.Map(kDataSize); - ASSERT_TRUE(rv); - - memory2.SetNow(Time::FromDoubleT(1)); - memory2.Unlock(0, 0); - - rv = memory2.Purge(Time::FromDoubleT(2)); - EXPECT_TRUE(rv); - - // Lock should fail as memory has been purged. - DiscardableSharedMemory::LockResult lock_rv = memory2.Lock(0, 0); - EXPECT_EQ(DiscardableSharedMemory::FAILED, lock_rv); -} - -#if defined(OS_ANDROID) -TEST(DiscardableSharedMemoryTest, LockShouldFailIfPlatformLockPagesFails) { - const uint32_t kDataSize = 1024; - - DiscardableSharedMemory memory1; - bool rv1 = memory1.CreateAndMap(kDataSize); - ASSERT_TRUE(rv1); - - base::UnsafeSharedMemoryRegion region = memory1.DuplicateRegion(); - int fd = region.GetPlatformHandle(); - DiscardableSharedMemory memory2(std::move(region)); - bool rv2 = memory2.Map(kDataSize); - ASSERT_TRUE(rv2); - - // Unlock() the first page of memory, so we can test Lock()ing it. - memory2.Unlock(0, base::GetPageSize()); - // To cause ashmem_pin_region() to fail, we arrange for it to be called with - // an invalid file-descriptor, which requires a valid-looking fd (i.e. we - // can't just Close() |memory|), but one on which the operation is invalid. - // We can overwrite the |memory| fd with a handle to a different file using - // dup2(), which has the nice properties that |memory| still has a valid fd - // that it can close, etc without errors, but on which ashmem_pin_region() - // will fail. - base::ScopedFD null(open("/dev/null", O_RDONLY)); - ASSERT_EQ(fd, dup2(null.get(), fd)); - - // Now re-Lock()ing the first page should fail. - DiscardableSharedMemory::LockResult lock_rv = - memory2.Lock(0, base::GetPageSize()); - EXPECT_EQ(DiscardableSharedMemory::FAILED, lock_rv); -} -#endif // defined(OS_ANDROID) - -TEST(DiscardableSharedMemoryTest, LockAndUnlockRange) { - const uint32_t kDataSize = 32; - - uint32_t data_size_in_bytes = kDataSize * base::GetPageSize(); - - TestDiscardableSharedMemory memory1; - bool rv = memory1.CreateAndMap(data_size_in_bytes); - ASSERT_TRUE(rv); - - UnsafeSharedMemoryRegion shared_region = memory1.DuplicateRegion(); - ASSERT_TRUE(shared_region.IsValid()); - - TestDiscardableSharedMemory memory2(std::move(shared_region)); - rv = memory2.Map(data_size_in_bytes); - ASSERT_TRUE(rv); - - // Unlock first page. - memory2.SetNow(Time::FromDoubleT(1)); - memory2.Unlock(0, base::GetPageSize()); - - rv = memory1.Purge(Time::FromDoubleT(2)); - EXPECT_FALSE(rv); - - // Lock first page again. - memory2.SetNow(Time::FromDoubleT(3)); - DiscardableSharedMemory::LockResult lock_rv = - memory2.Lock(0, base::GetPageSize()); - EXPECT_NE(DiscardableSharedMemory::FAILED, lock_rv); - - // Unlock first page. - memory2.SetNow(Time::FromDoubleT(4)); - memory2.Unlock(0, base::GetPageSize()); - - rv = memory1.Purge(Time::FromDoubleT(5)); - EXPECT_FALSE(rv); - - // Unlock second page. - memory2.SetNow(Time::FromDoubleT(6)); - memory2.Unlock(base::GetPageSize(), base::GetPageSize()); - - rv = memory1.Purge(Time::FromDoubleT(7)); - EXPECT_FALSE(rv); - - // Unlock anything onwards. - memory2.SetNow(Time::FromDoubleT(8)); - memory2.Unlock(2 * base::GetPageSize(), 0); - - // Memory is unlocked, but our usage timestamp is incorrect. - rv = memory1.Purge(Time::FromDoubleT(9)); - EXPECT_FALSE(rv); - - // The failed purge attempt should have updated usage time to the correct - // value. - EXPECT_EQ(Time::FromDoubleT(8), memory1.last_known_usage()); - - // Purge should now succeed. - rv = memory1.Purge(Time::FromDoubleT(10)); - EXPECT_TRUE(rv); -} - -TEST(DiscardableSharedMemoryTest, MappedSize) { - const uint32_t kDataSize = 1024; - - TestDiscardableSharedMemory memory; - bool rv = memory.CreateAndMap(kDataSize); - ASSERT_TRUE(rv); - - EXPECT_LE(kDataSize, memory.mapped_size()); - - // Mapped size should be 0 after memory segment has been unmapped. - rv = memory.Unmap(); - EXPECT_TRUE(rv); - EXPECT_EQ(0u, memory.mapped_size()); -} - -TEST(DiscardableSharedMemoryTest, Close) { - const uint32_t kDataSize = 1024; - - TestDiscardableSharedMemory memory; - bool rv = memory.CreateAndMap(kDataSize); - ASSERT_TRUE(rv); - - // Mapped size should be unchanged after memory segment has been closed. - memory.Close(); - EXPECT_LE(kDataSize, memory.mapped_size()); - - // Memory is initially locked. Unlock it. - memory.SetNow(Time::FromDoubleT(1)); - memory.Unlock(0, 0); - - // Lock and unlock memory. - DiscardableSharedMemory::LockResult lock_rv = memory.Lock(0, 0); - EXPECT_EQ(DiscardableSharedMemory::SUCCESS, lock_rv); - memory.SetNow(Time::FromDoubleT(2)); - memory.Unlock(0, 0); -} - -TEST(DiscardableSharedMemoryTest, ZeroSize) { - TestDiscardableSharedMemory memory; - bool rv = memory.CreateAndMap(0); - ASSERT_TRUE(rv); - - EXPECT_LE(0u, memory.mapped_size()); - - // Memory is initially locked. Unlock it. - memory.SetNow(Time::FromDoubleT(1)); - memory.Unlock(0, 0); - - // Lock and unlock memory. - DiscardableSharedMemory::LockResult lock_rv = memory.Lock(0, 0); - EXPECT_NE(DiscardableSharedMemory::FAILED, lock_rv); - memory.SetNow(Time::FromDoubleT(2)); - memory.Unlock(0, 0); -} - -// This test checks that zero-filled pages are returned after purging a segment -// when DISCARDABLE_SHARED_MEMORY_ZERO_FILL_ON_DEMAND_PAGES_AFTER_PURGE is -// defined and MADV_REMOVE is supported. -#if defined(DISCARDABLE_SHARED_MEMORY_ZERO_FILL_ON_DEMAND_PAGES_AFTER_PURGE) -TEST(DiscardableSharedMemoryTest, ZeroFilledPagesAfterPurge) { - const uint32_t kDataSize = 1024; - - TestDiscardableSharedMemory memory1; - bool rv = memory1.CreateAndMap(kDataSize); - ASSERT_TRUE(rv); - - UnsafeSharedMemoryRegion shared_region = memory1.DuplicateRegion(); - ASSERT_TRUE(shared_region.IsValid()); - - TestDiscardableSharedMemory memory2(std::move(shared_region)); - rv = memory2.Map(kDataSize); - ASSERT_TRUE(rv); - - // Initialize all memory to '0xaa'. - memset(memory2.memory(), 0xaa, kDataSize); - - // Unlock memory. - memory2.SetNow(Time::FromDoubleT(1)); - memory2.Unlock(0, 0); - EXPECT_FALSE(memory1.IsMemoryLocked()); - - // Memory is unlocked, but our usage timestamp is incorrect. - rv = memory1.Purge(Time::FromDoubleT(2)); - EXPECT_FALSE(rv); - rv = memory1.Purge(Time::FromDoubleT(3)); - EXPECT_TRUE(rv); - - // Check that reading memory after it has been purged is returning - // zero-filled pages. - uint8_t expected_data[kDataSize] = {}; - EXPECT_EQ(memcmp(memory2.memory(), expected_data, kDataSize), 0); -} -#endif - -TEST(DiscardableSharedMemoryTest, TracingOwnershipEdges) { - const uint32_t kDataSize = 1024; - TestDiscardableSharedMemory memory1; - bool rv = memory1.CreateAndMap(kDataSize); - ASSERT_TRUE(rv); - - base::trace_event::MemoryDumpArgs args = { - base::trace_event::MemoryDumpLevelOfDetail::DETAILED}; - trace_event::ProcessMemoryDump pmd(nullptr, args); - trace_event::MemoryAllocatorDump* client_dump = - pmd.CreateAllocatorDump("discardable_manager/map1"); - const bool is_owned = false; - memory1.CreateSharedMemoryOwnershipEdge(client_dump, &pmd, is_owned); - const auto* shm_dump = pmd.GetAllocatorDump( - SharedMemoryTracker::GetDumpNameForTracing(memory1.mapped_id())); - EXPECT_TRUE(shm_dump); - EXPECT_EQ(shm_dump->GetSizeInternal(), client_dump->GetSizeInternal()); - const auto edges = pmd.allocator_dumps_edges(); - EXPECT_EQ(2u, edges.size()); - EXPECT_NE(edges.end(), edges.find(shm_dump->guid())); - EXPECT_NE(edges.end(), edges.find(client_dump->guid())); - // TODO(ssid): test for weak global dump once the - // CreateWeakSharedMemoryOwnershipEdge() is fixed, crbug.com/661257. -} - -} // namespace base
diff --git a/base/memory/linked_ptr_unittest.cc b/base/memory/linked_ptr_unittest.cc deleted file mode 100644 index 344ffa4..0000000 --- a/base/memory/linked_ptr_unittest.cc +++ /dev/null
@@ -1,108 +0,0 @@ -// 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 <string> - -#include "base/memory/linked_ptr.h" -#include "base/strings/stringprintf.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -int num = 0; - -std::string history; - -// Class which tracks allocation/deallocation -struct A { - A(): mynum(num++) { history += base::StringPrintf("A%d ctor\n", mynum); } - virtual ~A() { history += base::StringPrintf("A%d dtor\n", mynum); } - virtual void Use() { history += base::StringPrintf("A%d use\n", mynum); } - int mynum; -}; - -// Subclass -struct B: public A { - B() { history += base::StringPrintf("B%d ctor\n", mynum); } - ~B() override { history += base::StringPrintf("B%d dtor\n", mynum); } - void Use() override { history += base::StringPrintf("B%d use\n", mynum); } -}; - -} // namespace - -TEST(LinkedPtrTest, Test) { - { - linked_ptr<A> a0, a1, a2; - a0 = *&a0; // The *& defeats Clang's -Wself-assign warning. - a1 = a2; - ASSERT_EQ(a0.get(), static_cast<A*>(nullptr)); - ASSERT_EQ(a1.get(), static_cast<A*>(nullptr)); - ASSERT_EQ(a2.get(), static_cast<A*>(nullptr)); - ASSERT_TRUE(a0 == nullptr); - ASSERT_TRUE(a1 == nullptr); - ASSERT_TRUE(a2 == nullptr); - - { - linked_ptr<A> a3(new A); - a0 = a3; - ASSERT_TRUE(a0 == a3); - ASSERT_TRUE(a0 != nullptr); - ASSERT_TRUE(a0.get() == a3); - ASSERT_TRUE(a0 == a3.get()); - linked_ptr<A> a4(a0); - a1 = a4; - linked_ptr<A> a5(new A); - ASSERT_TRUE(a5.get() != a3); - ASSERT_TRUE(a5 != a3.get()); - a2 = a5; - linked_ptr<B> b0(new B); - linked_ptr<A> a6(b0); - ASSERT_TRUE(b0 == a6); - ASSERT_TRUE(a6 == b0); - ASSERT_TRUE(b0 != nullptr); - a5 = b0; - a5 = b0; - a3->Use(); - a4->Use(); - a5->Use(); - a6->Use(); - b0->Use(); - (*b0).Use(); - b0.get()->Use(); - } - - a0->Use(); - a1->Use(); - a2->Use(); - - a1 = a2; - a2.reset(new A); - a0.reset(); - - linked_ptr<A> a7; - } - - ASSERT_EQ(history, - "A0 ctor\n" - "A1 ctor\n" - "A2 ctor\n" - "B2 ctor\n" - "A0 use\n" - "A0 use\n" - "B2 use\n" - "B2 use\n" - "B2 use\n" - "B2 use\n" - "B2 use\n" - "B2 dtor\n" - "A2 dtor\n" - "A0 use\n" - "A0 use\n" - "A1 use\n" - "A3 ctor\n" - "A0 dtor\n" - "A3 dtor\n" - "A1 dtor\n" - ); -}
diff --git a/base/memory/memory_coordinator_client_registry_unittest.cc b/base/memory/memory_coordinator_client_registry_unittest.cc deleted file mode 100644 index 37ed767..0000000 --- a/base/memory/memory_coordinator_client_registry_unittest.cc +++ /dev/null
@@ -1,58 +0,0 @@ -// 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/memory/memory_coordinator_client_registry.h" - -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -class TestMemoryCoordinatorClient : public MemoryCoordinatorClient { - public: - void OnMemoryStateChange(MemoryState state) override { state_ = state; } - - void OnPurgeMemory() override { ++purge_count_; } - - MemoryState state() const { return state_; } - size_t purge_count() const { return purge_count_; } - - private: - MemoryState state_ = MemoryState::UNKNOWN; - size_t purge_count_ = 0; -}; - -void RunUntilIdle() { - base::RunLoop loop; - loop.RunUntilIdle(); -} - -TEST(MemoryCoordinatorClientRegistryTest, NotifyStateChange) { - MessageLoop loop; - auto* registry = MemoryCoordinatorClientRegistry::GetInstance(); - TestMemoryCoordinatorClient client; - registry->Register(&client); - registry->Notify(MemoryState::THROTTLED); - RunUntilIdle(); - ASSERT_EQ(MemoryState::THROTTLED, client.state()); - registry->Unregister(&client); -} - -TEST(MemoryCoordinatorClientRegistryTest, PurgeMemory) { - MessageLoop loop; - auto* registry = MemoryCoordinatorClientRegistry::GetInstance(); - TestMemoryCoordinatorClient client; - registry->Register(&client); - registry->PurgeMemory(); - RunUntilIdle(); - ASSERT_EQ(1u, client.purge_count()); - registry->Unregister(&client); -} - -} // namespace - -} // namespace base
diff --git a/base/memory/memory_pressure_listener_unittest.cc b/base/memory/memory_pressure_listener_unittest.cc deleted file mode 100644 index 87d5f4c..0000000 --- a/base/memory/memory_pressure_listener_unittest.cc +++ /dev/null
@@ -1,79 +0,0 @@ -// 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/memory/memory_pressure_listener.h" - -#include "base/bind.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "testing/gmock/include/gmock/gmock.h" - -namespace base { - -using MemoryPressureLevel = MemoryPressureListener::MemoryPressureLevel; - -class MemoryPressureListenerTest : public testing::Test { - public: - void SetUp() override { - message_loop_.reset(new MessageLoopForUI()); - listener_.reset(new MemoryPressureListener( - Bind(&MemoryPressureListenerTest::OnMemoryPressure, Unretained(this)))); - } - - void TearDown() override { - listener_.reset(); - message_loop_.reset(); - } - - protected: - void ExpectNotification( - void (*notification_function)(MemoryPressureLevel), - MemoryPressureLevel level) { - EXPECT_CALL(*this, OnMemoryPressure(level)).Times(1); - notification_function(level); - RunLoop().RunUntilIdle(); - } - - void ExpectNoNotification( - void (*notification_function)(MemoryPressureLevel), - MemoryPressureLevel level) { - EXPECT_CALL(*this, OnMemoryPressure(testing::_)).Times(0); - notification_function(level); - RunLoop().RunUntilIdle(); - } - - private: - MOCK_METHOD1(OnMemoryPressure, - void(MemoryPressureListener::MemoryPressureLevel)); - - std::unique_ptr<MessageLoopForUI> message_loop_; - std::unique_ptr<MemoryPressureListener> listener_; -}; - -TEST_F(MemoryPressureListenerTest, NotifyMemoryPressure) { - // Memory pressure notifications are not suppressed by default. - EXPECT_FALSE(MemoryPressureListener::AreNotificationsSuppressed()); - ExpectNotification(&MemoryPressureListener::NotifyMemoryPressure, - MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_MODERATE); - ExpectNotification(&MemoryPressureListener::SimulatePressureNotification, - MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_MODERATE); - - // Enable suppressing memory pressure notifications. - MemoryPressureListener::SetNotificationsSuppressed(true); - EXPECT_TRUE(MemoryPressureListener::AreNotificationsSuppressed()); - ExpectNoNotification(&MemoryPressureListener::NotifyMemoryPressure, - MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_MODERATE); - ExpectNotification(&MemoryPressureListener::SimulatePressureNotification, - MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_MODERATE); - - // Disable suppressing memory pressure notifications. - MemoryPressureListener::SetNotificationsSuppressed(false); - EXPECT_FALSE(MemoryPressureListener::AreNotificationsSuppressed()); - ExpectNotification(&MemoryPressureListener::NotifyMemoryPressure, - MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_CRITICAL); - ExpectNotification(&MemoryPressureListener::SimulatePressureNotification, - MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_CRITICAL); -} - -} // namespace base
diff --git a/base/memory/memory_pressure_monitor_chromeos_unittest.cc b/base/memory/memory_pressure_monitor_chromeos_unittest.cc deleted file mode 100644 index ee00091..0000000 --- a/base/memory/memory_pressure_monitor_chromeos_unittest.cc +++ /dev/null
@@ -1,172 +0,0 @@ -// 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/memory/memory_pressure_monitor_chromeos.h" - -#include "base/macros.h" -#include "base/memory/memory_pressure_listener.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "base/sys_info.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace chromeos { - -namespace { - -// True if the memory notifier got called. -// Do not read/modify value directly. -bool on_memory_pressure_called = false; - -// If the memory notifier got called, this is the memory pressure reported. -MemoryPressureListener::MemoryPressureLevel on_memory_pressure_level = - MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE; - -// Processes OnMemoryPressure calls. -void OnMemoryPressure(MemoryPressureListener::MemoryPressureLevel level) { - on_memory_pressure_called = true; - on_memory_pressure_level = level; -} - -// Resets the indicator for memory pressure. -void ResetOnMemoryPressureCalled() { - on_memory_pressure_called = false; -} - -// Returns true when OnMemoryPressure was called (and resets it). -bool WasOnMemoryPressureCalled() { - bool b = on_memory_pressure_called; - ResetOnMemoryPressureCalled(); - return b; -} - -} // namespace - -class TestMemoryPressureMonitor : public MemoryPressureMonitor { - public: - TestMemoryPressureMonitor() - : MemoryPressureMonitor(THRESHOLD_DEFAULT), - memory_in_percent_override_(0) { - // Disable any timers which are going on and set a special memory reporting - // function. - StopObserving(); - } - ~TestMemoryPressureMonitor() override = default; - - void SetMemoryInPercentOverride(int percent) { - memory_in_percent_override_ = percent; - } - - void CheckMemoryPressureForTest() { - CheckMemoryPressure(); - } - - private: - int GetUsedMemoryInPercent() override { - return memory_in_percent_override_; - } - - int memory_in_percent_override_; - DISALLOW_COPY_AND_ASSIGN(TestMemoryPressureMonitor); -}; - -// This test tests the various transition states from memory pressure, looking -// for the correct behavior on event reposting as well as state updates. -TEST(ChromeOSMemoryPressureMonitorTest, CheckMemoryPressure) { - // crbug.com/844102: - if (base::SysInfo::IsRunningOnChromeOS()) - return; - - base::MessageLoopForUI message_loop; - std::unique_ptr<TestMemoryPressureMonitor> monitor( - new TestMemoryPressureMonitor); - std::unique_ptr<MemoryPressureListener> listener( - new MemoryPressureListener(base::Bind(&OnMemoryPressure))); - // Checking the memory pressure while 0% are used should not produce any - // events. - monitor->SetMemoryInPercentOverride(0); - ResetOnMemoryPressureCalled(); - - monitor->CheckMemoryPressureForTest(); - RunLoop().RunUntilIdle(); - EXPECT_FALSE(WasOnMemoryPressureCalled()); - EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE, - monitor->GetCurrentPressureLevel()); - - // Setting the memory level to 80% should produce a moderate pressure level. - monitor->SetMemoryInPercentOverride(80); - monitor->CheckMemoryPressureForTest(); - RunLoop().RunUntilIdle(); - EXPECT_TRUE(WasOnMemoryPressureCalled()); - EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE, - monitor->GetCurrentPressureLevel()); - EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE, - on_memory_pressure_level); - - // We need to check that the event gets reposted after a while. - int i = 0; - for (; i < 100; i++) { - monitor->CheckMemoryPressureForTest(); - RunLoop().RunUntilIdle(); - EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE, - monitor->GetCurrentPressureLevel()); - if (WasOnMemoryPressureCalled()) { - EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE, - on_memory_pressure_level); - break; - } - } - // Should be more than 5 and less than 100. - EXPECT_LE(5, i); - EXPECT_GE(99, i); - - // Setting the memory usage to 99% should produce critical levels. - monitor->SetMemoryInPercentOverride(99); - monitor->CheckMemoryPressureForTest(); - RunLoop().RunUntilIdle(); - EXPECT_TRUE(WasOnMemoryPressureCalled()); - EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL, - on_memory_pressure_level); - EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL, - monitor->GetCurrentPressureLevel()); - - // Calling it again should immediately produce a second call. - monitor->CheckMemoryPressureForTest(); - RunLoop().RunUntilIdle(); - EXPECT_TRUE(WasOnMemoryPressureCalled()); - EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL, - on_memory_pressure_level); - EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL, - monitor->GetCurrentPressureLevel()); - - // When lowering the pressure again we should not get an event, but the - // pressure should go back to moderate. - monitor->SetMemoryInPercentOverride(80); - monitor->CheckMemoryPressureForTest(); - RunLoop().RunUntilIdle(); - EXPECT_FALSE(WasOnMemoryPressureCalled()); - EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE, - monitor->GetCurrentPressureLevel()); - - // We should need exactly the same amount of calls as before, before the next - // call comes in. - int j = 0; - for (; j < 100; j++) { - monitor->CheckMemoryPressureForTest(); - RunLoop().RunUntilIdle(); - EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE, - monitor->GetCurrentPressureLevel()); - if (WasOnMemoryPressureCalled()) { - EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE, - on_memory_pressure_level); - break; - } - } - // We should have needed exactly the same amount of checks as before. - EXPECT_EQ(j, i); -} - -} // namespace chromeos -} // namespace base
diff --git a/base/memory/memory_pressure_monitor_mac_unittest.cc b/base/memory/memory_pressure_monitor_mac_unittest.cc deleted file mode 100644 index ff464fb..0000000 --- a/base/memory/memory_pressure_monitor_mac_unittest.cc +++ /dev/null
@@ -1,228 +0,0 @@ -// 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/memory/memory_pressure_monitor_mac.h" - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/mac/scoped_cftyperef.h" -#include "base/macros.h" -#include "base/test/histogram_tester.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace mac { - -class TestMemoryPressureMonitor : public MemoryPressureMonitor { - public: - using MemoryPressureMonitor::MemoryPressureLevelForMacMemoryPressureLevel; - - // A HistogramTester for verifying correct UMA stat generation. - base::HistogramTester tester; - - TestMemoryPressureMonitor() { } - - // Clears the next run loop update time so that the next pass of the run - // loop checks the memory pressure level immediately. Normally there's a - // 5 second delay between pressure readings. - void ResetRunLoopUpdateTime() { next_run_loop_update_time_ = 0; } - - // Sets the last UMA stat report time. Time spent in memory pressure is - // recorded in 5-second "ticks" from the last time statistics were recorded. - void SetLastStatisticReportTime(CFTimeInterval time) { - last_statistic_report_time_ = time; - } - - // Sets the raw macOS memory pressure level read by the memory pressure - // monitor. - int macos_pressure_level_for_testing_; - - // Exposes the UpdatePressureLevel() method for testing. - void UpdatePressureLevel() { MemoryPressureMonitor::UpdatePressureLevel(); } - - // Returns the number of seconds left over from the last UMA tick - // calculation. - int SubTickSeconds() { return subtick_seconds_; } - - // Returns the number of seconds per UMA tick. - static int GetSecondsPerUMATick() { - return MemoryPressureMonitor::GetSecondsPerUMATick(); - } - - private: - DISALLOW_COPY_AND_ASSIGN(TestMemoryPressureMonitor); - - int GetMacMemoryPressureLevel() override { - return macos_pressure_level_for_testing_; - } -}; - -TEST(MacMemoryPressureMonitorTest, MemoryPressureFromMacMemoryPressure) { - EXPECT_EQ( - MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE, - TestMemoryPressureMonitor::MemoryPressureLevelForMacMemoryPressureLevel( - DISPATCH_MEMORYPRESSURE_NORMAL)); - EXPECT_EQ( - MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE, - TestMemoryPressureMonitor::MemoryPressureLevelForMacMemoryPressureLevel( - DISPATCH_MEMORYPRESSURE_WARN)); - EXPECT_EQ( - MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL, - TestMemoryPressureMonitor::MemoryPressureLevelForMacMemoryPressureLevel( - DISPATCH_MEMORYPRESSURE_CRITICAL)); - EXPECT_EQ( - MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE, - TestMemoryPressureMonitor::MemoryPressureLevelForMacMemoryPressureLevel( - 0)); - EXPECT_EQ( - MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE, - TestMemoryPressureMonitor::MemoryPressureLevelForMacMemoryPressureLevel( - 3)); - EXPECT_EQ( - MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE, - TestMemoryPressureMonitor::MemoryPressureLevelForMacMemoryPressureLevel( - 5)); - EXPECT_EQ( - MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE, - TestMemoryPressureMonitor::MemoryPressureLevelForMacMemoryPressureLevel( - -1)); -} - -TEST(MacMemoryPressureMonitorTest, CurrentMemoryPressure) { - TestMemoryPressureMonitor monitor; - - MemoryPressureListener::MemoryPressureLevel memory_pressure = - monitor.GetCurrentPressureLevel(); - EXPECT_TRUE(memory_pressure == - MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE || - memory_pressure == - MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE || - memory_pressure == - MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL); -} - -TEST(MacMemoryPressureMonitorTest, MemoryPressureConversion) { - TestMemoryPressureMonitor monitor; - - monitor.macos_pressure_level_for_testing_ = DISPATCH_MEMORYPRESSURE_NORMAL; - monitor.UpdatePressureLevel(); - MemoryPressureListener::MemoryPressureLevel memory_pressure = - monitor.GetCurrentPressureLevel(); - EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE, - memory_pressure); - - monitor.macos_pressure_level_for_testing_ = DISPATCH_MEMORYPRESSURE_WARN; - monitor.UpdatePressureLevel(); - memory_pressure = monitor.GetCurrentPressureLevel(); - EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE, - memory_pressure); - - monitor.macos_pressure_level_for_testing_ = DISPATCH_MEMORYPRESSURE_CRITICAL; - monitor.UpdatePressureLevel(); - memory_pressure = monitor.GetCurrentPressureLevel(); - EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL, - memory_pressure); -} - -TEST(MacMemoryPressureMonitorTest, MemoryPressureRunLoopChecking) { - TestMemoryPressureMonitor monitor; - - // To test grabbing the memory presure at the end of the run loop, we have to - // run the run loop, but to do that the run loop needs a run loop source. Add - // a timer as the source. We know that the exit observer is attached to - // the kMessageLoopExclusiveRunLoopMode mode, so use that mode. - ScopedCFTypeRef<CFRunLoopTimerRef> timer_ref(CFRunLoopTimerCreate( - NULL, CFAbsoluteTimeGetCurrent() + 10, 0, 0, 0, nullptr, nullptr)); - CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer_ref, - kMessageLoopExclusiveRunLoopMode); - - monitor.macos_pressure_level_for_testing_ = DISPATCH_MEMORYPRESSURE_WARN; - monitor.ResetRunLoopUpdateTime(); - CFRunLoopRunInMode(kMessageLoopExclusiveRunLoopMode, 0, true); - EXPECT_EQ(monitor.GetCurrentPressureLevel(), - MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE); - - monitor.macos_pressure_level_for_testing_ = DISPATCH_MEMORYPRESSURE_CRITICAL; - monitor.ResetRunLoopUpdateTime(); - CFRunLoopRunInMode(kMessageLoopExclusiveRunLoopMode, 0, true); - EXPECT_EQ(monitor.GetCurrentPressureLevel(), - MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL); - - monitor.macos_pressure_level_for_testing_ = DISPATCH_MEMORYPRESSURE_NORMAL; - monitor.ResetRunLoopUpdateTime(); - CFRunLoopRunInMode(kMessageLoopExclusiveRunLoopMode, 0, true); - EXPECT_EQ(monitor.GetCurrentPressureLevel(), - MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE); - - CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), timer_ref, - kMessageLoopExclusiveRunLoopMode); -} - -TEST(MacMemoryPressureMonitorTest, RecordMemoryPressureStats) { - TestMemoryPressureMonitor monitor; - const char* kHistogram = "Memory.PressureLevel"; - CFTimeInterval now = CFAbsoluteTimeGetCurrent(); - const int seconds_per_tick = - TestMemoryPressureMonitor::GetSecondsPerUMATick(); - - // Set the initial pressure level. - monitor.macos_pressure_level_for_testing_ = DISPATCH_MEMORYPRESSURE_NORMAL; - // Incur one UMA tick of time (and include one extra second of elapsed time). - monitor.SetLastStatisticReportTime(now - (seconds_per_tick + 1)); - monitor.UpdatePressureLevel(); - monitor.tester.ExpectTotalCount(kHistogram, 1); - monitor.tester.ExpectBucketCount(kHistogram, 0, 1); - // The report time above included an extra second so there should be 1 - // sub-tick second left over. - EXPECT_EQ(1, monitor.SubTickSeconds()); - - // Simulate sitting in normal pressure for 1 second less than 6 UMA tick - // seconds and then elevating to warning. With the left over sub-tick second - // from above, the total elapsed ticks should be an even 6 UMA ticks. - monitor.macos_pressure_level_for_testing_ = DISPATCH_MEMORYPRESSURE_WARN; - monitor.SetLastStatisticReportTime(now - (seconds_per_tick * 6 - 1)); - monitor.UpdatePressureLevel(); - monitor.tester.ExpectTotalCount(kHistogram, 7); - monitor.tester.ExpectBucketCount(kHistogram, 0, 7); - monitor.tester.ExpectBucketCount(kHistogram, 1, 0); - EXPECT_EQ(0, monitor.SubTickSeconds()); - - // Simulate sitting in warning pressure for 20 UMA ticks and 2 seconds, and - // then elevating to critical. - monitor.macos_pressure_level_for_testing_ = DISPATCH_MEMORYPRESSURE_CRITICAL; - monitor.SetLastStatisticReportTime(now - (20 * seconds_per_tick + 2)); - monitor.UpdatePressureLevel(); - monitor.tester.ExpectTotalCount(kHistogram, 27); - monitor.tester.ExpectBucketCount(kHistogram, 0, 7); - monitor.tester.ExpectBucketCount(kHistogram, 1, 20); - monitor.tester.ExpectBucketCount(kHistogram, 2, 0); - EXPECT_EQ(2, monitor.SubTickSeconds()); - - // A quick update while critical - the stats should not budge because less - // than 1 tick of time has elapsed. - monitor.macos_pressure_level_for_testing_ = DISPATCH_MEMORYPRESSURE_CRITICAL; - monitor.SetLastStatisticReportTime(now - 1); - monitor.UpdatePressureLevel(); - monitor.tester.ExpectTotalCount(kHistogram, 27); - monitor.tester.ExpectBucketCount(kHistogram, 0, 7); - monitor.tester.ExpectBucketCount(kHistogram, 1, 20); - monitor.tester.ExpectBucketCount(kHistogram, 2, 0); - EXPECT_EQ(3, monitor.SubTickSeconds()); - - // A quick change back to normal. Less than 1 tick of time has elapsed, but - // in this case the pressure level changed, so the critical bucket should - // get another sample (otherwise we could miss quick level changes). - monitor.macos_pressure_level_for_testing_ = DISPATCH_MEMORYPRESSURE_NORMAL; - monitor.SetLastStatisticReportTime(now - 1); - monitor.UpdatePressureLevel(); - monitor.tester.ExpectTotalCount(kHistogram, 28); - monitor.tester.ExpectBucketCount(kHistogram, 0, 7); - monitor.tester.ExpectBucketCount(kHistogram, 1, 20); - monitor.tester.ExpectBucketCount(kHistogram, 2, 1); - // When less than 1 tick of time has elapsed but the pressure level changed, - // the subtick remainder gets zeroed out. - EXPECT_EQ(0, monitor.SubTickSeconds()); -} -} // namespace mac -} // namespace base
diff --git a/base/memory/memory_pressure_monitor_unittest.cc b/base/memory/memory_pressure_monitor_unittest.cc deleted file mode 100644 index e974741..0000000 --- a/base/memory/memory_pressure_monitor_unittest.cc +++ /dev/null
@@ -1,33 +0,0 @@ -// 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/memory/memory_pressure_monitor.h" - -#include "base/macros.h" -#include "base/memory/memory_pressure_listener.h" -#include "base/test/histogram_tester.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(MemoryPressureMonitorTest, RecordMemoryPressure) { - base::HistogramTester tester; - const char* kHistogram = "Memory.PressureLevel"; - - MemoryPressureMonitor::RecordMemoryPressure( - MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE, 3); - tester.ExpectTotalCount(kHistogram, 3); - tester.ExpectBucketCount(kHistogram, 0, 3); - - MemoryPressureMonitor::RecordMemoryPressure( - MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE, 2); - tester.ExpectTotalCount(kHistogram, 5); - tester.ExpectBucketCount(kHistogram, 1, 2); - - MemoryPressureMonitor::RecordMemoryPressure( - MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL, 1); - tester.ExpectTotalCount(kHistogram, 6); - tester.ExpectBucketCount(kHistogram, 2, 1); -} -} // namespace base
diff --git a/base/memory/memory_pressure_monitor_win_unittest.cc b/base/memory/memory_pressure_monitor_win_unittest.cc deleted file mode 100644 index 1002a01..0000000 --- a/base/memory/memory_pressure_monitor_win_unittest.cc +++ /dev/null
@@ -1,299 +0,0 @@ -// 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/memory/memory_pressure_monitor_win.h" - -#include "base/macros.h" -#include "base/memory/memory_pressure_listener.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace win { - -namespace { - -struct PressureSettings { - int phys_left_mb; - MemoryPressureListener::MemoryPressureLevel level; -}; - -} // namespace - -// This is outside of the anonymous namespace so that it can be seen as a friend -// to the monitor class. -class TestMemoryPressureMonitor : public MemoryPressureMonitor { - public: - using MemoryPressureMonitor::CalculateCurrentPressureLevel; - using MemoryPressureMonitor::CheckMemoryPressure; - - static const DWORDLONG kMBBytes = 1024 * 1024; - - explicit TestMemoryPressureMonitor(bool large_memory) - : mem_status_() { - // Generate a plausible amount of memory. - mem_status_.ullTotalPhys = - static_cast<DWORDLONG>(GenerateTotalMemoryMb(large_memory)) * kMBBytes; - - // Rerun InferThresholds using the test fixture's GetSystemMemoryStatus. - InferThresholds(); - // Stop the timer. - StopObserving(); - } - - TestMemoryPressureMonitor(int system_memory_mb, - int moderate_threshold_mb, - int critical_threshold_mb) - : MemoryPressureMonitor(moderate_threshold_mb, critical_threshold_mb), - mem_status_() { - // Set the amount of system memory. - mem_status_.ullTotalPhys = static_cast<DWORDLONG>( - system_memory_mb * kMBBytes); - - // Stop the timer. - StopObserving(); - } - - virtual ~TestMemoryPressureMonitor() {} - - MOCK_METHOD1(OnMemoryPressure, - void(MemoryPressureListener::MemoryPressureLevel level)); - - // Generates an amount of total memory that is consistent with the requested - // memory model. - int GenerateTotalMemoryMb(bool large_memory) { - int total_mb = 64; - while (total_mb < MemoryPressureMonitor::kLargeMemoryThresholdMb) - total_mb *= 2; - if (large_memory) - return total_mb * 2; - return total_mb / 2; - } - - // Sets up the memory status to reflect the provided absolute memory left. - void SetMemoryFree(int phys_left_mb) { - // ullTotalPhys is set in the constructor and not modified. - - // Set the amount of available memory. - mem_status_.ullAvailPhys = - static_cast<DWORDLONG>(phys_left_mb) * kMBBytes; - DCHECK_LT(mem_status_.ullAvailPhys, mem_status_.ullTotalPhys); - - // These fields are unused. - mem_status_.dwMemoryLoad = 0; - mem_status_.ullTotalPageFile = 0; - mem_status_.ullAvailPageFile = 0; - mem_status_.ullTotalVirtual = 0; - mem_status_.ullAvailVirtual = 0; - } - - void SetNone() { - SetMemoryFree(moderate_threshold_mb() + 1); - } - - void SetModerate() { - SetMemoryFree(moderate_threshold_mb() - 1); - } - - void SetCritical() { - SetMemoryFree(critical_threshold_mb() - 1); - } - - private: - bool GetSystemMemoryStatus(MEMORYSTATUSEX* mem_status) override { - // Simply copy the memory status set by the test fixture. - *mem_status = mem_status_; - return true; - } - - MEMORYSTATUSEX mem_status_; - - DISALLOW_COPY_AND_ASSIGN(TestMemoryPressureMonitor); -}; - -class WinMemoryPressureMonitorTest : public testing::Test { - protected: - void CalculateCurrentMemoryPressureLevelTest( - TestMemoryPressureMonitor* monitor) { - - int mod = monitor->moderate_threshold_mb(); - monitor->SetMemoryFree(mod + 1); - EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE, - monitor->CalculateCurrentPressureLevel()); - - monitor->SetMemoryFree(mod); - EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE, - monitor->CalculateCurrentPressureLevel()); - - monitor->SetMemoryFree(mod - 1); - EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE, - monitor->CalculateCurrentPressureLevel()); - - int crit = monitor->critical_threshold_mb(); - monitor->SetMemoryFree(crit + 1); - EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE, - monitor->CalculateCurrentPressureLevel()); - - monitor->SetMemoryFree(crit); - EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL, - monitor->CalculateCurrentPressureLevel()); - - monitor->SetMemoryFree(crit - 1); - EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL, - monitor->CalculateCurrentPressureLevel()); - } - - base::MessageLoopForUI message_loop_; -}; - -// Tests the fundamental direct calculation of memory pressure with automatic -// small-memory thresholds. -TEST_F(WinMemoryPressureMonitorTest, CalculateCurrentMemoryPressureLevelSmall) { - static const int kModerateMb = - MemoryPressureMonitor::kSmallMemoryDefaultModerateThresholdMb; - static const int kCriticalMb = - MemoryPressureMonitor::kSmallMemoryDefaultCriticalThresholdMb; - - TestMemoryPressureMonitor monitor(false); // Small-memory model. - - EXPECT_EQ(kModerateMb, monitor.moderate_threshold_mb()); - EXPECT_EQ(kCriticalMb, monitor.critical_threshold_mb()); - - ASSERT_NO_FATAL_FAILURE(CalculateCurrentMemoryPressureLevelTest(&monitor)); -} - -// Tests the fundamental direct calculation of memory pressure with automatic -// large-memory thresholds. -TEST_F(WinMemoryPressureMonitorTest, CalculateCurrentMemoryPressureLevelLarge) { - static const int kModerateMb = - MemoryPressureMonitor::kLargeMemoryDefaultModerateThresholdMb; - static const int kCriticalMb = - MemoryPressureMonitor::kLargeMemoryDefaultCriticalThresholdMb; - - TestMemoryPressureMonitor monitor(true); // Large-memory model. - - EXPECT_EQ(kModerateMb, monitor.moderate_threshold_mb()); - EXPECT_EQ(kCriticalMb, monitor.critical_threshold_mb()); - - ASSERT_NO_FATAL_FAILURE(CalculateCurrentMemoryPressureLevelTest(&monitor)); -} - -// Tests the fundamental direct calculation of memory pressure with manually -// specified threshold levels. -TEST_F(WinMemoryPressureMonitorTest, - CalculateCurrentMemoryPressureLevelCustom) { - static const int kSystemMb = 512; - static const int kModerateMb = 256; - static const int kCriticalMb = 128; - - TestMemoryPressureMonitor monitor(kSystemMb, kModerateMb, kCriticalMb); - - EXPECT_EQ(kModerateMb, monitor.moderate_threshold_mb()); - EXPECT_EQ(kCriticalMb, monitor.critical_threshold_mb()); - - ASSERT_NO_FATAL_FAILURE(CalculateCurrentMemoryPressureLevelTest(&monitor)); -} - -// This test tests the various transition states from memory pressure, looking -// for the correct behavior on event reposting as well as state updates. -TEST_F(WinMemoryPressureMonitorTest, CheckMemoryPressure) { - // Large-memory. - testing::StrictMock<TestMemoryPressureMonitor> monitor(true); - MemoryPressureListener listener( - base::Bind(&TestMemoryPressureMonitor::OnMemoryPressure, - base::Unretained(&monitor))); - - // Checking the memory pressure at 0% load should not produce any - // events. - monitor.SetNone(); - monitor.CheckMemoryPressure(); - RunLoop().RunUntilIdle(); - EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE, - monitor.GetCurrentPressureLevel()); - - // Setting the memory level to 80% should produce a moderate pressure level. - EXPECT_CALL(monitor, - OnMemoryPressure(MemoryPressureListener:: - MEMORY_PRESSURE_LEVEL_MODERATE)); - monitor.SetModerate(); - monitor.CheckMemoryPressure(); - RunLoop().RunUntilIdle(); - EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE, - monitor.GetCurrentPressureLevel()); - testing::Mock::VerifyAndClearExpectations(&monitor); - - // Check that the event gets reposted after a while. - for (int i = 0; i < monitor.kModeratePressureCooldownCycles; ++i) { - if (i + 1 == monitor.kModeratePressureCooldownCycles) { - EXPECT_CALL(monitor, - OnMemoryPressure(MemoryPressureListener:: - MEMORY_PRESSURE_LEVEL_MODERATE)); - } - monitor.CheckMemoryPressure(); - RunLoop().RunUntilIdle(); - EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE, - monitor.GetCurrentPressureLevel()); - testing::Mock::VerifyAndClearExpectations(&monitor); - } - - // Setting the memory usage to 99% should produce critical levels. - EXPECT_CALL(monitor, - OnMemoryPressure(MemoryPressureListener:: - MEMORY_PRESSURE_LEVEL_CRITICAL)); - monitor.SetCritical(); - monitor.CheckMemoryPressure(); - RunLoop().RunUntilIdle(); - EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL, - monitor.GetCurrentPressureLevel()); - testing::Mock::VerifyAndClearExpectations(&monitor); - - // Calling it again should immediately produce a second call. - EXPECT_CALL(monitor, - OnMemoryPressure(MemoryPressureListener:: - MEMORY_PRESSURE_LEVEL_CRITICAL)); - monitor.CheckMemoryPressure(); - RunLoop().RunUntilIdle(); - EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL, - monitor.GetCurrentPressureLevel()); - testing::Mock::VerifyAndClearExpectations(&monitor); - - // When lowering the pressure again there should be a notification and the - // pressure should go back to moderate. - EXPECT_CALL(monitor, - OnMemoryPressure(MemoryPressureListener:: - MEMORY_PRESSURE_LEVEL_MODERATE)); - monitor.SetModerate(); - monitor.CheckMemoryPressure(); - RunLoop().RunUntilIdle(); - EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE, - monitor.GetCurrentPressureLevel()); - testing::Mock::VerifyAndClearExpectations(&monitor); - - // Check that the event gets reposted after a while. - for (int i = 0; i < monitor.kModeratePressureCooldownCycles; ++i) { - if (i + 1 == monitor.kModeratePressureCooldownCycles) { - EXPECT_CALL(monitor, - OnMemoryPressure(MemoryPressureListener:: - MEMORY_PRESSURE_LEVEL_MODERATE)); - } - monitor.CheckMemoryPressure(); - RunLoop().RunUntilIdle(); - EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE, - monitor.GetCurrentPressureLevel()); - testing::Mock::VerifyAndClearExpectations(&monitor); - } - - // Going down to no pressure should not produce an notification. - monitor.SetNone(); - monitor.CheckMemoryPressure(); - RunLoop().RunUntilIdle(); - EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE, - monitor.GetCurrentPressureLevel()); - testing::Mock::VerifyAndClearExpectations(&monitor); -} - -} // namespace win -} // namespace base
diff --git a/base/memory/platform_shared_memory_region_unittest.cc b/base/memory/platform_shared_memory_region_unittest.cc deleted file mode 100644 index f4d3071..0000000 --- a/base/memory/platform_shared_memory_region_unittest.cc +++ /dev/null
@@ -1,288 +0,0 @@ -// 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/memory/platform_shared_memory_region.h" - -#include "base/memory/shared_memory_mapping.h" -#include "base/process/process_metrics.h" -#include "base/sys_info.h" -#include "base/test/gtest_util.h" -#include "base/test/test_shared_memory_util.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(OS_MACOSX) && !defined(OS_IOS) -#include <mach/mach_vm.h> -#endif - -namespace base { -namespace subtle { - -const size_t kRegionSize = 1024; - -class PlatformSharedMemoryRegionTest : public ::testing::Test {}; - -// Tests that a default constructed region is invalid and produces invalid -// mappings. -TEST_F(PlatformSharedMemoryRegionTest, DefaultConstructedRegionIsInvalid) { - PlatformSharedMemoryRegion region; - EXPECT_FALSE(region.IsValid()); - WritableSharedMemoryMapping mapping = MapForTesting(®ion); - EXPECT_FALSE(mapping.IsValid()); - PlatformSharedMemoryRegion duplicate = region.Duplicate(); - EXPECT_FALSE(duplicate.IsValid()); - EXPECT_FALSE(region.ConvertToReadOnly()); -} - -// Tests that creating a region of 0 size returns an invalid region. -TEST_F(PlatformSharedMemoryRegionTest, CreateRegionOfZeroSizeIsInvalid) { - PlatformSharedMemoryRegion region = - PlatformSharedMemoryRegion::CreateWritable(0); - EXPECT_FALSE(region.IsValid()); - - PlatformSharedMemoryRegion region2 = - PlatformSharedMemoryRegion::CreateUnsafe(0); - EXPECT_FALSE(region2.IsValid()); -} - -// Tests that creating a region of size bigger than the integer max value -// returns an invalid region. -TEST_F(PlatformSharedMemoryRegionTest, CreateTooLargeRegionIsInvalid) { - size_t too_large_region_size = - static_cast<size_t>(std::numeric_limits<int>::max()) + 1; - PlatformSharedMemoryRegion region = - PlatformSharedMemoryRegion::CreateWritable(too_large_region_size); - EXPECT_FALSE(region.IsValid()); - - PlatformSharedMemoryRegion region2 = - PlatformSharedMemoryRegion::CreateUnsafe(too_large_region_size); - EXPECT_FALSE(region2.IsValid()); -} - -// Tests that regions consistently report their size as the size requested at -// creation time even if their allocation size is larger due to platform -// constraints. -TEST_F(PlatformSharedMemoryRegionTest, ReportedSizeIsRequestedSize) { - constexpr size_t kTestSizes[] = {1, 2, 3, 64, 4096, 1024 * 1024}; - for (size_t size : kTestSizes) { - PlatformSharedMemoryRegion region = - PlatformSharedMemoryRegion::CreateWritable(size); - EXPECT_EQ(region.GetSize(), size); - - region.ConvertToReadOnly(); - EXPECT_EQ(region.GetSize(), size); - } -} - -// Tests that the platform-specific handle converted to read-only cannot be used -// to perform a writable mapping with low-level system APIs like mmap(). -TEST_F(PlatformSharedMemoryRegionTest, ReadOnlyHandleIsNotWritable) { - PlatformSharedMemoryRegion region = - PlatformSharedMemoryRegion::CreateWritable(kRegionSize); - ASSERT_TRUE(region.IsValid()); - EXPECT_TRUE(region.ConvertToReadOnly()); - EXPECT_EQ(region.GetMode(), PlatformSharedMemoryRegion::Mode::kReadOnly); - EXPECT_TRUE( - CheckReadOnlyPlatformSharedMemoryRegionForTesting(std::move(region))); -} - -// Tests that the PassPlatformHandle() call invalidates the region. -TEST_F(PlatformSharedMemoryRegionTest, InvalidAfterPass) { - PlatformSharedMemoryRegion region = - PlatformSharedMemoryRegion::CreateWritable(kRegionSize); - ASSERT_TRUE(region.IsValid()); - ignore_result(region.PassPlatformHandle()); - EXPECT_FALSE(region.IsValid()); -} - -// Tests that the region is invalid after move. -TEST_F(PlatformSharedMemoryRegionTest, InvalidAfterMove) { - PlatformSharedMemoryRegion region = - PlatformSharedMemoryRegion::CreateWritable(kRegionSize); - ASSERT_TRUE(region.IsValid()); - PlatformSharedMemoryRegion moved_region = std::move(region); - EXPECT_FALSE(region.IsValid()); - EXPECT_TRUE(moved_region.IsValid()); -} - -// Tests that calling Take() with the size parameter equal to zero returns an -// invalid region. -TEST_F(PlatformSharedMemoryRegionTest, TakeRegionOfZeroSizeIsInvalid) { - PlatformSharedMemoryRegion region = - PlatformSharedMemoryRegion::CreateWritable(kRegionSize); - ASSERT_TRUE(region.IsValid()); - PlatformSharedMemoryRegion region2 = PlatformSharedMemoryRegion::Take( - region.PassPlatformHandle(), region.GetMode(), 0, region.GetGUID()); - EXPECT_FALSE(region2.IsValid()); -} - -// Tests that calling Take() with the size parameter bigger than the integer max -// value returns an invalid region. -TEST_F(PlatformSharedMemoryRegionTest, TakeTooLargeRegionIsInvalid) { - PlatformSharedMemoryRegion region = - PlatformSharedMemoryRegion::CreateWritable(kRegionSize); - ASSERT_TRUE(region.IsValid()); - PlatformSharedMemoryRegion region2 = PlatformSharedMemoryRegion::Take( - region.PassPlatformHandle(), region.GetMode(), - static_cast<size_t>(std::numeric_limits<int>::max()) + 1, - region.GetGUID()); - EXPECT_FALSE(region2.IsValid()); -} - -// Tests that mapping bytes out of the region limits fails. -TEST_F(PlatformSharedMemoryRegionTest, MapAtOutOfTheRegionLimitsTest) { - PlatformSharedMemoryRegion region = - PlatformSharedMemoryRegion::CreateWritable(kRegionSize); - ASSERT_TRUE(region.IsValid()); - WritableSharedMemoryMapping mapping = - MapAtForTesting(®ion, 0, region.GetSize() + 1); - EXPECT_FALSE(mapping.IsValid()); -} - -// Tests that mapping with a size and offset causing overflow fails. -TEST_F(PlatformSharedMemoryRegionTest, MapAtWithOverflowTest) { - PlatformSharedMemoryRegion region = - PlatformSharedMemoryRegion::CreateWritable( - SysInfo::VMAllocationGranularity() * 2); - ASSERT_TRUE(region.IsValid()); - size_t size = std::numeric_limits<size_t>::max(); - size_t offset = SysInfo::VMAllocationGranularity(); - // |size| + |offset| should be below the region size due to overflow but - // mapping a region with these parameters should be invalid. - EXPECT_LT(size + offset, region.GetSize()); - WritableSharedMemoryMapping mapping = MapAtForTesting(®ion, offset, size); - EXPECT_FALSE(mapping.IsValid()); -} - -#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_FUCHSIA) && \ - !defined(OS_MACOSX) -// Tests that the second handle is closed after a conversion to read-only on -// POSIX. -TEST_F(PlatformSharedMemoryRegionTest, - ConvertToReadOnlyInvalidatesSecondHandle) { - PlatformSharedMemoryRegion region = - PlatformSharedMemoryRegion::CreateWritable(kRegionSize); - ASSERT_TRUE(region.IsValid()); - ASSERT_TRUE(region.ConvertToReadOnly()); - FDPair fds = region.GetPlatformHandle(); - EXPECT_LT(fds.readonly_fd, 0); -} -#endif - -#if defined(OS_MACOSX) && !defined(OS_IOS) -// Tests that protection bits are set correctly for read-only region on MacOS. -TEST_F(PlatformSharedMemoryRegionTest, MapCurrentAndMaxProtectionSetCorrectly) { - PlatformSharedMemoryRegion region = - PlatformSharedMemoryRegion::CreateWritable(kRegionSize); - ASSERT_TRUE(region.IsValid()); - ASSERT_TRUE(region.ConvertToReadOnly()); - WritableSharedMemoryMapping ro_mapping = MapForTesting(®ion); - ASSERT_TRUE(ro_mapping.IsValid()); - - vm_region_basic_info_64 basic_info; - mach_vm_size_t dummy_size = 0; - void* temp_addr = ro_mapping.memory(); - MachVMRegionResult result = GetBasicInfo( - mach_task_self(), &dummy_size, - reinterpret_cast<mach_vm_address_t*>(&temp_addr), &basic_info); - EXPECT_EQ(result, MachVMRegionResult::Success); - EXPECT_EQ(basic_info.protection & VM_PROT_ALL, VM_PROT_READ); - EXPECT_EQ(basic_info.max_protection & VM_PROT_ALL, VM_PROT_READ); -} -#endif - -// Tests that platform handle permissions are checked correctly. -TEST_F(PlatformSharedMemoryRegionTest, - CheckPlatformHandlePermissionsCorrespondToMode) { - using Mode = PlatformSharedMemoryRegion::Mode; - auto check = [](const PlatformSharedMemoryRegion& region, - PlatformSharedMemoryRegion::Mode mode) { - return PlatformSharedMemoryRegion:: - CheckPlatformHandlePermissionsCorrespondToMode( - region.GetPlatformHandle(), mode, region.GetSize()); - }; - - // Check kWritable region. - PlatformSharedMemoryRegion region = - PlatformSharedMemoryRegion::CreateWritable(kRegionSize); - ASSERT_TRUE(region.IsValid()); - EXPECT_TRUE(check(region, Mode::kWritable)); - EXPECT_FALSE(check(region, Mode::kReadOnly)); - - // Check kReadOnly region. - ASSERT_TRUE(region.ConvertToReadOnly()); - EXPECT_TRUE(check(region, Mode::kReadOnly)); - EXPECT_FALSE(check(region, Mode::kWritable)); - EXPECT_FALSE(check(region, Mode::kUnsafe)); - - // Check kUnsafe region. - PlatformSharedMemoryRegion region2 = - PlatformSharedMemoryRegion::CreateUnsafe(kRegionSize); - ASSERT_TRUE(region2.IsValid()); - EXPECT_TRUE(check(region2, Mode::kUnsafe)); - EXPECT_FALSE(check(region2, Mode::kReadOnly)); -} - -// Tests that it's impossible to create read-only platform shared memory region. -TEST_F(PlatformSharedMemoryRegionTest, CreateReadOnlyRegionDeathTest) { -#ifdef OFFICIAL_BUILD - // The official build does not print the reason a CHECK failed. - const char kErrorRegex[] = ""; -#else - const char kErrorRegex[] = - "Creating a region in read-only mode will lead to this region being " - "non-modifiable"; -#endif - EXPECT_DEATH_IF_SUPPORTED( - PlatformSharedMemoryRegion::Create( - PlatformSharedMemoryRegion::Mode::kReadOnly, kRegionSize), - kErrorRegex); -} - -// Tests that it's prohibited to duplicate a writable region. -TEST_F(PlatformSharedMemoryRegionTest, DuplicateWritableRegionDeathTest) { -#ifdef OFFICIAL_BUILD - const char kErrorRegex[] = ""; -#else - const char kErrorRegex[] = - "Duplicating a writable shared memory region is prohibited"; -#endif - PlatformSharedMemoryRegion region = - PlatformSharedMemoryRegion::CreateWritable(kRegionSize); - ASSERT_TRUE(region.IsValid()); - EXPECT_DEATH_IF_SUPPORTED(region.Duplicate(), kErrorRegex); -} - -// Tests that it's prohibited to convert an unsafe region to read-only. -TEST_F(PlatformSharedMemoryRegionTest, UnsafeRegionConvertToReadOnlyDeathTest) { -#ifdef OFFICIAL_BUILD - const char kErrorRegex[] = ""; -#else - const char kErrorRegex[] = - "Only writable shared memory region can be converted to read-only"; -#endif - PlatformSharedMemoryRegion region = - PlatformSharedMemoryRegion::CreateUnsafe(kRegionSize); - ASSERT_TRUE(region.IsValid()); - EXPECT_DEATH_IF_SUPPORTED(region.ConvertToReadOnly(), kErrorRegex); -} - -// Tests that it's prohibited to convert a read-only region to read-only. -TEST_F(PlatformSharedMemoryRegionTest, - ReadOnlyRegionConvertToReadOnlyDeathTest) { -#ifdef OFFICIAL_BUILD - const char kErrorRegex[] = ""; -#else - const char kErrorRegex[] = - "Only writable shared memory region can be converted to read-only"; -#endif - PlatformSharedMemoryRegion region = - PlatformSharedMemoryRegion::CreateWritable(kRegionSize); - ASSERT_TRUE(region.IsValid()); - EXPECT_TRUE(region.ConvertToReadOnly()); - EXPECT_DEATH_IF_SUPPORTED(region.ConvertToReadOnly(), kErrorRegex); -} - -} // namespace subtle -} // namespace base
diff --git a/base/memory/protected_memory_unittest.cc b/base/memory/protected_memory_unittest.cc deleted file mode 100644 index b6ec61d..0000000 --- a/base/memory/protected_memory_unittest.cc +++ /dev/null
@@ -1,117 +0,0 @@ -// 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/memory/protected_memory.h" -#include "base/memory/protected_memory_cfi.h" -#include "base/synchronization/lock.h" -#include "base/test/gtest_util.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -struct Data { - Data() = default; - Data(int foo_) : foo(foo_) {} - int foo; -}; - -} // namespace - -class ProtectedMemoryTest : public ::testing::Test { - protected: - // Run tests one at a time. Some of the negative tests can not be made thread - // safe. - void SetUp() final { lock.Acquire(); } - void TearDown() final { lock.Release(); } - - Lock lock; -}; - -PROTECTED_MEMORY_SECTION ProtectedMemory<int> init; - -TEST_F(ProtectedMemoryTest, Initializer) { - static ProtectedMemory<int>::Initializer I(&init, 4); - EXPECT_EQ(*init, 4); -} - -PROTECTED_MEMORY_SECTION ProtectedMemory<Data> data; - -TEST_F(ProtectedMemoryTest, Basic) { - AutoWritableMemory writer = AutoWritableMemory::Create(data); - data->foo = 5; - EXPECT_EQ(data->foo, 5); -} - -#if defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID) - -#if PROTECTED_MEMORY_ENABLED -TEST_F(ProtectedMemoryTest, ReadOnlyOnStart) { - EXPECT_DEATH({ data->foo = 6; AutoWritableMemory::Create(data); }, ""); -} - -TEST_F(ProtectedMemoryTest, ReadOnlyAfterSetWritable) { - { AutoWritableMemory writer = AutoWritableMemory::Create(data); } - EXPECT_DEATH({ data->foo = 7; }, ""); -} - -TEST_F(ProtectedMemoryTest, AssertMemoryIsReadOnly) { - AssertMemoryIsReadOnly(&data->foo); - { AutoWritableMemory::Create(data); } - AssertMemoryIsReadOnly(&data->foo); - - ProtectedMemory<Data> writable_data; - EXPECT_DCHECK_DEATH({ AssertMemoryIsReadOnly(&writable_data->foo); }); -} - -TEST_F(ProtectedMemoryTest, FailsIfDefinedOutsideOfProtectMemoryRegion) { - ProtectedMemory<Data> data; - EXPECT_DCHECK_DEATH({ AutoWritableMemory::Create(data); }); -} - -TEST_F(ProtectedMemoryTest, UnsanitizedCfiCallOutsideOfProtectedMemoryRegion) { - ProtectedMemory<void (*)(void)> data; - EXPECT_DCHECK_DEATH({ UnsanitizedCfiCall(data)(); }); -} -#endif // PROTECTED_MEMORY_ENABLED - -namespace { - -struct BadIcall { - BadIcall() = default; - BadIcall(int (*fp_)(int)) : fp(fp_) {} - int (*fp)(int); -}; - -unsigned int bad_icall(int i) { - return 4 + i; -} - -} // namespace - -PROTECTED_MEMORY_SECTION ProtectedMemory<BadIcall> icall_pm1; - -TEST_F(ProtectedMemoryTest, BadMemberCall) { - static ProtectedMemory<BadIcall>::Initializer I( - &icall_pm1, BadIcall(reinterpret_cast<int (*)(int)>(&bad_icall))); - - EXPECT_EQ(UnsanitizedCfiCall(icall_pm1, &BadIcall::fp)(1), 5); - EXPECT_EQ(icall_pm1->fp(1), 5); -} - -PROTECTED_MEMORY_SECTION ProtectedMemory<int (*)(int)> icall_pm2; - -TEST_F(ProtectedMemoryTest, BadFnPtrCall) { - static ProtectedMemory<int (*)(int)>::Initializer I( - &icall_pm2, reinterpret_cast<int (*)(int)>(&bad_icall)); - - EXPECT_EQ(UnsanitizedCfiCall(icall_pm2)(1), 5); - EXPECT_EQ((*icall_pm2)(1), 5); -} - -#endif // defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID) - -} // namespace base
diff --git a/base/memory/ptr_util_unittest.cc b/base/memory/ptr_util_unittest.cc deleted file mode 100644 index 3fa40d8..0000000 --- a/base/memory/ptr_util_unittest.cc +++ /dev/null
@@ -1,40 +0,0 @@ -// 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/memory/ptr_util.h" - -#include <stddef.h> - -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -class DeleteCounter { - public: - DeleteCounter() { ++count_; } - ~DeleteCounter() { --count_; } - - static size_t count() { return count_; } - - private: - static size_t count_; -}; - -size_t DeleteCounter::count_ = 0; - -} // namespace - -TEST(PtrUtilTest, WrapUnique) { - EXPECT_EQ(0u, DeleteCounter::count()); - DeleteCounter* counter = new DeleteCounter; - EXPECT_EQ(1u, DeleteCounter::count()); - std::unique_ptr<DeleteCounter> owned_counter = WrapUnique(counter); - EXPECT_EQ(1u, DeleteCounter::count()); - owned_counter.reset(); - EXPECT_EQ(0u, DeleteCounter::count()); -} - -} // namespace base
diff --git a/base/memory/ref_counted_memory_unittest.cc b/base/memory/ref_counted_memory_unittest.cc deleted file mode 100644 index b7498f9..0000000 --- a/base/memory/ref_counted_memory_unittest.cc +++ /dev/null
@@ -1,145 +0,0 @@ -// 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/memory/ref_counted_memory.h" - -#include <stdint.h> - -#include <utility> - -#include "base/memory/read_only_shared_memory_region.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using testing::Each; -using testing::ElementsAre; - -namespace base { - -TEST(RefCountedMemoryUnitTest, RefCountedStaticMemory) { - auto mem = MakeRefCounted<RefCountedStaticMemory>("static mem00", 10); - - EXPECT_EQ(10U, mem->size()); - EXPECT_EQ("static mem", std::string(mem->front_as<char>(), mem->size())); -} - -TEST(RefCountedMemoryUnitTest, RefCountedBytes) { - std::vector<uint8_t> data; - data.push_back(45); - data.push_back(99); - scoped_refptr<RefCountedMemory> mem = RefCountedBytes::TakeVector(&data); - - EXPECT_EQ(0U, data.size()); - - ASSERT_EQ(2U, mem->size()); - EXPECT_EQ(45U, mem->front()[0]); - EXPECT_EQ(99U, mem->front()[1]); - - scoped_refptr<RefCountedMemory> mem2; - { - const unsigned char kData[] = {12, 11, 99}; - mem2 = MakeRefCounted<RefCountedBytes>(kData, arraysize(kData)); - } - ASSERT_EQ(3U, mem2->size()); - EXPECT_EQ(12U, mem2->front()[0]); - EXPECT_EQ(11U, mem2->front()[1]); - EXPECT_EQ(99U, mem2->front()[2]); -} - -TEST(RefCountedMemoryUnitTest, RefCountedBytesMutable) { - auto mem = base::MakeRefCounted<RefCountedBytes>(10); - - ASSERT_EQ(10U, mem->size()); - EXPECT_THAT(mem->data(), Each(0U)); - - // Test non-const versions of data(), front() and front_as<>(). - mem->data()[0] = 1; - mem->front()[1] = 2; - mem->front_as<char>()[2] = 3; - - EXPECT_THAT(mem->data(), ElementsAre(1, 2, 3, 0, 0, 0, 0, 0, 0, 0)); -} - -TEST(RefCountedMemoryUnitTest, RefCountedString) { - std::string s("destroy me"); - scoped_refptr<RefCountedMemory> mem = RefCountedString::TakeString(&s); - - EXPECT_EQ(0U, s.size()); - - ASSERT_EQ(10U, mem->size()); - EXPECT_EQ('d', mem->front()[0]); - EXPECT_EQ('e', mem->front()[1]); - EXPECT_EQ('e', mem->front()[9]); -} - -TEST(RefCountedMemoryUnitTest, RefCountedSharedMemory) { - static const char kData[] = "shm_dummy_data"; - auto shm = std::make_unique<SharedMemory>(); - ASSERT_TRUE(shm->CreateAndMapAnonymous(sizeof(kData))); - memcpy(shm->memory(), kData, sizeof(kData)); - - auto mem = - MakeRefCounted<RefCountedSharedMemory>(std::move(shm), sizeof(kData)); - ASSERT_EQ(sizeof(kData), mem->size()); - EXPECT_EQ('s', mem->front()[0]); - EXPECT_EQ('h', mem->front()[1]); - EXPECT_EQ('_', mem->front()[9]); -} - -TEST(RefCountedMemoryUnitTest, RefCountedSharedMemoryMapping) { - static const char kData[] = "mem_region_dummy_data"; - scoped_refptr<RefCountedSharedMemoryMapping> mem; - { - MappedReadOnlyRegion region = - ReadOnlySharedMemoryRegion::Create(sizeof(kData)); - ReadOnlySharedMemoryMapping ro_mapping = region.region.Map(); - WritableSharedMemoryMapping rw_mapping = std::move(region.mapping); - ASSERT_TRUE(rw_mapping.IsValid()); - memcpy(rw_mapping.memory(), kData, sizeof(kData)); - mem = MakeRefCounted<RefCountedSharedMemoryMapping>(std::move(ro_mapping)); - } - - ASSERT_LE(sizeof(kData), mem->size()); - EXPECT_EQ('e', mem->front()[1]); - EXPECT_EQ('m', mem->front()[2]); - EXPECT_EQ('o', mem->front()[8]); - - { - MappedReadOnlyRegion region = - ReadOnlySharedMemoryRegion::Create(sizeof(kData)); - WritableSharedMemoryMapping rw_mapping = std::move(region.mapping); - ASSERT_TRUE(rw_mapping.IsValid()); - memcpy(rw_mapping.memory(), kData, sizeof(kData)); - mem = RefCountedSharedMemoryMapping::CreateFromWholeRegion(region.region); - } - - ASSERT_LE(sizeof(kData), mem->size()); - EXPECT_EQ('_', mem->front()[3]); - EXPECT_EQ('r', mem->front()[4]); - EXPECT_EQ('i', mem->front()[7]); -} - -TEST(RefCountedMemoryUnitTest, Equals) { - std::string s1("same"); - scoped_refptr<RefCountedMemory> mem1 = RefCountedString::TakeString(&s1); - - std::vector<unsigned char> d2 = {'s', 'a', 'm', 'e'}; - scoped_refptr<RefCountedMemory> mem2 = RefCountedBytes::TakeVector(&d2); - - EXPECT_TRUE(mem1->Equals(mem2)); - - std::string s3("diff"); - scoped_refptr<RefCountedMemory> mem3 = RefCountedString::TakeString(&s3); - - EXPECT_FALSE(mem1->Equals(mem3)); - EXPECT_FALSE(mem2->Equals(mem3)); -} - -TEST(RefCountedMemoryUnitTest, EqualsNull) { - std::string s("str"); - scoped_refptr<RefCountedMemory> mem = RefCountedString::TakeString(&s); - EXPECT_FALSE(mem->Equals(nullptr)); -} - -} // namespace base
diff --git a/base/memory/ref_counted_unittest.cc b/base/memory/ref_counted_unittest.cc deleted file mode 100644 index d88fc54..0000000 --- a/base/memory/ref_counted_unittest.cc +++ /dev/null
@@ -1,606 +0,0 @@ -// 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/memory/ref_counted.h" - -#include <type_traits> -#include <utility> - -#include "base/test/gtest_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -class SelfAssign : public base::RefCounted<SelfAssign> { - protected: - virtual ~SelfAssign() = default; - - private: - friend class base::RefCounted<SelfAssign>; -}; - -class Derived : public SelfAssign { - protected: - ~Derived() override = default; - - private: - friend class base::RefCounted<Derived>; -}; - -class CheckDerivedMemberAccess : public scoped_refptr<SelfAssign> { - public: - CheckDerivedMemberAccess() { - // This shouldn't compile if we don't have access to the member variable. - SelfAssign** pptr = &ptr_; - EXPECT_EQ(*pptr, ptr_); - } -}; - -class ScopedRefPtrToSelf : public base::RefCounted<ScopedRefPtrToSelf> { - public: - ScopedRefPtrToSelf() : self_ptr_(this) {} - - static bool was_destroyed() { return was_destroyed_; } - - static void reset_was_destroyed() { was_destroyed_ = false; } - - scoped_refptr<ScopedRefPtrToSelf> self_ptr_; - - private: - friend class base::RefCounted<ScopedRefPtrToSelf>; - ~ScopedRefPtrToSelf() { was_destroyed_ = true; } - - static bool was_destroyed_; -}; - -bool ScopedRefPtrToSelf::was_destroyed_ = false; - -class ScopedRefPtrCountBase : public base::RefCounted<ScopedRefPtrCountBase> { - public: - ScopedRefPtrCountBase() { ++constructor_count_; } - - static int constructor_count() { return constructor_count_; } - - static int destructor_count() { return destructor_count_; } - - static void reset_count() { - constructor_count_ = 0; - destructor_count_ = 0; - } - - protected: - virtual ~ScopedRefPtrCountBase() { ++destructor_count_; } - - private: - friend class base::RefCounted<ScopedRefPtrCountBase>; - - static int constructor_count_; - static int destructor_count_; -}; - -int ScopedRefPtrCountBase::constructor_count_ = 0; -int ScopedRefPtrCountBase::destructor_count_ = 0; - -class ScopedRefPtrCountDerived : public ScopedRefPtrCountBase { - public: - ScopedRefPtrCountDerived() { ++constructor_count_; } - - static int constructor_count() { return constructor_count_; } - - static int destructor_count() { return destructor_count_; } - - static void reset_count() { - constructor_count_ = 0; - destructor_count_ = 0; - } - - protected: - ~ScopedRefPtrCountDerived() override { ++destructor_count_; } - - private: - friend class base::RefCounted<ScopedRefPtrCountDerived>; - - static int constructor_count_; - static int destructor_count_; -}; - -int ScopedRefPtrCountDerived::constructor_count_ = 0; -int ScopedRefPtrCountDerived::destructor_count_ = 0; - -class Other : public base::RefCounted<Other> { - private: - friend class base::RefCounted<Other>; - - ~Other() = default; -}; - -class HasPrivateDestructorWithDeleter; - -struct Deleter { - static void Destruct(const HasPrivateDestructorWithDeleter* x); -}; - -class HasPrivateDestructorWithDeleter - : public base::RefCounted<HasPrivateDestructorWithDeleter, Deleter> { - public: - HasPrivateDestructorWithDeleter() = default; - - private: - friend struct Deleter; - ~HasPrivateDestructorWithDeleter() = default; -}; - -void Deleter::Destruct(const HasPrivateDestructorWithDeleter* x) { - delete x; -} - -scoped_refptr<Other> Overloaded(scoped_refptr<Other> other) { - return other; -} - -scoped_refptr<SelfAssign> Overloaded(scoped_refptr<SelfAssign> self_assign) { - return self_assign; -} - -class InitialRefCountIsOne : public base::RefCounted<InitialRefCountIsOne> { - public: - REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE(); - - InitialRefCountIsOne() = default; - - private: - friend class base::RefCounted<InitialRefCountIsOne>; - ~InitialRefCountIsOne() = default; -}; - -} // end namespace - -TEST(RefCountedUnitTest, TestSelfAssignment) { - SelfAssign* p = new SelfAssign; - scoped_refptr<SelfAssign> var(p); - var = *&var; // The *& defeats Clang's -Wself-assign warning. - EXPECT_EQ(var.get(), p); - var = std::move(var); - EXPECT_EQ(var.get(), p); - var.swap(var); - EXPECT_EQ(var.get(), p); - swap(var, var); - EXPECT_EQ(var.get(), p); -} - -TEST(RefCountedUnitTest, ScopedRefPtrMemberAccess) { - CheckDerivedMemberAccess check; -} - -TEST(RefCountedUnitTest, ScopedRefPtrToSelfPointerAssignment) { - ScopedRefPtrToSelf::reset_was_destroyed(); - - ScopedRefPtrToSelf* check = new ScopedRefPtrToSelf(); - EXPECT_FALSE(ScopedRefPtrToSelf::was_destroyed()); - check->self_ptr_ = nullptr; - EXPECT_TRUE(ScopedRefPtrToSelf::was_destroyed()); -} - -TEST(RefCountedUnitTest, ScopedRefPtrToSelfMoveAssignment) { - ScopedRefPtrToSelf::reset_was_destroyed(); - - ScopedRefPtrToSelf* check = new ScopedRefPtrToSelf(); - EXPECT_FALSE(ScopedRefPtrToSelf::was_destroyed()); - // Releasing |check->self_ptr_| will delete |check|. - // The move assignment operator must assign |check->self_ptr_| first then - // release |check->self_ptr_|. - check->self_ptr_ = scoped_refptr<ScopedRefPtrToSelf>(); - EXPECT_TRUE(ScopedRefPtrToSelf::was_destroyed()); -} - -TEST(RefCountedUnitTest, BooleanTesting) { - scoped_refptr<SelfAssign> ptr_to_an_instance = new SelfAssign; - EXPECT_TRUE(ptr_to_an_instance); - EXPECT_FALSE(!ptr_to_an_instance); - - if (ptr_to_an_instance) { - } else { - ADD_FAILURE() << "Pointer to an instance should result in true."; - } - - if (!ptr_to_an_instance) { // check for operator!(). - ADD_FAILURE() << "Pointer to an instance should result in !x being false."; - } - - scoped_refptr<SelfAssign> null_ptr; - EXPECT_FALSE(null_ptr); - EXPECT_TRUE(!null_ptr); - - if (null_ptr) { - ADD_FAILURE() << "Null pointer should result in false."; - } - - if (!null_ptr) { // check for operator!(). - } else { - ADD_FAILURE() << "Null pointer should result in !x being true."; - } -} - -TEST(RefCountedUnitTest, Equality) { - scoped_refptr<SelfAssign> p1(new SelfAssign); - scoped_refptr<SelfAssign> p2(new SelfAssign); - - EXPECT_EQ(p1, p1); - EXPECT_EQ(p2, p2); - - EXPECT_NE(p1, p2); - EXPECT_NE(p2, p1); -} - -TEST(RefCountedUnitTest, NullptrEquality) { - scoped_refptr<SelfAssign> ptr_to_an_instance(new SelfAssign); - scoped_refptr<SelfAssign> ptr_to_nullptr; - - EXPECT_NE(nullptr, ptr_to_an_instance); - EXPECT_NE(ptr_to_an_instance, nullptr); - EXPECT_EQ(nullptr, ptr_to_nullptr); - EXPECT_EQ(ptr_to_nullptr, nullptr); -} - -TEST(RefCountedUnitTest, ConvertibleEquality) { - scoped_refptr<Derived> p1(new Derived); - scoped_refptr<SelfAssign> p2; - - EXPECT_NE(p1, p2); - EXPECT_NE(p2, p1); - - p2 = p1; - - EXPECT_EQ(p1, p2); - EXPECT_EQ(p2, p1); -} - -TEST(RefCountedUnitTest, MoveAssignment1) { - ScopedRefPtrCountBase::reset_count(); - - { - ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase(); - scoped_refptr<ScopedRefPtrCountBase> p1(raw); - EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); - - { - scoped_refptr<ScopedRefPtrCountBase> p2; - - p2 = std::move(p1); - EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); - EXPECT_EQ(nullptr, p1.get()); - EXPECT_EQ(raw, p2.get()); - - // p2 goes out of scope. - } - EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); - - // p1 goes out of scope. - } - EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); -} - -TEST(RefCountedUnitTest, MoveAssignment2) { - ScopedRefPtrCountBase::reset_count(); - - { - ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase(); - scoped_refptr<ScopedRefPtrCountBase> p1; - EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); - - { - scoped_refptr<ScopedRefPtrCountBase> p2(raw); - EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); - - p1 = std::move(p2); - EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); - EXPECT_EQ(raw, p1.get()); - EXPECT_EQ(nullptr, p2.get()); - - // p2 goes out of scope. - } - EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); - - // p1 goes out of scope. - } - EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); -} - -TEST(RefCountedUnitTest, MoveAssignmentSameInstance1) { - ScopedRefPtrCountBase::reset_count(); - - { - ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase(); - scoped_refptr<ScopedRefPtrCountBase> p1(raw); - EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); - - { - scoped_refptr<ScopedRefPtrCountBase> p2(p1); - EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); - - p1 = std::move(p2); - EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); - EXPECT_EQ(raw, p1.get()); - EXPECT_EQ(nullptr, p2.get()); - - // p2 goes out of scope. - } - EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); - - // p1 goes out of scope. - } - EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); -} - -TEST(RefCountedUnitTest, MoveAssignmentSameInstance2) { - ScopedRefPtrCountBase::reset_count(); - - { - ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase(); - scoped_refptr<ScopedRefPtrCountBase> p1(raw); - EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); - - { - scoped_refptr<ScopedRefPtrCountBase> p2(p1); - EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); - - p2 = std::move(p1); - EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); - EXPECT_EQ(nullptr, p1.get()); - EXPECT_EQ(raw, p2.get()); - - // p2 goes out of scope. - } - EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); - - // p1 goes out of scope. - } - EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); -} - -TEST(RefCountedUnitTest, MoveAssignmentDifferentInstances) { - ScopedRefPtrCountBase::reset_count(); - - { - ScopedRefPtrCountBase *raw1 = new ScopedRefPtrCountBase(); - scoped_refptr<ScopedRefPtrCountBase> p1(raw1); - EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); - - { - ScopedRefPtrCountBase *raw2 = new ScopedRefPtrCountBase(); - scoped_refptr<ScopedRefPtrCountBase> p2(raw2); - EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); - - p1 = std::move(p2); - EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); - EXPECT_EQ(raw2, p1.get()); - EXPECT_EQ(nullptr, p2.get()); - - // p2 goes out of scope. - } - EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); - - // p1 goes out of scope. - } - EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(2, ScopedRefPtrCountBase::destructor_count()); -} - -TEST(RefCountedUnitTest, MoveAssignmentSelfMove) { - ScopedRefPtrCountBase::reset_count(); - - { - ScopedRefPtrCountBase* raw = new ScopedRefPtrCountBase; - scoped_refptr<ScopedRefPtrCountBase> p1(raw); - scoped_refptr<ScopedRefPtrCountBase>& p1_ref = p1; - - EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); - - p1 = std::move(p1_ref); - - // |p1| is "valid but unspecified", so don't bother inspecting its - // contents, just ensure that we don't crash. - } - - EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); -} - -TEST(RefCountedUnitTest, MoveAssignmentDerived) { - ScopedRefPtrCountBase::reset_count(); - ScopedRefPtrCountDerived::reset_count(); - - { - ScopedRefPtrCountBase *raw1 = new ScopedRefPtrCountBase(); - scoped_refptr<ScopedRefPtrCountBase> p1(raw1); - EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); - EXPECT_EQ(0, ScopedRefPtrCountDerived::constructor_count()); - EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count()); - - { - ScopedRefPtrCountDerived *raw2 = new ScopedRefPtrCountDerived(); - scoped_refptr<ScopedRefPtrCountDerived> p2(raw2); - EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); - EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count()); - EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count()); - - p1 = std::move(p2); - EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); - EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count()); - EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count()); - EXPECT_EQ(raw2, p1.get()); - EXPECT_EQ(nullptr, p2.get()); - - // p2 goes out of scope. - } - EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); - EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count()); - EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count()); - - // p1 goes out of scope. - } - EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(2, ScopedRefPtrCountBase::destructor_count()); - EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count()); - EXPECT_EQ(1, ScopedRefPtrCountDerived::destructor_count()); -} - -TEST(RefCountedUnitTest, MoveConstructor) { - ScopedRefPtrCountBase::reset_count(); - - { - ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase(); - scoped_refptr<ScopedRefPtrCountBase> p1(raw); - EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); - - { - scoped_refptr<ScopedRefPtrCountBase> p2(std::move(p1)); - EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); - EXPECT_EQ(nullptr, p1.get()); - EXPECT_EQ(raw, p2.get()); - - // p2 goes out of scope. - } - EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); - - // p1 goes out of scope. - } - EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); -} - -TEST(RefCountedUnitTest, MoveConstructorDerived) { - ScopedRefPtrCountBase::reset_count(); - ScopedRefPtrCountDerived::reset_count(); - - { - ScopedRefPtrCountDerived *raw1 = new ScopedRefPtrCountDerived(); - scoped_refptr<ScopedRefPtrCountDerived> p1(raw1); - EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); - EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count()); - EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count()); - - { - scoped_refptr<ScopedRefPtrCountBase> p2(std::move(p1)); - EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); - EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count()); - EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count()); - EXPECT_EQ(nullptr, p1.get()); - EXPECT_EQ(raw1, p2.get()); - - // p2 goes out of scope. - } - EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); - EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count()); - EXPECT_EQ(1, ScopedRefPtrCountDerived::destructor_count()); - - // p1 goes out of scope. - } - EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); - EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); - EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count()); - EXPECT_EQ(1, ScopedRefPtrCountDerived::destructor_count()); -} - -TEST(RefCountedUnitTest, TestOverloadResolutionCopy) { - const scoped_refptr<Derived> derived(new Derived); - const scoped_refptr<SelfAssign> expected(derived); - EXPECT_EQ(expected, Overloaded(derived)); - - const scoped_refptr<Other> other(new Other); - EXPECT_EQ(other, Overloaded(other)); -} - -TEST(RefCountedUnitTest, TestOverloadResolutionMove) { - scoped_refptr<Derived> derived(new Derived); - const scoped_refptr<SelfAssign> expected(derived); - EXPECT_EQ(expected, Overloaded(std::move(derived))); - - scoped_refptr<Other> other(new Other); - const scoped_refptr<Other> other2(other); - EXPECT_EQ(other2, Overloaded(std::move(other))); -} - -TEST(RefCountedUnitTest, TestMakeRefCounted) { - scoped_refptr<Derived> derived = new Derived; - EXPECT_TRUE(derived->HasOneRef()); - derived = nullptr; - - scoped_refptr<Derived> derived2 = base::MakeRefCounted<Derived>(); - EXPECT_TRUE(derived2->HasOneRef()); - derived2 = nullptr; -} - -TEST(RefCountedUnitTest, TestInitialRefCountIsOne) { - scoped_refptr<InitialRefCountIsOne> obj = - base::MakeRefCounted<InitialRefCountIsOne>(); - EXPECT_TRUE(obj->HasOneRef()); - obj = nullptr; - - scoped_refptr<InitialRefCountIsOne> obj2 = - base::AdoptRef(new InitialRefCountIsOne); - EXPECT_TRUE(obj2->HasOneRef()); - obj2 = nullptr; - - scoped_refptr<Other> obj3 = base::MakeRefCounted<Other>(); - EXPECT_TRUE(obj3->HasOneRef()); - obj3 = nullptr; -} - -TEST(RefCountedDeathTest, TestAdoptRef) { - // Check that WrapRefCounted() DCHECKs if passed a type that defines - // REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE. - EXPECT_DCHECK_DEATH(base::WrapRefCounted(new InitialRefCountIsOne)); - - // Check that AdoptRef() DCHECKs if passed a nullptr. - InitialRefCountIsOne* ptr = nullptr; - EXPECT_DCHECK_DEATH(base::AdoptRef(ptr)); - - // Check that AdoptRef() DCHECKs if passed an object that doesn't need to be - // adopted. - scoped_refptr<InitialRefCountIsOne> obj = - base::MakeRefCounted<InitialRefCountIsOne>(); - EXPECT_DCHECK_DEATH(base::AdoptRef(obj.get())); -} - -TEST(RefCountedUnitTest, TestPrivateDestructorWithDeleter) { - // Ensure that RefCounted doesn't need the access to the pointee dtor when - // a custom deleter is given. - scoped_refptr<HasPrivateDestructorWithDeleter> obj = - base::MakeRefCounted<HasPrivateDestructorWithDeleter>(); -}
diff --git a/base/memory/ref_counted_unittest.nc b/base/memory/ref_counted_unittest.nc deleted file mode 100644 index b8c371f..0000000 --- a/base/memory/ref_counted_unittest.nc +++ /dev/null
@@ -1,28 +0,0 @@ -// 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/memory/ref_counted.h" - -namespace base { - -class InitialRefCountIsZero : public base::RefCounted<InitialRefCountIsZero> { - public: - InitialRefCountIsZero() {} - private: - friend class base::RefCounted<InitialRefCountIsZero>; - ~InitialRefCountIsZero() {} -}; - -// TODO(hans): Remove .* and update the static_assert expectations once we roll -// past Clang r313315. https://crbug.com/765692. - -#if defined(NCTEST_ADOPT_REF_TO_ZERO_START) // [r"fatal error: static_assert failed .*\"Use AdoptRef only for the reference count starts from one\.\""] - -void WontCompile() { - AdoptRef(new InitialRefCountIsZero()); -} - -#endif - -} // namespace base
diff --git a/base/memory/shared_memory_mac_unittest.cc b/base/memory/shared_memory_mac_unittest.cc deleted file mode 100644 index b17dab7..0000000 --- a/base/memory/shared_memory_mac_unittest.cc +++ /dev/null
@@ -1,457 +0,0 @@ -// 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 <mach/mach.h> -#include <mach/mach_vm.h> -#include <servers/bootstrap.h> -#include <stddef.h> -#include <stdint.h> - -#include "base/command_line.h" -#include "base/mac/mac_util.h" -#include "base/mac/mach_logging.h" -#include "base/mac/scoped_mach_port.h" -#include "base/macros.h" -#include "base/memory/shared_memory.h" -#include "base/process/process_handle.h" -#include "base/rand_util.h" -#include "base/strings/stringprintf.h" -#include "base/sys_info.h" -#include "base/test/multiprocess_test.h" -#include "base/test/test_timeouts.h" -#include "base/unguessable_token.h" -#include "testing/multiprocess_func_list.h" - -namespace base { - -namespace { - -// Gets the current and maximum protection levels of the memory region. -// Returns whether the operation was successful. -// |current| and |max| are output variables only populated on success. -bool GetProtections(void* address, size_t size, int* current, int* max) { - vm_region_info_t region_info; - mach_vm_address_t mem_address = reinterpret_cast<mach_vm_address_t>(address); - mach_vm_size_t mem_size = size; - vm_region_basic_info_64 basic_info; - - region_info = reinterpret_cast<vm_region_recurse_info_t>(&basic_info); - vm_region_flavor_t flavor = VM_REGION_BASIC_INFO_64; - memory_object_name_t memory_object; - mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64; - - kern_return_t kr = - mach_vm_region(mach_task_self(), &mem_address, &mem_size, flavor, - region_info, &count, &memory_object); - if (kr != KERN_SUCCESS) { - MACH_LOG(ERROR, kr) << "Failed to get region info."; - return false; - } - - *current = basic_info.protection; - *max = basic_info.max_protection; - return true; -} - -// Creates a new SharedMemory with the given |size|, filled with 'a'. -std::unique_ptr<SharedMemory> CreateSharedMemory(int size) { - SharedMemoryHandle shm(size, UnguessableToken::Create()); - if (!shm.IsValid()) { - LOG(ERROR) << "Failed to make SharedMemoryHandle"; - return nullptr; - } - std::unique_ptr<SharedMemory> shared_memory(new SharedMemory(shm, false)); - shared_memory->Map(size); - memset(shared_memory->memory(), 'a', size); - return shared_memory; -} - -static const std::string g_service_switch_name = "service_name"; - -// Structs used to pass a mach port from client to server. -struct MachSendPortMessage { - mach_msg_header_t header; - mach_msg_body_t body; - mach_msg_port_descriptor_t data; -}; -struct MachReceivePortMessage { - mach_msg_header_t header; - mach_msg_body_t body; - mach_msg_port_descriptor_t data; - mach_msg_trailer_t trailer; -}; - -// Makes the current process into a Mach Server with the given |service_name|. -mach_port_t BecomeMachServer(const char* service_name) { - mach_port_t port; - kern_return_t kr = bootstrap_check_in(bootstrap_port, service_name, &port); - MACH_CHECK(kr == KERN_SUCCESS, kr) << "BecomeMachServer"; - return port; -} - -// Returns the mach port for the Mach Server with the given |service_name|. -mach_port_t LookupServer(const char* service_name) { - mach_port_t server_port; - kern_return_t kr = - bootstrap_look_up(bootstrap_port, service_name, &server_port); - MACH_CHECK(kr == KERN_SUCCESS, kr) << "LookupServer"; - return server_port; -} - -mach_port_t MakeReceivingPort() { - mach_port_t client_port; - kern_return_t kr = - mach_port_allocate(mach_task_self(), // our task is acquiring - MACH_PORT_RIGHT_RECEIVE, // a new receive right - &client_port); // with this name - MACH_CHECK(kr == KERN_SUCCESS, kr) << "MakeReceivingPort"; - return client_port; -} - -// Blocks until a mach message is sent to |server_port|. This mach message -// must contain a mach port. Returns that mach port. -mach_port_t ReceiveMachPort(mach_port_t port_to_listen_on) { - MachReceivePortMessage recv_msg; - mach_msg_header_t* recv_hdr = &(recv_msg.header); - recv_hdr->msgh_local_port = port_to_listen_on; - recv_hdr->msgh_size = sizeof(recv_msg); - kern_return_t kr = - mach_msg(recv_hdr, // message buffer - MACH_RCV_MSG, // option indicating service - 0, // send size - recv_hdr->msgh_size, // size of header + body - port_to_listen_on, // receive name - MACH_MSG_TIMEOUT_NONE, // no timeout, wait forever - MACH_PORT_NULL); // no notification port - MACH_CHECK(kr == KERN_SUCCESS, kr) << "ReceiveMachPort"; - mach_port_t other_task_port = recv_msg.data.name; - return other_task_port; -} - -// Passes a copy of the send right of |port_to_send| to |receiving_port|. -void SendMachPort(mach_port_t receiving_port, - mach_port_t port_to_send, - int disposition) { - MachSendPortMessage send_msg; - mach_msg_header_t* send_hdr; - send_hdr = &(send_msg.header); - send_hdr->msgh_bits = - MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0) | MACH_MSGH_BITS_COMPLEX; - send_hdr->msgh_size = sizeof(send_msg); - send_hdr->msgh_remote_port = receiving_port; - send_hdr->msgh_local_port = MACH_PORT_NULL; - send_hdr->msgh_reserved = 0; - send_hdr->msgh_id = 0; - send_msg.body.msgh_descriptor_count = 1; - send_msg.data.name = port_to_send; - send_msg.data.disposition = disposition; - send_msg.data.type = MACH_MSG_PORT_DESCRIPTOR; - int kr = mach_msg(send_hdr, // message buffer - MACH_SEND_MSG, // option indicating send - send_hdr->msgh_size, // size of header + body - 0, // receive limit - MACH_PORT_NULL, // receive name - MACH_MSG_TIMEOUT_NONE, // no timeout, wait forever - MACH_PORT_NULL); // no notification port - MACH_CHECK(kr == KERN_SUCCESS, kr) << "SendMachPort"; -} - -std::string CreateRandomServiceName() { - return StringPrintf("SharedMemoryMacMultiProcessTest.%llu", RandUint64()); -} - -// Sets up the mach communication ports with the server. Returns a port to which -// the server will send mach objects. -mach_port_t CommonChildProcessSetUp() { - CommandLine cmd_line = *CommandLine::ForCurrentProcess(); - std::string service_name = - cmd_line.GetSwitchValueASCII(g_service_switch_name); - mac::ScopedMachSendRight server_port(LookupServer(service_name.c_str())); - mach_port_t client_port = MakeReceivingPort(); - - // Send the port that this process is listening on to the server. - SendMachPort(server_port.get(), client_port, MACH_MSG_TYPE_MAKE_SEND); - return client_port; -} - -// The number of active names in the current task's port name space. -mach_msg_type_number_t GetActiveNameCount() { - mach_port_name_array_t name_array; - mach_msg_type_number_t names_count; - mach_port_type_array_t type_array; - mach_msg_type_number_t types_count; - kern_return_t kr = mach_port_names(mach_task_self(), &name_array, - &names_count, &type_array, &types_count); - MACH_CHECK(kr == KERN_SUCCESS, kr) << "GetActiveNameCount"; - return names_count; -} - -} // namespace - -class SharedMemoryMacMultiProcessTest : public MultiProcessTest { - public: - SharedMemoryMacMultiProcessTest() {} - - CommandLine MakeCmdLine(const std::string& procname) override { - CommandLine command_line = MultiProcessTest::MakeCmdLine(procname); - // Pass the service name to the child process. - command_line.AppendSwitchASCII(g_service_switch_name, service_name_); - return command_line; - } - - void SetUpChild(const std::string& name) { - // Make a random service name so that this test doesn't conflict with other - // similar tests. - service_name_ = CreateRandomServiceName(); - server_port_.reset(BecomeMachServer(service_name_.c_str())); - child_process_ = SpawnChild(name); - client_port_.reset(ReceiveMachPort(server_port_.get())); - } - - static const int s_memory_size = 99999; - - protected: - std::string service_name_; - - // A port on which the main process listens for mach messages from the child - // process. - mac::ScopedMachReceiveRight server_port_; - - // A port on which the child process listens for mach messages from the main - // process. - mac::ScopedMachSendRight client_port_; - - base::Process child_process_; - DISALLOW_COPY_AND_ASSIGN(SharedMemoryMacMultiProcessTest); -}; - -// Tests that content written to shared memory in the server process can be read -// by the child process. -TEST_F(SharedMemoryMacMultiProcessTest, MachBasedSharedMemory) { - SetUpChild("MachBasedSharedMemoryClient"); - - std::unique_ptr<SharedMemory> shared_memory( - CreateSharedMemory(s_memory_size)); - - // Send the underlying memory object to the client process. - SendMachPort(client_port_.get(), shared_memory->handle().GetMemoryObject(), - MACH_MSG_TYPE_COPY_SEND); - int rv = -1; - ASSERT_TRUE(child_process_.WaitForExitWithTimeout( - TestTimeouts::action_timeout(), &rv)); - EXPECT_EQ(0, rv); -} - -MULTIPROCESS_TEST_MAIN(MachBasedSharedMemoryClient) { - mac::ScopedMachReceiveRight client_port(CommonChildProcessSetUp()); - // The next mach port should be for a memory object. - mach_port_t memory_object = ReceiveMachPort(client_port.get()); - SharedMemoryHandle shm(memory_object, - SharedMemoryMacMultiProcessTest::s_memory_size, - UnguessableToken::Create()); - SharedMemory shared_memory(shm, false); - shared_memory.Map(SharedMemoryMacMultiProcessTest::s_memory_size); - const char* start = static_cast<const char*>(shared_memory.memory()); - for (int i = 0; i < SharedMemoryMacMultiProcessTest::s_memory_size; ++i) { - DCHECK_EQ(start[i], 'a'); - } - return 0; -} - -// Tests that mapping shared memory with an offset works correctly. -TEST_F(SharedMemoryMacMultiProcessTest, MachBasedSharedMemoryWithOffset) { - SetUpChild("MachBasedSharedMemoryWithOffsetClient"); - - SharedMemoryHandle shm(s_memory_size, UnguessableToken::Create()); - ASSERT_TRUE(shm.IsValid()); - SharedMemory shared_memory(shm, false); - shared_memory.Map(s_memory_size); - - size_t page_size = SysInfo::VMAllocationGranularity(); - char* start = static_cast<char*>(shared_memory.memory()); - memset(start, 'a', page_size); - memset(start + page_size, 'b', page_size); - memset(start + 2 * page_size, 'c', page_size); - - // Send the underlying memory object to the client process. - SendMachPort( - client_port_.get(), shm.GetMemoryObject(), MACH_MSG_TYPE_COPY_SEND); - int rv = -1; - ASSERT_TRUE(child_process_.WaitForExitWithTimeout( - TestTimeouts::action_timeout(), &rv)); - EXPECT_EQ(0, rv); -} - -MULTIPROCESS_TEST_MAIN(MachBasedSharedMemoryWithOffsetClient) { - mac::ScopedMachReceiveRight client_port(CommonChildProcessSetUp()); - // The next mach port should be for a memory object. - mach_port_t memory_object = ReceiveMachPort(client_port.get()); - SharedMemoryHandle shm(memory_object, - SharedMemoryMacMultiProcessTest::s_memory_size, - UnguessableToken::Create()); - SharedMemory shared_memory(shm, false); - size_t page_size = SysInfo::VMAllocationGranularity(); - shared_memory.MapAt(page_size, 2 * page_size); - const char* start = static_cast<const char*>(shared_memory.memory()); - for (size_t i = 0; i < page_size; ++i) { - DCHECK_EQ(start[i], 'b'); - } - for (size_t i = page_size; i < 2 * page_size; ++i) { - DCHECK_EQ(start[i], 'c'); - } - return 0; -} - -// Tests that duplication and closing has the right effect on Mach reference -// counts. -TEST_F(SharedMemoryMacMultiProcessTest, MachDuplicateAndClose) { - mach_msg_type_number_t active_name_count = GetActiveNameCount(); - - // Making a new SharedMemoryHandle increments the name count. - SharedMemoryHandle shm(s_memory_size, UnguessableToken::Create()); - ASSERT_TRUE(shm.IsValid()); - EXPECT_EQ(active_name_count + 1, GetActiveNameCount()); - - // Duplicating the SharedMemoryHandle increments the ref count, but doesn't - // make a new name. - shm.Duplicate(); - EXPECT_EQ(active_name_count + 1, GetActiveNameCount()); - - // Closing the SharedMemoryHandle decrements the ref count. The first time has - // no effect. - shm.Close(); - EXPECT_EQ(active_name_count + 1, GetActiveNameCount()); - - // Closing the SharedMemoryHandle decrements the ref count. The second time - // destroys the port. - shm.Close(); - EXPECT_EQ(active_name_count, GetActiveNameCount()); -} - -// Tests that Mach shared memory can be mapped and unmapped. -TEST_F(SharedMemoryMacMultiProcessTest, MachUnmapMap) { - mach_msg_type_number_t active_name_count = GetActiveNameCount(); - - std::unique_ptr<SharedMemory> shared_memory = - CreateSharedMemory(s_memory_size); - ASSERT_TRUE(shared_memory->Unmap()); - ASSERT_TRUE(shared_memory->Map(s_memory_size)); - shared_memory.reset(); - EXPECT_EQ(active_name_count, GetActiveNameCount()); -} - -// Tests that passing a SharedMemoryHandle to a SharedMemory object also passes -// ownership, and that destroying the SharedMemory closes the SharedMemoryHandle -// as well. -TEST_F(SharedMemoryMacMultiProcessTest, MachSharedMemoryTakesOwnership) { - mach_msg_type_number_t active_name_count = GetActiveNameCount(); - - // Making a new SharedMemoryHandle increments the name count. - SharedMemoryHandle shm(s_memory_size, UnguessableToken::Create()); - ASSERT_TRUE(shm.IsValid()); - EXPECT_EQ(active_name_count + 1, GetActiveNameCount()); - - // Name count doesn't change when mapping the memory. - std::unique_ptr<SharedMemory> shared_memory(new SharedMemory(shm, false)); - shared_memory->Map(s_memory_size); - EXPECT_EQ(active_name_count + 1, GetActiveNameCount()); - - // Destroying the SharedMemory object frees the resource. - shared_memory.reset(); - EXPECT_EQ(active_name_count, GetActiveNameCount()); -} - -// Tests that the read-only flag works. -TEST_F(SharedMemoryMacMultiProcessTest, MachReadOnly) { - std::unique_ptr<SharedMemory> shared_memory( - CreateSharedMemory(s_memory_size)); - - SharedMemoryHandle shm2 = shared_memory->handle().Duplicate(); - ASSERT_TRUE(shm2.IsValid()); - SharedMemory shared_memory2(shm2, true); - shared_memory2.Map(s_memory_size); - ASSERT_DEATH(memset(shared_memory2.memory(), 'b', s_memory_size), ""); -} - -// Tests that duplication of the underlying handle works. -TEST_F(SharedMemoryMacMultiProcessTest, MachDuplicate) { - mach_msg_type_number_t active_name_count = GetActiveNameCount(); - - { - std::unique_ptr<SharedMemory> shared_memory( - CreateSharedMemory(s_memory_size)); - - SharedMemoryHandle shm2 = shared_memory->handle().Duplicate(); - ASSERT_TRUE(shm2.IsValid()); - SharedMemory shared_memory2(shm2, true); - shared_memory2.Map(s_memory_size); - - ASSERT_EQ(0, memcmp(shared_memory->memory(), shared_memory2.memory(), - s_memory_size)); - } - - EXPECT_EQ(active_name_count, GetActiveNameCount()); -} - -// Tests that the method GetReadOnlyHandle() creates a memory object that -// is read only. -TEST_F(SharedMemoryMacMultiProcessTest, MachReadonly) { - std::unique_ptr<SharedMemory> shared_memory( - CreateSharedMemory(s_memory_size)); - - // Check the protection levels. - int current_prot, max_prot; - ASSERT_TRUE(GetProtections(shared_memory->memory(), - shared_memory->mapped_size(), ¤t_prot, - &max_prot)); - ASSERT_EQ(VM_PROT_READ | VM_PROT_WRITE, current_prot); - ASSERT_EQ(VM_PROT_READ | VM_PROT_WRITE, max_prot); - - // Make a new memory object. - SharedMemoryHandle shm2 = shared_memory->GetReadOnlyHandle(); - ASSERT_TRUE(shm2.IsValid()); - EXPECT_EQ(shared_memory->handle().GetGUID(), shm2.GetGUID()); - - // Mapping with |readonly| set to |false| should fail. - SharedMemory shared_memory2(shm2, false); - shared_memory2.Map(s_memory_size); - ASSERT_EQ(nullptr, shared_memory2.memory()); - - // Now trying mapping with |readonly| set to |true|. - SharedMemory shared_memory3(shm2.Duplicate(), true); - shared_memory3.Map(s_memory_size); - ASSERT_NE(nullptr, shared_memory3.memory()); - - // Check the protection levels. - ASSERT_TRUE(GetProtections(shared_memory3.memory(), - shared_memory3.mapped_size(), ¤t_prot, - &max_prot)); - ASSERT_EQ(VM_PROT_READ, current_prot); - ASSERT_EQ(VM_PROT_READ, max_prot); - - // The memory should still be readonly, since the underlying memory object - // is readonly. - ASSERT_DEATH(memset(shared_memory2.memory(), 'b', s_memory_size), ""); -} - -// Tests that the method GetReadOnlyHandle() doesn't leak. -TEST_F(SharedMemoryMacMultiProcessTest, MachReadonlyLeak) { - mach_msg_type_number_t active_name_count = GetActiveNameCount(); - - { - std::unique_ptr<SharedMemory> shared_memory( - CreateSharedMemory(s_memory_size)); - - SharedMemoryHandle shm2 = shared_memory->GetReadOnlyHandle(); - ASSERT_TRUE(shm2.IsValid()); - - // Intentionally map with |readonly| set to |false|. - SharedMemory shared_memory2(shm2, false); - shared_memory2.Map(s_memory_size); - } - - EXPECT_EQ(active_name_count, GetActiveNameCount()); -} - -} // namespace base
diff --git a/base/memory/shared_memory_region_unittest.cc b/base/memory/shared_memory_region_unittest.cc deleted file mode 100644 index e917154..0000000 --- a/base/memory/shared_memory_region_unittest.cc +++ /dev/null
@@ -1,279 +0,0 @@ -// 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 <utility> - -#include "base/memory/platform_shared_memory_region.h" -#include "base/memory/read_only_shared_memory_region.h" -#include "base/memory/unsafe_shared_memory_region.h" -#include "base/memory/writable_shared_memory_region.h" -#include "base/sys_info.h" -#include "base/test/test_shared_memory_util.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -const size_t kRegionSize = 1024; - -bool IsMemoryFilledWithByte(const void* memory, size_t size, char byte) { - const char* start_ptr = static_cast<const char*>(memory); - const char* end_ptr = start_ptr + size; - for (const char* ptr = start_ptr; ptr < end_ptr; ++ptr) { - if (*ptr != byte) - return false; - } - - return true; -} - -template <typename SharedMemoryRegionType> -class SharedMemoryRegionTest : public ::testing::Test { - public: - void SetUp() override { - std::tie(region_, rw_mapping_) = - CreateMappedRegion<SharedMemoryRegionType>(kRegionSize); - ASSERT_TRUE(region_.IsValid()); - ASSERT_TRUE(rw_mapping_.IsValid()); - memset(rw_mapping_.memory(), 'G', kRegionSize); - EXPECT_TRUE(IsMemoryFilledWithByte(rw_mapping_.memory(), kRegionSize, 'G')); - } - - protected: - SharedMemoryRegionType region_; - WritableSharedMemoryMapping rw_mapping_; -}; - -typedef ::testing::Types<WritableSharedMemoryRegion, - UnsafeSharedMemoryRegion, - ReadOnlySharedMemoryRegion> - AllRegionTypes; -TYPED_TEST_CASE(SharedMemoryRegionTest, AllRegionTypes); - -TYPED_TEST(SharedMemoryRegionTest, NonValidRegion) { - TypeParam region; - EXPECT_FALSE(region.IsValid()); - // We shouldn't crash on Map but should return an invalid mapping. - typename TypeParam::MappingType mapping = region.Map(); - EXPECT_FALSE(mapping.IsValid()); -} - -TYPED_TEST(SharedMemoryRegionTest, MoveRegion) { - TypeParam moved_region = std::move(this->region_); - EXPECT_FALSE(this->region_.IsValid()); - ASSERT_TRUE(moved_region.IsValid()); - - // Check that moved region maps correctly. - typename TypeParam::MappingType mapping = moved_region.Map(); - ASSERT_TRUE(mapping.IsValid()); - EXPECT_NE(this->rw_mapping_.memory(), mapping.memory()); - EXPECT_EQ(memcmp(this->rw_mapping_.memory(), mapping.memory(), kRegionSize), - 0); - - // Verify that the second mapping reflects changes in the first. - memset(this->rw_mapping_.memory(), '#', kRegionSize); - EXPECT_EQ(memcmp(this->rw_mapping_.memory(), mapping.memory(), kRegionSize), - 0); -} - -TYPED_TEST(SharedMemoryRegionTest, MappingValidAfterClose) { - // Check the mapping is still valid after the region is closed. - this->region_ = TypeParam(); - EXPECT_FALSE(this->region_.IsValid()); - ASSERT_TRUE(this->rw_mapping_.IsValid()); - EXPECT_TRUE( - IsMemoryFilledWithByte(this->rw_mapping_.memory(), kRegionSize, 'G')); -} - -TYPED_TEST(SharedMemoryRegionTest, MapTwice) { - // The second mapping is either writable or read-only. - typename TypeParam::MappingType mapping = this->region_.Map(); - ASSERT_TRUE(mapping.IsValid()); - EXPECT_NE(this->rw_mapping_.memory(), mapping.memory()); - EXPECT_EQ(memcmp(this->rw_mapping_.memory(), mapping.memory(), kRegionSize), - 0); - - // Verify that the second mapping reflects changes in the first. - memset(this->rw_mapping_.memory(), '#', kRegionSize); - EXPECT_EQ(memcmp(this->rw_mapping_.memory(), mapping.memory(), kRegionSize), - 0); - - // Close the region and unmap the first memory segment, verify the second - // still has the right data. - this->region_ = TypeParam(); - this->rw_mapping_ = WritableSharedMemoryMapping(); - EXPECT_TRUE(IsMemoryFilledWithByte(mapping.memory(), kRegionSize, '#')); -} - -TYPED_TEST(SharedMemoryRegionTest, MapUnmapMap) { - this->rw_mapping_ = WritableSharedMemoryMapping(); - - typename TypeParam::MappingType mapping = this->region_.Map(); - ASSERT_TRUE(mapping.IsValid()); - EXPECT_TRUE(IsMemoryFilledWithByte(mapping.memory(), kRegionSize, 'G')); -} - -TYPED_TEST(SharedMemoryRegionTest, SerializeAndDeserialize) { - subtle::PlatformSharedMemoryRegion platform_region = - TypeParam::TakeHandleForSerialization(std::move(this->region_)); - EXPECT_EQ(platform_region.GetGUID(), this->rw_mapping_.guid()); - TypeParam region = TypeParam::Deserialize(std::move(platform_region)); - EXPECT_TRUE(region.IsValid()); - EXPECT_FALSE(this->region_.IsValid()); - typename TypeParam::MappingType mapping = region.Map(); - ASSERT_TRUE(mapping.IsValid()); - EXPECT_TRUE(IsMemoryFilledWithByte(mapping.memory(), kRegionSize, 'G')); - - // Verify that the second mapping reflects changes in the first. - memset(this->rw_mapping_.memory(), '#', kRegionSize); - EXPECT_EQ(memcmp(this->rw_mapping_.memory(), mapping.memory(), kRegionSize), - 0); -} - -// Map() will return addresses which are aligned to the platform page size, this -// varies from platform to platform though. Since we'd like to advertise a -// minimum alignment that callers can count on, test for it here. -TYPED_TEST(SharedMemoryRegionTest, MapMinimumAlignment) { - EXPECT_EQ(0U, - reinterpret_cast<uintptr_t>(this->rw_mapping_.memory()) & - (subtle::PlatformSharedMemoryRegion::kMapMinimumAlignment - 1)); -} - -TYPED_TEST(SharedMemoryRegionTest, MapSize) { - EXPECT_EQ(this->rw_mapping_.size(), kRegionSize); - EXPECT_GE(this->rw_mapping_.mapped_size(), kRegionSize); -} - -TYPED_TEST(SharedMemoryRegionTest, MapGranularity) { - EXPECT_LT(this->rw_mapping_.mapped_size(), - kRegionSize + SysInfo::VMAllocationGranularity()); -} - -TYPED_TEST(SharedMemoryRegionTest, MapAt) { - const size_t kPageSize = SysInfo::VMAllocationGranularity(); - ASSERT_TRUE(kPageSize >= sizeof(uint32_t)); - ASSERT_EQ(kPageSize % sizeof(uint32_t), 0U); - const size_t kDataSize = kPageSize * 2; - const size_t kCount = kDataSize / sizeof(uint32_t); - - TypeParam region; - WritableSharedMemoryMapping rw_mapping; - std::tie(region, rw_mapping) = CreateMappedRegion<TypeParam>(kDataSize); - ASSERT_TRUE(region.IsValid()); - ASSERT_TRUE(rw_mapping.IsValid()); - uint32_t* ptr = static_cast<uint32_t*>(rw_mapping.memory()); - - for (size_t i = 0; i < kCount; ++i) - ptr[i] = i; - - rw_mapping = WritableSharedMemoryMapping(); - off_t bytes_offset = kPageSize; - typename TypeParam::MappingType mapping = - region.MapAt(bytes_offset, kDataSize - bytes_offset); - ASSERT_TRUE(mapping.IsValid()); - - off_t int_offset = bytes_offset / sizeof(uint32_t); - const uint32_t* ptr2 = static_cast<const uint32_t*>(mapping.memory()); - for (size_t i = int_offset; i < kCount; ++i) { - EXPECT_EQ(ptr2[i - int_offset], i); - } -} - -TYPED_TEST(SharedMemoryRegionTest, MapAtNotAlignedOffsetFails) { - const size_t kDataSize = SysInfo::VMAllocationGranularity(); - - TypeParam region; - WritableSharedMemoryMapping rw_mapping; - std::tie(region, rw_mapping) = CreateMappedRegion<TypeParam>(kDataSize); - ASSERT_TRUE(region.IsValid()); - ASSERT_TRUE(rw_mapping.IsValid()); - off_t offset = kDataSize / 2; - typename TypeParam::MappingType mapping = - region.MapAt(offset, kDataSize - offset); - EXPECT_FALSE(mapping.IsValid()); -} - -TYPED_TEST(SharedMemoryRegionTest, MapMoreBytesThanRegionSizeFails) { - size_t region_real_size = this->region_.GetSize(); - typename TypeParam::MappingType mapping = - this->region_.MapAt(0, region_real_size + 1); - EXPECT_FALSE(mapping.IsValid()); -} - -template <typename DuplicatableSharedMemoryRegion> -class DuplicatableSharedMemoryRegionTest - : public SharedMemoryRegionTest<DuplicatableSharedMemoryRegion> {}; - -typedef ::testing::Types<UnsafeSharedMemoryRegion, ReadOnlySharedMemoryRegion> - DuplicatableRegionTypes; -TYPED_TEST_CASE(DuplicatableSharedMemoryRegionTest, DuplicatableRegionTypes); - -TYPED_TEST(DuplicatableSharedMemoryRegionTest, Duplicate) { - TypeParam dup_region = this->region_.Duplicate(); - typename TypeParam::MappingType mapping = dup_region.Map(); - ASSERT_TRUE(mapping.IsValid()); - EXPECT_NE(this->rw_mapping_.memory(), mapping.memory()); - EXPECT_EQ(this->rw_mapping_.guid(), mapping.guid()); - EXPECT_TRUE(IsMemoryFilledWithByte(mapping.memory(), kRegionSize, 'G')); -} - -class ReadOnlySharedMemoryRegionTest : public ::testing::Test { - public: - ReadOnlySharedMemoryRegion GetInitiallyReadOnlyRegion(size_t size) { - MappedReadOnlyRegion mapped_region = - ReadOnlySharedMemoryRegion::Create(size); - ReadOnlySharedMemoryRegion region = std::move(mapped_region.region); - return region; - } - - ReadOnlySharedMemoryRegion GetConvertedToReadOnlyRegion(size_t size) { - WritableSharedMemoryRegion region = - WritableSharedMemoryRegion::Create(kRegionSize); - ReadOnlySharedMemoryRegion ro_region = - WritableSharedMemoryRegion::ConvertToReadOnly(std::move(region)); - return ro_region; - } -}; - -TEST_F(ReadOnlySharedMemoryRegionTest, - InitiallyReadOnlyRegionCannotBeMappedAsWritable) { - ReadOnlySharedMemoryRegion region = GetInitiallyReadOnlyRegion(kRegionSize); - ASSERT_TRUE(region.IsValid()); - - EXPECT_TRUE(CheckReadOnlyPlatformSharedMemoryRegionForTesting( - ReadOnlySharedMemoryRegion::TakeHandleForSerialization( - std::move(region)))); -} - -TEST_F(ReadOnlySharedMemoryRegionTest, - ConvertedToReadOnlyRegionCannotBeMappedAsWritable) { - ReadOnlySharedMemoryRegion region = GetConvertedToReadOnlyRegion(kRegionSize); - ASSERT_TRUE(region.IsValid()); - - EXPECT_TRUE(CheckReadOnlyPlatformSharedMemoryRegionForTesting( - ReadOnlySharedMemoryRegion::TakeHandleForSerialization( - std::move(region)))); -} - -TEST_F(ReadOnlySharedMemoryRegionTest, - InitiallyReadOnlyRegionProducedMappingWriteDeathTest) { - ReadOnlySharedMemoryRegion region = GetInitiallyReadOnlyRegion(kRegionSize); - ASSERT_TRUE(region.IsValid()); - ReadOnlySharedMemoryMapping mapping = region.Map(); - ASSERT_TRUE(mapping.IsValid()); - void* memory_ptr = const_cast<void*>(mapping.memory()); - EXPECT_DEATH_IF_SUPPORTED(memset(memory_ptr, 'G', kRegionSize), ""); -} - -TEST_F(ReadOnlySharedMemoryRegionTest, - ConvertedToReadOnlyRegionProducedMappingWriteDeathTest) { - ReadOnlySharedMemoryRegion region = GetConvertedToReadOnlyRegion(kRegionSize); - ASSERT_TRUE(region.IsValid()); - ReadOnlySharedMemoryMapping mapping = region.Map(); - ASSERT_TRUE(mapping.IsValid()); - void* memory_ptr = const_cast<void*>(mapping.memory()); - EXPECT_DEATH_IF_SUPPORTED(memset(memory_ptr, 'G', kRegionSize), ""); -} - -} // namespace base
diff --git a/base/memory/shared_memory_unittest.cc b/base/memory/shared_memory_unittest.cc deleted file mode 100644 index c4c21c4..0000000 --- a/base/memory/shared_memory_unittest.cc +++ /dev/null
@@ -1,965 +0,0 @@ -// 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/memory/shared_memory.h" - -#include <stddef.h> -#include <stdint.h> - -#include <memory> - -#include "base/atomicops.h" -#include "base/base_switches.h" -#include "base/bind.h" -#include "base/command_line.h" -#include "base/logging.h" -#include "base/macros.h" -#include "base/memory/shared_memory_handle.h" -#include "base/process/kill.h" -#include "base/rand_util.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_piece.h" -#include "base/strings/string_util.h" -#include "base/sys_info.h" -#include "base/test/multiprocess_test.h" -#include "base/threading/platform_thread.h" -#include "base/time/time.h" -#include "base/unguessable_token.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/multiprocess_func_list.h" - -#if defined(OS_ANDROID) -#include "base/callback.h" -#endif - -#if defined(OS_POSIX) -#include <errno.h> -#include <fcntl.h> -#include <sys/mman.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> -#endif - -#if defined(OS_LINUX) -#include <sys/syscall.h> -#endif - -#if defined(OS_WIN) -#include "base/win/scoped_handle.h" -#endif - -#if defined(OS_FUCHSIA) -#include <zircon/process.h> -#include <zircon/syscalls.h> -#include "base/fuchsia/scoped_zx_handle.h" -#endif - -namespace base { - -namespace { - -#if !defined(OS_MACOSX) && !defined(OS_FUCHSIA) -// Each thread will open the shared memory. Each thread will take a different 4 -// byte int pointer, and keep changing it, with some small pauses in between. -// Verify that each thread's value in the shared memory is always correct. -class MultipleThreadMain : public PlatformThread::Delegate { - public: - explicit MultipleThreadMain(int16_t id) : id_(id) {} - ~MultipleThreadMain() override = default; - - static void CleanUp() { - SharedMemory memory; - memory.Delete(s_test_name_); - } - - // PlatformThread::Delegate interface. - void ThreadMain() override { - const uint32_t kDataSize = 1024; - SharedMemory memory; - bool rv = memory.CreateNamedDeprecated(s_test_name_, true, kDataSize); - EXPECT_TRUE(rv); - rv = memory.Map(kDataSize); - EXPECT_TRUE(rv); - int* ptr = static_cast<int*>(memory.memory()) + id_; - EXPECT_EQ(0, *ptr); - - for (int idx = 0; idx < 100; idx++) { - *ptr = idx; - PlatformThread::Sleep(TimeDelta::FromMilliseconds(1)); - EXPECT_EQ(*ptr, idx); - } - // Reset back to 0 for the next test that uses the same name. - *ptr = 0; - - memory.Close(); - } - - private: - int16_t id_; - - static const char s_test_name_[]; - - DISALLOW_COPY_AND_ASSIGN(MultipleThreadMain); -}; - -const char MultipleThreadMain::s_test_name_[] = - "SharedMemoryOpenThreadTest"; -#endif // !defined(OS_MACOSX) && !defined(OS_FUCHSIA) - -enum class Mode { - Default, -#if defined(OS_LINUX) && !defined(OS_CHROMEOS) - DisableDevShm = 1, -#endif -}; - -class SharedMemoryTest : public ::testing::TestWithParam<Mode> { - public: - void SetUp() override { - switch (GetParam()) { - case Mode::Default: - break; -#if defined(OS_LINUX) && !defined(OS_CHROMEOS) - case Mode::DisableDevShm: - CommandLine* cmdline = CommandLine::ForCurrentProcess(); - cmdline->AppendSwitch(switches::kDisableDevShmUsage); - break; -#endif // defined(OS_LINUX) && !defined(OS_CHROMEOS) - } - } -}; - -} // namespace - -// Android/Mac/Fuchsia doesn't support SharedMemory::Open/Delete/ -// CreateNamedDeprecated(openExisting=true) -#if !defined(OS_ANDROID) && !defined(OS_MACOSX) && !defined(OS_FUCHSIA) - -TEST_P(SharedMemoryTest, OpenClose) { - const uint32_t kDataSize = 1024; - std::string test_name = "SharedMemoryOpenCloseTest"; - - // Open two handles to a memory segment, confirm that they are mapped - // separately yet point to the same space. - SharedMemory memory1; - bool rv = memory1.Delete(test_name); - EXPECT_TRUE(rv); - rv = memory1.Delete(test_name); - EXPECT_TRUE(rv); - rv = memory1.Open(test_name, false); - EXPECT_FALSE(rv); - rv = memory1.CreateNamedDeprecated(test_name, false, kDataSize); - EXPECT_TRUE(rv); - rv = memory1.Map(kDataSize); - EXPECT_TRUE(rv); - SharedMemory memory2; - rv = memory2.Open(test_name, false); - EXPECT_TRUE(rv); - rv = memory2.Map(kDataSize); - EXPECT_TRUE(rv); - EXPECT_NE(memory1.memory(), memory2.memory()); // Compare the pointers. - - // Make sure we don't segfault. (it actually happened!) - ASSERT_NE(memory1.memory(), static_cast<void*>(nullptr)); - ASSERT_NE(memory2.memory(), static_cast<void*>(nullptr)); - - // Write data to the first memory segment, verify contents of second. - memset(memory1.memory(), '1', kDataSize); - EXPECT_EQ(memcmp(memory1.memory(), memory2.memory(), kDataSize), 0); - - // Close the first memory segment, and verify the second has the right data. - memory1.Close(); - char* start_ptr = static_cast<char*>(memory2.memory()); - char* end_ptr = start_ptr + kDataSize; - for (char* ptr = start_ptr; ptr < end_ptr; ptr++) - EXPECT_EQ(*ptr, '1'); - - // Close the second memory segment. - memory2.Close(); - - rv = memory1.Delete(test_name); - EXPECT_TRUE(rv); - rv = memory2.Delete(test_name); - EXPECT_TRUE(rv); -} - -TEST_P(SharedMemoryTest, OpenExclusive) { - const uint32_t kDataSize = 1024; - const uint32_t kDataSize2 = 2048; - std::ostringstream test_name_stream; - test_name_stream << "SharedMemoryOpenExclusiveTest." - << Time::Now().ToDoubleT(); - std::string test_name = test_name_stream.str(); - - // Open two handles to a memory segment and check that - // open_existing_deprecated works as expected. - SharedMemory memory1; - bool rv = memory1.CreateNamedDeprecated(test_name, false, kDataSize); - EXPECT_TRUE(rv); - - // Memory1 knows it's size because it created it. - EXPECT_EQ(memory1.requested_size(), kDataSize); - - rv = memory1.Map(kDataSize); - EXPECT_TRUE(rv); - - // The mapped memory1 must be at least the size we asked for. - EXPECT_GE(memory1.mapped_size(), kDataSize); - - // The mapped memory1 shouldn't exceed rounding for allocation granularity. - EXPECT_LT(memory1.mapped_size(), - kDataSize + SysInfo::VMAllocationGranularity()); - - memset(memory1.memory(), 'G', kDataSize); - - SharedMemory memory2; - // Should not be able to create if openExisting is false. - rv = memory2.CreateNamedDeprecated(test_name, false, kDataSize2); - EXPECT_FALSE(rv); - - // Should be able to create with openExisting true. - rv = memory2.CreateNamedDeprecated(test_name, true, kDataSize2); - EXPECT_TRUE(rv); - - // Memory2 shouldn't know the size because we didn't create it. - EXPECT_EQ(memory2.requested_size(), 0U); - - // We should be able to map the original size. - rv = memory2.Map(kDataSize); - EXPECT_TRUE(rv); - - // The mapped memory2 must be at least the size of the original. - EXPECT_GE(memory2.mapped_size(), kDataSize); - - // The mapped memory2 shouldn't exceed rounding for allocation granularity. - EXPECT_LT(memory2.mapped_size(), - kDataSize2 + SysInfo::VMAllocationGranularity()); - - // Verify that opening memory2 didn't truncate or delete memory 1. - char* start_ptr = static_cast<char*>(memory2.memory()); - char* end_ptr = start_ptr + kDataSize; - for (char* ptr = start_ptr; ptr < end_ptr; ptr++) { - EXPECT_EQ(*ptr, 'G'); - } - - memory1.Close(); - memory2.Close(); - - rv = memory1.Delete(test_name); - EXPECT_TRUE(rv); -} -#endif // !defined(OS_ANDROID) && !defined(OS_MACOSX) && !defined(OS_FUCHSIA) - -// Check that memory is still mapped after its closed. -TEST_P(SharedMemoryTest, CloseNoUnmap) { - const size_t kDataSize = 4096; - - SharedMemory memory; - ASSERT_TRUE(memory.CreateAndMapAnonymous(kDataSize)); - char* ptr = static_cast<char*>(memory.memory()); - ASSERT_NE(ptr, static_cast<void*>(nullptr)); - memset(ptr, 'G', kDataSize); - - memory.Close(); - - EXPECT_EQ(ptr, memory.memory()); - EXPECT_TRUE(!memory.handle().IsValid()); - - for (size_t i = 0; i < kDataSize; i++) { - EXPECT_EQ('G', ptr[i]); - } - - memory.Unmap(); - EXPECT_EQ(nullptr, memory.memory()); -} - -#if !defined(OS_MACOSX) && !defined(OS_FUCHSIA) -// Create a set of N threads to each open a shared memory segment and write to -// it. Verify that they are always reading/writing consistent data. -TEST_P(SharedMemoryTest, MultipleThreads) { - const int kNumThreads = 5; - - MultipleThreadMain::CleanUp(); - // On POSIX we have a problem when 2 threads try to create the shmem - // (a file) at exactly the same time, since create both creates the - // file and zerofills it. We solve the problem for this unit test - // (make it not flaky) by starting with 1 thread, then - // intentionally don't clean up its shmem before running with - // kNumThreads. - - int threadcounts[] = { 1, kNumThreads }; - for (size_t i = 0; i < arraysize(threadcounts); i++) { - int numthreads = threadcounts[i]; - std::unique_ptr<PlatformThreadHandle[]> thread_handles; - std::unique_ptr<MultipleThreadMain* []> thread_delegates; - - thread_handles.reset(new PlatformThreadHandle[numthreads]); - thread_delegates.reset(new MultipleThreadMain*[numthreads]); - - // Spawn the threads. - for (int16_t index = 0; index < numthreads; index++) { - PlatformThreadHandle pth; - thread_delegates[index] = new MultipleThreadMain(index); - EXPECT_TRUE(PlatformThread::Create(0, thread_delegates[index], &pth)); - thread_handles[index] = pth; - } - - // Wait for the threads to finish. - for (int index = 0; index < numthreads; index++) { - PlatformThread::Join(thread_handles[index]); - delete thread_delegates[index]; - } - } - MultipleThreadMain::CleanUp(); -} -#endif - -// Allocate private (unique) shared memory with an empty string for a -// name. Make sure several of them don't point to the same thing as -// we might expect if the names are equal. -TEST_P(SharedMemoryTest, AnonymousPrivate) { - int i, j; - int count = 4; - bool rv; - const uint32_t kDataSize = 8192; - - std::unique_ptr<SharedMemory[]> memories(new SharedMemory[count]); - std::unique_ptr<int* []> pointers(new int*[count]); - ASSERT_TRUE(memories.get()); - ASSERT_TRUE(pointers.get()); - - for (i = 0; i < count; i++) { - rv = memories[i].CreateAndMapAnonymous(kDataSize); - EXPECT_TRUE(rv); - int* ptr = static_cast<int*>(memories[i].memory()); - EXPECT_TRUE(ptr); - pointers[i] = ptr; - } - - for (i = 0; i < count; i++) { - // zero out the first int in each except for i; for that one, make it 100. - for (j = 0; j < count; j++) { - if (i == j) - pointers[j][0] = 100; - else - pointers[j][0] = 0; - } - // make sure there is no bleeding of the 100 into the other pointers - for (j = 0; j < count; j++) { - if (i == j) - EXPECT_EQ(100, pointers[j][0]); - else - EXPECT_EQ(0, pointers[j][0]); - } - } - - for (int i = 0; i < count; i++) { - memories[i].Close(); - } -} - -TEST_P(SharedMemoryTest, GetReadOnlyHandle) { - StringPiece contents = "Hello World"; - - SharedMemory writable_shmem; - SharedMemoryCreateOptions options; - options.size = contents.size(); - options.share_read_only = true; -#if defined(OS_MACOSX) && !defined(OS_IOS) - // The Mach functionality is tested in shared_memory_mac_unittest.cc. - options.type = SharedMemoryHandle::POSIX; -#endif - ASSERT_TRUE(writable_shmem.Create(options)); - ASSERT_TRUE(writable_shmem.Map(options.size)); - memcpy(writable_shmem.memory(), contents.data(), contents.size()); - EXPECT_TRUE(writable_shmem.Unmap()); - - SharedMemoryHandle readonly_handle = writable_shmem.GetReadOnlyHandle(); - EXPECT_EQ(writable_shmem.handle().GetGUID(), readonly_handle.GetGUID()); - EXPECT_EQ(writable_shmem.handle().GetSize(), readonly_handle.GetSize()); - ASSERT_TRUE(readonly_handle.IsValid()); - SharedMemory readonly_shmem(readonly_handle, /*readonly=*/true); - - ASSERT_TRUE(readonly_shmem.Map(contents.size())); - EXPECT_EQ(contents, - StringPiece(static_cast<const char*>(readonly_shmem.memory()), - contents.size())); - EXPECT_TRUE(readonly_shmem.Unmap()); - -#if defined(OS_ANDROID) - // On Android, mapping a region through a read-only descriptor makes the - // region read-only. Any writable mapping attempt should fail. - ASSERT_FALSE(writable_shmem.Map(contents.size())); -#else - // Make sure the writable instance is still writable. - ASSERT_TRUE(writable_shmem.Map(contents.size())); - StringPiece new_contents = "Goodbye"; - memcpy(writable_shmem.memory(), new_contents.data(), new_contents.size()); - EXPECT_EQ(new_contents, - StringPiece(static_cast<const char*>(writable_shmem.memory()), - new_contents.size())); -#endif - - // We'd like to check that if we send the read-only segment to another - // process, then that other process can't reopen it read/write. (Since that - // would be a security hole.) Setting up multiple processes is hard in a - // unittest, so this test checks that the *current* process can't reopen the - // segment read/write. I think the test here is stronger than we actually - // care about, but there's a remote possibility that sending a file over a - // pipe would transform it into read/write. - SharedMemoryHandle handle = readonly_shmem.handle(); - -#if defined(OS_ANDROID) - // The "read-only" handle is still writable on Android: - // http://crbug.com/320865 - (void)handle; -#elif defined(OS_FUCHSIA) - uintptr_t addr; - EXPECT_NE(ZX_OK, zx_vmar_map(zx_vmar_root_self(), 0, handle.GetHandle(), 0, - contents.size(), ZX_VM_FLAG_PERM_WRITE, &addr)) - << "Shouldn't be able to map as writable."; - - ScopedZxHandle duped_handle; - EXPECT_NE(ZX_OK, zx_handle_duplicate(handle.GetHandle(), ZX_RIGHT_WRITE, - duped_handle.receive())) - << "Shouldn't be able to duplicate the handle into a writable one."; - - EXPECT_EQ(ZX_OK, zx_handle_duplicate(handle.GetHandle(), ZX_RIGHT_READ, - duped_handle.receive())) - << "Should be able to duplicate the handle into a readable one."; -#elif defined(OS_POSIX) - int handle_fd = SharedMemory::GetFdFromSharedMemoryHandle(handle); - EXPECT_EQ(O_RDONLY, fcntl(handle_fd, F_GETFL) & O_ACCMODE) - << "The descriptor itself should be read-only."; - - errno = 0; - void* writable = mmap(nullptr, contents.size(), PROT_READ | PROT_WRITE, - MAP_SHARED, handle_fd, 0); - int mmap_errno = errno; - EXPECT_EQ(MAP_FAILED, writable) - << "It shouldn't be possible to re-mmap the descriptor writable."; - EXPECT_EQ(EACCES, mmap_errno) << strerror(mmap_errno); - if (writable != MAP_FAILED) - EXPECT_EQ(0, munmap(writable, readonly_shmem.mapped_size())); - -#elif defined(OS_WIN) - EXPECT_EQ(NULL, MapViewOfFile(handle.GetHandle(), FILE_MAP_WRITE, 0, 0, 0)) - << "Shouldn't be able to map memory writable."; - - HANDLE temp_handle; - BOOL rv = ::DuplicateHandle(GetCurrentProcess(), handle.GetHandle(), - GetCurrentProcess(), &temp_handle, - FILE_MAP_ALL_ACCESS, false, 0); - EXPECT_EQ(FALSE, rv) - << "Shouldn't be able to duplicate the handle into a writable one."; - if (rv) - win::ScopedHandle writable_handle(temp_handle); - rv = ::DuplicateHandle(GetCurrentProcess(), handle.GetHandle(), - GetCurrentProcess(), &temp_handle, FILE_MAP_READ, - false, 0); - EXPECT_EQ(TRUE, rv) - << "Should be able to duplicate the handle into a readable one."; - if (rv) - win::ScopedHandle writable_handle(temp_handle); -#else -#error Unexpected platform; write a test that tries to make 'handle' writable. -#endif // defined(OS_POSIX) || defined(OS_WIN) -} - -TEST_P(SharedMemoryTest, ShareToSelf) { - StringPiece contents = "Hello World"; - - SharedMemory shmem; - ASSERT_TRUE(shmem.CreateAndMapAnonymous(contents.size())); - memcpy(shmem.memory(), contents.data(), contents.size()); - EXPECT_TRUE(shmem.Unmap()); - - SharedMemoryHandle shared_handle = shmem.handle().Duplicate(); - ASSERT_TRUE(shared_handle.IsValid()); - EXPECT_TRUE(shared_handle.OwnershipPassesToIPC()); - EXPECT_EQ(shared_handle.GetGUID(), shmem.handle().GetGUID()); - EXPECT_EQ(shared_handle.GetSize(), shmem.handle().GetSize()); - SharedMemory shared(shared_handle, /*readonly=*/false); - - ASSERT_TRUE(shared.Map(contents.size())); - EXPECT_EQ( - contents, - StringPiece(static_cast<const char*>(shared.memory()), contents.size())); - - shared_handle = shmem.handle().Duplicate(); - ASSERT_TRUE(shared_handle.IsValid()); - ASSERT_TRUE(shared_handle.OwnershipPassesToIPC()); - SharedMemory readonly(shared_handle, /*readonly=*/true); - - ASSERT_TRUE(readonly.Map(contents.size())); - EXPECT_EQ(contents, - StringPiece(static_cast<const char*>(readonly.memory()), - contents.size())); -} - -TEST_P(SharedMemoryTest, ShareWithMultipleInstances) { - static const StringPiece kContents = "Hello World"; - - SharedMemory shmem; - ASSERT_TRUE(shmem.CreateAndMapAnonymous(kContents.size())); - // We do not need to unmap |shmem| to let |shared| map. - const StringPiece shmem_contents(static_cast<const char*>(shmem.memory()), - shmem.requested_size()); - - SharedMemoryHandle shared_handle = shmem.handle().Duplicate(); - ASSERT_TRUE(shared_handle.IsValid()); - SharedMemory shared(shared_handle, /*readonly=*/false); - ASSERT_TRUE(shared.Map(kContents.size())); - // The underlying shared memory is created by |shmem|, so both - // |shared|.requested_size() and |readonly|.requested_size() are zero. - ASSERT_EQ(0U, shared.requested_size()); - const StringPiece shared_contents(static_cast<const char*>(shared.memory()), - shmem.requested_size()); - - shared_handle = shmem.handle().Duplicate(); - ASSERT_TRUE(shared_handle.IsValid()); - ASSERT_TRUE(shared_handle.OwnershipPassesToIPC()); - SharedMemory readonly(shared_handle, /*readonly=*/true); - ASSERT_TRUE(readonly.Map(kContents.size())); - ASSERT_EQ(0U, readonly.requested_size()); - const StringPiece readonly_contents( - static_cast<const char*>(readonly.memory()), - shmem.requested_size()); - - // |shmem| should be able to update the content. - memcpy(shmem.memory(), kContents.data(), kContents.size()); - - ASSERT_EQ(kContents, shmem_contents); - ASSERT_EQ(kContents, shared_contents); - ASSERT_EQ(kContents, readonly_contents); - - // |shared| should also be able to update the content. - memcpy(shared.memory(), ToLowerASCII(kContents).c_str(), kContents.size()); - - ASSERT_EQ(StringPiece(ToLowerASCII(kContents)), shmem_contents); - ASSERT_EQ(StringPiece(ToLowerASCII(kContents)), shared_contents); - ASSERT_EQ(StringPiece(ToLowerASCII(kContents)), readonly_contents); -} - -TEST_P(SharedMemoryTest, MapAt) { - ASSERT_TRUE(SysInfo::VMAllocationGranularity() >= sizeof(uint32_t)); - const size_t kCount = SysInfo::VMAllocationGranularity(); - const size_t kDataSize = kCount * sizeof(uint32_t); - - SharedMemory memory; - ASSERT_TRUE(memory.CreateAndMapAnonymous(kDataSize)); - uint32_t* ptr = static_cast<uint32_t*>(memory.memory()); - ASSERT_NE(ptr, static_cast<void*>(nullptr)); - - for (size_t i = 0; i < kCount; ++i) { - ptr[i] = i; - } - - memory.Unmap(); - - off_t offset = SysInfo::VMAllocationGranularity(); - ASSERT_TRUE(memory.MapAt(offset, kDataSize - offset)); - offset /= sizeof(uint32_t); - ptr = static_cast<uint32_t*>(memory.memory()); - ASSERT_NE(ptr, static_cast<void*>(nullptr)); - for (size_t i = offset; i < kCount; ++i) { - EXPECT_EQ(ptr[i - offset], i); - } -} - -TEST_P(SharedMemoryTest, MapTwice) { - const uint32_t kDataSize = 1024; - SharedMemory memory; - bool rv = memory.CreateAndMapAnonymous(kDataSize); - EXPECT_TRUE(rv); - - void* old_address = memory.memory(); - - rv = memory.Map(kDataSize); - EXPECT_FALSE(rv); - EXPECT_EQ(old_address, memory.memory()); -} - -#if defined(OS_POSIX) -// This test is not applicable for iOS (crbug.com/399384). -#if !defined(OS_IOS) -// Create a shared memory object, mmap it, and mprotect it to PROT_EXEC. -TEST_P(SharedMemoryTest, AnonymousExecutable) { - const uint32_t kTestSize = 1 << 16; - - SharedMemory shared_memory; - SharedMemoryCreateOptions options; - options.size = kTestSize; - options.executable = true; -#if defined(OS_MACOSX) && !defined(OS_IOS) - // The Mach functionality is tested in shared_memory_mac_unittest.cc. - options.type = SharedMemoryHandle::POSIX; -#endif - - EXPECT_TRUE(shared_memory.Create(options)); - EXPECT_TRUE(shared_memory.Map(shared_memory.requested_size())); - - EXPECT_EQ(0, mprotect(shared_memory.memory(), shared_memory.requested_size(), - PROT_READ | PROT_EXEC)); -} -#endif // !defined(OS_IOS) - -#if defined(OS_ANDROID) -// This test is restricted to Android since there is no way on other platforms -// to guarantee that a region can never be mapped with PROT_EXEC. E.g. on -// Linux, anonymous shared regions come from /dev/shm which can be mounted -// without 'noexec'. In this case, anything can perform an mprotect() to -// change the protection mask of a given page. -TEST(SharedMemoryTest, AnonymousIsNotExecutableByDefault) { - const uint32_t kTestSize = 1 << 16; - - SharedMemory shared_memory; - SharedMemoryCreateOptions options; - options.size = kTestSize; - - EXPECT_TRUE(shared_memory.Create(options)); - EXPECT_TRUE(shared_memory.Map(shared_memory.requested_size())); - - errno = 0; - EXPECT_EQ(-1, mprotect(shared_memory.memory(), shared_memory.requested_size(), - PROT_READ | PROT_EXEC)); - EXPECT_EQ(EACCES, errno); -} -#endif // OS_ANDROID - -// Android supports a different permission model than POSIX for its "ashmem" -// shared memory implementation. So the tests about file permissions are not -// included on Android. Fuchsia does not use a file-backed shared memory -// implementation. - -#if !defined(OS_ANDROID) && !defined(OS_FUCHSIA) - -// Set a umask and restore the old mask on destruction. -class ScopedUmaskSetter { - public: - explicit ScopedUmaskSetter(mode_t target_mask) { - old_umask_ = umask(target_mask); - } - ~ScopedUmaskSetter() { umask(old_umask_); } - private: - mode_t old_umask_; - DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedUmaskSetter); -}; - -// Create a shared memory object, check its permissions. -TEST_P(SharedMemoryTest, FilePermissionsAnonymous) { - const uint32_t kTestSize = 1 << 8; - - SharedMemory shared_memory; - SharedMemoryCreateOptions options; - options.size = kTestSize; -#if defined(OS_MACOSX) && !defined(OS_IOS) - // The Mach functionality is tested in shared_memory_mac_unittest.cc. - options.type = SharedMemoryHandle::POSIX; -#endif - // Set a file mode creation mask that gives all permissions. - ScopedUmaskSetter permissive_mask(S_IWGRP | S_IWOTH); - - EXPECT_TRUE(shared_memory.Create(options)); - - int shm_fd = - SharedMemory::GetFdFromSharedMemoryHandle(shared_memory.handle()); - struct stat shm_stat; - EXPECT_EQ(0, fstat(shm_fd, &shm_stat)); - // Neither the group, nor others should be able to read the shared memory - // file. - EXPECT_FALSE(shm_stat.st_mode & S_IRWXO); - EXPECT_FALSE(shm_stat.st_mode & S_IRWXG); -} - -// Create a shared memory object, check its permissions. -TEST_P(SharedMemoryTest, FilePermissionsNamed) { - const uint32_t kTestSize = 1 << 8; - - SharedMemory shared_memory; - SharedMemoryCreateOptions options; - options.size = kTestSize; -#if defined(OS_MACOSX) && !defined(OS_IOS) - // The Mach functionality is tested in shared_memory_mac_unittest.cc. - options.type = SharedMemoryHandle::POSIX; -#endif - - // Set a file mode creation mask that gives all permissions. - ScopedUmaskSetter permissive_mask(S_IWGRP | S_IWOTH); - - EXPECT_TRUE(shared_memory.Create(options)); - - int fd = SharedMemory::GetFdFromSharedMemoryHandle(shared_memory.handle()); - struct stat shm_stat; - EXPECT_EQ(0, fstat(fd, &shm_stat)); - // Neither the group, nor others should have been able to open the shared - // memory file while its name existed. - EXPECT_FALSE(shm_stat.st_mode & S_IRWXO); - EXPECT_FALSE(shm_stat.st_mode & S_IRWXG); -} -#endif // !defined(OS_ANDROID) && !defined(OS_FUCHSIA) - -#endif // defined(OS_POSIX) - -// Map() will return addresses which are aligned to the platform page size, this -// varies from platform to platform though. Since we'd like to advertise a -// minimum alignment that callers can count on, test for it here. -TEST_P(SharedMemoryTest, MapMinimumAlignment) { - static const int kDataSize = 8192; - - SharedMemory shared_memory; - ASSERT_TRUE(shared_memory.CreateAndMapAnonymous(kDataSize)); - EXPECT_EQ(0U, reinterpret_cast<uintptr_t>( - shared_memory.memory()) & (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1)); - shared_memory.Close(); -} - -#if defined(OS_WIN) -TEST_P(SharedMemoryTest, UnsafeImageSection) { - const char kTestSectionName[] = "UnsafeImageSection"; - wchar_t path[MAX_PATH]; - EXPECT_GT(::GetModuleFileName(nullptr, path, arraysize(path)), 0U); - - // Map the current executable image to save us creating a new PE file on disk. - base::win::ScopedHandle file_handle(::CreateFile( - path, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr)); - EXPECT_TRUE(file_handle.IsValid()); - base::win::ScopedHandle section_handle( - ::CreateFileMappingA(file_handle.Get(), nullptr, - PAGE_READONLY | SEC_IMAGE, 0, 0, kTestSectionName)); - EXPECT_TRUE(section_handle.IsValid()); - - // Check direct opening by name, from handle and duplicated from handle. - SharedMemory shared_memory_open; - EXPECT_TRUE(shared_memory_open.Open(kTestSectionName, true)); - EXPECT_FALSE(shared_memory_open.Map(1)); - EXPECT_EQ(nullptr, shared_memory_open.memory()); - - SharedMemory shared_memory_handle_local( - SharedMemoryHandle(section_handle.Take(), 1, UnguessableToken::Create()), - true); - EXPECT_FALSE(shared_memory_handle_local.Map(1)); - EXPECT_EQ(nullptr, shared_memory_handle_local.memory()); - - // Check that a handle without SECTION_QUERY also can't be mapped as it can't - // be checked. - SharedMemory shared_memory_handle_dummy; - SharedMemoryCreateOptions options; - options.size = 0x1000; - EXPECT_TRUE(shared_memory_handle_dummy.Create(options)); - HANDLE handle_no_query; - EXPECT_TRUE(::DuplicateHandle( - ::GetCurrentProcess(), shared_memory_handle_dummy.handle().GetHandle(), - ::GetCurrentProcess(), &handle_no_query, FILE_MAP_READ, FALSE, 0)); - SharedMemory shared_memory_handle_no_query( - SharedMemoryHandle(handle_no_query, options.size, - UnguessableToken::Create()), - true); - EXPECT_FALSE(shared_memory_handle_no_query.Map(1)); - EXPECT_EQ(nullptr, shared_memory_handle_no_query.memory()); -} -#endif // defined(OS_WIN) - -// iOS does not allow multiple processes. -// Android ashmem does not support named shared memory. -// Fuchsia SharedMemory does not support named shared memory. -// Mac SharedMemory does not support named shared memory. crbug.com/345734 -#if !defined(OS_IOS) && !defined(OS_ANDROID) && !defined(OS_MACOSX) && \ - !defined(OS_FUCHSIA) -// On POSIX it is especially important we test shmem across processes, -// not just across threads. But the test is enabled on all platforms. -class SharedMemoryProcessTest : public MultiProcessTest { - public: - static void CleanUp() { - SharedMemory memory; - memory.Delete(s_test_name_); - } - - static int TaskTestMain() { - int errors = 0; - SharedMemory memory; - bool rv = memory.CreateNamedDeprecated(s_test_name_, true, s_data_size_); - EXPECT_TRUE(rv); - if (rv != true) - errors++; - rv = memory.Map(s_data_size_); - EXPECT_TRUE(rv); - if (rv != true) - errors++; - int* ptr = static_cast<int*>(memory.memory()); - - // This runs concurrently in multiple processes. Writes need to be atomic. - subtle::Barrier_AtomicIncrement(ptr, 1); - memory.Close(); - return errors; - } - - static const char s_test_name_[]; - static const uint32_t s_data_size_; -}; - -const char SharedMemoryProcessTest::s_test_name_[] = "MPMem"; -const uint32_t SharedMemoryProcessTest::s_data_size_ = 1024; - -TEST_F(SharedMemoryProcessTest, SharedMemoryAcrossProcesses) { - const int kNumTasks = 5; - - SharedMemoryProcessTest::CleanUp(); - - // Create a shared memory region. Set the first word to 0. - SharedMemory memory; - bool rv = memory.CreateNamedDeprecated(s_test_name_, true, s_data_size_); - ASSERT_TRUE(rv); - rv = memory.Map(s_data_size_); - ASSERT_TRUE(rv); - int* ptr = static_cast<int*>(memory.memory()); - *ptr = 0; - - // Start |kNumTasks| processes, each of which atomically increments the first - // word by 1. - Process processes[kNumTasks]; - for (int index = 0; index < kNumTasks; ++index) { - processes[index] = SpawnChild("SharedMemoryTestMain"); - ASSERT_TRUE(processes[index].IsValid()); - } - - // Check that each process exited correctly. - int exit_code = 0; - for (int index = 0; index < kNumTasks; ++index) { - EXPECT_TRUE(processes[index].WaitForExit(&exit_code)); - EXPECT_EQ(0, exit_code); - } - - // Check that the shared memory region reflects |kNumTasks| increments. - ASSERT_EQ(kNumTasks, *ptr); - - memory.Close(); - SharedMemoryProcessTest::CleanUp(); -} - -MULTIPROCESS_TEST_MAIN(SharedMemoryTestMain) { - return SharedMemoryProcessTest::TaskTestMain(); -} -#endif // !defined(OS_IOS) && !defined(OS_ANDROID) && !defined(OS_MACOSX) && - // !defined(OS_FUCHSIA) - -TEST_P(SharedMemoryTest, MappedId) { - const uint32_t kDataSize = 1024; - SharedMemory memory; - SharedMemoryCreateOptions options; - options.size = kDataSize; -#if defined(OS_MACOSX) && !defined(OS_IOS) - // The Mach functionality is tested in shared_memory_mac_unittest.cc. - options.type = SharedMemoryHandle::POSIX; -#endif - - EXPECT_TRUE(memory.Create(options)); - base::UnguessableToken id = memory.handle().GetGUID(); - EXPECT_FALSE(id.is_empty()); - EXPECT_TRUE(memory.mapped_id().is_empty()); - - EXPECT_TRUE(memory.Map(kDataSize)); - EXPECT_EQ(id, memory.mapped_id()); - - memory.Close(); - EXPECT_EQ(id, memory.mapped_id()); - - memory.Unmap(); - EXPECT_TRUE(memory.mapped_id().is_empty()); -} - -INSTANTIATE_TEST_CASE_P(Default, - SharedMemoryTest, - ::testing::Values(Mode::Default)); -#if defined(OS_LINUX) && !defined(OS_CHROMEOS) -INSTANTIATE_TEST_CASE_P(SkipDevShm, - SharedMemoryTest, - ::testing::Values(Mode::DisableDevShm)); -#endif // defined(OS_LINUX) && !defined(OS_CHROMEOS) - -#if defined(OS_ANDROID) -TEST(SharedMemoryTest, ReadOnlyRegions) { - const uint32_t kDataSize = 1024; - SharedMemory memory; - SharedMemoryCreateOptions options; - options.size = kDataSize; - EXPECT_TRUE(memory.Create(options)); - - EXPECT_FALSE(memory.handle().IsRegionReadOnly()); - - // Check that it is possible to map the region directly from the fd. - int region_fd = memory.handle().GetHandle(); - EXPECT_GE(region_fd, 0); - void* address = mmap(nullptr, kDataSize, PROT_READ | PROT_WRITE, MAP_SHARED, - region_fd, 0); - bool success = address && address != MAP_FAILED; - ASSERT_TRUE(address); - ASSERT_NE(address, MAP_FAILED); - if (success) { - EXPECT_EQ(0, munmap(address, kDataSize)); - } - - ASSERT_TRUE(memory.handle().SetRegionReadOnly()); - EXPECT_TRUE(memory.handle().IsRegionReadOnly()); - - // Check that it is no longer possible to map the region read/write. - errno = 0; - address = mmap(nullptr, kDataSize, PROT_READ | PROT_WRITE, MAP_SHARED, - region_fd, 0); - success = address && address != MAP_FAILED; - ASSERT_FALSE(success); - ASSERT_EQ(EPERM, errno); - if (success) { - EXPECT_EQ(0, munmap(address, kDataSize)); - } -} - -TEST(SharedMemoryTest, ReadOnlyDescriptors) { - const uint32_t kDataSize = 1024; - SharedMemory memory; - SharedMemoryCreateOptions options; - options.size = kDataSize; - EXPECT_TRUE(memory.Create(options)); - - EXPECT_FALSE(memory.handle().IsRegionReadOnly()); - - // Getting a read-only descriptor should not make the region read-only itself. - SharedMemoryHandle ro_handle = memory.GetReadOnlyHandle(); - EXPECT_FALSE(memory.handle().IsRegionReadOnly()); - - // Mapping a writable region from a read-only descriptor should not - // be possible, it will DCHECK() in debug builds (see test below), - // while returning false on release ones. - { - bool dcheck_fired = false; - logging::ScopedLogAssertHandler log_assert( - base::BindRepeating([](bool* flag, const char*, int, base::StringPiece, - base::StringPiece) { *flag = true; }, - base::Unretained(&dcheck_fired))); - - SharedMemory rw_region(ro_handle.Duplicate(), /* read_only */ false); - EXPECT_FALSE(rw_region.Map(kDataSize)); - EXPECT_EQ(DCHECK_IS_ON() ? true : false, dcheck_fired); - } - - // Nor shall it turn the region read-only itself. - EXPECT_FALSE(ro_handle.IsRegionReadOnly()); - - // Mapping a read-only region from a read-only descriptor should work. - SharedMemory ro_region(ro_handle.Duplicate(), /* read_only */ true); - EXPECT_TRUE(ro_region.Map(kDataSize)); - - // And it should turn the region read-only too. - EXPECT_TRUE(ro_handle.IsRegionReadOnly()); - EXPECT_TRUE(memory.handle().IsRegionReadOnly()); - EXPECT_FALSE(memory.Map(kDataSize)); - - ro_handle.Close(); -} - -#endif // OS_ANDROID - -} // namespace base
diff --git a/base/memory/shared_memory_win_unittest.cc b/base/memory/shared_memory_win_unittest.cc deleted file mode 100644 index 5fc132d..0000000 --- a/base/memory/shared_memory_win_unittest.cc +++ /dev/null
@@ -1,224 +0,0 @@ -// 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 <windows.h> -#include <sddl.h> - -#include <memory> - -#include "base/command_line.h" -#include "base/memory/free_deleter.h" -#include "base/memory/shared_memory.h" -#include "base/process/process.h" -#include "base/rand_util.h" -#include "base/strings/stringprintf.h" -#include "base/strings/sys_string_conversions.h" -#include "base/test/multiprocess_test.h" -#include "base/test/test_timeouts.h" -#include "base/win/scoped_handle.h" -#include "base/win/win_util.h" -#include "testing/multiprocess_func_list.h" - -namespace base { -namespace { -const char* kHandleSwitchName = "shared_memory_win_test_switch"; - -// Creates a process token with a low integrity SID. -win::ScopedHandle CreateLowIntegritySID() { - HANDLE process_token_raw = nullptr; - BOOL success = ::OpenProcessToken(GetCurrentProcess(), - TOKEN_DUPLICATE | TOKEN_ADJUST_DEFAULT | - TOKEN_QUERY | TOKEN_ASSIGN_PRIMARY, - &process_token_raw); - if (!success) - return base::win::ScopedHandle(); - win::ScopedHandle process_token(process_token_raw); - - HANDLE lowered_process_token_raw = nullptr; - success = - ::DuplicateTokenEx(process_token.Get(), 0, NULL, SecurityImpersonation, - TokenPrimary, &lowered_process_token_raw); - if (!success) - return base::win::ScopedHandle(); - win::ScopedHandle lowered_process_token(lowered_process_token_raw); - - // Low integrity SID - WCHAR integrity_sid_string[20] = L"S-1-16-4096"; - PSID integrity_sid = nullptr; - success = ::ConvertStringSidToSid(integrity_sid_string, &integrity_sid); - if (!success) - return base::win::ScopedHandle(); - - TOKEN_MANDATORY_LABEL TIL = {}; - TIL.Label.Attributes = SE_GROUP_INTEGRITY; - TIL.Label.Sid = integrity_sid; - success = ::SetTokenInformation( - lowered_process_token.Get(), TokenIntegrityLevel, &TIL, - sizeof(TOKEN_MANDATORY_LABEL) + GetLengthSid(integrity_sid)); - if (!success) - return base::win::ScopedHandle(); - return lowered_process_token; -} - -// Reads a HANDLE from the pipe as a raw int, least significant digit first. -win::ScopedHandle ReadHandleFromPipe(HANDLE pipe) { - // Read from parent pipe. - const size_t buf_size = 1000; - char buffer[buf_size]; - memset(buffer, 0, buf_size); - DWORD bytes_read; - BOOL success = ReadFile(pipe, buffer, buf_size, &bytes_read, NULL); - - if (!success || bytes_read == 0) { - LOG(ERROR) << "Failed to read handle from pipe."; - return win::ScopedHandle(); - } - - int handle_as_int = 0; - int power_of_ten = 1; - for (unsigned int i = 0; i < bytes_read; ++i) { - handle_as_int += buffer[i] * power_of_ten; - power_of_ten *= 10; - } - - return win::ScopedHandle(reinterpret_cast<HANDLE>(handle_as_int)); -} - -// Writes a HANDLE to a pipe as a raw int, least significant digit first. -void WriteHandleToPipe(HANDLE pipe, HANDLE handle) { - uint32_t handle_as_int = base::win::HandleToUint32(handle); - - std::unique_ptr<char, base::FreeDeleter> buffer( - static_cast<char*>(malloc(1000))); - size_t index = 0; - while (handle_as_int > 0) { - buffer.get()[index] = handle_as_int % 10; - handle_as_int /= 10; - ++index; - } - - ::ConnectNamedPipe(pipe, nullptr); - DWORD written; - ASSERT_TRUE(::WriteFile(pipe, buffer.get(), index, &written, NULL)); -} - -// Creates a communication pipe with the given name. -win::ScopedHandle CreateCommunicationPipe(const std::wstring& name) { - return win::ScopedHandle(CreateNamedPipe(name.c_str(), // pipe name - PIPE_ACCESS_DUPLEX, PIPE_WAIT, 255, - 1000, 1000, 0, NULL)); -} - -// Generates a random name for a communication pipe. -std::wstring CreateCommunicationPipeName() { - uint64_t rand_values[4]; - RandBytes(&rand_values, sizeof(rand_values)); - std::wstring child_pipe_name = StringPrintf( - L"\\\\.\\pipe\\SharedMemoryWinTest_%016llx%016llx%016llx%016llx", - rand_values[0], rand_values[1], rand_values[2], rand_values[3]); - return child_pipe_name; -} - -class SharedMemoryWinTest : public base::MultiProcessTest { - protected: - CommandLine MakeCmdLine(const std::string& procname) override { - CommandLine line = base::MultiProcessTest::MakeCmdLine(procname); - line.AppendSwitchASCII(kHandleSwitchName, communication_pipe_name_); - return line; - } - - std::string communication_pipe_name_; -}; - -MULTIPROCESS_TEST_MAIN(LowerPermissions) { - std::string handle_name = - CommandLine::ForCurrentProcess()->GetSwitchValueASCII(kHandleSwitchName); - std::wstring handle_name16 = SysUTF8ToWide(handle_name); - win::ScopedHandle parent_pipe( - ::CreateFile(handle_name16.c_str(), // pipe name - GENERIC_READ, - 0, // no sharing - NULL, // default security attributes - OPEN_EXISTING, // opens existing pipe - 0, // default attributes - NULL)); // no template file - if (parent_pipe.Get() == INVALID_HANDLE_VALUE) { - LOG(ERROR) << "Failed to open communication pipe."; - return 1; - } - - win::ScopedHandle received_handle = ReadHandleFromPipe(parent_pipe.Get()); - if (!received_handle.Get()) { - LOG(ERROR) << "Failed to read handle from pipe."; - return 1; - } - - // Attempting to add the WRITE_DAC permission should fail. - HANDLE duped_handle; - BOOL success = ::DuplicateHandle(GetCurrentProcess(), received_handle.Get(), - GetCurrentProcess(), &duped_handle, - FILE_MAP_READ | WRITE_DAC, FALSE, 0); - if (success) { - LOG(ERROR) << "Should not have been able to add WRITE_DAC permission."; - return 1; - } - - // Attempting to add the FILE_MAP_WRITE permission should fail. - success = ::DuplicateHandle(GetCurrentProcess(), received_handle.Get(), - GetCurrentProcess(), &duped_handle, - FILE_MAP_READ | FILE_MAP_WRITE, FALSE, 0); - if (success) { - LOG(ERROR) << "Should not have been able to add FILE_MAP_WRITE permission."; - return 1; - } - - // Attempting to duplicate the HANDLE with the same permissions should - // succeed. - success = ::DuplicateHandle(GetCurrentProcess(), received_handle.Get(), - GetCurrentProcess(), &duped_handle, FILE_MAP_READ, - FALSE, 0); - if (!success) { - LOG(ERROR) << "Failed to duplicate handle."; - return 4; - } - ::CloseHandle(duped_handle); - return 0; -} - -TEST_F(SharedMemoryWinTest, LowerPermissions) { - std::wstring communication_pipe_name = CreateCommunicationPipeName(); - communication_pipe_name_ = SysWideToUTF8(communication_pipe_name); - - win::ScopedHandle communication_pipe = - CreateCommunicationPipe(communication_pipe_name); - ASSERT_TRUE(communication_pipe.Get()); - - win::ScopedHandle lowered_process_token = CreateLowIntegritySID(); - ASSERT_TRUE(lowered_process_token.Get()); - - base::LaunchOptions options; - options.as_user = lowered_process_token.Get(); - base::Process process = SpawnChildWithOptions("LowerPermissions", options); - ASSERT_TRUE(process.IsValid()); - - SharedMemory memory; - memory.CreateAndMapAnonymous(1001); - - // Duplicate into child process, giving only FILE_MAP_READ permissions. - HANDLE raw_handle = nullptr; - ::DuplicateHandle(::GetCurrentProcess(), memory.handle().GetHandle(), - process.Handle(), &raw_handle, - FILE_MAP_READ | SECTION_QUERY, FALSE, 0); - ASSERT_TRUE(raw_handle); - - WriteHandleToPipe(communication_pipe.Get(), raw_handle); - - int exit_code; - EXPECT_TRUE(process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(), - &exit_code)); - EXPECT_EQ(0, exit_code); -} - -} // namespace -} // namespace base
diff --git a/base/memory/singleton_unittest.cc b/base/memory/singleton_unittest.cc deleted file mode 100644 index 06e53b2..0000000 --- a/base/memory/singleton_unittest.cc +++ /dev/null
@@ -1,299 +0,0 @@ -// 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 <stdint.h> - -#include "base/at_exit.h" -#include "base/memory/singleton.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -static_assert(DefaultSingletonTraits<int>::kRegisterAtExit == true, - "object must be deleted on process exit"); - -typedef void (*CallbackFunc)(); - -template <size_t alignment> -class AlignedData { - public: - AlignedData() = default; - ~AlignedData() = default; - alignas(alignment) char data_[alignment]; -}; - -class IntSingleton { - public: - static IntSingleton* GetInstance() { - return Singleton<IntSingleton>::get(); - } - - int value_; -}; - -class Init5Singleton { - public: - struct Trait; - - static Init5Singleton* GetInstance() { - return Singleton<Init5Singleton, Trait>::get(); - } - - int value_; -}; - -struct Init5Singleton::Trait : public DefaultSingletonTraits<Init5Singleton> { - static Init5Singleton* New() { - Init5Singleton* instance = new Init5Singleton(); - instance->value_ = 5; - return instance; - } -}; - -int* SingletonInt() { - return &IntSingleton::GetInstance()->value_; -} - -int* SingletonInt5() { - return &Init5Singleton::GetInstance()->value_; -} - -template <typename Type> -struct CallbackTrait : public DefaultSingletonTraits<Type> { - static void Delete(Type* instance) { - if (instance->callback_) - (instance->callback_)(); - DefaultSingletonTraits<Type>::Delete(instance); - } -}; - -class CallbackSingleton { - public: - CallbackSingleton() : callback_(nullptr) {} - CallbackFunc callback_; -}; - -class CallbackSingletonWithNoLeakTrait : public CallbackSingleton { - public: - struct Trait : public CallbackTrait<CallbackSingletonWithNoLeakTrait> { }; - - CallbackSingletonWithNoLeakTrait() : CallbackSingleton() { } - - static CallbackSingletonWithNoLeakTrait* GetInstance() { - return Singleton<CallbackSingletonWithNoLeakTrait, Trait>::get(); - } -}; - -class CallbackSingletonWithLeakTrait : public CallbackSingleton { - public: - struct Trait : public CallbackTrait<CallbackSingletonWithLeakTrait> { - static const bool kRegisterAtExit = false; - }; - - CallbackSingletonWithLeakTrait() : CallbackSingleton() { } - - static CallbackSingletonWithLeakTrait* GetInstance() { - return Singleton<CallbackSingletonWithLeakTrait, Trait>::get(); - } -}; - -class CallbackSingletonWithStaticTrait : public CallbackSingleton { - public: - struct Trait; - - CallbackSingletonWithStaticTrait() : CallbackSingleton() { } - - static CallbackSingletonWithStaticTrait* GetInstance() { - return Singleton<CallbackSingletonWithStaticTrait, Trait>::get(); - } -}; - -struct CallbackSingletonWithStaticTrait::Trait - : public StaticMemorySingletonTraits<CallbackSingletonWithStaticTrait> { - static void Delete(CallbackSingletonWithStaticTrait* instance) { - if (instance->callback_) - (instance->callback_)(); - StaticMemorySingletonTraits<CallbackSingletonWithStaticTrait>::Delete( - instance); - } -}; - -template <class Type> -class AlignedTestSingleton { - public: - AlignedTestSingleton() = default; - ~AlignedTestSingleton() = default; - static AlignedTestSingleton* GetInstance() { - return Singleton<AlignedTestSingleton, - StaticMemorySingletonTraits<AlignedTestSingleton>>::get(); - } - - Type type_; -}; - - -void SingletonNoLeak(CallbackFunc CallOnQuit) { - CallbackSingletonWithNoLeakTrait::GetInstance()->callback_ = CallOnQuit; -} - -void SingletonLeak(CallbackFunc CallOnQuit) { - CallbackSingletonWithLeakTrait::GetInstance()->callback_ = CallOnQuit; -} - -CallbackFunc* GetLeakySingleton() { - return &CallbackSingletonWithLeakTrait::GetInstance()->callback_; -} - -void DeleteLeakySingleton() { - DefaultSingletonTraits<CallbackSingletonWithLeakTrait>::Delete( - CallbackSingletonWithLeakTrait::GetInstance()); -} - -void SingletonStatic(CallbackFunc CallOnQuit) { - CallbackSingletonWithStaticTrait::GetInstance()->callback_ = CallOnQuit; -} - -CallbackFunc* GetStaticSingleton() { - return &CallbackSingletonWithStaticTrait::GetInstance()->callback_; -} - - -class SingletonTest : public testing::Test { - public: - SingletonTest() = default; - - void SetUp() override { - non_leak_called_ = false; - leaky_called_ = false; - static_called_ = false; - } - - protected: - void VerifiesCallbacks() { - EXPECT_TRUE(non_leak_called_); - EXPECT_FALSE(leaky_called_); - EXPECT_TRUE(static_called_); - non_leak_called_ = false; - leaky_called_ = false; - static_called_ = false; - } - - void VerifiesCallbacksNotCalled() { - EXPECT_FALSE(non_leak_called_); - EXPECT_FALSE(leaky_called_); - EXPECT_FALSE(static_called_); - non_leak_called_ = false; - leaky_called_ = false; - static_called_ = false; - } - - static void CallbackNoLeak() { - non_leak_called_ = true; - } - - static void CallbackLeak() { - leaky_called_ = true; - } - - static void CallbackStatic() { - static_called_ = true; - } - - private: - static bool non_leak_called_; - static bool leaky_called_; - static bool static_called_; -}; - -bool SingletonTest::non_leak_called_ = false; -bool SingletonTest::leaky_called_ = false; -bool SingletonTest::static_called_ = false; - -TEST_F(SingletonTest, Basic) { - int* singleton_int; - int* singleton_int_5; - CallbackFunc* leaky_singleton; - CallbackFunc* static_singleton; - - { - ShadowingAtExitManager sem; - { - singleton_int = SingletonInt(); - } - // Ensure POD type initialization. - EXPECT_EQ(*singleton_int, 0); - *singleton_int = 1; - - EXPECT_EQ(singleton_int, SingletonInt()); - EXPECT_EQ(*singleton_int, 1); - - { - singleton_int_5 = SingletonInt5(); - } - // Is default initialized to 5. - EXPECT_EQ(*singleton_int_5, 5); - - SingletonNoLeak(&CallbackNoLeak); - SingletonLeak(&CallbackLeak); - SingletonStatic(&CallbackStatic); - static_singleton = GetStaticSingleton(); - leaky_singleton = GetLeakySingleton(); - EXPECT_TRUE(leaky_singleton); - } - - // Verify that only the expected callback has been called. - VerifiesCallbacks(); - // Delete the leaky singleton. - DeleteLeakySingleton(); - - // The static singleton can't be acquired post-atexit. - EXPECT_EQ(nullptr, GetStaticSingleton()); - - { - ShadowingAtExitManager sem; - // Verifiy that the variables were reset. - { - singleton_int = SingletonInt(); - EXPECT_EQ(*singleton_int, 0); - } - { - singleton_int_5 = SingletonInt5(); - EXPECT_EQ(*singleton_int_5, 5); - } - { - // Resurrect the static singleton, and assert that it - // still points to the same (static) memory. - CallbackSingletonWithStaticTrait::Trait::ResurrectForTesting(); - EXPECT_EQ(GetStaticSingleton(), static_singleton); - } - } - // The leaky singleton shouldn't leak since SingletonLeak has not been called. - VerifiesCallbacksNotCalled(); -} - -#define EXPECT_ALIGNED(ptr, align) \ - EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1)) - -TEST_F(SingletonTest, Alignment) { - // Create some static singletons with increasing sizes and alignment - // requirements. By ordering this way, the linker will need to do some work to - // ensure proper alignment of the static data. - AlignedTestSingleton<int32_t>* align4 = - AlignedTestSingleton<int32_t>::GetInstance(); - AlignedTestSingleton<AlignedData<32>>* align32 = - AlignedTestSingleton<AlignedData<32>>::GetInstance(); - AlignedTestSingleton<AlignedData<128>>* align128 = - AlignedTestSingleton<AlignedData<128>>::GetInstance(); - AlignedTestSingleton<AlignedData<4096>>* align4096 = - AlignedTestSingleton<AlignedData<4096>>::GetInstance(); - - EXPECT_ALIGNED(align4, 4); - EXPECT_ALIGNED(align32, 32); - EXPECT_ALIGNED(align128, 128); - EXPECT_ALIGNED(align4096, 4096); -} - -} // namespace -} // namespace base
diff --git a/base/memory/weak_ptr_unittest.cc b/base/memory/weak_ptr_unittest.cc deleted file mode 100644 index f8dfb7c..0000000 --- a/base/memory/weak_ptr_unittest.cc +++ /dev/null
@@ -1,716 +0,0 @@ -// 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/memory/weak_ptr.h" - -#include <memory> -#include <string> - -#include "base/bind.h" -#include "base/debug/leak_annotations.h" -#include "base/location.h" -#include "base/single_thread_task_runner.h" -#include "base/synchronization/waitable_event.h" -#include "base/test/gtest_util.h" -#include "base/threading/thread.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -WeakPtr<int> PassThru(WeakPtr<int> ptr) { - return ptr; -} - -template <class T> -class OffThreadObjectCreator { - public: - static T* NewObject() { - T* result; - { - Thread creator_thread("creator_thread"); - creator_thread.Start(); - creator_thread.task_runner()->PostTask( - FROM_HERE, - base::BindOnce(OffThreadObjectCreator::CreateObject, &result)); - } - DCHECK(result); // We synchronized on thread destruction above. - return result; - } - private: - static void CreateObject(T** result) { - *result = new T; - } -}; - -struct Base { - std::string member; -}; -struct Derived : public Base {}; - -struct TargetBase {}; -struct Target : public TargetBase, public SupportsWeakPtr<Target> { - virtual ~Target() = default; -}; - -struct DerivedTarget : public Target {}; - -// A class inheriting from Target and defining a nested type called 'Base'. -// To guard against strange compilation errors. -struct DerivedTargetWithNestedBase : public Target { - using Base = void; -}; - -// A struct with a virtual destructor. -struct VirtualDestructor { - virtual ~VirtualDestructor() = default; -}; - -// A class inheriting from Target where Target is not the first base, and where -// the first base has a virtual method table. This creates a structure where the -// Target base is not positioned at the beginning of -// DerivedTargetMultipleInheritance. -struct DerivedTargetMultipleInheritance : public VirtualDestructor, - public Target {}; - -struct Arrow { - WeakPtr<Target> target; -}; -struct TargetWithFactory : public Target { - TargetWithFactory() : factory(this) {} - WeakPtrFactory<Target> factory; -}; - -// Helper class to create and destroy weak pointer copies -// and delete objects on a background thread. -class BackgroundThread : public Thread { - public: - BackgroundThread() : Thread("owner_thread") {} - - ~BackgroundThread() override { Stop(); } - - void CreateArrowFromTarget(Arrow** arrow, Target* target) { - WaitableEvent completion(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - task_runner()->PostTask( - FROM_HERE, base::BindOnce(&BackgroundThread::DoCreateArrowFromTarget, - arrow, target, &completion)); - completion.Wait(); - } - - void CreateArrowFromArrow(Arrow** arrow, const Arrow* other) { - WaitableEvent completion(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - task_runner()->PostTask( - FROM_HERE, base::BindOnce(&BackgroundThread::DoCreateArrowFromArrow, - arrow, other, &completion)); - completion.Wait(); - } - - void DeleteTarget(Target* object) { - WaitableEvent completion(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - task_runner()->PostTask( - FROM_HERE, - base::BindOnce(&BackgroundThread::DoDeleteTarget, object, &completion)); - completion.Wait(); - } - - void CopyAndAssignArrow(Arrow* object) { - WaitableEvent completion(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - task_runner()->PostTask( - FROM_HERE, base::BindOnce(&BackgroundThread::DoCopyAndAssignArrow, - object, &completion)); - completion.Wait(); - } - - void CopyAndAssignArrowBase(Arrow* object) { - WaitableEvent completion(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - task_runner()->PostTask( - FROM_HERE, base::BindOnce(&BackgroundThread::DoCopyAndAssignArrowBase, - object, &completion)); - completion.Wait(); - } - - void DeleteArrow(Arrow* object) { - WaitableEvent completion(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - task_runner()->PostTask( - FROM_HERE, - base::BindOnce(&BackgroundThread::DoDeleteArrow, object, &completion)); - completion.Wait(); - } - - Target* DeRef(const Arrow* arrow) { - WaitableEvent completion(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - Target* result = nullptr; - task_runner()->PostTask( - FROM_HERE, base::BindOnce(&BackgroundThread::DoDeRef, arrow, &result, - &completion)); - completion.Wait(); - return result; - } - - protected: - static void DoCreateArrowFromArrow(Arrow** arrow, - const Arrow* other, - WaitableEvent* completion) { - *arrow = new Arrow; - **arrow = *other; - completion->Signal(); - } - - static void DoCreateArrowFromTarget(Arrow** arrow, - Target* target, - WaitableEvent* completion) { - *arrow = new Arrow; - (*arrow)->target = target->AsWeakPtr(); - completion->Signal(); - } - - static void DoDeRef(const Arrow* arrow, - Target** result, - WaitableEvent* completion) { - *result = arrow->target.get(); - completion->Signal(); - } - - static void DoDeleteTarget(Target* object, WaitableEvent* completion) { - delete object; - completion->Signal(); - } - - static void DoCopyAndAssignArrow(Arrow* object, WaitableEvent* completion) { - // Copy constructor. - Arrow a = *object; - // Assignment operator. - *object = a; - completion->Signal(); - } - - static void DoCopyAndAssignArrowBase( - Arrow* object, - WaitableEvent* completion) { - // Copy constructor. - WeakPtr<TargetBase> b = object->target; - // Assignment operator. - WeakPtr<TargetBase> c; - c = object->target; - completion->Signal(); - } - - static void DoDeleteArrow(Arrow* object, WaitableEvent* completion) { - delete object; - completion->Signal(); - } -}; - -} // namespace - -TEST(WeakPtrFactoryTest, Basic) { - int data; - WeakPtrFactory<int> factory(&data); - WeakPtr<int> ptr = factory.GetWeakPtr(); - EXPECT_EQ(&data, ptr.get()); -} - -TEST(WeakPtrFactoryTest, Comparison) { - int data; - WeakPtrFactory<int> factory(&data); - WeakPtr<int> ptr = factory.GetWeakPtr(); - WeakPtr<int> ptr2 = ptr; - EXPECT_EQ(ptr.get(), ptr2.get()); -} - -TEST(WeakPtrFactoryTest, Move) { - int data; - WeakPtrFactory<int> factory(&data); - WeakPtr<int> ptr = factory.GetWeakPtr(); - WeakPtr<int> ptr2 = factory.GetWeakPtr(); - WeakPtr<int> ptr3 = std::move(ptr2); - EXPECT_NE(ptr.get(), ptr2.get()); - EXPECT_EQ(ptr.get(), ptr3.get()); -} - -TEST(WeakPtrFactoryTest, OutOfScope) { - WeakPtr<int> ptr; - EXPECT_EQ(nullptr, ptr.get()); - { - int data; - WeakPtrFactory<int> factory(&data); - ptr = factory.GetWeakPtr(); - } - EXPECT_EQ(nullptr, ptr.get()); -} - -TEST(WeakPtrFactoryTest, Multiple) { - WeakPtr<int> a, b; - { - int data; - WeakPtrFactory<int> factory(&data); - a = factory.GetWeakPtr(); - b = factory.GetWeakPtr(); - EXPECT_EQ(&data, a.get()); - EXPECT_EQ(&data, b.get()); - } - EXPECT_EQ(nullptr, a.get()); - EXPECT_EQ(nullptr, b.get()); -} - -TEST(WeakPtrFactoryTest, MultipleStaged) { - WeakPtr<int> a; - { - int data; - WeakPtrFactory<int> factory(&data); - a = factory.GetWeakPtr(); - { - WeakPtr<int> b = factory.GetWeakPtr(); - } - EXPECT_NE(nullptr, a.get()); - } - EXPECT_EQ(nullptr, a.get()); -} - -TEST(WeakPtrFactoryTest, Dereference) { - Base data; - data.member = "123456"; - WeakPtrFactory<Base> factory(&data); - WeakPtr<Base> ptr = factory.GetWeakPtr(); - EXPECT_EQ(&data, ptr.get()); - EXPECT_EQ(data.member, (*ptr).member); - EXPECT_EQ(data.member, ptr->member); -} - -TEST(WeakPtrFactoryTest, UpCast) { - Derived data; - WeakPtrFactory<Derived> factory(&data); - WeakPtr<Base> ptr = factory.GetWeakPtr(); - ptr = factory.GetWeakPtr(); - EXPECT_EQ(ptr.get(), &data); -} - -TEST(WeakPtrTest, ConstructFromNullptr) { - WeakPtr<int> ptr = PassThru(nullptr); - EXPECT_EQ(nullptr, ptr.get()); -} - -TEST(WeakPtrTest, SupportsWeakPtr) { - Target target; - WeakPtr<Target> ptr = target.AsWeakPtr(); - EXPECT_EQ(&target, ptr.get()); -} - -TEST(WeakPtrTest, DerivedTarget) { - DerivedTarget target; - WeakPtr<DerivedTarget> ptr = AsWeakPtr(&target); - EXPECT_EQ(&target, ptr.get()); -} - -TEST(WeakPtrTest, DerivedTargetWithNestedBase) { - DerivedTargetWithNestedBase target; - WeakPtr<DerivedTargetWithNestedBase> ptr = AsWeakPtr(&target); - EXPECT_EQ(&target, ptr.get()); -} - -TEST(WeakPtrTest, DerivedTargetMultipleInheritance) { - DerivedTargetMultipleInheritance d; - Target& b = d; - EXPECT_NE(static_cast<void*>(&d), static_cast<void*>(&b)); - const WeakPtr<Target> pb = AsWeakPtr(&b); - EXPECT_EQ(pb.get(), &b); - const WeakPtr<DerivedTargetMultipleInheritance> pd = AsWeakPtr(&d); - EXPECT_EQ(pd.get(), &d); -} - -TEST(WeakPtrFactoryTest, BooleanTesting) { - int data; - WeakPtrFactory<int> factory(&data); - - WeakPtr<int> ptr_to_an_instance = factory.GetWeakPtr(); - EXPECT_TRUE(ptr_to_an_instance); - EXPECT_FALSE(!ptr_to_an_instance); - - if (ptr_to_an_instance) { - } else { - ADD_FAILURE() << "Pointer to an instance should result in true."; - } - - if (!ptr_to_an_instance) { // check for operator!(). - ADD_FAILURE() << "Pointer to an instance should result in !x being false."; - } - - WeakPtr<int> null_ptr; - EXPECT_FALSE(null_ptr); - EXPECT_TRUE(!null_ptr); - - if (null_ptr) { - ADD_FAILURE() << "Null pointer should result in false."; - } - - if (!null_ptr) { // check for operator!(). - } else { - ADD_FAILURE() << "Null pointer should result in !x being true."; - } -} - -TEST(WeakPtrFactoryTest, ComparisonToNull) { - int data; - WeakPtrFactory<int> factory(&data); - - WeakPtr<int> ptr_to_an_instance = factory.GetWeakPtr(); - EXPECT_NE(nullptr, ptr_to_an_instance); - EXPECT_NE(ptr_to_an_instance, nullptr); - - WeakPtr<int> null_ptr; - EXPECT_EQ(null_ptr, nullptr); - EXPECT_EQ(nullptr, null_ptr); -} - -TEST(WeakPtrTest, InvalidateWeakPtrs) { - int data; - WeakPtrFactory<int> factory(&data); - WeakPtr<int> ptr = factory.GetWeakPtr(); - EXPECT_EQ(&data, ptr.get()); - EXPECT_TRUE(factory.HasWeakPtrs()); - factory.InvalidateWeakPtrs(); - EXPECT_EQ(nullptr, ptr.get()); - EXPECT_FALSE(factory.HasWeakPtrs()); - - // Test that the factory can create new weak pointers after a - // InvalidateWeakPtrs call, and they remain valid until the next - // InvalidateWeakPtrs call. - WeakPtr<int> ptr2 = factory.GetWeakPtr(); - EXPECT_EQ(&data, ptr2.get()); - EXPECT_TRUE(factory.HasWeakPtrs()); - factory.InvalidateWeakPtrs(); - EXPECT_EQ(nullptr, ptr2.get()); - EXPECT_FALSE(factory.HasWeakPtrs()); -} - -TEST(WeakPtrTest, HasWeakPtrs) { - int data; - WeakPtrFactory<int> factory(&data); - { - WeakPtr<int> ptr = factory.GetWeakPtr(); - EXPECT_TRUE(factory.HasWeakPtrs()); - } - EXPECT_FALSE(factory.HasWeakPtrs()); -} - -TEST(WeakPtrTest, ObjectAndWeakPtrOnDifferentThreads) { - // Test that it is OK to create an object that supports WeakPtr on one thread, - // but use it on another. This tests that we do not trip runtime checks that - // ensure that a WeakPtr is not used by multiple threads. - std::unique_ptr<Target> target(OffThreadObjectCreator<Target>::NewObject()); - WeakPtr<Target> weak_ptr = target->AsWeakPtr(); - EXPECT_EQ(target.get(), weak_ptr.get()); -} - -TEST(WeakPtrTest, WeakPtrInitiateAndUseOnDifferentThreads) { - // Test that it is OK to create an object that has a WeakPtr member on one - // thread, but use it on another. This tests that we do not trip runtime - // checks that ensure that a WeakPtr is not used by multiple threads. - std::unique_ptr<Arrow> arrow(OffThreadObjectCreator<Arrow>::NewObject()); - Target target; - arrow->target = target.AsWeakPtr(); - EXPECT_EQ(&target, arrow->target.get()); -} - -TEST(WeakPtrTest, MoveOwnershipImplicitly) { - // Move object ownership to another thread by releasing all weak pointers - // on the original thread first, and then establish WeakPtr on a different - // thread. - BackgroundThread background; - background.Start(); - - Target* target = new Target(); - { - WeakPtr<Target> weak_ptr = target->AsWeakPtr(); - // Main thread deletes the WeakPtr, then the thread ownership of the - // object can be implicitly moved. - } - Arrow* arrow; - - // Background thread creates WeakPtr(and implicitly owns the object). - background.CreateArrowFromTarget(&arrow, target); - EXPECT_EQ(background.DeRef(arrow), target); - - { - // Main thread creates another WeakPtr, but this does not trigger implicitly - // thread ownership move. - Arrow arrow; - arrow.target = target->AsWeakPtr(); - - // The new WeakPtr is owned by background thread. - EXPECT_EQ(target, background.DeRef(&arrow)); - } - - // Target can only be deleted on background thread. - background.DeleteTarget(target); - background.DeleteArrow(arrow); -} - -TEST(WeakPtrTest, MoveOwnershipOfUnreferencedObject) { - BackgroundThread background; - background.Start(); - - Arrow* arrow; - { - Target target; - // Background thread creates WeakPtr. - background.CreateArrowFromTarget(&arrow, &target); - - // Bind to background thread. - EXPECT_EQ(&target, background.DeRef(arrow)); - - // Release the only WeakPtr. - arrow->target.reset(); - - // Now we should be able to create a new reference from this thread. - arrow->target = target.AsWeakPtr(); - - // Re-bind to main thread. - EXPECT_EQ(&target, arrow->target.get()); - - // And the main thread can now delete the target. - } - - delete arrow; -} - -TEST(WeakPtrTest, MoveOwnershipAfterInvalidate) { - BackgroundThread background; - background.Start(); - - Arrow arrow; - std::unique_ptr<TargetWithFactory> target(new TargetWithFactory); - - // Bind to main thread. - arrow.target = target->factory.GetWeakPtr(); - EXPECT_EQ(target.get(), arrow.target.get()); - - target->factory.InvalidateWeakPtrs(); - EXPECT_EQ(nullptr, arrow.target.get()); - - arrow.target = target->factory.GetWeakPtr(); - // Re-bind to background thread. - EXPECT_EQ(target.get(), background.DeRef(&arrow)); - - // And the background thread can now delete the target. - background.DeleteTarget(target.release()); -} - -TEST(WeakPtrTest, MainThreadRefOutlivesBackgroundThreadRef) { - // Originating thread has a WeakPtr that outlives others. - // - Main thread creates a WeakPtr - // - Background thread creates a WeakPtr copy from the one in main thread - // - Destruct the WeakPtr on background thread - // - Destruct the WeakPtr on main thread - BackgroundThread background; - background.Start(); - - Target target; - Arrow arrow; - arrow.target = target.AsWeakPtr(); - - Arrow* arrow_copy; - background.CreateArrowFromArrow(&arrow_copy, &arrow); - EXPECT_EQ(arrow_copy->target.get(), &target); - background.DeleteArrow(arrow_copy); -} - -TEST(WeakPtrTest, BackgroundThreadRefOutlivesMainThreadRef) { - // Originating thread drops all references before another thread. - // - Main thread creates a WeakPtr and passes copy to background thread - // - Destruct the pointer on main thread - // - Destruct the pointer on background thread - BackgroundThread background; - background.Start(); - - Target target; - Arrow* arrow_copy; - { - Arrow arrow; - arrow.target = target.AsWeakPtr(); - background.CreateArrowFromArrow(&arrow_copy, &arrow); - } - EXPECT_EQ(arrow_copy->target.get(), &target); - background.DeleteArrow(arrow_copy); -} - -TEST(WeakPtrTest, OwnerThreadDeletesObject) { - // Originating thread invalidates WeakPtrs while its held by other thread. - // - Main thread creates WeakPtr and passes Copy to background thread - // - Object gets destroyed on main thread - // (invalidates WeakPtr on background thread) - // - WeakPtr gets destroyed on Thread B - BackgroundThread background; - background.Start(); - Arrow* arrow_copy; - { - Target target; - Arrow arrow; - arrow.target = target.AsWeakPtr(); - background.CreateArrowFromArrow(&arrow_copy, &arrow); - } - EXPECT_EQ(nullptr, arrow_copy->target.get()); - background.DeleteArrow(arrow_copy); -} - -TEST(WeakPtrTest, NonOwnerThreadCanCopyAndAssignWeakPtr) { - // Main thread creates a Target object. - Target target; - // Main thread creates an arrow referencing the Target. - Arrow *arrow = new Arrow(); - arrow->target = target.AsWeakPtr(); - - // Background can copy and assign arrow (as well as the WeakPtr inside). - BackgroundThread background; - background.Start(); - background.CopyAndAssignArrow(arrow); - background.DeleteArrow(arrow); -} - -TEST(WeakPtrTest, NonOwnerThreadCanCopyAndAssignWeakPtrBase) { - // Main thread creates a Target object. - Target target; - // Main thread creates an arrow referencing the Target. - Arrow *arrow = new Arrow(); - arrow->target = target.AsWeakPtr(); - - // Background can copy and assign arrow's WeakPtr to a base class WeakPtr. - BackgroundThread background; - background.Start(); - background.CopyAndAssignArrowBase(arrow); - background.DeleteArrow(arrow); -} - -TEST(WeakPtrTest, NonOwnerThreadCanDeleteWeakPtr) { - // Main thread creates a Target object. - Target target; - // Main thread creates an arrow referencing the Target. - Arrow* arrow = new Arrow(); - arrow->target = target.AsWeakPtr(); - - // Background can delete arrow (as well as the WeakPtr inside). - BackgroundThread background; - background.Start(); - background.DeleteArrow(arrow); -} - -TEST(WeakPtrDeathTest, WeakPtrCopyDoesNotChangeThreadBinding) { - // The default style "fast" does not support multi-threaded tests - // (introduces deadlock on Linux). - ::testing::FLAGS_gtest_death_test_style = "threadsafe"; - - BackgroundThread background; - background.Start(); - - // Main thread creates a Target object. - Target target; - // Main thread creates an arrow referencing the Target. - Arrow arrow; - arrow.target = target.AsWeakPtr(); - - // Background copies the WeakPtr. - Arrow* arrow_copy; - background.CreateArrowFromArrow(&arrow_copy, &arrow); - - // The copy is still bound to main thread so I can deref. - EXPECT_EQ(arrow.target.get(), arrow_copy->target.get()); - - // Although background thread created the copy, it can not deref the copied - // WeakPtr. - ASSERT_DCHECK_DEATH(background.DeRef(arrow_copy)); - - background.DeleteArrow(arrow_copy); -} - -TEST(WeakPtrDeathTest, NonOwnerThreadDereferencesWeakPtrAfterReference) { - // The default style "fast" does not support multi-threaded tests - // (introduces deadlock on Linux). - ::testing::FLAGS_gtest_death_test_style = "threadsafe"; - - // Main thread creates a Target object. - Target target; - - // Main thread creates an arrow referencing the Target (so target's - // thread ownership can not be implicitly moved). - Arrow arrow; - arrow.target = target.AsWeakPtr(); - arrow.target.get(); - - // Background thread tries to deref target, which violates thread ownership. - BackgroundThread background; - background.Start(); - ASSERT_DCHECK_DEATH(background.DeRef(&arrow)); -} - -TEST(WeakPtrDeathTest, NonOwnerThreadDeletesWeakPtrAfterReference) { - // The default style "fast" does not support multi-threaded tests - // (introduces deadlock on Linux). - ::testing::FLAGS_gtest_death_test_style = "threadsafe"; - - std::unique_ptr<Target> target(new Target()); - - // Main thread creates an arrow referencing the Target. - Arrow arrow; - arrow.target = target->AsWeakPtr(); - - // Background thread tries to deref target, binding it to the thread. - BackgroundThread background; - background.Start(); - background.DeRef(&arrow); - - // Main thread deletes Target, violating thread binding. - ASSERT_DCHECK_DEATH(target.reset()); - - // |target.reset()| died so |target| still holds the object, so we - // must pass it to the background thread to teardown. - background.DeleteTarget(target.release()); -} - -TEST(WeakPtrDeathTest, NonOwnerThreadDeletesObjectAfterReference) { - // The default style "fast" does not support multi-threaded tests - // (introduces deadlock on Linux). - ::testing::FLAGS_gtest_death_test_style = "threadsafe"; - - std::unique_ptr<Target> target(new Target()); - - // Main thread creates an arrow referencing the Target, and references it, so - // that it becomes bound to the thread. - Arrow arrow; - arrow.target = target->AsWeakPtr(); - arrow.target.get(); - - // Background thread tries to delete target, volating thread binding. - BackgroundThread background; - background.Start(); - ASSERT_DCHECK_DEATH(background.DeleteTarget(target.release())); -} - -TEST(WeakPtrDeathTest, NonOwnerThreadReferencesObjectAfterDeletion) { - // The default style "fast" does not support multi-threaded tests - // (introduces deadlock on Linux). - ::testing::FLAGS_gtest_death_test_style = "threadsafe"; - - std::unique_ptr<Target> target(new Target()); - - // Main thread creates an arrow referencing the Target. - Arrow arrow; - arrow.target = target->AsWeakPtr(); - - // Background thread tries to delete target, binding the object to the thread. - BackgroundThread background; - background.Start(); - background.DeleteTarget(target.release()); - - // Main thread attempts to dereference the target, violating thread binding. - ASSERT_DCHECK_DEATH(arrow.target.get()); -} - -} // namespace base
diff --git a/base/memory/weak_ptr_unittest.nc b/base/memory/weak_ptr_unittest.nc deleted file mode 100644 index b96b033..0000000 --- a/base/memory/weak_ptr_unittest.nc +++ /dev/null
@@ -1,144 +0,0 @@ -// 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 is a "No Compile Test" suite. -// http://dev.chromium.org/developers/testing/no-compile-tests - -#include "base/memory/weak_ptr.h" - -namespace base { - -struct Producer : SupportsWeakPtr<Producer> {}; -struct DerivedProducer : Producer {}; -struct OtherDerivedProducer : Producer {}; -struct MultiplyDerivedProducer : Producer, - SupportsWeakPtr<MultiplyDerivedProducer> {}; -struct Unrelated {}; -struct DerivedUnrelated : Unrelated {}; - -#if defined(NCTEST_AUTO_DOWNCAST) // [r"cannot initialize a variable of type 'base::DerivedProducer \*' with an rvalue of type 'base::Producer \*'"] - -void WontCompile() { - Producer f; - WeakPtr<Producer> ptr = f.AsWeakPtr(); - WeakPtr<DerivedProducer> derived_ptr = ptr; -} - -#elif defined(NCTEST_STATIC_DOWNCAST) // [r"cannot initialize a variable of type 'base::DerivedProducer \*' with an rvalue of type 'base::Producer \*'"] - -void WontCompile() { - Producer f; - WeakPtr<Producer> ptr = f.AsWeakPtr(); - WeakPtr<DerivedProducer> derived_ptr = - static_cast<WeakPtr<DerivedProducer> >(ptr); -} - -#elif defined(NCTEST_AUTO_REF_DOWNCAST) // [r"fatal error: non-const lvalue reference to type 'WeakPtr<base::DerivedProducer>' cannot bind to a value of unrelated type 'WeakPtr<base::Producer>'"] - -void WontCompile() { - Producer f; - WeakPtr<Producer> ptr = f.AsWeakPtr(); - WeakPtr<DerivedProducer>& derived_ptr = ptr; -} - -#elif defined(NCTEST_STATIC_REF_DOWNCAST) // [r"fatal error: non-const lvalue reference to type 'WeakPtr<base::DerivedProducer>' cannot bind to a value of unrelated type 'WeakPtr<base::Producer>'"] - -void WontCompile() { - Producer f; - WeakPtr<Producer> ptr = f.AsWeakPtr(); - WeakPtr<DerivedProducer>& derived_ptr = - static_cast<WeakPtr<DerivedProducer>&>(ptr); -} - -#elif defined(NCTEST_STATIC_ASWEAKPTR_DOWNCAST) // [r"no matching function"] - -void WontCompile() { - Producer f; - WeakPtr<DerivedProducer> ptr = - SupportsWeakPtr<Producer>::StaticAsWeakPtr<DerivedProducer>(&f); -} - -#elif defined(NCTEST_UNSAFE_HELPER_DOWNCAST) // [r"cannot initialize a variable of type 'base::DerivedProducer \*' with an rvalue of type 'base::Producer \*'"] - -void WontCompile() { - Producer f; - WeakPtr<DerivedProducer> ptr = AsWeakPtr(&f); -} - -#elif defined(NCTEST_UNSAFE_INSTANTIATED_HELPER_DOWNCAST) // [r"no matching function"] - -void WontCompile() { - Producer f; - WeakPtr<DerivedProducer> ptr = AsWeakPtr<DerivedProducer>(&f); -} - -#elif defined(NCTEST_UNSAFE_WRONG_INSANTIATED_HELPER_DOWNCAST) // [r"cannot initialize a variable of type 'base::DerivedProducer \*' with an rvalue of type 'base::Producer \*'"] - -void WontCompile() { - Producer f; - WeakPtr<DerivedProducer> ptr = AsWeakPtr<Producer>(&f); -} - -#elif defined(NCTEST_UNSAFE_HELPER_CAST) // [r"cannot initialize a variable of type 'base::OtherDerivedProducer \*' with an rvalue of type 'base::DerivedProducer \*'"] - -void WontCompile() { - DerivedProducer f; - WeakPtr<OtherDerivedProducer> ptr = AsWeakPtr(&f); -} - -#elif defined(NCTEST_UNSAFE_INSTANTIATED_HELPER_SIDECAST) // [r"fatal error: no matching function for call to 'AsWeakPtr'"] - -void WontCompile() { - DerivedProducer f; - WeakPtr<OtherDerivedProducer> ptr = AsWeakPtr<OtherDerivedProducer>(&f); -} - -#elif defined(NCTEST_UNSAFE_WRONG_INSTANTIATED_HELPER_SIDECAST) // [r"cannot initialize a variable of type 'base::OtherDerivedProducer \*' with an rvalue of type 'base::DerivedProducer \*'"] - -void WontCompile() { - DerivedProducer f; - WeakPtr<OtherDerivedProducer> ptr = AsWeakPtr<DerivedProducer>(&f); -} - -#elif defined(NCTEST_UNRELATED_HELPER) // [r"cannot initialize a variable of type 'base::Unrelated \*' with an rvalue of type 'base::DerivedProducer \*'"] - -void WontCompile() { - DerivedProducer f; - WeakPtr<Unrelated> ptr = AsWeakPtr(&f); -} - -#elif defined(NCTEST_UNRELATED_INSTANTIATED_HELPER) // [r"no matching function"] - -void WontCompile() { - DerivedProducer f; - WeakPtr<Unrelated> ptr = AsWeakPtr<Unrelated>(&f); -} - -// TODO(hans): Remove .* and update the static_assert expectations once we roll -// past Clang r313315. https://crbug.com/765692. - -#elif defined(NCTEST_COMPLETELY_UNRELATED_HELPER) // [r"fatal error: static_assert failed .*\"AsWeakPtr argument must inherit from SupportsWeakPtr\""] - -void WontCompile() { - Unrelated f; - WeakPtr<Unrelated> ptr = AsWeakPtr(&f); -} - -#elif defined(NCTEST_DERIVED_COMPLETELY_UNRELATED_HELPER) // [r"fatal error: static_assert failed .*\"AsWeakPtr argument must inherit from SupportsWeakPtr\""] - -void WontCompile() { - DerivedUnrelated f; - WeakPtr<Unrelated> ptr = AsWeakPtr(&f); -} - -#elif defined(NCTEST_AMBIGUOUS_ANCESTORS) // [r"fatal error: use of undeclared identifier 'AsWeakPtrImpl'"] - -void WontCompile() { - MultiplyDerivedProducer f; - WeakPtr<MultiplyDerivedProducer> ptr = AsWeakPtr(&f); -} - -#endif - -}
diff --git a/base/message_loop/message_loop_io_posix_unittest.cc b/base/message_loop/message_loop_io_posix_unittest.cc deleted file mode 100644 index 9ecd606..0000000 --- a/base/message_loop/message_loop_io_posix_unittest.cc +++ /dev/null
@@ -1,418 +0,0 @@ -// 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/message_loop/message_loop.h" - -#include "base/bind.h" -#include "base/compiler_specific.h" -#include "base/files/file_util.h" -#include "base/files/scoped_file.h" -#include "base/logging.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/message_loop/message_loop_current.h" -#include "base/message_loop/message_pump_for_io.h" -#include "base/posix/eintr_wrapper.h" -#include "base/run_loop.h" -#include "base/test/gtest_util.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -#if !defined(OS_NACL) - -namespace { - -class MessageLoopForIoPosixTest : public testing::Test { - public: - MessageLoopForIoPosixTest() = default; - - // testing::Test interface. - void SetUp() override { - // Create a file descriptor. Doesn't need to be readable or writable, - // as we don't need to actually get any notifications. - // pipe() is just the easiest way to do it. - int pipefds[2]; - int err = pipe(pipefds); - ASSERT_EQ(0, err); - read_fd_ = ScopedFD(pipefds[0]); - write_fd_ = ScopedFD(pipefds[1]); - } - - void TriggerReadEvent() { - // Write from the other end of the pipe to trigger the event. - char c = '\0'; - EXPECT_EQ(1, HANDLE_EINTR(write(write_fd_.get(), &c, 1))); - } - - protected: - ScopedFD read_fd_; - ScopedFD write_fd_; - - DISALLOW_COPY_AND_ASSIGN(MessageLoopForIoPosixTest); -}; - -class TestHandler : public MessagePumpForIO::FdWatcher { - public: - void OnFileCanReadWithoutBlocking(int fd) override { - watcher_to_delete_ = nullptr; - is_readable_ = true; - RunLoop::QuitCurrentWhenIdleDeprecated(); - } - void OnFileCanWriteWithoutBlocking(int fd) override { - watcher_to_delete_ = nullptr; - is_writable_ = true; - RunLoop::QuitCurrentWhenIdleDeprecated(); - } - - bool is_readable_ = false; - bool is_writable_ = false; - - // If set then the contained watcher will be deleted on notification. - std::unique_ptr<MessagePumpForIO::FdWatchController> watcher_to_delete_; -}; - -// Watcher that calls specified closures when read/write events occur. Verifies -// that each non-null closure passed to this class is called once and only once. -// Also resets the read event by reading from the FD. -class CallClosureHandler : public MessagePumpForIO::FdWatcher { - public: - CallClosureHandler(OnceClosure read_closure, OnceClosure write_closure) - : read_closure_(std::move(read_closure)), - write_closure_(std::move(write_closure)) {} - - ~CallClosureHandler() override { - EXPECT_TRUE(read_closure_.is_null()); - EXPECT_TRUE(write_closure_.is_null()); - } - - void SetReadClosure(OnceClosure read_closure) { - EXPECT_TRUE(read_closure_.is_null()); - read_closure_ = std::move(read_closure); - } - - void SetWriteClosure(OnceClosure write_closure) { - EXPECT_TRUE(write_closure_.is_null()); - write_closure_ = std::move(write_closure); - } - - // base:MessagePumpFuchsia::Watcher interface. - void OnFileCanReadWithoutBlocking(int fd) override { - // Empty the pipe buffer to reset the event. Otherwise libevent - // implementation of MessageLoop may call the event handler again even if - // |read_closure_| below quits the RunLoop. - char c; - int result = HANDLE_EINTR(read(fd, &c, 1)); - if (result == -1) { - PLOG(ERROR) << "read"; - FAIL(); - } - EXPECT_EQ(result, 1); - - ASSERT_FALSE(read_closure_.is_null()); - std::move(read_closure_).Run(); - } - - void OnFileCanWriteWithoutBlocking(int fd) override { - ASSERT_FALSE(write_closure_.is_null()); - std::move(write_closure_).Run(); - } - - private: - OnceClosure read_closure_; - OnceClosure write_closure_; -}; - -TEST_F(MessageLoopForIoPosixTest, FileDescriptorWatcherOutlivesMessageLoop) { - // Simulate a MessageLoop that dies before an FileDescriptorWatcher. - // This could happen when people use the Singleton pattern or atexit. - - // Arrange for watcher to live longer than message loop. - MessagePumpForIO::FdWatchController watcher(FROM_HERE); - TestHandler handler; - { - MessageLoopForIO message_loop; - - MessageLoopCurrentForIO::Get()->WatchFileDescriptor( - write_fd_.get(), true, MessagePumpForIO::WATCH_WRITE, &watcher, - &handler); - // Don't run the message loop, just destroy it. - } - - ASSERT_FALSE(handler.is_readable_); - ASSERT_FALSE(handler.is_writable_); -} - -TEST_F(MessageLoopForIoPosixTest, FileDescriptorWatcherDoubleStop) { - // Verify that it's ok to call StopWatchingFileDescriptor(). - - // Arrange for message loop to live longer than watcher. - MessageLoopForIO message_loop; - { - MessagePumpForIO::FdWatchController watcher(FROM_HERE); - - TestHandler handler; - MessageLoopCurrentForIO::Get()->WatchFileDescriptor( - write_fd_.get(), true, MessagePumpForIO::WATCH_WRITE, &watcher, - &handler); - ASSERT_TRUE(watcher.StopWatchingFileDescriptor()); - ASSERT_TRUE(watcher.StopWatchingFileDescriptor()); - } -} - -TEST_F(MessageLoopForIoPosixTest, FileDescriptorWatcherDeleteInCallback) { - // Verify that it is OK to delete the FileDescriptorWatcher from within a - // callback. - MessageLoopForIO message_loop; - - TestHandler handler; - handler.watcher_to_delete_ = - std::make_unique<MessagePumpForIO::FdWatchController>(FROM_HERE); - - MessageLoopCurrentForIO::Get()->WatchFileDescriptor( - write_fd_.get(), true, MessagePumpForIO::WATCH_WRITE, - handler.watcher_to_delete_.get(), &handler); - RunLoop().Run(); -} - -// Verify that basic readable notification works. -TEST_F(MessageLoopForIoPosixTest, WatchReadable) { - MessageLoopForIO message_loop; - MessagePumpForIO::FdWatchController watcher(FROM_HERE); - TestHandler handler; - - // Watch the pipe for readability. - ASSERT_TRUE(MessageLoopCurrentForIO::Get()->WatchFileDescriptor( - read_fd_.get(), /*persistent=*/false, MessagePumpForIO::WATCH_READ, - &watcher, &handler)); - - // The pipe should not be readable when first created. - RunLoop().RunUntilIdle(); - ASSERT_FALSE(handler.is_readable_); - ASSERT_FALSE(handler.is_writable_); - - TriggerReadEvent(); - - // We don't want to assume that the read fd becomes readable the - // instant a bytes is written, so Run until quit by an event. - RunLoop().Run(); - - ASSERT_TRUE(handler.is_readable_); - ASSERT_FALSE(handler.is_writable_); -} - -// Verify that watching a file descriptor for writability succeeds. -TEST_F(MessageLoopForIoPosixTest, WatchWritable) { - MessageLoopForIO message_loop; - MessagePumpForIO::FdWatchController watcher(FROM_HERE); - TestHandler handler; - - // Watch the pipe for writability. - ASSERT_TRUE(MessageLoopCurrentForIO::Get()->WatchFileDescriptor( - write_fd_.get(), /*persistent=*/false, MessagePumpForIO::WATCH_WRITE, - &watcher, &handler)); - - // We should not receive a writable notification until we process events. - ASSERT_FALSE(handler.is_readable_); - ASSERT_FALSE(handler.is_writable_); - - // The pipe should be writable immediately, but wait for the quit closure - // anyway, to be sure. - RunLoop().Run(); - - ASSERT_FALSE(handler.is_readable_); - ASSERT_TRUE(handler.is_writable_); -} - -// Verify that RunUntilIdle() receives IO notifications. -TEST_F(MessageLoopForIoPosixTest, RunUntilIdle) { - MessageLoopForIO message_loop; - MessagePumpForIO::FdWatchController watcher(FROM_HERE); - TestHandler handler; - - // Watch the pipe for readability. - ASSERT_TRUE(MessageLoopCurrentForIO::Get()->WatchFileDescriptor( - read_fd_.get(), /*persistent=*/false, MessagePumpForIO::WATCH_READ, - &watcher, &handler)); - - // The pipe should not be readable when first created. - RunLoop().RunUntilIdle(); - ASSERT_FALSE(handler.is_readable_); - - TriggerReadEvent(); - - while (!handler.is_readable_) - RunLoop().RunUntilIdle(); -} - -void StopWatching(MessagePumpForIO::FdWatchController* controller, - RunLoop* run_loop) { - controller->StopWatchingFileDescriptor(); - run_loop->Quit(); -} - -// Verify that StopWatchingFileDescriptor() works from an event handler. -TEST_F(MessageLoopForIoPosixTest, StopFromHandler) { - MessageLoopForIO message_loop; - RunLoop run_loop; - MessagePumpForIO::FdWatchController watcher(FROM_HERE); - CallClosureHandler handler(BindOnce(&StopWatching, &watcher, &run_loop), - OnceClosure()); - - // Create persistent watcher. - ASSERT_TRUE(MessageLoopCurrentForIO::Get()->WatchFileDescriptor( - read_fd_.get(), /*persistent=*/true, MessagePumpForIO::WATCH_READ, - &watcher, &handler)); - - TriggerReadEvent(); - run_loop.Run(); - - // Trigger the event again. The event handler should not be called again. - TriggerReadEvent(); - RunLoop().RunUntilIdle(); -} - -// Verify that non-persistent watcher is called only once. -TEST_F(MessageLoopForIoPosixTest, NonPersistentWatcher) { - MessageLoopForIO message_loop; - MessagePumpForIO::FdWatchController watcher(FROM_HERE); - - RunLoop run_loop; - CallClosureHandler handler(run_loop.QuitClosure(), OnceClosure()); - - // Create a non-persistent watcher. - ASSERT_TRUE(MessageLoopCurrentForIO::Get()->WatchFileDescriptor( - read_fd_.get(), /*persistent=*/false, MessagePumpForIO::WATCH_READ, - &watcher, &handler)); - - TriggerReadEvent(); - run_loop.Run(); - - // Trigger the event again. handler should not be called again. - TriggerReadEvent(); - RunLoop().RunUntilIdle(); -} - -// Verify that persistent watcher is called every time the event is triggered. -TEST_F(MessageLoopForIoPosixTest, PersistentWatcher) { - MessageLoopForIO message_loop; - MessagePumpForIO::FdWatchController watcher(FROM_HERE); - - RunLoop run_loop1; - CallClosureHandler handler(run_loop1.QuitClosure(), OnceClosure()); - - // Create persistent watcher. - ASSERT_TRUE(MessageLoopCurrentForIO::Get()->WatchFileDescriptor( - read_fd_.get(), /*persistent=*/true, MessagePumpForIO::WATCH_READ, - &watcher, &handler)); - - TriggerReadEvent(); - run_loop1.Run(); - - RunLoop run_loop2; - handler.SetReadClosure(run_loop2.QuitClosure()); - - // Trigger the event again. handler should be called now, which will quit - // run_loop2. - TriggerReadEvent(); - run_loop2.Run(); -} - -void StopWatchingAndWatchAgain(MessagePumpForIO::FdWatchController* controller, - int fd, - MessagePumpForIO::FdWatcher* new_handler, - RunLoop* run_loop) { - controller->StopWatchingFileDescriptor(); - - ASSERT_TRUE(MessageLoopCurrentForIO::Get()->WatchFileDescriptor( - fd, /*persistent=*/true, MessagePumpForIO::WATCH_READ, controller, - new_handler)); - - run_loop->Quit(); -} - -// Verify that a watcher can be stopped and reused from an event handler. -TEST_F(MessageLoopForIoPosixTest, StopAndRestartFromHandler) { - MessageLoopForIO message_loop; - MessagePumpForIO::FdWatchController watcher(FROM_HERE); - - RunLoop run_loop1; - RunLoop run_loop2; - CallClosureHandler handler2(run_loop2.QuitClosure(), OnceClosure()); - CallClosureHandler handler1(BindOnce(&StopWatchingAndWatchAgain, &watcher, - read_fd_.get(), &handler2, &run_loop1), - OnceClosure()); - - // Create persistent watcher. - ASSERT_TRUE(MessageLoopCurrentForIO::Get()->WatchFileDescriptor( - read_fd_.get(), /*persistent=*/true, MessagePumpForIO::WATCH_READ, - &watcher, &handler1)); - - TriggerReadEvent(); - run_loop1.Run(); - - // Trigger the event again. handler2 should be called now, which will quit - // run_loop2 - TriggerReadEvent(); - run_loop2.Run(); -} - -// Verify that the pump properly handles a delayed task after an IO event. -TEST_F(MessageLoopForIoPosixTest, IoEventThenTimer) { - MessageLoopForIO message_loop; - MessagePumpForIO::FdWatchController watcher(FROM_HERE); - - RunLoop timer_run_loop; - message_loop.task_runner()->PostDelayedTask( - FROM_HERE, timer_run_loop.QuitClosure(), - base::TimeDelta::FromMilliseconds(10)); - - RunLoop watcher_run_loop; - CallClosureHandler handler(watcher_run_loop.QuitClosure(), OnceClosure()); - - // Create a non-persistent watcher. - ASSERT_TRUE(MessageLoopCurrentForIO::Get()->WatchFileDescriptor( - read_fd_.get(), /*persistent=*/false, MessagePumpForIO::WATCH_READ, - &watcher, &handler)); - - TriggerReadEvent(); - - // Normally the IO event will be received before the delayed task is - // executed, so this run loop will first handle the IO event and then quit on - // the timer. - timer_run_loop.Run(); - - // Run watcher_run_loop in case the IO event wasn't received before the - // delayed task. - watcher_run_loop.Run(); -} - -// Verify that the pipe can handle an IO event after a delayed task. -TEST_F(MessageLoopForIoPosixTest, TimerThenIoEvent) { - MessageLoopForIO message_loop; - MessagePumpForIO::FdWatchController watcher(FROM_HERE); - - // Trigger read event from a delayed task. - message_loop.task_runner()->PostDelayedTask( - FROM_HERE, - BindOnce(&MessageLoopForIoPosixTest::TriggerReadEvent, Unretained(this)), - TimeDelta::FromMilliseconds(1)); - - RunLoop run_loop; - CallClosureHandler handler(run_loop.QuitClosure(), OnceClosure()); - - // Create a non-persistent watcher. - ASSERT_TRUE(MessageLoopCurrentForIO::Get()->WatchFileDescriptor( - read_fd_.get(), /*persistent=*/false, MessagePumpForIO::WATCH_READ, - &watcher, &handler)); - - run_loop.Run(); -} - -} // namespace - -#endif // !defined(OS_NACL) - -} // namespace base
diff --git a/base/message_loop/message_loop_task_runner_unittest.cc b/base/message_loop/message_loop_task_runner_unittest.cc deleted file mode 100644 index c7e9aa0..0000000 --- a/base/message_loop/message_loop_task_runner_unittest.cc +++ /dev/null
@@ -1,365 +0,0 @@ -// 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/message_loop/message_loop_task_runner.h" - -#include <memory> - -#include "base/atomic_sequence_num.h" -#include "base/bind.h" -#include "base/debug/leak_annotations.h" -#include "base/message_loop/message_loop.h" -#include "base/message_loop/message_loop_task_runner.h" -#include "base/run_loop.h" -#include "base/synchronization/waitable_event.h" -#include "base/threading/thread.h" -#include "base/threading/thread_task_runner_handle.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/platform_test.h" - -namespace base { - -class MessageLoopTaskRunnerTest : public testing::Test { - public: - MessageLoopTaskRunnerTest() - : current_loop_(new MessageLoop()), - task_thread_("task_thread"), - thread_sync_(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED) {} - - void DeleteCurrentMessageLoop() { current_loop_.reset(); } - - protected: - void SetUp() override { - // Use SetUp() instead of the constructor to avoid posting a task to a - // partially constructed object. - task_thread_.Start(); - - // Allow us to pause the |task_thread_|'s MessageLoop. - task_thread_.task_runner()->PostTask( - FROM_HERE, BindOnce(&MessageLoopTaskRunnerTest::BlockTaskThreadHelper, - Unretained(this))); - } - - void TearDown() override { - // Make sure the |task_thread_| is not blocked, and stop the thread - // fully before destruction because its tasks may still depend on the - // |thread_sync_| event. - thread_sync_.Signal(); - task_thread_.Stop(); - DeleteCurrentMessageLoop(); - } - - // Make LoopRecorder threadsafe so that there is defined behavior even if a - // threading mistake sneaks into the PostTaskAndReplyRelay implementation. - class LoopRecorder : public RefCountedThreadSafe<LoopRecorder> { - public: - LoopRecorder(MessageLoop** run_on, - MessageLoop** deleted_on, - int* destruct_order) - : run_on_(run_on), - deleted_on_(deleted_on), - destruct_order_(destruct_order) {} - - void RecordRun() { *run_on_ = MessageLoop::current(); } - - private: - friend class RefCountedThreadSafe<LoopRecorder>; - ~LoopRecorder() { - *deleted_on_ = MessageLoop::current(); - *destruct_order_ = g_order.GetNext(); - } - - MessageLoop** run_on_; - MessageLoop** deleted_on_; - int* destruct_order_; - }; - - static void RecordLoop(scoped_refptr<LoopRecorder> recorder) { - recorder->RecordRun(); - } - - static void RecordLoopAndQuit(scoped_refptr<LoopRecorder> recorder) { - recorder->RecordRun(); - RunLoop::QuitCurrentWhenIdleDeprecated(); - } - - void UnblockTaskThread() { thread_sync_.Signal(); } - - void BlockTaskThreadHelper() { thread_sync_.Wait(); } - - static AtomicSequenceNumber g_order; - - std::unique_ptr<MessageLoop> current_loop_; - Thread task_thread_; - - private: - base::WaitableEvent thread_sync_; -}; - -AtomicSequenceNumber MessageLoopTaskRunnerTest::g_order; - -TEST_F(MessageLoopTaskRunnerTest, PostTaskAndReply_Basic) { - MessageLoop* task_run_on = nullptr; - MessageLoop* task_deleted_on = nullptr; - int task_delete_order = -1; - MessageLoop* reply_run_on = nullptr; - MessageLoop* reply_deleted_on = nullptr; - int reply_delete_order = -1; - - scoped_refptr<LoopRecorder> task_recorder = - new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order); - scoped_refptr<LoopRecorder> reply_recorder = - new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order); - - ASSERT_TRUE(task_thread_.task_runner()->PostTaskAndReply( - FROM_HERE, BindOnce(&RecordLoop, task_recorder), - BindOnce(&RecordLoopAndQuit, reply_recorder))); - - // Die if base::Bind doesn't retain a reference to the recorders. - task_recorder = nullptr; - reply_recorder = nullptr; - ASSERT_FALSE(task_deleted_on); - ASSERT_FALSE(reply_deleted_on); - - UnblockTaskThread(); - RunLoop().Run(); - - EXPECT_EQ(task_thread_.message_loop(), task_run_on); - EXPECT_EQ(task_thread_.message_loop(), task_deleted_on); - EXPECT_EQ(current_loop_.get(), reply_run_on); - EXPECT_EQ(current_loop_.get(), reply_deleted_on); - EXPECT_LT(task_delete_order, reply_delete_order); -} - -TEST_F(MessageLoopTaskRunnerTest, PostTaskAndReplyOnDeletedThreadDoesNotLeak) { - MessageLoop* task_run_on = nullptr; - MessageLoop* task_deleted_on = nullptr; - int task_delete_order = -1; - MessageLoop* reply_run_on = nullptr; - MessageLoop* reply_deleted_on = nullptr; - int reply_delete_order = -1; - - scoped_refptr<LoopRecorder> task_recorder = - new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order); - scoped_refptr<LoopRecorder> reply_recorder = - new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order); - - // Grab a task runner to a dead MessageLoop. - scoped_refptr<SingleThreadTaskRunner> task_runner = - task_thread_.task_runner(); - UnblockTaskThread(); - task_thread_.Stop(); - - ASSERT_FALSE(task_runner->PostTaskAndReply( - FROM_HERE, BindOnce(&RecordLoop, task_recorder), - BindOnce(&RecordLoopAndQuit, reply_recorder))); - - // The relay should have properly deleted its resources leaving us as the only - // reference. - EXPECT_EQ(task_delete_order, reply_delete_order); - ASSERT_TRUE(task_recorder->HasOneRef()); - ASSERT_TRUE(reply_recorder->HasOneRef()); - - // Nothing should have run though. - EXPECT_FALSE(task_run_on); - EXPECT_FALSE(reply_run_on); -} - -TEST_F(MessageLoopTaskRunnerTest, PostTaskAndReply_SameLoop) { - MessageLoop* task_run_on = nullptr; - MessageLoop* task_deleted_on = nullptr; - int task_delete_order = -1; - MessageLoop* reply_run_on = nullptr; - MessageLoop* reply_deleted_on = nullptr; - int reply_delete_order = -1; - - scoped_refptr<LoopRecorder> task_recorder = - new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order); - scoped_refptr<LoopRecorder> reply_recorder = - new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order); - - // Enqueue the relay. - ASSERT_TRUE(current_loop_->task_runner()->PostTaskAndReply( - FROM_HERE, BindOnce(&RecordLoop, task_recorder), - BindOnce(&RecordLoopAndQuit, reply_recorder))); - - // Die if base::Bind doesn't retain a reference to the recorders. - task_recorder = nullptr; - reply_recorder = nullptr; - ASSERT_FALSE(task_deleted_on); - ASSERT_FALSE(reply_deleted_on); - - RunLoop().Run(); - - EXPECT_EQ(current_loop_.get(), task_run_on); - EXPECT_EQ(current_loop_.get(), task_deleted_on); - EXPECT_EQ(current_loop_.get(), reply_run_on); - EXPECT_EQ(current_loop_.get(), reply_deleted_on); - EXPECT_LT(task_delete_order, reply_delete_order); -} - -TEST_F(MessageLoopTaskRunnerTest, - PostTaskAndReply_DeadReplyTaskRunnerBehavior) { - // Annotate the scope as having memory leaks to suppress heapchecker reports. - ANNOTATE_SCOPED_MEMORY_LEAK; - MessageLoop* task_run_on = nullptr; - MessageLoop* task_deleted_on = nullptr; - int task_delete_order = -1; - MessageLoop* reply_run_on = nullptr; - MessageLoop* reply_deleted_on = nullptr; - int reply_delete_order = -1; - - scoped_refptr<LoopRecorder> task_recorder = - new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order); - scoped_refptr<LoopRecorder> reply_recorder = - new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order); - - // Enqueue the relay. - task_thread_.task_runner()->PostTaskAndReply( - FROM_HERE, BindOnce(&RecordLoop, task_recorder), - BindOnce(&RecordLoopAndQuit, reply_recorder)); - - // Die if base::Bind doesn't retain a reference to the recorders. - task_recorder = nullptr; - reply_recorder = nullptr; - ASSERT_FALSE(task_deleted_on); - ASSERT_FALSE(reply_deleted_on); - - UnblockTaskThread(); - - // Mercilessly whack the current loop before |reply| gets to run. - current_loop_.reset(); - - // This should ensure the relay has been run. We need to record the - // MessageLoop pointer before stopping the thread because Thread::Stop() will - // NULL out its own pointer. - MessageLoop* task_loop = task_thread_.message_loop(); - task_thread_.Stop(); - - // Even if the reply task runner is already gone, the original task should - // already be deleted. However, the reply which hasn't executed yet should - // leak to avoid thread-safety issues. - EXPECT_EQ(task_loop, task_run_on); - EXPECT_EQ(task_loop, task_deleted_on); - EXPECT_FALSE(reply_run_on); - ASSERT_FALSE(reply_deleted_on); - - // The PostTaskAndReplyRelay is leaked here. Even if we had a reference to - // it, we cannot just delete it because PostTaskAndReplyRelay's destructor - // checks that MessageLoop::current() is the the same as when the - // PostTaskAndReplyRelay object was constructed. However, this loop must have - // already been deleted in order to perform this test. See - // http://crbug.com/86301. -} - -class MessageLoopTaskRunnerThreadingTest : public testing::Test { - public: - void Release() const { - AssertOnIOThread(); - Quit(); - } - - void Quit() const { - loop_.task_runner()->PostTask( - FROM_HERE, RunLoop::QuitCurrentWhenIdleClosureDeprecated()); - } - - void AssertOnIOThread() const { - ASSERT_TRUE(io_thread_->task_runner()->BelongsToCurrentThread()); - ASSERT_EQ(io_thread_->task_runner(), ThreadTaskRunnerHandle::Get()); - } - - void AssertOnFileThread() const { - ASSERT_TRUE(file_thread_->task_runner()->BelongsToCurrentThread()); - ASSERT_EQ(file_thread_->task_runner(), ThreadTaskRunnerHandle::Get()); - } - - protected: - void SetUp() override { - io_thread_.reset(new Thread("MessageLoopTaskRunnerThreadingTest_IO")); - file_thread_.reset(new Thread("MessageLoopTaskRunnerThreadingTest_File")); - io_thread_->Start(); - file_thread_->Start(); - } - - void TearDown() override { - io_thread_->Stop(); - file_thread_->Stop(); - } - - static void BasicFunction(MessageLoopTaskRunnerThreadingTest* test) { - test->AssertOnFileThread(); - test->Quit(); - } - - static void AssertNotRun() { FAIL() << "Callback Should not get executed."; } - - class DeletedOnFile { - public: - explicit DeletedOnFile(MessageLoopTaskRunnerThreadingTest* test) - : test_(test) {} - - ~DeletedOnFile() { - test_->AssertOnFileThread(); - test_->Quit(); - } - - private: - MessageLoopTaskRunnerThreadingTest* test_; - }; - - std::unique_ptr<Thread> io_thread_; - std::unique_ptr<Thread> file_thread_; - - private: - mutable MessageLoop loop_; -}; - -TEST_F(MessageLoopTaskRunnerThreadingTest, Release) { - EXPECT_TRUE(io_thread_->task_runner()->ReleaseSoon(FROM_HERE, this)); - RunLoop().Run(); -} - -TEST_F(MessageLoopTaskRunnerThreadingTest, Delete) { - DeletedOnFile* deleted_on_file = new DeletedOnFile(this); - EXPECT_TRUE( - file_thread_->task_runner()->DeleteSoon(FROM_HERE, deleted_on_file)); - RunLoop().Run(); -} - -TEST_F(MessageLoopTaskRunnerThreadingTest, PostTask) { - EXPECT_TRUE(file_thread_->task_runner()->PostTask( - FROM_HERE, BindOnce(&MessageLoopTaskRunnerThreadingTest::BasicFunction, - Unretained(this)))); - RunLoop().Run(); -} - -TEST_F(MessageLoopTaskRunnerThreadingTest, PostTaskAfterThreadExits) { - std::unique_ptr<Thread> test_thread( - new Thread("MessageLoopTaskRunnerThreadingTest_Dummy")); - test_thread->Start(); - scoped_refptr<SingleThreadTaskRunner> task_runner = - test_thread->task_runner(); - test_thread->Stop(); - - bool ret = task_runner->PostTask( - FROM_HERE, BindOnce(&MessageLoopTaskRunnerThreadingTest::AssertNotRun)); - EXPECT_FALSE(ret); -} - -TEST_F(MessageLoopTaskRunnerThreadingTest, PostTaskAfterThreadIsDeleted) { - scoped_refptr<SingleThreadTaskRunner> task_runner; - { - std::unique_ptr<Thread> test_thread( - new Thread("MessageLoopTaskRunnerThreadingTest_Dummy")); - test_thread->Start(); - task_runner = test_thread->task_runner(); - } - bool ret = task_runner->PostTask( - FROM_HERE, BindOnce(&MessageLoopTaskRunnerThreadingTest::AssertNotRun)); - EXPECT_FALSE(ret); -} - -} // namespace base
diff --git a/base/message_loop/message_loop_unittest.cc b/base/message_loop/message_loop_unittest.cc deleted file mode 100644 index 970f6d1..0000000 --- a/base/message_loop/message_loop_unittest.cc +++ /dev/null
@@ -1,2184 +0,0 @@ -// 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 <stddef.h> -#include <stdint.h> - -#include <vector> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/compiler_specific.h" -#include "base/logging.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/memory/ref_counted.h" -#include "base/message_loop/message_loop.h" -#include "base/message_loop/message_loop_current.h" -#include "base/message_loop/message_pump_for_io.h" -#include "base/pending_task.h" -#include "base/posix/eintr_wrapper.h" -#include "base/run_loop.h" -#include "base/single_thread_task_runner.h" -#include "base/synchronization/waitable_event.h" -#include "base/task_scheduler/task_scheduler.h" -#include "base/test/test_simple_task_runner.h" -#include "base/test/test_timeouts.h" -#include "base/threading/platform_thread.h" -#include "base/threading/sequence_local_storage_slot.h" -#include "base/threading/thread.h" -#include "base/threading/thread_task_runner_handle.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(OS_ANDROID) -#include "base/android/java_handler_thread.h" -#include "base/android/jni_android.h" -#include "base/test/android/java_handler_thread_helpers.h" -#endif - -#if defined(OS_WIN) -#include "base/message_loop/message_pump_win.h" -#include "base/process/memory.h" -#include "base/strings/string16.h" -#include "base/win/current_module.h" -#include "base/win/scoped_handle.h" -#endif - -namespace base { - -// TODO(darin): Platform-specific MessageLoop tests should be grouped together -// to avoid chopping this file up with so many #ifdefs. - -namespace { - -class Foo : public RefCounted<Foo> { - public: - Foo() : test_count_(0) { - } - - void Test0() { ++test_count_; } - - void Test1ConstRef(const std::string& a) { - ++test_count_; - result_.append(a); - } - - void Test1Ptr(std::string* a) { - ++test_count_; - result_.append(*a); - } - - void Test1Int(int a) { test_count_ += a; } - - void Test2Ptr(std::string* a, std::string* b) { - ++test_count_; - result_.append(*a); - result_.append(*b); - } - - void Test2Mixed(const std::string& a, std::string* b) { - ++test_count_; - result_.append(a); - result_.append(*b); - } - - int test_count() const { return test_count_; } - const std::string& result() const { return result_; } - - private: - friend class RefCounted<Foo>; - - ~Foo() = default; - - int test_count_; - std::string result_; - - DISALLOW_COPY_AND_ASSIGN(Foo); -}; - -// This function runs slowly to simulate a large amount of work being done. -static void SlowFunc(TimeDelta pause, int* quit_counter) { - PlatformThread::Sleep(pause); - if (--(*quit_counter) == 0) - RunLoop::QuitCurrentWhenIdleDeprecated(); -} - -// This function records the time when Run was called in a Time object, which is -// useful for building a variety of MessageLoop tests. -static void RecordRunTimeFunc(TimeTicks* run_time, int* quit_counter) { - *run_time = TimeTicks::Now(); - - // Cause our Run function to take some time to execute. As a result we can - // count on subsequent RecordRunTimeFunc()s running at a future time, - // without worry about the resolution of our system clock being an issue. - SlowFunc(TimeDelta::FromMilliseconds(10), quit_counter); -} - -enum TaskType { - MESSAGEBOX, - ENDDIALOG, - RECURSIVE, - TIMEDMESSAGELOOP, - QUITMESSAGELOOP, - ORDERED, - PUMPS, - SLEEP, - RUNS, -}; - -// Saves the order in which the tasks executed. -struct TaskItem { - TaskItem(TaskType t, int c, bool s) - : type(t), - cookie(c), - start(s) { - } - - TaskType type; - int cookie; - bool start; - - bool operator == (const TaskItem& other) const { - return type == other.type && cookie == other.cookie && start == other.start; - } -}; - -std::ostream& operator <<(std::ostream& os, TaskType type) { - switch (type) { - case MESSAGEBOX: os << "MESSAGEBOX"; break; - case ENDDIALOG: os << "ENDDIALOG"; break; - case RECURSIVE: os << "RECURSIVE"; break; - case TIMEDMESSAGELOOP: os << "TIMEDMESSAGELOOP"; break; - case QUITMESSAGELOOP: os << "QUITMESSAGELOOP"; break; - case ORDERED: os << "ORDERED"; break; - case PUMPS: os << "PUMPS"; break; - case SLEEP: os << "SLEEP"; break; - default: - NOTREACHED(); - os << "Unknown TaskType"; - break; - } - return os; -} - -std::ostream& operator <<(std::ostream& os, const TaskItem& item) { - if (item.start) - return os << item.type << " " << item.cookie << " starts"; - else - return os << item.type << " " << item.cookie << " ends"; -} - -class TaskList { - public: - void RecordStart(TaskType type, int cookie) { - TaskItem item(type, cookie, true); - DVLOG(1) << item; - task_list_.push_back(item); - } - - void RecordEnd(TaskType type, int cookie) { - TaskItem item(type, cookie, false); - DVLOG(1) << item; - task_list_.push_back(item); - } - - size_t Size() { - return task_list_.size(); - } - - TaskItem Get(int n) { - return task_list_[n]; - } - - private: - std::vector<TaskItem> task_list_; -}; - -class DummyTaskObserver : public MessageLoop::TaskObserver { - public: - explicit DummyTaskObserver(int num_tasks) - : num_tasks_started_(0), num_tasks_processed_(0), num_tasks_(num_tasks) {} - - DummyTaskObserver(int num_tasks, int num_tasks_started) - : num_tasks_started_(num_tasks_started), - num_tasks_processed_(0), - num_tasks_(num_tasks) {} - - ~DummyTaskObserver() override = default; - - void WillProcessTask(const PendingTask& pending_task) override { - num_tasks_started_++; - EXPECT_LE(num_tasks_started_, num_tasks_); - EXPECT_EQ(num_tasks_started_, num_tasks_processed_ + 1); - } - - void DidProcessTask(const PendingTask& pending_task) override { - num_tasks_processed_++; - EXPECT_LE(num_tasks_started_, num_tasks_); - EXPECT_EQ(num_tasks_started_, num_tasks_processed_); - } - - int num_tasks_started() const { return num_tasks_started_; } - int num_tasks_processed() const { return num_tasks_processed_; } - - private: - int num_tasks_started_; - int num_tasks_processed_; - const int num_tasks_; - - DISALLOW_COPY_AND_ASSIGN(DummyTaskObserver); -}; - -void RecursiveFunc(TaskList* order, int cookie, int depth, - bool is_reentrant) { - order->RecordStart(RECURSIVE, cookie); - if (depth > 0) { - if (is_reentrant) - MessageLoopCurrent::Get()->SetNestableTasksAllowed(true); - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - BindOnce(&RecursiveFunc, order, cookie, depth - 1, is_reentrant)); - } - order->RecordEnd(RECURSIVE, cookie); -} - -void QuitFunc(TaskList* order, int cookie) { - order->RecordStart(QUITMESSAGELOOP, cookie); - RunLoop::QuitCurrentWhenIdleDeprecated(); - order->RecordEnd(QUITMESSAGELOOP, cookie); -} - -void PostNTasks(int posts_remaining) { - if (posts_remaining > 1) { - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce(&PostNTasks, posts_remaining - 1)); - } -} - -enum class TaskSchedulerAvailability { - NO_TASK_SCHEDULER, - WITH_TASK_SCHEDULER, -}; - -std::string TaskSchedulerAvailabilityToString( - TaskSchedulerAvailability availability) { - switch (availability) { - case TaskSchedulerAvailability::NO_TASK_SCHEDULER: - return "NoTaskScheduler"; - case TaskSchedulerAvailability::WITH_TASK_SCHEDULER: - return "WithTaskScheduler"; - } - NOTREACHED(); - return "Unknown"; -} - -class MessageLoopTest - : public ::testing::TestWithParam<TaskSchedulerAvailability> { - public: - MessageLoopTest() = default; - ~MessageLoopTest() override = default; - - void SetUp() override { - if (GetParam() == TaskSchedulerAvailability::WITH_TASK_SCHEDULER) - TaskScheduler::CreateAndStartWithDefaultParams("MessageLoopTest"); - } - - void TearDown() override { - if (GetParam() == TaskSchedulerAvailability::WITH_TASK_SCHEDULER) { - // Failure to call FlushForTesting() could result in task leaks as tasks - // are skipped on shutdown. - base::TaskScheduler::GetInstance()->FlushForTesting(); - base::TaskScheduler::GetInstance()->Shutdown(); - base::TaskScheduler::GetInstance()->JoinForTesting(); - base::TaskScheduler::SetInstance(nullptr); - } - } - - static std::string ParamInfoToString( - ::testing::TestParamInfo<TaskSchedulerAvailability> param_info) { - return TaskSchedulerAvailabilityToString(param_info.param); - } - - private: - DISALLOW_COPY_AND_ASSIGN(MessageLoopTest); -}; - -#if defined(OS_ANDROID) -void DoNotRun() { - ASSERT_TRUE(false); -} - -void RunTest_AbortDontRunMoreTasks(bool delayed, bool init_java_first) { - WaitableEvent test_done_event(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - std::unique_ptr<android::JavaHandlerThread> java_thread; - if (init_java_first) { - java_thread = android::JavaHandlerThreadHelpers::CreateJavaFirst(); - } else { - java_thread = std::make_unique<android::JavaHandlerThread>( - "JavaHandlerThreadForTesting from AbortDontRunMoreTasks"); - } - java_thread->Start(); - java_thread->ListenForUncaughtExceptionsForTesting(); - - auto target = - BindOnce(&android::JavaHandlerThreadHelpers::ThrowExceptionAndAbort, - &test_done_event); - if (delayed) { - java_thread->message_loop()->task_runner()->PostDelayedTask( - FROM_HERE, std::move(target), TimeDelta::FromMilliseconds(10)); - } else { - java_thread->message_loop()->task_runner()->PostTask(FROM_HERE, - std::move(target)); - java_thread->message_loop()->task_runner()->PostTask(FROM_HERE, - BindOnce(&DoNotRun)); - } - test_done_event.Wait(); - java_thread->Stop(); - android::ScopedJavaLocalRef<jthrowable> exception = - java_thread->GetUncaughtExceptionIfAny(); - ASSERT_TRUE( - android::JavaHandlerThreadHelpers::IsExceptionTestException(exception)); -} - -TEST_P(MessageLoopTest, JavaExceptionAbort) { - constexpr bool delayed = false; - constexpr bool init_java_first = false; - RunTest_AbortDontRunMoreTasks(delayed, init_java_first); -} -TEST_P(MessageLoopTest, DelayedJavaExceptionAbort) { - constexpr bool delayed = true; - constexpr bool init_java_first = false; - RunTest_AbortDontRunMoreTasks(delayed, init_java_first); -} -TEST_P(MessageLoopTest, JavaExceptionAbortInitJavaFirst) { - constexpr bool delayed = false; - constexpr bool init_java_first = true; - RunTest_AbortDontRunMoreTasks(delayed, init_java_first); -} - -TEST_P(MessageLoopTest, RunTasksWhileShuttingDownJavaThread) { - const int kNumPosts = 6; - DummyTaskObserver observer(kNumPosts, 1); - - auto java_thread = std::make_unique<android::JavaHandlerThread>("test"); - java_thread->Start(); - - java_thread->message_loop()->task_runner()->PostTask( - FROM_HERE, - BindOnce( - [](android::JavaHandlerThread* java_thread, - DummyTaskObserver* observer, int num_posts) { - java_thread->message_loop()->AddTaskObserver(observer); - ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, BindOnce([]() { ADD_FAILURE(); }), - TimeDelta::FromDays(1)); - java_thread->StopMessageLoopForTesting(); - PostNTasks(num_posts); - }, - Unretained(java_thread.get()), Unretained(&observer), kNumPosts)); - - java_thread->JoinForTesting(); - java_thread.reset(); - - EXPECT_EQ(kNumPosts, observer.num_tasks_started()); - EXPECT_EQ(kNumPosts, observer.num_tasks_processed()); -} -#endif // defined(OS_ANDROID) - -#if defined(OS_WIN) - -void SubPumpFunc() { - MessageLoopCurrent::Get()->SetNestableTasksAllowed(true); - MSG msg; - while (GetMessage(&msg, NULL, 0, 0)) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - RunLoop::QuitCurrentWhenIdleDeprecated(); -} - -void RunTest_PostDelayedTask_SharedTimer_SubPump() { - MessageLoop message_loop(MessageLoop::TYPE_UI); - - // Test that the interval of the timer, used to run the next delayed task, is - // set to a value corresponding to when the next delayed task should run. - - // By setting num_tasks to 1, we ensure that the first task to run causes the - // run loop to exit. - int num_tasks = 1; - TimeTicks run_time; - - message_loop.task_runner()->PostTask(FROM_HERE, BindOnce(&SubPumpFunc)); - - // This very delayed task should never run. - message_loop.task_runner()->PostDelayedTask( - FROM_HERE, BindOnce(&RecordRunTimeFunc, &run_time, &num_tasks), - TimeDelta::FromSeconds(1000)); - - // This slightly delayed task should run from within SubPumpFunc. - message_loop.task_runner()->PostDelayedTask(FROM_HERE, - BindOnce(&PostQuitMessage, 0), - TimeDelta::FromMilliseconds(10)); - - Time start_time = Time::Now(); - - RunLoop().Run(); - EXPECT_EQ(1, num_tasks); - - // Ensure that we ran in far less time than the slower timer. - TimeDelta total_time = Time::Now() - start_time; - EXPECT_GT(5000, total_time.InMilliseconds()); - - // In case both timers somehow run at nearly the same time, sleep a little - // and then run all pending to force them both to have run. This is just - // encouraging flakiness if there is any. - PlatformThread::Sleep(TimeDelta::FromMilliseconds(100)); - RunLoop().RunUntilIdle(); - - EXPECT_TRUE(run_time.is_null()); -} - -const wchar_t kMessageBoxTitle[] = L"MessageLoop Unit Test"; - -// MessageLoop implicitly start a "modal message loop". Modal dialog boxes, -// common controls (like OpenFile) and StartDoc printing function can cause -// implicit message loops. -void MessageBoxFunc(TaskList* order, int cookie, bool is_reentrant) { - order->RecordStart(MESSAGEBOX, cookie); - if (is_reentrant) - MessageLoopCurrent::Get()->SetNestableTasksAllowed(true); - MessageBox(NULL, L"Please wait...", kMessageBoxTitle, MB_OK); - order->RecordEnd(MESSAGEBOX, cookie); -} - -// Will end the MessageBox. -void EndDialogFunc(TaskList* order, int cookie) { - order->RecordStart(ENDDIALOG, cookie); - HWND window = GetActiveWindow(); - if (window != NULL) { - EXPECT_NE(EndDialog(window, IDCONTINUE), 0); - // Cheap way to signal that the window wasn't found if RunEnd() isn't - // called. - order->RecordEnd(ENDDIALOG, cookie); - } -} - -void RecursiveFuncWin(scoped_refptr<SingleThreadTaskRunner> task_runner, - HANDLE event, - bool expect_window, - TaskList* order, - bool is_reentrant) { - task_runner->PostTask(FROM_HERE, - BindOnce(&RecursiveFunc, order, 1, 2, is_reentrant)); - task_runner->PostTask(FROM_HERE, - BindOnce(&MessageBoxFunc, order, 2, is_reentrant)); - task_runner->PostTask(FROM_HERE, - BindOnce(&RecursiveFunc, order, 3, 2, is_reentrant)); - // The trick here is that for recursive task processing, this task will be - // ran _inside_ the MessageBox message loop, dismissing the MessageBox - // without a chance. - // For non-recursive task processing, this will be executed _after_ the - // MessageBox will have been dismissed by the code below, where - // expect_window_ is true. - task_runner->PostTask(FROM_HERE, BindOnce(&EndDialogFunc, order, 4)); - task_runner->PostTask(FROM_HERE, BindOnce(&QuitFunc, order, 5)); - - // Enforce that every tasks are sent before starting to run the main thread - // message loop. - ASSERT_TRUE(SetEvent(event)); - - // Poll for the MessageBox. Don't do this at home! At the speed we do it, - // you will never realize one MessageBox was shown. - for (; expect_window;) { - HWND window = FindWindow(L"#32770", kMessageBoxTitle); - if (window) { - // Dismiss it. - for (;;) { - HWND button = FindWindowEx(window, NULL, L"Button", NULL); - if (button != NULL) { - EXPECT_EQ(0, SendMessage(button, WM_LBUTTONDOWN, 0, 0)); - EXPECT_EQ(0, SendMessage(button, WM_LBUTTONUP, 0, 0)); - break; - } - } - break; - } - } -} - -// TODO(darin): These tests need to be ported since they test critical -// message loop functionality. - -// A side effect of this test is the generation a beep. Sorry. -void RunTest_RecursiveDenial2(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - Thread worker("RecursiveDenial2_worker"); - Thread::Options options; - options.message_loop_type = message_loop_type; - ASSERT_EQ(true, worker.StartWithOptions(options)); - TaskList order; - win::ScopedHandle event(CreateEvent(NULL, FALSE, FALSE, NULL)); - worker.task_runner()->PostTask( - FROM_HERE, BindOnce(&RecursiveFuncWin, ThreadTaskRunnerHandle::Get(), - event.Get(), true, &order, false)); - // Let the other thread execute. - WaitForSingleObject(event.Get(), INFINITE); - RunLoop().Run(); - - ASSERT_EQ(17u, order.Size()); - EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(2), TaskItem(MESSAGEBOX, 2, true)); - EXPECT_EQ(order.Get(3), TaskItem(MESSAGEBOX, 2, false)); - EXPECT_EQ(order.Get(4), TaskItem(RECURSIVE, 3, true)); - EXPECT_EQ(order.Get(5), TaskItem(RECURSIVE, 3, false)); - // When EndDialogFunc is processed, the window is already dismissed, hence no - // "end" entry. - EXPECT_EQ(order.Get(6), TaskItem(ENDDIALOG, 4, true)); - EXPECT_EQ(order.Get(7), TaskItem(QUITMESSAGELOOP, 5, true)); - EXPECT_EQ(order.Get(8), TaskItem(QUITMESSAGELOOP, 5, false)); - EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 3, true)); - EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 3, false)); - EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(14), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(15), TaskItem(RECURSIVE, 3, true)); - EXPECT_EQ(order.Get(16), TaskItem(RECURSIVE, 3, false)); -} - -// A side effect of this test is the generation a beep. Sorry. This test also -// needs to process windows messages on the current thread. -void RunTest_RecursiveSupport2(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - Thread worker("RecursiveSupport2_worker"); - Thread::Options options; - options.message_loop_type = message_loop_type; - ASSERT_EQ(true, worker.StartWithOptions(options)); - TaskList order; - win::ScopedHandle event(CreateEvent(NULL, FALSE, FALSE, NULL)); - worker.task_runner()->PostTask( - FROM_HERE, BindOnce(&RecursiveFuncWin, ThreadTaskRunnerHandle::Get(), - event.Get(), false, &order, true)); - // Let the other thread execute. - WaitForSingleObject(event.Get(), INFINITE); - RunLoop().Run(); - - ASSERT_EQ(18u, order.Size()); - EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(2), TaskItem(MESSAGEBOX, 2, true)); - // Note that this executes in the MessageBox modal loop. - EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 3, true)); - EXPECT_EQ(order.Get(4), TaskItem(RECURSIVE, 3, false)); - EXPECT_EQ(order.Get(5), TaskItem(ENDDIALOG, 4, true)); - EXPECT_EQ(order.Get(6), TaskItem(ENDDIALOG, 4, false)); - EXPECT_EQ(order.Get(7), TaskItem(MESSAGEBOX, 2, false)); - /* The order can subtly change here. The reason is that when RecursiveFunc(1) - is called in the main thread, if it is faster than getting to the - PostTask(FROM_HERE, BindOnce(&QuitFunc) execution, the order of task - execution can change. We don't care anyway that the order isn't correct. - EXPECT_EQ(order.Get(8), TaskItem(QUITMESSAGELOOP, 5, true)); - EXPECT_EQ(order.Get(9), TaskItem(QUITMESSAGELOOP, 5, false)); - EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false)); - */ - EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 3, true)); - EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 3, false)); - EXPECT_EQ(order.Get(14), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(15), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(16), TaskItem(RECURSIVE, 3, true)); - EXPECT_EQ(order.Get(17), TaskItem(RECURSIVE, 3, false)); -} - -#endif // defined(OS_WIN) - -void PostNTasksThenQuit(int posts_remaining) { - if (posts_remaining > 1) { - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce(&PostNTasksThenQuit, posts_remaining - 1)); - } else { - RunLoop::QuitCurrentWhenIdleDeprecated(); - } -} - -#if defined(OS_WIN) - -class TestIOHandler : public MessagePumpForIO::IOHandler { - public: - TestIOHandler(const wchar_t* name, HANDLE signal, bool wait); - - void OnIOCompleted(MessagePumpForIO::IOContext* context, - DWORD bytes_transfered, - DWORD error) override; - - void Init(); - void WaitForIO(); - OVERLAPPED* context() { return &context_.overlapped; } - DWORD size() { return sizeof(buffer_); } - - private: - char buffer_[48]; - MessagePumpForIO::IOContext context_; - HANDLE signal_; - win::ScopedHandle file_; - bool wait_; -}; - -TestIOHandler::TestIOHandler(const wchar_t* name, HANDLE signal, bool wait) - : signal_(signal), wait_(wait) { - memset(buffer_, 0, sizeof(buffer_)); - - file_.Set(CreateFile(name, GENERIC_READ, 0, NULL, OPEN_EXISTING, - FILE_FLAG_OVERLAPPED, NULL)); - EXPECT_TRUE(file_.IsValid()); -} - -void TestIOHandler::Init() { - MessageLoopCurrentForIO::Get()->RegisterIOHandler(file_.Get(), this); - - DWORD read; - EXPECT_FALSE(ReadFile(file_.Get(), buffer_, size(), &read, context())); - EXPECT_EQ(static_cast<DWORD>(ERROR_IO_PENDING), GetLastError()); - if (wait_) - WaitForIO(); -} - -void TestIOHandler::OnIOCompleted(MessagePumpForIO::IOContext* context, - DWORD bytes_transfered, - DWORD error) { - ASSERT_TRUE(context == &context_); - ASSERT_TRUE(SetEvent(signal_)); -} - -void TestIOHandler::WaitForIO() { - EXPECT_TRUE(MessageLoopCurrentForIO::Get()->WaitForIOCompletion(300, this)); - EXPECT_TRUE(MessageLoopCurrentForIO::Get()->WaitForIOCompletion(400, this)); -} - -void RunTest_IOHandler() { - win::ScopedHandle callback_called(CreateEvent(NULL, TRUE, FALSE, NULL)); - ASSERT_TRUE(callback_called.IsValid()); - - const wchar_t* kPipeName = L"\\\\.\\pipe\\iohandler_pipe"; - win::ScopedHandle server( - CreateNamedPipe(kPipeName, PIPE_ACCESS_OUTBOUND, 0, 1, 0, 0, 0, NULL)); - ASSERT_TRUE(server.IsValid()); - - Thread thread("IOHandler test"); - Thread::Options options; - options.message_loop_type = MessageLoop::TYPE_IO; - ASSERT_TRUE(thread.StartWithOptions(options)); - - TestIOHandler handler(kPipeName, callback_called.Get(), false); - thread.task_runner()->PostTask( - FROM_HERE, BindOnce(&TestIOHandler::Init, Unretained(&handler))); - // Make sure the thread runs and sleeps for lack of work. - PlatformThread::Sleep(TimeDelta::FromMilliseconds(100)); - - const char buffer[] = "Hello there!"; - DWORD written; - EXPECT_TRUE(WriteFile(server.Get(), buffer, sizeof(buffer), &written, NULL)); - - DWORD result = WaitForSingleObject(callback_called.Get(), 1000); - EXPECT_EQ(WAIT_OBJECT_0, result); - - thread.Stop(); -} - -void RunTest_WaitForIO() { - win::ScopedHandle callback1_called( - CreateEvent(NULL, TRUE, FALSE, NULL)); - win::ScopedHandle callback2_called( - CreateEvent(NULL, TRUE, FALSE, NULL)); - ASSERT_TRUE(callback1_called.IsValid()); - ASSERT_TRUE(callback2_called.IsValid()); - - const wchar_t* kPipeName1 = L"\\\\.\\pipe\\iohandler_pipe1"; - const wchar_t* kPipeName2 = L"\\\\.\\pipe\\iohandler_pipe2"; - win::ScopedHandle server1( - CreateNamedPipe(kPipeName1, PIPE_ACCESS_OUTBOUND, 0, 1, 0, 0, 0, NULL)); - win::ScopedHandle server2( - CreateNamedPipe(kPipeName2, PIPE_ACCESS_OUTBOUND, 0, 1, 0, 0, 0, NULL)); - ASSERT_TRUE(server1.IsValid()); - ASSERT_TRUE(server2.IsValid()); - - Thread thread("IOHandler test"); - Thread::Options options; - options.message_loop_type = MessageLoop::TYPE_IO; - ASSERT_TRUE(thread.StartWithOptions(options)); - - TestIOHandler handler1(kPipeName1, callback1_called.Get(), false); - TestIOHandler handler2(kPipeName2, callback2_called.Get(), true); - thread.task_runner()->PostTask( - FROM_HERE, BindOnce(&TestIOHandler::Init, Unretained(&handler1))); - // TODO(ajwong): Do we really need such long Sleeps in this function? - // Make sure the thread runs and sleeps for lack of work. - TimeDelta delay = TimeDelta::FromMilliseconds(100); - PlatformThread::Sleep(delay); - thread.task_runner()->PostTask( - FROM_HERE, BindOnce(&TestIOHandler::Init, Unretained(&handler2))); - PlatformThread::Sleep(delay); - - // At this time handler1 is waiting to be called, and the thread is waiting - // on the Init method of handler2, filtering only handler2 callbacks. - - const char buffer[] = "Hello there!"; - DWORD written; - EXPECT_TRUE(WriteFile(server1.Get(), buffer, sizeof(buffer), &written, NULL)); - PlatformThread::Sleep(2 * delay); - EXPECT_EQ(static_cast<DWORD>(WAIT_TIMEOUT), - WaitForSingleObject(callback1_called.Get(), 0)) - << "handler1 has not been called"; - - EXPECT_TRUE(WriteFile(server2.Get(), buffer, sizeof(buffer), &written, NULL)); - - HANDLE objects[2] = { callback1_called.Get(), callback2_called.Get() }; - DWORD result = WaitForMultipleObjects(2, objects, TRUE, 1000); - EXPECT_EQ(WAIT_OBJECT_0, result); - - thread.Stop(); -} - -#endif // defined(OS_WIN) - -} // namespace - -//----------------------------------------------------------------------------- -// Each test is run against each type of MessageLoop. That way we are sure -// that message loops work properly in all configurations. Of course, in some -// cases, a unit test may only be for a particular type of loop. - -namespace { - -struct MessageLoopTypedTestParams { - MessageLoopTypedTestParams( - MessageLoop::Type type_in, - TaskSchedulerAvailability task_scheduler_availability_in) { - type = type_in; - task_scheduler_availability = task_scheduler_availability_in; - } - - MessageLoop::Type type; - TaskSchedulerAvailability task_scheduler_availability; -}; - -class MessageLoopTypedTest - : public ::testing::TestWithParam<MessageLoopTypedTestParams> { - public: - MessageLoopTypedTest() = default; - ~MessageLoopTypedTest() = default; - - void SetUp() override { - if (GetTaskSchedulerAvailability() == - TaskSchedulerAvailability::WITH_TASK_SCHEDULER) { - TaskScheduler::CreateAndStartWithDefaultParams("MessageLoopTypedTest"); - } - } - - void TearDown() override { - if (GetTaskSchedulerAvailability() == - TaskSchedulerAvailability::WITH_TASK_SCHEDULER) { - // Failure to call FlushForTesting() could result in task leaks as tasks - // are skipped on shutdown. - base::TaskScheduler::GetInstance()->FlushForTesting(); - base::TaskScheduler::GetInstance()->Shutdown(); - base::TaskScheduler::GetInstance()->JoinForTesting(); - base::TaskScheduler::SetInstance(nullptr); - } - } - - static std::string ParamInfoToString( - ::testing::TestParamInfo<MessageLoopTypedTestParams> param_info) { - return MessageLoopTypeToString(param_info.param.type) + "_" + - TaskSchedulerAvailabilityToString( - param_info.param.task_scheduler_availability); - } - - protected: - MessageLoop::Type GetMessageLoopType() { return GetParam().type; } - - private: - static std::string MessageLoopTypeToString(MessageLoop::Type type) { - switch (type) { - case MessageLoop::TYPE_DEFAULT: - return "Default"; - case MessageLoop::TYPE_IO: - return "IO"; - case MessageLoop::TYPE_UI: - return "UI"; - case MessageLoop::TYPE_CUSTOM: -#if defined(OS_ANDROID) - case MessageLoop::TYPE_JAVA: -#endif // defined(OS_ANDROID) - break; - } - NOTREACHED(); - return "NotSupported"; - } - - TaskSchedulerAvailability GetTaskSchedulerAvailability() { - return GetParam().task_scheduler_availability; - } - - DISALLOW_COPY_AND_ASSIGN(MessageLoopTypedTest); -}; - -} // namespace - -TEST_P(MessageLoopTypedTest, PostTask) { - MessageLoop loop(GetMessageLoopType()); - // Add tests to message loop - scoped_refptr<Foo> foo(new Foo()); - std::string a("a"), b("b"), c("c"), d("d"); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - BindOnce(&Foo::Test0, foo)); - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce(&Foo::Test1ConstRef, foo, a)); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - BindOnce(&Foo::Test1Ptr, foo, &b)); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - BindOnce(&Foo::Test1Int, foo, 100)); - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce(&Foo::Test2Ptr, foo, &a, &c)); - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce(&Foo::Test2Mixed, foo, a, &d)); - // After all tests, post a message that will shut down the message loop - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce(&RunLoop::QuitCurrentWhenIdleDeprecated)); - - // Now kick things off - RunLoop().Run(); - - EXPECT_EQ(foo->test_count(), 105); - EXPECT_EQ(foo->result(), "abacad"); -} - -TEST_P(MessageLoopTypedTest, PostDelayedTask_Basic) { - MessageLoop loop(GetMessageLoopType()); - - // Test that PostDelayedTask results in a delayed task. - - const TimeDelta kDelay = TimeDelta::FromMilliseconds(100); - - int num_tasks = 1; - TimeTicks run_time; - - TimeTicks time_before_run = TimeTicks::Now(); - loop.task_runner()->PostDelayedTask( - FROM_HERE, BindOnce(&RecordRunTimeFunc, &run_time, &num_tasks), kDelay); - RunLoop().Run(); - TimeTicks time_after_run = TimeTicks::Now(); - - EXPECT_EQ(0, num_tasks); - EXPECT_LT(kDelay, time_after_run - time_before_run); -} - -TEST_P(MessageLoopTypedTest, PostDelayedTask_InDelayOrder) { - MessageLoop loop(GetMessageLoopType()); - - // Test that two tasks with different delays run in the right order. - int num_tasks = 2; - TimeTicks run_time1, run_time2; - - loop.task_runner()->PostDelayedTask( - FROM_HERE, BindOnce(&RecordRunTimeFunc, &run_time1, &num_tasks), - TimeDelta::FromMilliseconds(200)); - // If we get a large pause in execution (due to a context switch) here, this - // test could fail. - loop.task_runner()->PostDelayedTask( - FROM_HERE, BindOnce(&RecordRunTimeFunc, &run_time2, &num_tasks), - TimeDelta::FromMilliseconds(10)); - - RunLoop().Run(); - EXPECT_EQ(0, num_tasks); - - EXPECT_TRUE(run_time2 < run_time1); -} - -TEST_P(MessageLoopTypedTest, PostDelayedTask_InPostOrder) { - MessageLoop loop(GetMessageLoopType()); - - // Test that two tasks with the same delay 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. - - const TimeDelta kDelay = TimeDelta::FromMilliseconds(100); - - int num_tasks = 2; - TimeTicks run_time1, run_time2; - - loop.task_runner()->PostDelayedTask( - FROM_HERE, BindOnce(&RecordRunTimeFunc, &run_time1, &num_tasks), kDelay); - loop.task_runner()->PostDelayedTask( - FROM_HERE, BindOnce(&RecordRunTimeFunc, &run_time2, &num_tasks), kDelay); - - RunLoop().Run(); - EXPECT_EQ(0, num_tasks); - - EXPECT_TRUE(run_time1 < run_time2); -} - -TEST_P(MessageLoopTypedTest, PostDelayedTask_InPostOrder_2) { - MessageLoop loop(GetMessageLoopType()); - - // Test that a delayed task still runs after a normal tasks even if the - // normal tasks take a long time to run. - - const TimeDelta kPause = TimeDelta::FromMilliseconds(50); - - int num_tasks = 2; - TimeTicks run_time; - - loop.task_runner()->PostTask(FROM_HERE, - BindOnce(&SlowFunc, kPause, &num_tasks)); - loop.task_runner()->PostDelayedTask( - FROM_HERE, BindOnce(&RecordRunTimeFunc, &run_time, &num_tasks), - TimeDelta::FromMilliseconds(10)); - - TimeTicks time_before_run = TimeTicks::Now(); - RunLoop().Run(); - TimeTicks time_after_run = TimeTicks::Now(); - - EXPECT_EQ(0, num_tasks); - - EXPECT_LT(kPause, time_after_run - time_before_run); -} - -TEST_P(MessageLoopTypedTest, PostDelayedTask_InPostOrder_3) { - MessageLoop loop(GetMessageLoopType()); - - // Test that a delayed task still runs after a pile of normal tasks. The key - // difference between this test and the previous one is that here we return - // the MessageLoop a lot so we give the MessageLoop plenty of opportunities - // to maybe run the delayed task. It should know not to do so until the - // delayed task's delay has passed. - - int num_tasks = 11; - TimeTicks run_time1, run_time2; - - // Clutter the ML with tasks. - for (int i = 1; i < num_tasks; ++i) - loop.task_runner()->PostTask( - FROM_HERE, BindOnce(&RecordRunTimeFunc, &run_time1, &num_tasks)); - - loop.task_runner()->PostDelayedTask( - FROM_HERE, BindOnce(&RecordRunTimeFunc, &run_time2, &num_tasks), - TimeDelta::FromMilliseconds(1)); - - RunLoop().Run(); - EXPECT_EQ(0, num_tasks); - - EXPECT_TRUE(run_time2 > run_time1); -} - -TEST_P(MessageLoopTypedTest, PostDelayedTask_SharedTimer) { - MessageLoop loop(GetMessageLoopType()); - - // Test that the interval of the timer, used to run the next delayed task, is - // set to a value corresponding to when the next delayed task should run. - - // By setting num_tasks to 1, we ensure that the first task to run causes the - // run loop to exit. - int num_tasks = 1; - TimeTicks run_time1, run_time2; - - loop.task_runner()->PostDelayedTask( - FROM_HERE, BindOnce(&RecordRunTimeFunc, &run_time1, &num_tasks), - TimeDelta::FromSeconds(1000)); - loop.task_runner()->PostDelayedTask( - FROM_HERE, BindOnce(&RecordRunTimeFunc, &run_time2, &num_tasks), - TimeDelta::FromMilliseconds(10)); - - TimeTicks start_time = TimeTicks::Now(); - - RunLoop().Run(); - EXPECT_EQ(0, num_tasks); - - // Ensure that we ran in far less time than the slower timer. - TimeDelta total_time = TimeTicks::Now() - start_time; - EXPECT_GT(5000, total_time.InMilliseconds()); - - // In case both timers somehow run at nearly the same time, sleep a little - // and then run all pending to force them both to have run. This is just - // encouraging flakiness if there is any. - PlatformThread::Sleep(TimeDelta::FromMilliseconds(100)); - RunLoop().RunUntilIdle(); - - EXPECT_TRUE(run_time1.is_null()); - EXPECT_FALSE(run_time2.is_null()); -} - -namespace { - -// This is used to inject a test point for recording the destructor calls for -// Closure objects send to MessageLoop::PostTask(). It is awkward usage since we -// are trying to hook the actual destruction, which is not a common operation. -class RecordDeletionProbe : public RefCounted<RecordDeletionProbe> { - public: - RecordDeletionProbe(RecordDeletionProbe* post_on_delete, bool* was_deleted) - : post_on_delete_(post_on_delete), was_deleted_(was_deleted) {} - void Run() {} - - private: - friend class RefCounted<RecordDeletionProbe>; - - ~RecordDeletionProbe() { - *was_deleted_ = true; - if (post_on_delete_.get()) - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce(&RecordDeletionProbe::Run, post_on_delete_)); - } - - scoped_refptr<RecordDeletionProbe> post_on_delete_; - bool* was_deleted_; -}; - -} // namespace - -/* TODO(darin): MessageLoop does not support deleting all tasks in the */ -/* destructor. */ -/* Fails, http://crbug.com/50272. */ -TEST_P(MessageLoopTypedTest, DISABLED_EnsureDeletion) { - bool a_was_deleted = false; - bool b_was_deleted = false; - { - MessageLoop loop(GetMessageLoopType()); - loop.task_runner()->PostTask( - FROM_HERE, BindOnce(&RecordDeletionProbe::Run, - new RecordDeletionProbe(nullptr, &a_was_deleted))); - // TODO(ajwong): Do we really need 1000ms here? - loop.task_runner()->PostDelayedTask( - FROM_HERE, - BindOnce(&RecordDeletionProbe::Run, - new RecordDeletionProbe(nullptr, &b_was_deleted)), - TimeDelta::FromMilliseconds(1000)); - } - EXPECT_TRUE(a_was_deleted); - EXPECT_TRUE(b_was_deleted); -} - -/* TODO(darin): MessageLoop does not support deleting all tasks in the */ -/* destructor. */ -/* Fails, http://crbug.com/50272. */ -TEST_P(MessageLoopTypedTest, DISABLED_EnsureDeletion_Chain) { - bool a_was_deleted = false; - bool b_was_deleted = false; - bool c_was_deleted = false; - { - MessageLoop loop(GetMessageLoopType()); - // The scoped_refptr for each of the below is held either by the chained - // RecordDeletionProbe, or the bound RecordDeletionProbe::Run() callback. - RecordDeletionProbe* a = new RecordDeletionProbe(nullptr, &a_was_deleted); - RecordDeletionProbe* b = new RecordDeletionProbe(a, &b_was_deleted); - RecordDeletionProbe* c = new RecordDeletionProbe(b, &c_was_deleted); - loop.task_runner()->PostTask(FROM_HERE, - BindOnce(&RecordDeletionProbe::Run, c)); - } - EXPECT_TRUE(a_was_deleted); - EXPECT_TRUE(b_was_deleted); - EXPECT_TRUE(c_was_deleted); -} - -namespace { - -void NestingFunc(int* depth) { - if (*depth > 0) { - *depth -= 1; - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - BindOnce(&NestingFunc, depth)); - - MessageLoopCurrent::Get()->SetNestableTasksAllowed(true); - RunLoop().Run(); - } - base::RunLoop::QuitCurrentWhenIdleDeprecated(); -} - -} // namespace - -TEST_P(MessageLoopTypedTest, Nesting) { - MessageLoop loop(GetMessageLoopType()); - - int depth = 50; - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - BindOnce(&NestingFunc, &depth)); - RunLoop().Run(); - EXPECT_EQ(depth, 0); -} - -TEST_P(MessageLoopTypedTest, RecursiveDenial1) { - MessageLoop loop(GetMessageLoopType()); - - EXPECT_TRUE(MessageLoopCurrent::Get()->NestableTasksAllowed()); - TaskList order; - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce(&RecursiveFunc, &order, 1, 2, false)); - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce(&RecursiveFunc, &order, 2, 2, false)); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - BindOnce(&QuitFunc, &order, 3)); - - RunLoop().Run(); - - // FIFO order. - ASSERT_EQ(14U, order.Size()); - EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true)); - EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false)); - EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true)); - EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false)); - EXPECT_EQ(order.Get(6), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(7), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true)); - EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false)); - EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 2, true)); - EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 2, false)); -} - -namespace { - -void RecursiveSlowFunc(TaskList* order, - int cookie, - int depth, - bool is_reentrant) { - RecursiveFunc(order, cookie, depth, is_reentrant); - PlatformThread::Sleep(TimeDelta::FromMilliseconds(10)); -} - -void OrderedFunc(TaskList* order, int cookie) { - order->RecordStart(ORDERED, cookie); - order->RecordEnd(ORDERED, cookie); -} - -} // namespace - -TEST_P(MessageLoopTypedTest, RecursiveDenial3) { - MessageLoop loop(GetMessageLoopType()); - - EXPECT_TRUE(MessageLoopCurrent::Get()->NestableTasksAllowed()); - TaskList order; - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce(&RecursiveSlowFunc, &order, 1, 2, false)); - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce(&RecursiveSlowFunc, &order, 2, 2, false)); - ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, BindOnce(&OrderedFunc, &order, 3), - TimeDelta::FromMilliseconds(5)); - ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, BindOnce(&QuitFunc, &order, 4), - TimeDelta::FromMilliseconds(5)); - - RunLoop().Run(); - - // FIFO order. - ASSERT_EQ(16U, order.Size()); - EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true)); - EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false)); - EXPECT_EQ(order.Get(4), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(5), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(6), TaskItem(ORDERED, 3, true)); - EXPECT_EQ(order.Get(7), TaskItem(ORDERED, 3, false)); - EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true)); - EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false)); - EXPECT_EQ(order.Get(10), TaskItem(QUITMESSAGELOOP, 4, true)); - EXPECT_EQ(order.Get(11), TaskItem(QUITMESSAGELOOP, 4, false)); - EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(14), TaskItem(RECURSIVE, 2, true)); - EXPECT_EQ(order.Get(15), TaskItem(RECURSIVE, 2, false)); -} - -TEST_P(MessageLoopTypedTest, RecursiveSupport1) { - MessageLoop loop(GetMessageLoopType()); - - TaskList order; - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce(&RecursiveFunc, &order, 1, 2, true)); - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce(&RecursiveFunc, &order, 2, 2, true)); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - BindOnce(&QuitFunc, &order, 3)); - - RunLoop().Run(); - - // FIFO order. - ASSERT_EQ(14U, order.Size()); - EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true)); - EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false)); - EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true)); - EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false)); - EXPECT_EQ(order.Get(6), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(7), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true)); - EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false)); - EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 2, true)); - EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 2, false)); -} - -// Tests that non nestable tasks run in FIFO if there are no nested loops. -TEST_P(MessageLoopTypedTest, NonNestableWithNoNesting) { - MessageLoop loop(GetMessageLoopType()); - - TaskList order; - - ThreadTaskRunnerHandle::Get()->PostNonNestableTask( - FROM_HERE, BindOnce(&OrderedFunc, &order, 1)); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - BindOnce(&OrderedFunc, &order, 2)); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - BindOnce(&QuitFunc, &order, 3)); - RunLoop().Run(); - - // FIFO order. - ASSERT_EQ(6U, order.Size()); - EXPECT_EQ(order.Get(0), TaskItem(ORDERED, 1, true)); - EXPECT_EQ(order.Get(1), TaskItem(ORDERED, 1, false)); - EXPECT_EQ(order.Get(2), TaskItem(ORDERED, 2, true)); - EXPECT_EQ(order.Get(3), TaskItem(ORDERED, 2, false)); - EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true)); - EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false)); -} - -namespace { - -void FuncThatPumps(TaskList* order, int cookie) { - order->RecordStart(PUMPS, cookie); - RunLoop(RunLoop::Type::kNestableTasksAllowed).RunUntilIdle(); - order->RecordEnd(PUMPS, cookie); -} - -void SleepFunc(TaskList* order, int cookie, TimeDelta delay) { - order->RecordStart(SLEEP, cookie); - PlatformThread::Sleep(delay); - order->RecordEnd(SLEEP, cookie); -} - -} // namespace - -// Tests that non nestable tasks don't run when there's code in the call stack. -TEST_P(MessageLoopTypedTest, NonNestableDelayedInNestedLoop) { - MessageLoop loop(GetMessageLoopType()); - - TaskList order; - - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - BindOnce(&FuncThatPumps, &order, 1)); - ThreadTaskRunnerHandle::Get()->PostNonNestableTask( - FROM_HERE, BindOnce(&OrderedFunc, &order, 2)); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - BindOnce(&OrderedFunc, &order, 3)); - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - BindOnce(&SleepFunc, &order, 4, TimeDelta::FromMilliseconds(50))); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - BindOnce(&OrderedFunc, &order, 5)); - ThreadTaskRunnerHandle::Get()->PostNonNestableTask( - FROM_HERE, BindOnce(&QuitFunc, &order, 6)); - - RunLoop().Run(); - - // FIFO order. - ASSERT_EQ(12U, order.Size()); - EXPECT_EQ(order.Get(0), TaskItem(PUMPS, 1, true)); - EXPECT_EQ(order.Get(1), TaskItem(ORDERED, 3, true)); - EXPECT_EQ(order.Get(2), TaskItem(ORDERED, 3, false)); - EXPECT_EQ(order.Get(3), TaskItem(SLEEP, 4, true)); - EXPECT_EQ(order.Get(4), TaskItem(SLEEP, 4, false)); - EXPECT_EQ(order.Get(5), TaskItem(ORDERED, 5, true)); - EXPECT_EQ(order.Get(6), TaskItem(ORDERED, 5, false)); - EXPECT_EQ(order.Get(7), TaskItem(PUMPS, 1, false)); - EXPECT_EQ(order.Get(8), TaskItem(ORDERED, 2, true)); - EXPECT_EQ(order.Get(9), TaskItem(ORDERED, 2, false)); - EXPECT_EQ(order.Get(10), TaskItem(QUITMESSAGELOOP, 6, true)); - EXPECT_EQ(order.Get(11), TaskItem(QUITMESSAGELOOP, 6, false)); -} - -namespace { - -void FuncThatRuns(TaskList* order, int cookie, RunLoop* run_loop) { - order->RecordStart(RUNS, cookie); - { - MessageLoopCurrent::ScopedNestableTaskAllower allow; - run_loop->Run(); - } - order->RecordEnd(RUNS, cookie); -} - -void FuncThatQuitsNow() { - base::RunLoop::QuitCurrentDeprecated(); -} - -} // namespace - -// Tests RunLoopQuit only quits the corresponding MessageLoop::Run. -TEST_P(MessageLoopTypedTest, QuitNow) { - MessageLoop loop(GetMessageLoopType()); - - TaskList order; - - RunLoop run_loop; - - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce(&FuncThatRuns, &order, 1, Unretained(&run_loop))); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - BindOnce(&OrderedFunc, &order, 2)); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - BindOnce(&FuncThatQuitsNow)); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - BindOnce(&OrderedFunc, &order, 3)); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - BindOnce(&FuncThatQuitsNow)); - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce(&OrderedFunc, &order, 4)); // never runs - - RunLoop().Run(); - - ASSERT_EQ(6U, order.Size()); - int task_index = 0; - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, false)); - EXPECT_EQ(static_cast<size_t>(task_index), order.Size()); -} - -// Tests RunLoopQuit only quits the corresponding MessageLoop::Run. -TEST_P(MessageLoopTypedTest, RunLoopQuitTop) { - MessageLoop loop(GetMessageLoopType()); - - TaskList order; - - RunLoop outer_run_loop; - RunLoop nested_run_loop; - - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - BindOnce(&FuncThatRuns, &order, 1, Unretained(&nested_run_loop))); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - outer_run_loop.QuitClosure()); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - BindOnce(&OrderedFunc, &order, 2)); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - nested_run_loop.QuitClosure()); - - outer_run_loop.Run(); - - ASSERT_EQ(4U, order.Size()); - int task_index = 0; - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); - EXPECT_EQ(static_cast<size_t>(task_index), order.Size()); -} - -// Tests RunLoopQuit only quits the corresponding MessageLoop::Run. -TEST_P(MessageLoopTypedTest, RunLoopQuitNested) { - MessageLoop loop(GetMessageLoopType()); - - TaskList order; - - RunLoop outer_run_loop; - RunLoop nested_run_loop; - - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - BindOnce(&FuncThatRuns, &order, 1, Unretained(&nested_run_loop))); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - nested_run_loop.QuitClosure()); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - BindOnce(&OrderedFunc, &order, 2)); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - outer_run_loop.QuitClosure()); - - outer_run_loop.Run(); - - ASSERT_EQ(4U, order.Size()); - int task_index = 0; - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false)); - EXPECT_EQ(static_cast<size_t>(task_index), order.Size()); -} - -// Quits current loop and immediately runs a nested loop. -void QuitAndRunNestedLoop(TaskList* order, - int cookie, - RunLoop* outer_run_loop, - RunLoop* nested_run_loop) { - order->RecordStart(RUNS, cookie); - outer_run_loop->Quit(); - nested_run_loop->Run(); - order->RecordEnd(RUNS, cookie); -} - -// Test that we can run nested loop after quitting the current one. -TEST_P(MessageLoopTypedTest, RunLoopNestedAfterQuit) { - MessageLoop loop(GetMessageLoopType()); - - TaskList order; - - RunLoop outer_run_loop; - RunLoop nested_run_loop; - - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - nested_run_loop.QuitClosure()); - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce(&QuitAndRunNestedLoop, &order, 1, &outer_run_loop, - &nested_run_loop)); - - outer_run_loop.Run(); - - ASSERT_EQ(2U, order.Size()); - int task_index = 0; - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); - EXPECT_EQ(static_cast<size_t>(task_index), order.Size()); -} - -// Tests RunLoopQuit only quits the corresponding MessageLoop::Run. -TEST_P(MessageLoopTypedTest, RunLoopQuitBogus) { - MessageLoop loop(GetMessageLoopType()); - - TaskList order; - - RunLoop outer_run_loop; - RunLoop nested_run_loop; - RunLoop bogus_run_loop; - - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - BindOnce(&FuncThatRuns, &order, 1, Unretained(&nested_run_loop))); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - bogus_run_loop.QuitClosure()); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - BindOnce(&OrderedFunc, &order, 2)); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - outer_run_loop.QuitClosure()); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - nested_run_loop.QuitClosure()); - - outer_run_loop.Run(); - - ASSERT_EQ(4U, order.Size()); - int task_index = 0; - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); - EXPECT_EQ(static_cast<size_t>(task_index), order.Size()); -} - -// Tests RunLoopQuit only quits the corresponding MessageLoop::Run. -TEST_P(MessageLoopTypedTest, RunLoopQuitDeep) { - MessageLoop loop(GetMessageLoopType()); - - TaskList order; - - RunLoop outer_run_loop; - RunLoop nested_loop1; - RunLoop nested_loop2; - RunLoop nested_loop3; - RunLoop nested_loop4; - - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce(&FuncThatRuns, &order, 1, Unretained(&nested_loop1))); - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce(&FuncThatRuns, &order, 2, Unretained(&nested_loop2))); - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce(&FuncThatRuns, &order, 3, Unretained(&nested_loop3))); - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce(&FuncThatRuns, &order, 4, Unretained(&nested_loop4))); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - BindOnce(&OrderedFunc, &order, 5)); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - outer_run_loop.QuitClosure()); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - BindOnce(&OrderedFunc, &order, 6)); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - nested_loop1.QuitClosure()); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - BindOnce(&OrderedFunc, &order, 7)); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - nested_loop2.QuitClosure()); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - BindOnce(&OrderedFunc, &order, 8)); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - nested_loop3.QuitClosure()); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - BindOnce(&OrderedFunc, &order, 9)); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - nested_loop4.QuitClosure()); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - BindOnce(&OrderedFunc, &order, 10)); - - outer_run_loop.Run(); - - ASSERT_EQ(18U, order.Size()); - int task_index = 0; - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 2, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 3, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 4, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 5, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 5, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 6, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 6, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 7, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 7, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 8, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 8, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 9, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 9, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 4, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 3, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 2, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); - EXPECT_EQ(static_cast<size_t>(task_index), order.Size()); -} - -// Tests RunLoopQuit works before RunWithID. -TEST_P(MessageLoopTypedTest, RunLoopQuitOrderBefore) { - MessageLoop loop(GetMessageLoopType()); - - TaskList order; - - RunLoop run_loop; - - run_loop.Quit(); - - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce(&OrderedFunc, &order, 1)); // never runs - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce(&FuncThatQuitsNow)); // never runs - - run_loop.Run(); - - ASSERT_EQ(0U, order.Size()); -} - -// Tests RunLoopQuit works during RunWithID. -TEST_P(MessageLoopTypedTest, RunLoopQuitOrderDuring) { - MessageLoop loop(GetMessageLoopType()); - - TaskList order; - - RunLoop run_loop; - - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - BindOnce(&OrderedFunc, &order, 1)); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, run_loop.QuitClosure()); - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce(&OrderedFunc, &order, 2)); // never runs - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce(&FuncThatQuitsNow)); // never runs - - run_loop.Run(); - - ASSERT_EQ(2U, order.Size()); - int task_index = 0; - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 1, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 1, false)); - EXPECT_EQ(static_cast<size_t>(task_index), order.Size()); -} - -// Tests RunLoopQuit works after RunWithID. -TEST_P(MessageLoopTypedTest, RunLoopQuitOrderAfter) { - MessageLoop loop(GetMessageLoopType()); - - TaskList order; - - RunLoop run_loop; - - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce(&FuncThatRuns, &order, 1, Unretained(&run_loop))); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - BindOnce(&OrderedFunc, &order, 2)); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - BindOnce(&FuncThatQuitsNow)); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - BindOnce(&OrderedFunc, &order, 3)); - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, run_loop.QuitClosure()); // has no affect - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - BindOnce(&OrderedFunc, &order, 4)); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - BindOnce(&FuncThatQuitsNow)); - - RunLoop outer_run_loop; - outer_run_loop.Run(); - - ASSERT_EQ(8U, order.Size()); - int task_index = 0; - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 4, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 4, false)); - EXPECT_EQ(static_cast<size_t>(task_index), order.Size()); -} - -// There was a bug in the MessagePumpGLib where posting tasks recursively -// caused the message loop to hang, due to the buffer of the internal pipe -// becoming full. Test all MessageLoop types to ensure this issue does not -// exist in other MessagePumps. -// -// On Linux, the pipe buffer size is 64KiB by default. The bug caused one -// byte accumulated in the pipe per two posts, so we should repeat 128K -// times to reproduce the bug. -TEST_P(MessageLoopTypedTest, RecursivePosts) { - const int kNumTimes = 1 << 17; - MessageLoop loop(GetMessageLoopType()); - loop.task_runner()->PostTask(FROM_HERE, - BindOnce(&PostNTasksThenQuit, kNumTimes)); - RunLoop().Run(); -} - -TEST_P(MessageLoopTypedTest, NestableTasksAllowedAtTopLevel) { - MessageLoop loop(GetMessageLoopType()); - EXPECT_TRUE(MessageLoopCurrent::Get()->NestableTasksAllowed()); -} - -// Nestable tasks shouldn't be allowed to run reentrantly by default (regression -// test for https://crbug.com/754112). -TEST_P(MessageLoopTypedTest, NestableTasksDisallowedByDefault) { - MessageLoop loop(GetMessageLoopType()); - RunLoop run_loop; - loop.task_runner()->PostTask( - FROM_HERE, - BindOnce( - [](RunLoop* run_loop) { - EXPECT_FALSE(MessageLoopCurrent::Get()->NestableTasksAllowed()); - run_loop->Quit(); - }, - Unretained(&run_loop))); - run_loop.Run(); -} - -TEST_P(MessageLoopTypedTest, NestableTasksProcessedWhenRunLoopAllows) { - MessageLoop loop(GetMessageLoopType()); - RunLoop run_loop; - loop.task_runner()->PostTask( - FROM_HERE, - BindOnce( - [](RunLoop* run_loop) { - // This test would hang if this RunLoop wasn't of type - // kNestableTasksAllowed (i.e. this is testing that this is - // processed and doesn't hang). - RunLoop nested_run_loop(RunLoop::Type::kNestableTasksAllowed); - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - BindOnce( - [](RunLoop* nested_run_loop) { - // Each additional layer of application task nesting - // requires its own allowance. The kNestableTasksAllowed - // RunLoop allowed this task to be processed but further - // nestable tasks are by default disallowed from this - // layer. - EXPECT_FALSE( - MessageLoopCurrent::Get()->NestableTasksAllowed()); - nested_run_loop->Quit(); - }, - Unretained(&nested_run_loop))); - nested_run_loop.Run(); - - run_loop->Quit(); - }, - Unretained(&run_loop))); - run_loop.Run(); -} - -TEST_P(MessageLoopTypedTest, NestableTasksAllowedExplicitlyInScope) { - MessageLoop loop(GetMessageLoopType()); - RunLoop run_loop; - loop.task_runner()->PostTask( - FROM_HERE, - BindOnce( - [](RunLoop* run_loop) { - { - MessageLoopCurrent::ScopedNestableTaskAllower - allow_nestable_tasks; - EXPECT_TRUE(MessageLoopCurrent::Get()->NestableTasksAllowed()); - } - EXPECT_FALSE(MessageLoopCurrent::Get()->NestableTasksAllowed()); - run_loop->Quit(); - }, - Unretained(&run_loop))); - run_loop.Run(); -} - -TEST_P(MessageLoopTypedTest, NestableTasksAllowedManually) { - MessageLoop loop(GetMessageLoopType()); - RunLoop run_loop; - loop.task_runner()->PostTask( - FROM_HERE, - BindOnce( - [](RunLoop* run_loop) { - EXPECT_FALSE(MessageLoopCurrent::Get()->NestableTasksAllowed()); - MessageLoopCurrent::Get()->SetNestableTasksAllowed(true); - EXPECT_TRUE(MessageLoopCurrent::Get()->NestableTasksAllowed()); - MessageLoopCurrent::Get()->SetNestableTasksAllowed(false); - EXPECT_FALSE(MessageLoopCurrent::Get()->NestableTasksAllowed()); - run_loop->Quit(); - }, - Unretained(&run_loop))); - run_loop.Run(); -} - -INSTANTIATE_TEST_CASE_P( - , - MessageLoopTypedTest, - ::testing::Values(MessageLoopTypedTestParams( - MessageLoop::TYPE_DEFAULT, - TaskSchedulerAvailability::NO_TASK_SCHEDULER), - MessageLoopTypedTestParams( - MessageLoop::TYPE_IO, - TaskSchedulerAvailability::NO_TASK_SCHEDULER), - MessageLoopTypedTestParams( - MessageLoop::TYPE_UI, - TaskSchedulerAvailability::NO_TASK_SCHEDULER), - MessageLoopTypedTestParams( - MessageLoop::TYPE_DEFAULT, - TaskSchedulerAvailability::WITH_TASK_SCHEDULER), - MessageLoopTypedTestParams( - MessageLoop::TYPE_IO, - TaskSchedulerAvailability::WITH_TASK_SCHEDULER), - MessageLoopTypedTestParams( - MessageLoop::TYPE_UI, - TaskSchedulerAvailability::WITH_TASK_SCHEDULER)), - MessageLoopTypedTest::ParamInfoToString); - -#if defined(OS_WIN) -// Verifies that the MessageLoop ignores WM_QUIT, rather than quitting. -// Users of MessageLoop typically expect to control when their RunLoops stop -// Run()ning explicitly, via QuitClosure() etc (see https://crbug.com/720078) -TEST_P(MessageLoopTest, WmQuitIsIgnored) { - MessageLoop loop(MessageLoop::TYPE_UI); - RunLoop run_loop; - // Post a WM_QUIT message to the current thread. - ::PostQuitMessage(0); - - // Post a task to the current thread, with a small delay to make it less - // likely that we process the posted task before looking for WM_* messages. - bool task_was_run = false; - loop.task_runner()->PostDelayedTask( - FROM_HERE, - BindOnce( - [](bool* flag, OnceClosure closure) { - *flag = true; - std::move(closure).Run(); - }, - &task_was_run, run_loop.QuitClosure()), - TestTimeouts::tiny_timeout()); - - // Run the loop, and ensure that the posted task is processed before we quit. - run_loop.Run(); - EXPECT_TRUE(task_was_run); -} - -TEST_P(MessageLoopTest, PostDelayedTask_SharedTimer_SubPump) { - RunTest_PostDelayedTask_SharedTimer_SubPump(); -} - -// This test occasionally hangs. See http://crbug.com/44567. -TEST_P(MessageLoopTest, DISABLED_RecursiveDenial2) { - RunTest_RecursiveDenial2(MessageLoop::TYPE_DEFAULT); - RunTest_RecursiveDenial2(MessageLoop::TYPE_UI); - RunTest_RecursiveDenial2(MessageLoop::TYPE_IO); -} - -TEST_P(MessageLoopTest, RecursiveSupport2) { - // This test requires a UI loop. - RunTest_RecursiveSupport2(MessageLoop::TYPE_UI); -} -#endif // defined(OS_WIN) - -TEST_P(MessageLoopTest, TaskObserver) { - const int kNumPosts = 6; - DummyTaskObserver observer(kNumPosts); - - MessageLoop loop; - loop.AddTaskObserver(&observer); - loop.task_runner()->PostTask(FROM_HERE, - BindOnce(&PostNTasksThenQuit, kNumPosts)); - RunLoop().Run(); - loop.RemoveTaskObserver(&observer); - - EXPECT_EQ(kNumPosts, observer.num_tasks_started()); - EXPECT_EQ(kNumPosts, observer.num_tasks_processed()); -} - -#if defined(OS_WIN) -TEST_P(MessageLoopTest, IOHandler) { - RunTest_IOHandler(); -} - -TEST_P(MessageLoopTest, WaitForIO) { - RunTest_WaitForIO(); -} - -TEST_P(MessageLoopTest, HighResolutionTimer) { - MessageLoop message_loop; - Time::EnableHighResolutionTimer(true); - - constexpr TimeDelta kFastTimer = TimeDelta::FromMilliseconds(5); - constexpr TimeDelta kSlowTimer = TimeDelta::FromMilliseconds(100); - - { - // Post a fast task to enable the high resolution timers. - RunLoop run_loop; - message_loop.task_runner()->PostDelayedTask( - FROM_HERE, - BindOnce( - [](RunLoop* run_loop) { - EXPECT_TRUE(Time::IsHighResolutionTimerInUse()); - run_loop->QuitWhenIdle(); - }, - &run_loop), - kFastTimer); - run_loop.Run(); - } - EXPECT_FALSE(Time::IsHighResolutionTimerInUse()); - { - // Check that a slow task does not trigger the high resolution logic. - RunLoop run_loop; - message_loop.task_runner()->PostDelayedTask( - FROM_HERE, - BindOnce( - [](RunLoop* run_loop) { - EXPECT_FALSE(Time::IsHighResolutionTimerInUse()); - run_loop->QuitWhenIdle(); - }, - &run_loop), - kSlowTimer); - run_loop.Run(); - } - Time::EnableHighResolutionTimer(false); - Time::ResetHighResolutionTimerUsage(); -} - -#endif // defined(OS_WIN) - -namespace { -// Inject a test point for recording the destructor calls for Closure objects -// send to MessageLoop::PostTask(). It is awkward usage since we are trying to -// hook the actual destruction, which is not a common operation. -class DestructionObserverProbe : - public RefCounted<DestructionObserverProbe> { - public: - DestructionObserverProbe(bool* task_destroyed, - bool* destruction_observer_called) - : task_destroyed_(task_destroyed), - destruction_observer_called_(destruction_observer_called) { - } - virtual void Run() { - // This task should never run. - ADD_FAILURE(); - } - private: - friend class RefCounted<DestructionObserverProbe>; - - virtual ~DestructionObserverProbe() { - EXPECT_FALSE(*destruction_observer_called_); - *task_destroyed_ = true; - } - - bool* task_destroyed_; - bool* destruction_observer_called_; -}; - -class MLDestructionObserver : public MessageLoopCurrent::DestructionObserver { - public: - MLDestructionObserver(bool* task_destroyed, bool* destruction_observer_called) - : task_destroyed_(task_destroyed), - destruction_observer_called_(destruction_observer_called), - task_destroyed_before_message_loop_(false) { - } - void WillDestroyCurrentMessageLoop() override { - task_destroyed_before_message_loop_ = *task_destroyed_; - *destruction_observer_called_ = true; - } - bool task_destroyed_before_message_loop() const { - return task_destroyed_before_message_loop_; - } - private: - bool* task_destroyed_; - bool* destruction_observer_called_; - bool task_destroyed_before_message_loop_; -}; - -} // namespace - -TEST_P(MessageLoopTest, DestructionObserverTest) { - // Verify that the destruction observer gets called at the very end (after - // all the pending tasks have been destroyed). - MessageLoop* loop = new MessageLoop; - const TimeDelta kDelay = TimeDelta::FromMilliseconds(100); - - bool task_destroyed = false; - bool destruction_observer_called = false; - - MLDestructionObserver observer(&task_destroyed, &destruction_observer_called); - loop->AddDestructionObserver(&observer); - loop->task_runner()->PostDelayedTask( - FROM_HERE, - BindOnce(&DestructionObserverProbe::Run, - new DestructionObserverProbe(&task_destroyed, - &destruction_observer_called)), - kDelay); - delete loop; - EXPECT_TRUE(observer.task_destroyed_before_message_loop()); - // The task should have been destroyed when we deleted the loop. - EXPECT_TRUE(task_destroyed); - EXPECT_TRUE(destruction_observer_called); -} - - -// Verify that MessageLoop sets ThreadMainTaskRunner::current() and it -// posts tasks on that message loop. -TEST_P(MessageLoopTest, ThreadMainTaskRunner) { - MessageLoop loop; - - scoped_refptr<Foo> foo(new Foo()); - std::string a("a"); - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce(&Foo::Test1ConstRef, foo, a)); - - // Post quit task; - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce(&RunLoop::QuitCurrentWhenIdleDeprecated)); - - // Now kick things off - RunLoop().Run(); - - EXPECT_EQ(foo->test_count(), 1); - EXPECT_EQ(foo->result(), "a"); -} - -TEST_P(MessageLoopTest, IsType) { - MessageLoop loop(MessageLoop::TYPE_UI); - EXPECT_TRUE(loop.IsType(MessageLoop::TYPE_UI)); - EXPECT_FALSE(loop.IsType(MessageLoop::TYPE_IO)); - EXPECT_FALSE(loop.IsType(MessageLoop::TYPE_DEFAULT)); -} - -#if defined(OS_WIN) -void EmptyFunction() {} - -void PostMultipleTasks() { - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - base::BindOnce(&EmptyFunction)); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - base::BindOnce(&EmptyFunction)); -} - -static const int kSignalMsg = WM_USER + 2; - -void PostWindowsMessage(HWND message_hwnd) { - PostMessage(message_hwnd, kSignalMsg, 0, 2); -} - -void EndTest(bool* did_run, HWND hwnd) { - *did_run = true; - PostMessage(hwnd, WM_CLOSE, 0, 0); -} - -int kMyMessageFilterCode = 0x5002; - -LRESULT CALLBACK TestWndProcThunk(HWND hwnd, UINT message, - WPARAM wparam, LPARAM lparam) { - if (message == WM_CLOSE) - EXPECT_TRUE(DestroyWindow(hwnd)); - if (message != kSignalMsg) - return DefWindowProc(hwnd, message, wparam, lparam); - - switch (lparam) { - case 1: - // First, we post a task that will post multiple no-op tasks to make sure - // that the pump's incoming task queue does not become empty during the - // test. - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - base::BindOnce(&PostMultipleTasks)); - // Next, we post a task that posts a windows message to trigger the second - // stage of the test. - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&PostWindowsMessage, hwnd)); - break; - case 2: - // Since we're about to enter a modal loop, tell the message loop that we - // intend to nest tasks. - MessageLoopCurrent::Get()->SetNestableTasksAllowed(true); - bool did_run = false; - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&EndTest, &did_run, hwnd)); - // Run a nested windows-style message loop and verify that our task runs. If - // it doesn't, then we'll loop here until the test times out. - MSG msg; - while (GetMessage(&msg, 0, 0, 0)) { - if (!CallMsgFilter(&msg, kMyMessageFilterCode)) - DispatchMessage(&msg); - // If this message is a WM_CLOSE, explicitly exit the modal loop. Posting - // a WM_QUIT should handle this, but unfortunately MessagePumpWin eats - // WM_QUIT messages even when running inside a modal loop. - if (msg.message == WM_CLOSE) - break; - } - EXPECT_TRUE(did_run); - RunLoop::QuitCurrentWhenIdleDeprecated(); - break; - } - return 0; -} - -TEST_P(MessageLoopTest, AlwaysHaveUserMessageWhenNesting) { - MessageLoop loop(MessageLoop::TYPE_UI); - HINSTANCE instance = CURRENT_MODULE(); - WNDCLASSEX wc = {0}; - wc.cbSize = sizeof(wc); - wc.lpfnWndProc = TestWndProcThunk; - wc.hInstance = instance; - wc.lpszClassName = L"MessageLoopTest_HWND"; - ATOM atom = RegisterClassEx(&wc); - ASSERT_TRUE(atom); - - HWND message_hwnd = CreateWindow(MAKEINTATOM(atom), 0, 0, 0, 0, 0, 0, - HWND_MESSAGE, 0, instance, 0); - ASSERT_TRUE(message_hwnd) << GetLastError(); - - ASSERT_TRUE(PostMessage(message_hwnd, kSignalMsg, 0, 1)); - - RunLoop().Run(); - - ASSERT_TRUE(UnregisterClass(MAKEINTATOM(atom), instance)); -} -#endif // defined(OS_WIN) - -TEST_P(MessageLoopTest, SetTaskRunner) { - MessageLoop loop; - scoped_refptr<SingleThreadTaskRunner> new_runner(new TestSimpleTaskRunner()); - - loop.SetTaskRunner(new_runner); - EXPECT_EQ(new_runner, loop.task_runner()); - EXPECT_EQ(new_runner, ThreadTaskRunnerHandle::Get()); -} - -TEST_P(MessageLoopTest, OriginalRunnerWorks) { - MessageLoop loop; - scoped_refptr<SingleThreadTaskRunner> new_runner(new TestSimpleTaskRunner()); - scoped_refptr<SingleThreadTaskRunner> original_runner(loop.task_runner()); - loop.SetTaskRunner(new_runner); - - scoped_refptr<Foo> foo(new Foo()); - original_runner->PostTask(FROM_HERE, BindOnce(&Foo::Test1ConstRef, foo, "a")); - RunLoop().RunUntilIdle(); - EXPECT_EQ(1, foo->test_count()); -} - -TEST_P(MessageLoopTest, DeleteUnboundLoop) { - // It should be possible to delete an unbound message loop on a thread which - // already has another active loop. This happens when thread creation fails. - MessageLoop loop; - std::unique_ptr<MessageLoop> unbound_loop(MessageLoop::CreateUnbound( - MessageLoop::TYPE_DEFAULT, MessageLoop::MessagePumpFactoryCallback())); - unbound_loop.reset(); - EXPECT_EQ(&loop, MessageLoop::current()); - EXPECT_EQ(loop.task_runner(), ThreadTaskRunnerHandle::Get()); -} - -TEST_P(MessageLoopTest, ThreadName) { - { - std::string kThreadName("foo"); - MessageLoop loop; - PlatformThread::SetName(kThreadName); - EXPECT_EQ(kThreadName, loop.GetThreadName()); - } - - { - std::string kThreadName("bar"); - base::Thread thread(kThreadName); - ASSERT_TRUE(thread.StartAndWaitForTesting()); - EXPECT_EQ(kThreadName, thread.message_loop()->GetThreadName()); - } -} - -// Verify that tasks posted to and code running in the scope of the same -// MessageLoop access the same SequenceLocalStorage values. -TEST_P(MessageLoopTest, SequenceLocalStorageSetGet) { - MessageLoop loop; - - SequenceLocalStorageSlot<int> slot; - - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - BindOnce(&SequenceLocalStorageSlot<int>::Set, Unretained(&slot), 11)); - - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce( - [](SequenceLocalStorageSlot<int>* slot) { - EXPECT_EQ(slot->Get(), 11); - }, - &slot)); - - RunLoop().RunUntilIdle(); - EXPECT_EQ(slot.Get(), 11); -} - -// Verify that tasks posted to and code running in different MessageLoops access -// different SequenceLocalStorage values. -TEST_P(MessageLoopTest, SequenceLocalStorageDifferentMessageLoops) { - SequenceLocalStorageSlot<int> slot; - - { - MessageLoop loop; - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - BindOnce(&SequenceLocalStorageSlot<int>::Set, Unretained(&slot), 11)); - - RunLoop().RunUntilIdle(); - EXPECT_EQ(slot.Get(), 11); - } - - MessageLoop loop; - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce( - [](SequenceLocalStorageSlot<int>* slot) { - EXPECT_NE(slot->Get(), 11); - }, - &slot)); - - RunLoop().RunUntilIdle(); - EXPECT_NE(slot.Get(), 11); -} - -INSTANTIATE_TEST_CASE_P( - , - MessageLoopTest, - ::testing::Values(TaskSchedulerAvailability::NO_TASK_SCHEDULER, - TaskSchedulerAvailability::WITH_TASK_SCHEDULER), - MessageLoopTest::ParamInfoToString); - -} // namespace base
diff --git a/base/message_loop/message_pump_glib_unittest.cc b/base/message_loop/message_pump_glib_unittest.cc deleted file mode 100644 index 70be2a4..0000000 --- a/base/message_loop/message_pump_glib_unittest.cc +++ /dev/null
@@ -1,523 +0,0 @@ -// 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/message_loop/message_pump_glib.h" - -#include <glib.h> -#include <math.h> - -#include <algorithm> -#include <vector> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/callback.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/message_loop/message_loop.h" -#include "base/message_loop/message_loop_current.h" -#include "base/run_loop.h" -#include "base/single_thread_task_runner.h" -#include "base/threading/thread.h" -#include "base/threading/thread_task_runner_handle.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -// This class injects dummy "events" into the GLib loop. When "handled" these -// events can run tasks. This is intended to mock gtk events (the corresponding -// GLib source runs at the same priority). -class EventInjector { - public: - EventInjector() : processed_events_(0) { - source_ = static_cast<Source*>(g_source_new(&SourceFuncs, sizeof(Source))); - source_->injector = this; - g_source_attach(source_, nullptr); - g_source_set_can_recurse(source_, TRUE); - } - - ~EventInjector() { - g_source_destroy(source_); - g_source_unref(source_); - } - - int HandlePrepare() { - // If the queue is empty, block. - if (events_.empty()) - return -1; - TimeDelta delta = events_[0].time - Time::NowFromSystemTime(); - return std::max(0, static_cast<int>(ceil(delta.InMillisecondsF()))); - } - - bool HandleCheck() { - if (events_.empty()) - return false; - return events_[0].time <= Time::NowFromSystemTime(); - } - - void HandleDispatch() { - if (events_.empty()) - return; - Event event = std::move(events_[0]); - events_.erase(events_.begin()); - ++processed_events_; - if (!event.callback.is_null()) - std::move(event.callback).Run(); - else if (!event.task.is_null()) - std::move(event.task).Run(); - } - - // Adds an event to the queue. When "handled", executes |callback|. - // delay_ms is relative to the last event if any, or to Now() otherwise. - void AddEvent(int delay_ms, OnceClosure callback) { - AddEventHelper(delay_ms, std::move(callback), OnceClosure()); - } - - void AddDummyEvent(int delay_ms) { - AddEventHelper(delay_ms, OnceClosure(), OnceClosure()); - } - - void AddEventAsTask(int delay_ms, OnceClosure task) { - AddEventHelper(delay_ms, OnceClosure(), std::move(task)); - } - - void Reset() { - processed_events_ = 0; - events_.clear(); - } - - int processed_events() const { return processed_events_; } - - private: - struct Event { - Time time; - OnceClosure callback; - OnceClosure task; - }; - - struct Source : public GSource { - EventInjector* injector; - }; - - void AddEventHelper(int delay_ms, OnceClosure callback, OnceClosure task) { - Time last_time; - if (!events_.empty()) - last_time = (events_.end()-1)->time; - else - last_time = Time::NowFromSystemTime(); - - Time future = last_time + TimeDelta::FromMilliseconds(delay_ms); - EventInjector::Event event = {future, std::move(callback), std::move(task)}; - events_.push_back(std::move(event)); - } - - static gboolean Prepare(GSource* source, gint* timeout_ms) { - *timeout_ms = static_cast<Source*>(source)->injector->HandlePrepare(); - return FALSE; - } - - static gboolean Check(GSource* source) { - return static_cast<Source*>(source)->injector->HandleCheck(); - } - - static gboolean Dispatch(GSource* source, - GSourceFunc unused_func, - gpointer unused_data) { - static_cast<Source*>(source)->injector->HandleDispatch(); - return TRUE; - } - - Source* source_; - std::vector<Event> events_; - int processed_events_; - static GSourceFuncs SourceFuncs; - DISALLOW_COPY_AND_ASSIGN(EventInjector); -}; - -GSourceFuncs EventInjector::SourceFuncs = {EventInjector::Prepare, - EventInjector::Check, - EventInjector::Dispatch, nullptr}; - -void IncrementInt(int *value) { - ++*value; -} - -// Checks how many events have been processed by the injector. -void ExpectProcessedEvents(EventInjector* injector, int count) { - EXPECT_EQ(injector->processed_events(), count); -} - -// Posts a task on the current message loop. -void PostMessageLoopTask(const Location& from_here, OnceClosure task) { - ThreadTaskRunnerHandle::Get()->PostTask(from_here, std::move(task)); -} - -// Test fixture. -class MessagePumpGLibTest : public testing::Test { - public: - MessagePumpGLibTest() : loop_(nullptr), injector_(nullptr) {} - - // Overridden from testing::Test: - void SetUp() override { - loop_ = new MessageLoop(MessageLoop::TYPE_UI); - injector_ = new EventInjector(); - } - void TearDown() override { - delete injector_; - injector_ = nullptr; - delete loop_; - loop_ = nullptr; - } - - MessageLoop* loop() const { return loop_; } - EventInjector* injector() const { return injector_; } - - private: - MessageLoop* loop_; - EventInjector* injector_; - DISALLOW_COPY_AND_ASSIGN(MessagePumpGLibTest); -}; - -} // namespace - -TEST_F(MessagePumpGLibTest, TestQuit) { - // Checks that Quit works and that the basic infrastructure is working. - - // Quit from a task - RunLoop().RunUntilIdle(); - EXPECT_EQ(0, injector()->processed_events()); - - injector()->Reset(); - // Quit from an event - injector()->AddEvent(0, RunLoop::QuitCurrentWhenIdleClosureDeprecated()); - RunLoop().Run(); - EXPECT_EQ(1, injector()->processed_events()); -} - -TEST_F(MessagePumpGLibTest, TestEventTaskInterleave) { - // Checks that tasks posted by events are executed before the next event if - // the posted task queue is empty. - // MessageLoop doesn't make strong guarantees that it is the case, but the - // current implementation ensures it and the tests below rely on it. - // If changes cause this test to fail, it is reasonable to change it, but - // TestWorkWhileWaitingForEvents and TestEventsWhileWaitingForWork have to be - // changed accordingly, otherwise they can become flaky. - injector()->AddEventAsTask(0, DoNothing()); - OnceClosure check_task = - BindOnce(&ExpectProcessedEvents, Unretained(injector()), 2); - OnceClosure posted_task = - BindOnce(&PostMessageLoopTask, FROM_HERE, std::move(check_task)); - injector()->AddEventAsTask(0, std::move(posted_task)); - injector()->AddEventAsTask(0, DoNothing()); - injector()->AddEvent(0, RunLoop::QuitCurrentWhenIdleClosureDeprecated()); - RunLoop().Run(); - EXPECT_EQ(4, injector()->processed_events()); - - injector()->Reset(); - injector()->AddEventAsTask(0, DoNothing()); - check_task = BindOnce(&ExpectProcessedEvents, Unretained(injector()), 2); - posted_task = - BindOnce(&PostMessageLoopTask, FROM_HERE, std::move(check_task)); - injector()->AddEventAsTask(0, std::move(posted_task)); - injector()->AddEventAsTask(10, DoNothing()); - injector()->AddEvent(0, RunLoop::QuitCurrentWhenIdleClosureDeprecated()); - RunLoop().Run(); - EXPECT_EQ(4, injector()->processed_events()); -} - -TEST_F(MessagePumpGLibTest, TestWorkWhileWaitingForEvents) { - int task_count = 0; - // Tests that we process tasks while waiting for new events. - // The event queue is empty at first. - for (int i = 0; i < 10; ++i) { - loop()->task_runner()->PostTask(FROM_HERE, - BindOnce(&IncrementInt, &task_count)); - } - // After all the previous tasks have executed, enqueue an event that will - // quit. - loop()->task_runner()->PostTask( - FROM_HERE, BindOnce(&EventInjector::AddEvent, Unretained(injector()), 0, - RunLoop::QuitCurrentWhenIdleClosureDeprecated())); - RunLoop().Run(); - ASSERT_EQ(10, task_count); - EXPECT_EQ(1, injector()->processed_events()); - - // Tests that we process delayed tasks while waiting for new events. - injector()->Reset(); - task_count = 0; - for (int i = 0; i < 10; ++i) { - loop()->task_runner()->PostDelayedTask(FROM_HERE, - BindOnce(&IncrementInt, &task_count), - TimeDelta::FromMilliseconds(10 * i)); - } - // After all the previous tasks have executed, enqueue an event that will - // quit. - // This relies on the fact that delayed tasks are executed in delay order. - // That is verified in message_loop_unittest.cc. - loop()->task_runner()->PostDelayedTask( - FROM_HERE, - BindOnce(&EventInjector::AddEvent, Unretained(injector()), 10, - RunLoop::QuitCurrentWhenIdleClosureDeprecated()), - TimeDelta::FromMilliseconds(150)); - RunLoop().Run(); - ASSERT_EQ(10, task_count); - EXPECT_EQ(1, injector()->processed_events()); -} - -TEST_F(MessagePumpGLibTest, TestEventsWhileWaitingForWork) { - // Tests that we process events while waiting for work. - // The event queue is empty at first. - for (int i = 0; i < 10; ++i) { - injector()->AddDummyEvent(0); - } - // After all the events have been processed, post a task that will check that - // the events have been processed (note: the task executes after the event - // that posted it has been handled, so we expect 11 at that point). - OnceClosure check_task = - BindOnce(&ExpectProcessedEvents, Unretained(injector()), 11); - OnceClosure posted_task = - BindOnce(&PostMessageLoopTask, FROM_HERE, std::move(check_task)); - injector()->AddEventAsTask(10, std::move(posted_task)); - - // And then quit (relies on the condition tested by TestEventTaskInterleave). - injector()->AddEvent(10, RunLoop::QuitCurrentWhenIdleClosureDeprecated()); - RunLoop().Run(); - - EXPECT_EQ(12, injector()->processed_events()); -} - -namespace { - -// This class is a helper for the concurrent events / posted tasks test below. -// It will quit the main loop once enough tasks and events have been processed, -// while making sure there is always work to do and events in the queue. -class ConcurrentHelper : public RefCounted<ConcurrentHelper> { - public: - explicit ConcurrentHelper(EventInjector* injector) - : injector_(injector), - event_count_(kStartingEventCount), - task_count_(kStartingTaskCount) { - } - - void FromTask() { - if (task_count_ > 0) { - --task_count_; - } - if (task_count_ == 0 && event_count_ == 0) { - RunLoop::QuitCurrentWhenIdleDeprecated(); - } else { - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce(&ConcurrentHelper::FromTask, this)); - } - } - - void FromEvent() { - if (event_count_ > 0) { - --event_count_; - } - if (task_count_ == 0 && event_count_ == 0) { - RunLoop::QuitCurrentWhenIdleDeprecated(); - } else { - injector_->AddEventAsTask(0, - BindOnce(&ConcurrentHelper::FromEvent, this)); - } - } - - int event_count() const { return event_count_; } - int task_count() const { return task_count_; } - - private: - friend class RefCounted<ConcurrentHelper>; - - ~ConcurrentHelper() {} - - static const int kStartingEventCount = 20; - static const int kStartingTaskCount = 20; - - EventInjector* injector_; - int event_count_; - int task_count_; -}; - -} // namespace - -TEST_F(MessagePumpGLibTest, TestConcurrentEventPostedTask) { - // Tests that posted tasks don't starve events, nor the opposite. - // We use the helper class above. We keep both event and posted task queues - // full, the helper verifies that both tasks and events get processed. - // If that is not the case, either event_count_ or task_count_ will not get - // to 0, and MessageLoop::QuitWhenIdle() will never be called. - scoped_refptr<ConcurrentHelper> helper = new ConcurrentHelper(injector()); - - // Add 2 events to the queue to make sure it is always full (when we remove - // the event before processing it). - injector()->AddEventAsTask(0, BindOnce(&ConcurrentHelper::FromEvent, helper)); - injector()->AddEventAsTask(0, BindOnce(&ConcurrentHelper::FromEvent, helper)); - - // Similarly post 2 tasks. - loop()->task_runner()->PostTask( - FROM_HERE, BindOnce(&ConcurrentHelper::FromTask, helper)); - loop()->task_runner()->PostTask( - FROM_HERE, BindOnce(&ConcurrentHelper::FromTask, helper)); - - RunLoop().Run(); - EXPECT_EQ(0, helper->event_count()); - EXPECT_EQ(0, helper->task_count()); -} - -namespace { - -void AddEventsAndDrainGLib(EventInjector* injector) { - // Add a couple of dummy events - injector->AddDummyEvent(0); - injector->AddDummyEvent(0); - // Then add an event that will quit the main loop. - injector->AddEvent(0, RunLoop::QuitCurrentWhenIdleClosureDeprecated()); - - // Post a couple of dummy tasks - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, DoNothing()); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, DoNothing()); - - // Drain the events - while (g_main_context_pending(nullptr)) { - g_main_context_iteration(nullptr, FALSE); - } -} - -} // namespace - -TEST_F(MessagePumpGLibTest, TestDrainingGLib) { - // Tests that draining events using GLib works. - loop()->task_runner()->PostTask( - FROM_HERE, BindOnce(&AddEventsAndDrainGLib, Unretained(injector()))); - RunLoop().Run(); - - EXPECT_EQ(3, injector()->processed_events()); -} - -namespace { - -// Helper class that lets us run the GLib message loop. -class GLibLoopRunner : public RefCounted<GLibLoopRunner> { - public: - GLibLoopRunner() : quit_(false) { } - - void RunGLib() { - while (!quit_) { - g_main_context_iteration(nullptr, TRUE); - } - } - - void RunLoop() { - while (!quit_) { - g_main_context_iteration(nullptr, TRUE); - } - } - - void Quit() { - quit_ = true; - } - - void Reset() { - quit_ = false; - } - - private: - friend class RefCounted<GLibLoopRunner>; - - ~GLibLoopRunner() {} - - bool quit_; -}; - -void TestGLibLoopInternal(EventInjector* injector) { - // Allow tasks to be processed from 'native' event loops. - MessageLoopCurrent::Get()->SetNestableTasksAllowed(true); - scoped_refptr<GLibLoopRunner> runner = new GLibLoopRunner(); - - int task_count = 0; - // Add a couple of dummy events - injector->AddDummyEvent(0); - injector->AddDummyEvent(0); - // Post a couple of dummy tasks - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - BindOnce(&IncrementInt, &task_count)); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - BindOnce(&IncrementInt, &task_count)); - // Delayed events - injector->AddDummyEvent(10); - injector->AddDummyEvent(10); - // Delayed work - ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, BindOnce(&IncrementInt, &task_count), - TimeDelta::FromMilliseconds(30)); - ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, BindOnce(&GLibLoopRunner::Quit, runner), - TimeDelta::FromMilliseconds(40)); - - // Run a nested, straight GLib message loop. - runner->RunGLib(); - - ASSERT_EQ(3, task_count); - EXPECT_EQ(4, injector->processed_events()); - RunLoop::QuitCurrentWhenIdleDeprecated(); -} - -void TestGtkLoopInternal(EventInjector* injector) { - // Allow tasks to be processed from 'native' event loops. - MessageLoopCurrent::Get()->SetNestableTasksAllowed(true); - scoped_refptr<GLibLoopRunner> runner = new GLibLoopRunner(); - - int task_count = 0; - // Add a couple of dummy events - injector->AddDummyEvent(0); - injector->AddDummyEvent(0); - // Post a couple of dummy tasks - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - BindOnce(&IncrementInt, &task_count)); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - BindOnce(&IncrementInt, &task_count)); - // Delayed events - injector->AddDummyEvent(10); - injector->AddDummyEvent(10); - // Delayed work - ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, BindOnce(&IncrementInt, &task_count), - TimeDelta::FromMilliseconds(30)); - ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, BindOnce(&GLibLoopRunner::Quit, runner), - TimeDelta::FromMilliseconds(40)); - - // Run a nested, straight Gtk message loop. - runner->RunLoop(); - - ASSERT_EQ(3, task_count); - EXPECT_EQ(4, injector->processed_events()); - RunLoop::QuitCurrentWhenIdleDeprecated(); -} - -} // namespace - -TEST_F(MessagePumpGLibTest, TestGLibLoop) { - // Tests that events and posted tasks are correctly executed if the message - // loop is not run by MessageLoop::Run() but by a straight GLib loop. - // Note that in this case we don't make strong guarantees about niceness - // between events and posted tasks. - loop()->task_runner()->PostTask( - FROM_HERE, BindOnce(&TestGLibLoopInternal, Unretained(injector()))); - RunLoop().Run(); -} - -TEST_F(MessagePumpGLibTest, TestGtkLoop) { - // Tests that events and posted tasks are correctly executed if the message - // loop is not run by MessageLoop::Run() but by a straight Gtk loop. - // Note that in this case we don't make strong guarantees about niceness - // between events and posted tasks. - loop()->task_runner()->PostTask( - FROM_HERE, BindOnce(&TestGtkLoopInternal, Unretained(injector()))); - RunLoop().Run(); -} - -} // namespace base
diff --git a/base/message_loop/message_pump_io_ios_unittest.cc b/base/message_loop/message_pump_io_ios_unittest.cc deleted file mode 100644 index 4d15d44..0000000 --- a/base/message_loop/message_pump_io_ios_unittest.cc +++ /dev/null
@@ -1,153 +0,0 @@ -// Copyright 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/message_loop/message_pump_io_ios.h" - -#include <unistd.h> - -#include "base/macros.h" -#include "base/posix/eintr_wrapper.h" -#include "base/test/gtest_util.h" -#include "base/threading/thread.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -class MessagePumpIOSForIOTest : public testing::Test { - protected: - MessagePumpIOSForIOTest() = default; - ~MessagePumpIOSForIOTest() override = default; - - void SetUp() override { - int ret = pipe(pipefds_); - ASSERT_EQ(0, ret); - ret = pipe(alternate_pipefds_); - ASSERT_EQ(0, ret); - } - - void TearDown() override { - if (IGNORE_EINTR(close(pipefds_[0])) < 0) - PLOG(ERROR) << "close"; - if (IGNORE_EINTR(close(pipefds_[1])) < 0) - PLOG(ERROR) << "close"; - } - - void HandleFdIOEvent(MessagePumpForIO::FdWatchController* watcher) { - MessagePumpIOSForIO::HandleFdIOEvent(watcher->fdref_.get(), - kCFFileDescriptorReadCallBack | kCFFileDescriptorWriteCallBack, - watcher); - } - - int pipefds_[2]; - int alternate_pipefds_[2]; - - private: - DISALLOW_COPY_AND_ASSIGN(MessagePumpIOSForIOTest); -}; - -namespace { - -// Concrete implementation of MessagePumpIOSForIO::FdWatcher that does -// nothing useful. -class StupidWatcher : public MessagePumpIOSForIO::FdWatcher { - public: - ~StupidWatcher() override {} - - // base:MessagePumpIOSForIO::FdWatcher interface - void OnFileCanReadWithoutBlocking(int fd) override {} - void OnFileCanWriteWithoutBlocking(int fd) override {} -}; - -class BaseWatcher : public MessagePumpIOSForIO::FdWatcher { - public: - BaseWatcher(MessagePumpIOSForIO::FdWatchController* controller) - : controller_(controller) { - DCHECK(controller_); - } - ~BaseWatcher() override {} - - // MessagePumpIOSForIO::FdWatcher interface - void OnFileCanReadWithoutBlocking(int /* fd */) override { NOTREACHED(); } - - void OnFileCanWriteWithoutBlocking(int /* fd */) override { NOTREACHED(); } - - protected: - MessagePumpIOSForIO::FdWatchController* controller_; -}; - -class DeleteWatcher : public BaseWatcher { - public: - explicit DeleteWatcher(MessagePumpIOSForIO::FdWatchController* controller) - : BaseWatcher(controller) {} - - ~DeleteWatcher() override { DCHECK(!controller_); } - - void OnFileCanWriteWithoutBlocking(int /* fd */) override { - DCHECK(controller_); - delete controller_; - controller_ = NULL; - } -}; - -TEST_F(MessagePumpIOSForIOTest, DeleteWatcher) { - std::unique_ptr<MessagePumpIOSForIO> pump(new MessagePumpIOSForIO); - MessagePumpIOSForIO::FdWatchController* watcher = - new MessagePumpIOSForIO::FdWatchController(FROM_HERE); - DeleteWatcher delegate(watcher); - pump->WatchFileDescriptor(pipefds_[1], - false, MessagePumpIOSForIO::WATCH_READ_WRITE, watcher, &delegate); - - // Spoof a callback. - HandleFdIOEvent(watcher); -} - -class StopWatcher : public BaseWatcher { - public: - StopWatcher(MessagePumpIOSForIO::FdWatchController* controller, - MessagePumpIOSForIO* pump, - int fd_to_start_watching = -1) - : BaseWatcher(controller), - pump_(pump), - fd_to_start_watching_(fd_to_start_watching) {} - - ~StopWatcher() override {} - - void OnFileCanWriteWithoutBlocking(int /* fd */) override { - controller_->StopWatchingFileDescriptor(); - if (fd_to_start_watching_ >= 0) { - pump_->WatchFileDescriptor(fd_to_start_watching_, - false, MessagePumpIOSForIO::WATCH_READ_WRITE, controller_, this); - } - } - - private: - MessagePumpIOSForIO* pump_; - int fd_to_start_watching_; -}; - -TEST_F(MessagePumpIOSForIOTest, StopWatcher) { - std::unique_ptr<MessagePumpIOSForIO> pump(new MessagePumpIOSForIO); - MessagePumpIOSForIO::FdWatchController watcher(FROM_HERE); - StopWatcher delegate(&watcher, pump.get()); - pump->WatchFileDescriptor(pipefds_[1], - false, MessagePumpIOSForIO::WATCH_READ_WRITE, &watcher, &delegate); - - // Spoof a callback. - HandleFdIOEvent(&watcher); -} - -TEST_F(MessagePumpIOSForIOTest, StopWatcherAndWatchSomethingElse) { - std::unique_ptr<MessagePumpIOSForIO> pump(new MessagePumpIOSForIO); - MessagePumpIOSForIO::FdWatchController watcher(FROM_HERE); - StopWatcher delegate(&watcher, pump.get(), alternate_pipefds_[1]); - pump->WatchFileDescriptor(pipefds_[1], - false, MessagePumpIOSForIO::WATCH_READ_WRITE, &watcher, &delegate); - - // Spoof a callback. - HandleFdIOEvent(&watcher); -} - -} // namespace - -} // namespace base
diff --git a/base/message_loop/message_pump_libevent_unittest.cc b/base/message_loop/message_pump_libevent_unittest.cc deleted file mode 100644 index bb26c29..0000000 --- a/base/message_loop/message_pump_libevent_unittest.cc +++ /dev/null
@@ -1,263 +0,0 @@ -// 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/message_loop/message_pump_libevent.h" - -#include <unistd.h> - -#include <memory> -#include <utility> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/files/file_util.h" -#include "base/memory/ptr_util.h" -#include "base/message_loop/message_loop.h" -#include "base/posix/eintr_wrapper.h" -#include "base/run_loop.h" -#include "base/single_thread_task_runner.h" -#include "base/synchronization/waitable_event.h" -#include "base/synchronization/waitable_event_watcher.h" -#include "base/test/gtest_util.h" -#include "base/third_party/libevent/event.h" -#include "base/threading/sequenced_task_runner_handle.h" -#include "base/threading/thread.h" -#include "base/threading/thread_task_runner_handle.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -class MessagePumpLibeventTest : public testing::Test { - protected: - MessagePumpLibeventTest() - : ui_loop_(new MessageLoop(MessageLoop::TYPE_UI)), - io_thread_("MessagePumpLibeventTestIOThread") {} - ~MessagePumpLibeventTest() override = default; - - void SetUp() override { - Thread::Options options(MessageLoop::TYPE_IO, 0); - ASSERT_TRUE(io_thread_.StartWithOptions(options)); - ASSERT_EQ(MessageLoop::TYPE_IO, io_thread_.message_loop()->type()); - int ret = pipe(pipefds_); - ASSERT_EQ(0, ret); - } - - void TearDown() override { - if (IGNORE_EINTR(close(pipefds_[0])) < 0) - PLOG(ERROR) << "close"; - if (IGNORE_EINTR(close(pipefds_[1])) < 0) - PLOG(ERROR) << "close"; - } - - void WaitUntilIoThreadStarted() { - ASSERT_TRUE(io_thread_.WaitUntilThreadStarted()); - } - - scoped_refptr<SingleThreadTaskRunner> io_runner() const { - return io_thread_.task_runner(); - } - - void OnLibeventNotification( - MessagePumpLibevent* pump, - MessagePumpLibevent::FdWatchController* controller) { - pump->OnLibeventNotification(0, EV_WRITE | EV_READ, controller); - } - - int pipefds_[2]; - std::unique_ptr<MessageLoop> ui_loop_; - - private: - Thread io_thread_; -}; - -namespace { - -// Concrete implementation of MessagePumpLibevent::FdWatcher that does -// nothing useful. -class StupidWatcher : public MessagePumpLibevent::FdWatcher { - public: - ~StupidWatcher() override = default; - - // base:MessagePumpLibevent::FdWatcher interface - void OnFileCanReadWithoutBlocking(int fd) override {} - void OnFileCanWriteWithoutBlocking(int fd) override {} -}; - -TEST_F(MessagePumpLibeventTest, QuitOutsideOfRun) { - std::unique_ptr<MessagePumpLibevent> pump(new MessagePumpLibevent); - ASSERT_DCHECK_DEATH(pump->Quit()); -} - -class BaseWatcher : public MessagePumpLibevent::FdWatcher { - public: - explicit BaseWatcher(MessagePumpLibevent::FdWatchController* controller) - : controller_(controller) { - DCHECK(controller_); - } - ~BaseWatcher() override = default; - - // base:MessagePumpLibevent::FdWatcher interface - void OnFileCanReadWithoutBlocking(int /* fd */) override { NOTREACHED(); } - - void OnFileCanWriteWithoutBlocking(int /* fd */) override { NOTREACHED(); } - - protected: - MessagePumpLibevent::FdWatchController* controller_; -}; - -class DeleteWatcher : public BaseWatcher { - public: - explicit DeleteWatcher(MessagePumpLibevent::FdWatchController* controller) - : BaseWatcher(controller) {} - - ~DeleteWatcher() override { DCHECK(!controller_); } - - void OnFileCanWriteWithoutBlocking(int /* fd */) override { - DCHECK(controller_); - delete controller_; - controller_ = nullptr; - } -}; - -TEST_F(MessagePumpLibeventTest, DeleteWatcher) { - std::unique_ptr<MessagePumpLibevent> pump(new MessagePumpLibevent); - MessagePumpLibevent::FdWatchController* watcher = - new MessagePumpLibevent::FdWatchController(FROM_HERE); - DeleteWatcher delegate(watcher); - pump->WatchFileDescriptor(pipefds_[1], - false, MessagePumpLibevent::WATCH_READ_WRITE, watcher, &delegate); - - // Spoof a libevent notification. - OnLibeventNotification(pump.get(), watcher); -} - -class StopWatcher : public BaseWatcher { - public: - explicit StopWatcher(MessagePumpLibevent::FdWatchController* controller) - : BaseWatcher(controller) {} - - ~StopWatcher() override = default; - - void OnFileCanWriteWithoutBlocking(int /* fd */) override { - controller_->StopWatchingFileDescriptor(); - } -}; - -TEST_F(MessagePumpLibeventTest, StopWatcher) { - std::unique_ptr<MessagePumpLibevent> pump(new MessagePumpLibevent); - MessagePumpLibevent::FdWatchController watcher(FROM_HERE); - StopWatcher delegate(&watcher); - pump->WatchFileDescriptor(pipefds_[1], - false, MessagePumpLibevent::WATCH_READ_WRITE, &watcher, &delegate); - - // Spoof a libevent notification. - OnLibeventNotification(pump.get(), &watcher); -} - -void QuitMessageLoopAndStart(const Closure& quit_closure) { - quit_closure.Run(); - - RunLoop runloop(RunLoop::Type::kNestableTasksAllowed); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, runloop.QuitClosure()); - runloop.Run(); -} - -class NestedPumpWatcher : public MessagePumpLibevent::FdWatcher { - public: - NestedPumpWatcher() = default; - ~NestedPumpWatcher() override = default; - - void OnFileCanReadWithoutBlocking(int /* fd */) override { - RunLoop runloop; - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce(&QuitMessageLoopAndStart, runloop.QuitClosure())); - runloop.Run(); - } - - void OnFileCanWriteWithoutBlocking(int /* fd */) override {} -}; - -TEST_F(MessagePumpLibeventTest, NestedPumpWatcher) { - std::unique_ptr<MessagePumpLibevent> pump(new MessagePumpLibevent); - MessagePumpLibevent::FdWatchController watcher(FROM_HERE); - NestedPumpWatcher delegate; - pump->WatchFileDescriptor(pipefds_[1], - false, MessagePumpLibevent::WATCH_READ, &watcher, &delegate); - - // Spoof a libevent notification. - OnLibeventNotification(pump.get(), &watcher); -} - -void FatalClosure() { - FAIL() << "Reached fatal closure."; -} - -class QuitWatcher : public BaseWatcher { - public: - QuitWatcher(MessagePumpLibevent::FdWatchController* controller, - base::Closure quit_closure) - : BaseWatcher(controller), quit_closure_(std::move(quit_closure)) {} - - void OnFileCanReadWithoutBlocking(int /* fd */) override { - // Post a fatal closure to the MessageLoop before we quit it. - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, BindOnce(&FatalClosure)); - - quit_closure_.Run(); - } - - private: - base::Closure quit_closure_; -}; - -void WriteFDWrapper(const int fd, - const char* buf, - int size, - WaitableEvent* event) { - ASSERT_TRUE(WriteFileDescriptor(fd, buf, size)); -} - -// Tests that MessagePumpLibevent quits immediately when it is quit from -// libevent's event_base_loop(). -TEST_F(MessagePumpLibeventTest, QuitWatcher) { - // Delete the old MessageLoop so that we can manage our own one here. - ui_loop_.reset(); - - MessagePumpLibevent* pump = new MessagePumpLibevent; // owned by |loop|. - MessageLoop loop(WrapUnique(pump)); - RunLoop run_loop; - MessagePumpLibevent::FdWatchController controller(FROM_HERE); - QuitWatcher delegate(&controller, run_loop.QuitClosure()); - WaitableEvent event(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - std::unique_ptr<WaitableEventWatcher> watcher(new WaitableEventWatcher); - - // Tell the pump to watch the pipe. - pump->WatchFileDescriptor(pipefds_[0], false, MessagePumpLibevent::WATCH_READ, - &controller, &delegate); - - // Make the IO thread wait for |event| before writing to pipefds[1]. - const char buf = 0; - WaitableEventWatcher::EventCallback write_fd_task = - BindOnce(&WriteFDWrapper, pipefds_[1], &buf, 1); - io_runner()->PostTask( - FROM_HERE, BindOnce(IgnoreResult(&WaitableEventWatcher::StartWatching), - Unretained(watcher.get()), &event, - std::move(write_fd_task), io_runner())); - - // Queue |event| to signal on |loop|. - loop.task_runner()->PostTask( - FROM_HERE, BindOnce(&WaitableEvent::Signal, Unretained(&event))); - - // Now run the MessageLoop. - run_loop.Run(); - - // StartWatching can move |watcher| to IO thread. Release on IO thread. - io_runner()->PostTask(FROM_HERE, BindOnce(&WaitableEventWatcher::StopWatching, - Owned(watcher.release()))); -} - -} // namespace - -} // namespace base
diff --git a/base/metrics/bucket_ranges_unittest.cc b/base/metrics/bucket_ranges_unittest.cc deleted file mode 100644 index 481054c..0000000 --- a/base/metrics/bucket_ranges_unittest.cc +++ /dev/null
@@ -1,94 +0,0 @@ -// 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/metrics/bucket_ranges.h" - -#include <stdint.h> - -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -TEST(BucketRangesTest, NormalSetup) { - BucketRanges ranges(5); - ASSERT_EQ(5u, ranges.size()); - ASSERT_EQ(4u, ranges.bucket_count()); - - for (int i = 0; i < 5; ++i) { - EXPECT_EQ(0, ranges.range(i)); - } - EXPECT_EQ(0u, ranges.checksum()); - - ranges.set_range(3, 100); - EXPECT_EQ(100, ranges.range(3)); -} - -TEST(BucketRangesTest, Equals) { - // Compare empty ranges. - BucketRanges ranges1(3); - BucketRanges ranges2(3); - BucketRanges ranges3(5); - - EXPECT_TRUE(ranges1.Equals(&ranges2)); - EXPECT_FALSE(ranges1.Equals(&ranges3)); - EXPECT_FALSE(ranges2.Equals(&ranges3)); - - // Compare full filled ranges. - ranges1.set_range(0, 0); - ranges1.set_range(1, 1); - ranges1.set_range(2, 2); - ranges1.set_checksum(100); - ranges2.set_range(0, 0); - ranges2.set_range(1, 1); - ranges2.set_range(2, 2); - ranges2.set_checksum(100); - - EXPECT_TRUE(ranges1.Equals(&ranges2)); - - // Checksum does not match. - ranges1.set_checksum(99); - EXPECT_FALSE(ranges1.Equals(&ranges2)); - ranges1.set_checksum(100); - - // Range does not match. - ranges1.set_range(1, 3); - EXPECT_FALSE(ranges1.Equals(&ranges2)); -} - -TEST(BucketRangesTest, Checksum) { - BucketRanges ranges(3); - ranges.set_range(0, 0); - ranges.set_range(1, 1); - ranges.set_range(2, 2); - - ranges.ResetChecksum(); - EXPECT_EQ(289217253u, ranges.checksum()); - - ranges.set_range(2, 3); - EXPECT_FALSE(ranges.HasValidChecksum()); - - ranges.ResetChecksum(); - EXPECT_EQ(2843835776u, ranges.checksum()); - EXPECT_TRUE(ranges.HasValidChecksum()); -} - -// Table was generated similarly to sample code for CRC-32 given on: -// http://www.w3.org/TR/PNG/#D-CRCAppendix. -TEST(BucketRangesTest, Crc32TableTest) { - for (int i = 0; i < 256; ++i) { - uint32_t checksum = i; - for (int j = 0; j < 8; ++j) { - const uint32_t kReversedPolynomial = 0xedb88320L; - if (checksum & 1) - checksum = kReversedPolynomial ^ (checksum >> 1); - else - checksum >>= 1; - } - EXPECT_EQ(kCrcTable[i], checksum); - } -} - -} // namespace -} // namespace base
diff --git a/base/metrics/field_trial_params_unittest.cc b/base/metrics/field_trial_params_unittest.cc deleted file mode 100644 index d310c0d..0000000 --- a/base/metrics/field_trial_params_unittest.cc +++ /dev/null
@@ -1,458 +0,0 @@ -// 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/metrics/field_trial_params.h" - -#include "base/feature_list.h" -#include "base/macros.h" -#include "base/metrics/field_trial.h" -#include "base/metrics/field_trial_param_associator.h" -#include "base/test/scoped_feature_list.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -// Call FieldTrialList::FactoryGetFieldTrial() with a future expiry date. -scoped_refptr<FieldTrial> CreateFieldTrial( - const std::string& trial_name, - int total_probability, - const std::string& default_group_name, - int* default_group_number) { - return FieldTrialList::FactoryGetFieldTrial( - trial_name, total_probability, default_group_name, - FieldTrialList::kNoExpirationYear, 1, 1, FieldTrial::SESSION_RANDOMIZED, - default_group_number); -} - -} // namespace - -class FieldTrialParamsTest : public ::testing::Test { - public: - FieldTrialParamsTest() : field_trial_list_(nullptr) {} - - ~FieldTrialParamsTest() override { - // Ensure that the maps are cleared between tests, since they are stored as - // process singletons. - FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting(); - } - - void CreateFeatureWithTrial(const Feature& feature, - FeatureList::OverrideState override_state, - FieldTrial* trial) { - std::unique_ptr<FeatureList> feature_list(new FeatureList); - feature_list->RegisterFieldTrialOverride(feature.name, override_state, - trial); - scoped_feature_list_.InitWithFeatureList(std::move(feature_list)); - } - - private: - FieldTrialList field_trial_list_; - test::ScopedFeatureList scoped_feature_list_; - - DISALLOW_COPY_AND_ASSIGN(FieldTrialParamsTest); -}; - -TEST_F(FieldTrialParamsTest, AssociateFieldTrialParams) { - const std::string kTrialName = "AssociateFieldTrialParams"; - - { - std::map<std::string, std::string> params; - params["a"] = "10"; - params["b"] = "test"; - ASSERT_TRUE(AssociateFieldTrialParams(kTrialName, "A", params)); - } - { - std::map<std::string, std::string> params; - params["a"] = "5"; - ASSERT_TRUE(AssociateFieldTrialParams(kTrialName, "B", params)); - } - - FieldTrialList::CreateFieldTrial(kTrialName, "B"); - EXPECT_EQ("5", GetFieldTrialParamValue(kTrialName, "a")); - EXPECT_EQ(std::string(), GetFieldTrialParamValue(kTrialName, "b")); - EXPECT_EQ(std::string(), GetFieldTrialParamValue(kTrialName, "x")); - - std::map<std::string, std::string> params; - EXPECT_TRUE(GetFieldTrialParams(kTrialName, ¶ms)); - EXPECT_EQ(1U, params.size()); - EXPECT_EQ("5", params["a"]); -} - -TEST_F(FieldTrialParamsTest, AssociateFieldTrialParams_Fail) { - const std::string kTrialName = "AssociateFieldTrialParams_Fail"; - const std::string kGroupName = "A"; - - std::map<std::string, std::string> params; - params["a"] = "10"; - ASSERT_TRUE(AssociateFieldTrialParams(kTrialName, kGroupName, params)); - params["a"] = "1"; - params["b"] = "2"; - ASSERT_FALSE(AssociateFieldTrialParams(kTrialName, kGroupName, params)); - - FieldTrialList::CreateFieldTrial(kTrialName, kGroupName); - EXPECT_EQ("10", GetFieldTrialParamValue(kTrialName, "a")); - EXPECT_EQ(std::string(), GetFieldTrialParamValue(kTrialName, "b")); -} - -TEST_F(FieldTrialParamsTest, AssociateFieldTrialParams_TrialActiveFail) { - const std::string kTrialName = "AssociateFieldTrialParams_TrialActiveFail"; - FieldTrialList::CreateFieldTrial(kTrialName, "A"); - ASSERT_EQ("A", FieldTrialList::FindFullName(kTrialName)); - - std::map<std::string, std::string> params; - params["a"] = "10"; - EXPECT_FALSE(AssociateFieldTrialParams(kTrialName, "B", params)); - EXPECT_FALSE(AssociateFieldTrialParams(kTrialName, "A", params)); -} - -TEST_F(FieldTrialParamsTest, AssociateFieldTrialParams_DoesntActivateTrial) { - const std::string kTrialName = - "AssociateFieldTrialParams_DoesntActivateTrial"; - - ASSERT_FALSE(FieldTrialList::IsTrialActive(kTrialName)); - scoped_refptr<FieldTrial> trial( - CreateFieldTrial(kTrialName, 100, "A", nullptr)); - ASSERT_FALSE(FieldTrialList::IsTrialActive(kTrialName)); - - std::map<std::string, std::string> params; - params["a"] = "10"; - EXPECT_TRUE(AssociateFieldTrialParams(kTrialName, "A", params)); - ASSERT_FALSE(FieldTrialList::IsTrialActive(kTrialName)); -} - -TEST_F(FieldTrialParamsTest, GetFieldTrialParams_NoTrial) { - const std::string kTrialName = "GetFieldTrialParams_NoParams"; - - std::map<std::string, std::string> params; - EXPECT_FALSE(GetFieldTrialParams(kTrialName, ¶ms)); - EXPECT_EQ(std::string(), GetFieldTrialParamValue(kTrialName, "x")); - EXPECT_EQ(std::string(), GetFieldTrialParamValue(kTrialName, "y")); -} - -TEST_F(FieldTrialParamsTest, GetFieldTrialParams_NoParams) { - const std::string kTrialName = "GetFieldTrialParams_NoParams"; - - FieldTrialList::CreateFieldTrial(kTrialName, "A"); - - std::map<std::string, std::string> params; - EXPECT_FALSE(GetFieldTrialParams(kTrialName, ¶ms)); - EXPECT_EQ(std::string(), GetFieldTrialParamValue(kTrialName, "x")); - EXPECT_EQ(std::string(), GetFieldTrialParamValue(kTrialName, "y")); -} - -TEST_F(FieldTrialParamsTest, GetFieldTrialParams_ActivatesTrial) { - const std::string kTrialName = "GetFieldTrialParams_ActivatesTrial"; - - ASSERT_FALSE(FieldTrialList::IsTrialActive(kTrialName)); - scoped_refptr<FieldTrial> trial( - CreateFieldTrial(kTrialName, 100, "A", nullptr)); - ASSERT_FALSE(FieldTrialList::IsTrialActive(kTrialName)); - - std::map<std::string, std::string> params; - EXPECT_FALSE(GetFieldTrialParams(kTrialName, ¶ms)); - ASSERT_TRUE(FieldTrialList::IsTrialActive(kTrialName)); -} - -TEST_F(FieldTrialParamsTest, GetFieldTrialParamValue_ActivatesTrial) { - const std::string kTrialName = "GetFieldTrialParamValue_ActivatesTrial"; - - ASSERT_FALSE(FieldTrialList::IsTrialActive(kTrialName)); - scoped_refptr<FieldTrial> trial( - CreateFieldTrial(kTrialName, 100, "A", nullptr)); - ASSERT_FALSE(FieldTrialList::IsTrialActive(kTrialName)); - - std::map<std::string, std::string> params; - EXPECT_EQ(std::string(), GetFieldTrialParamValue(kTrialName, "x")); - ASSERT_TRUE(FieldTrialList::IsTrialActive(kTrialName)); -} - -TEST_F(FieldTrialParamsTest, GetFieldTrialParamsByFeature) { - const std::string kTrialName = "GetFieldTrialParamsByFeature"; - const Feature kFeature{"TestFeature", FEATURE_DISABLED_BY_DEFAULT}; - - std::map<std::string, std::string> params; - params["x"] = "1"; - AssociateFieldTrialParams(kTrialName, "A", params); - scoped_refptr<FieldTrial> trial( - CreateFieldTrial(kTrialName, 100, "A", nullptr)); - - CreateFeatureWithTrial(kFeature, FeatureList::OVERRIDE_ENABLE_FEATURE, - trial.get()); - - std::map<std::string, std::string> actualParams; - EXPECT_TRUE(GetFieldTrialParamsByFeature(kFeature, &actualParams)); - EXPECT_EQ(params, actualParams); -} - -TEST_F(FieldTrialParamsTest, GetFieldTrialParamValueByFeature) { - const std::string kTrialName = "GetFieldTrialParamsByFeature"; - const Feature kFeature{"TestFeature", FEATURE_DISABLED_BY_DEFAULT}; - - std::map<std::string, std::string> params; - params["x"] = "1"; - AssociateFieldTrialParams(kTrialName, "A", params); - scoped_refptr<FieldTrial> trial( - CreateFieldTrial(kTrialName, 100, "A", nullptr)); - - CreateFeatureWithTrial(kFeature, FeatureList::OVERRIDE_ENABLE_FEATURE, - trial.get()); - - std::map<std::string, std::string> actualParams; - EXPECT_EQ(params["x"], GetFieldTrialParamValueByFeature(kFeature, "x")); -} - -TEST_F(FieldTrialParamsTest, GetFieldTrialParamsByFeature_Disable) { - const std::string kTrialName = "GetFieldTrialParamsByFeature"; - const Feature kFeature{"TestFeature", FEATURE_DISABLED_BY_DEFAULT}; - - std::map<std::string, std::string> params; - params["x"] = "1"; - AssociateFieldTrialParams(kTrialName, "A", params); - scoped_refptr<FieldTrial> trial( - CreateFieldTrial(kTrialName, 100, "A", nullptr)); - - CreateFeatureWithTrial(kFeature, FeatureList::OVERRIDE_DISABLE_FEATURE, - trial.get()); - - std::map<std::string, std::string> actualParams; - EXPECT_FALSE(GetFieldTrialParamsByFeature(kFeature, &actualParams)); -} - -TEST_F(FieldTrialParamsTest, GetFieldTrialParamValueByFeature_Disable) { - const std::string kTrialName = "GetFieldTrialParamsByFeature"; - const Feature kFeature{"TestFeature", FEATURE_DISABLED_BY_DEFAULT}; - - std::map<std::string, std::string> params; - params["x"] = "1"; - AssociateFieldTrialParams(kTrialName, "A", params); - scoped_refptr<FieldTrial> trial( - CreateFieldTrial(kTrialName, 100, "A", nullptr)); - - CreateFeatureWithTrial(kFeature, FeatureList::OVERRIDE_DISABLE_FEATURE, - trial.get()); - - std::map<std::string, std::string> actualParams; - EXPECT_EQ(std::string(), GetFieldTrialParamValueByFeature(kFeature, "x")); -} - -TEST_F(FieldTrialParamsTest, FeatureParamString) { - const std::string kTrialName = "GetFieldTrialParamsByFeature"; - - static const Feature kFeature{"TestFeature", FEATURE_DISABLED_BY_DEFAULT}; - static const FeatureParam<std::string> a{&kFeature, "a", "default"}; - static const FeatureParam<std::string> b{&kFeature, "b", ""}; - static const FeatureParam<std::string> c{&kFeature, "c", "default"}; - static const FeatureParam<std::string> d{&kFeature, "d", ""}; - static const FeatureParam<std::string> e{&kFeature, "e", "default"}; - static const FeatureParam<std::string> f{&kFeature, "f", ""}; - - std::map<std::string, std::string> params; - params["a"] = ""; - params["b"] = "non-default"; - params["c"] = "non-default"; - params["d"] = ""; - // "e" is not registered - // "f" is not registered - AssociateFieldTrialParams(kTrialName, "A", params); - scoped_refptr<FieldTrial> trial( - CreateFieldTrial(kTrialName, 100, "A", nullptr)); - - CreateFeatureWithTrial(kFeature, FeatureList::OVERRIDE_ENABLE_FEATURE, - trial.get()); - - EXPECT_EQ("default", a.Get()); // empty - EXPECT_EQ("non-default", b.Get()); - EXPECT_EQ("non-default", c.Get()); - EXPECT_EQ("", d.Get()); // empty - EXPECT_EQ("default", e.Get()); // not registered - EXPECT_EQ("", f.Get()); // not registered -} - -TEST_F(FieldTrialParamsTest, FeatureParamInt) { - const std::string kTrialName = "GetFieldTrialParamsByFeature"; - - static const Feature kFeature{"TestFeature", FEATURE_DISABLED_BY_DEFAULT}; - static const FeatureParam<int> a{&kFeature, "a", 0}; - static const FeatureParam<int> b{&kFeature, "b", 0}; - static const FeatureParam<int> c{&kFeature, "c", 0}; - static const FeatureParam<int> d{&kFeature, "d", 0}; - static const FeatureParam<int> e{&kFeature, "e", 0}; - - std::map<std::string, std::string> params; - params["a"] = "1"; - params["b"] = "1.5"; - params["c"] = "foo"; - params["d"] = ""; - // "e" is not registered - AssociateFieldTrialParams(kTrialName, "A", params); - scoped_refptr<FieldTrial> trial( - CreateFieldTrial(kTrialName, 100, "A", nullptr)); - - CreateFeatureWithTrial(kFeature, FeatureList::OVERRIDE_ENABLE_FEATURE, - trial.get()); - - EXPECT_EQ(1, GetFieldTrialParamByFeatureAsInt(kFeature, "a", 0)); - EXPECT_EQ(0, GetFieldTrialParamByFeatureAsInt(kFeature, "b", 0)); // invalid - EXPECT_EQ(0, GetFieldTrialParamByFeatureAsInt(kFeature, "c", 0)); // invalid - EXPECT_EQ(0, GetFieldTrialParamByFeatureAsInt(kFeature, "d", 0)); // empty - EXPECT_EQ(0, GetFieldTrialParamByFeatureAsInt(kFeature, "e", 0)); // empty - - EXPECT_EQ(1, a.Get()); - EXPECT_EQ(0, b.Get()); // invalid - EXPECT_EQ(0, c.Get()); // invalid - EXPECT_EQ(0, d.Get()); // empty - EXPECT_EQ(0, e.Get()); // empty -} - -TEST_F(FieldTrialParamsTest, FeatureParamDouble) { - const std::string kTrialName = "GetFieldTrialParamsByFeature"; - - static const Feature kFeature{"TestFeature", FEATURE_DISABLED_BY_DEFAULT}; - static const FeatureParam<double> a{&kFeature, "a", 0.0}; - static const FeatureParam<double> b{&kFeature, "b", 0.0}; - static const FeatureParam<double> c{&kFeature, "c", 0.0}; - static const FeatureParam<double> d{&kFeature, "d", 0.0}; - static const FeatureParam<double> e{&kFeature, "e", 0.0}; - static const FeatureParam<double> f{&kFeature, "f", 0.0}; - - std::map<std::string, std::string> params; - params["a"] = "1"; - params["b"] = "1.5"; - params["c"] = "1.0e-10"; - params["d"] = "foo"; - params["e"] = ""; - // "f" is not registered - AssociateFieldTrialParams(kTrialName, "A", params); - scoped_refptr<FieldTrial> trial( - CreateFieldTrial(kTrialName, 100, "A", nullptr)); - - CreateFeatureWithTrial(kFeature, FeatureList::OVERRIDE_ENABLE_FEATURE, - trial.get()); - - EXPECT_EQ(1, GetFieldTrialParamByFeatureAsDouble(kFeature, "a", 0)); - EXPECT_EQ(1.5, GetFieldTrialParamByFeatureAsDouble(kFeature, "b", 0)); - EXPECT_EQ(1.0e-10, GetFieldTrialParamByFeatureAsDouble(kFeature, "c", 0)); - EXPECT_EQ(0, - GetFieldTrialParamByFeatureAsDouble(kFeature, "d", 0)); // invalid - EXPECT_EQ(0, GetFieldTrialParamByFeatureAsDouble(kFeature, "e", 0)); // empty - EXPECT_EQ(0, GetFieldTrialParamByFeatureAsDouble(kFeature, "f", 0)); // empty - - EXPECT_EQ(1, a.Get()); - EXPECT_EQ(1.5, b.Get()); - EXPECT_EQ(1.0e-10, c.Get()); - EXPECT_EQ(0, d.Get()); // invalid - EXPECT_EQ(0, e.Get()); // empty - EXPECT_EQ(0, f.Get()); // empty -} - -TEST_F(FieldTrialParamsTest, FeatureParamBool) { - const std::string kTrialName = "GetFieldTrialParamsByFeature"; - - static const Feature kFeature{"TestFeature", FEATURE_DISABLED_BY_DEFAULT}; - static const FeatureParam<bool> a{&kFeature, "a", false}; - static const FeatureParam<bool> b{&kFeature, "b", true}; - static const FeatureParam<bool> c{&kFeature, "c", false}; - static const FeatureParam<bool> d{&kFeature, "d", true}; - static const FeatureParam<bool> e{&kFeature, "e", true}; - static const FeatureParam<bool> f{&kFeature, "f", true}; - - std::map<std::string, std::string> params; - params["a"] = "true"; - params["b"] = "false"; - params["c"] = "1"; - params["d"] = "False"; - params["e"] = ""; - // "f" is not registered - AssociateFieldTrialParams(kTrialName, "A", params); - scoped_refptr<FieldTrial> trial( - CreateFieldTrial(kTrialName, 100, "A", nullptr)); - - CreateFeatureWithTrial(kFeature, FeatureList::OVERRIDE_ENABLE_FEATURE, - trial.get()); - - EXPECT_TRUE(a.Get()); - EXPECT_FALSE(b.Get()); - EXPECT_FALSE(c.Get()); // invalid - EXPECT_TRUE(d.Get()); // invalid - EXPECT_TRUE(e.Get()); // empty - EXPECT_TRUE(f.Get()); // empty -} - -enum Hand { ROCK, PAPER, SCISSORS }; - -TEST_F(FieldTrialParamsTest, FeatureParamEnum) { - const std::string kTrialName = "GetFieldTrialParamsByFeature"; - - static const FeatureParam<Hand>::Option hands[] = { - {ROCK, "rock"}, {PAPER, "paper"}, {SCISSORS, "scissors"}}; - static const Feature kFeature{"TestFeature", FEATURE_DISABLED_BY_DEFAULT}; - static const FeatureParam<Hand> a{&kFeature, "a", ROCK, &hands}; - static const FeatureParam<Hand> b{&kFeature, "b", ROCK, &hands}; - static const FeatureParam<Hand> c{&kFeature, "c", ROCK, &hands}; - static const FeatureParam<Hand> d{&kFeature, "d", ROCK, &hands}; - static const FeatureParam<Hand> e{&kFeature, "e", PAPER, &hands}; - static const FeatureParam<Hand> f{&kFeature, "f", SCISSORS, &hands}; - - std::map<std::string, std::string> params; - params["a"] = "rock"; - params["b"] = "paper"; - params["c"] = "scissors"; - params["d"] = "lizard"; - params["e"] = ""; - // "f" is not registered - AssociateFieldTrialParams(kTrialName, "A", params); - scoped_refptr<FieldTrial> trial( - CreateFieldTrial(kTrialName, 100, "A", nullptr)); - - CreateFeatureWithTrial(kFeature, FeatureList::OVERRIDE_ENABLE_FEATURE, - trial.get()); - - EXPECT_EQ(ROCK, a.Get()); - EXPECT_EQ(PAPER, b.Get()); - EXPECT_EQ(SCISSORS, c.Get()); - EXPECT_EQ(ROCK, d.Get()); // invalid - EXPECT_EQ(PAPER, e.Get()); // invalid/empty - EXPECT_EQ(SCISSORS, f.Get()); // not registered -} - -enum class UI { ONE_D, TWO_D, THREE_D }; - -TEST_F(FieldTrialParamsTest, FeatureParamEnumClass) { - const std::string kTrialName = "GetFieldTrialParamsByFeature"; - - static const FeatureParam<UI>::Option uis[] = { - {UI::ONE_D, "1d"}, {UI::TWO_D, "2d"}, {UI::THREE_D, "3d"}}; - static const Feature kFeature{"TestFeature", FEATURE_DISABLED_BY_DEFAULT}; - static const FeatureParam<UI> a{&kFeature, "a", UI::ONE_D, &uis}; - static const FeatureParam<UI> b{&kFeature, "b", UI::ONE_D, &uis}; - static const FeatureParam<UI> c{&kFeature, "c", UI::ONE_D, &uis}; - static const FeatureParam<UI> d{&kFeature, "d", UI::ONE_D, &uis}; - static const FeatureParam<UI> e{&kFeature, "e", UI::TWO_D, &uis}; - static const FeatureParam<UI> f{&kFeature, "f", UI::THREE_D, &uis}; - - std::map<std::string, std::string> params; - params["a"] = "1d"; - params["b"] = "2d"; - params["c"] = "3d"; - params["d"] = "4d"; - params["e"] = ""; - // "f" is not registered - AssociateFieldTrialParams(kTrialName, "A", params); - scoped_refptr<FieldTrial> trial( - CreateFieldTrial(kTrialName, 100, "A", nullptr)); - - CreateFeatureWithTrial(kFeature, FeatureList::OVERRIDE_ENABLE_FEATURE, - trial.get()); - - EXPECT_EQ(UI::ONE_D, a.Get()); - EXPECT_EQ(UI::TWO_D, b.Get()); - EXPECT_EQ(UI::THREE_D, c.Get()); - EXPECT_EQ(UI::ONE_D, d.Get()); // invalid - EXPECT_EQ(UI::TWO_D, e.Get()); // invalid/empty - EXPECT_EQ(UI::THREE_D, f.Get()); // not registered -} - -} // namespace base
diff --git a/base/metrics/field_trial_params_unittest.nc b/base/metrics/field_trial_params_unittest.nc deleted file mode 100644 index 4c6005e..0000000 --- a/base/metrics/field_trial_params_unittest.nc +++ /dev/null
@@ -1,47 +0,0 @@ -// 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. - -// This is a "No Compile Test" suite. -// http://dev.chromium.org/developers/testing/no-compile-tests - -#include "base/feature_list.h" -#include "base/metrics/field_trial_params.h" - -constexpr base::Feature kFeature{"NoCompileFeature"}; - -enum Param { FOO, BAR }; - -#if defined(NCTEST_NO_PARAM_TYPE) // [r"too few template arguments"] - -constexpr base::FeatureParam<> kParam{ - &kFeature, "Param"}; - -#elif defined(NCTEST_VOID_PARAM_TYPE) // [r"unsupported FeatureParam<> type"] - -constexpr base::FeatureParam<void> kParam{ - &kFeature, "Param"}; - -#elif defined(NCTEST_INVALID_PARAM_TYPE) // [r"unsupported FeatureParam<> type"] - -constexpr base::FeatureParam<size_t> kParam{ - &kFeature, "Param", 1u}; - -#elif defined(NCTEST_ENUM_NULL_OPTIONS) // [r"candidate template ignored: could not match"] - -constexpr base::FeatureParam<Param> kParam{ - &kFeature, "Param", FOO, nullptr}; - -#elif defined(NCTEST_ENUM_EMPTY_OPTIONS) // [r"zero-length arrays are not permitted"] - -constexpr base::FeatureParam<Param>::Option kParamOptions[] = {}; -constexpr base::FeatureParam<Param> kParam{ - &kFeature, "Param", FOO, &kParamOptions}; - -#else - -void suppress_unused_variable_warning() { - (void)kFeature; -} - -#endif
diff --git a/base/metrics/field_trial_unittest.cc b/base/metrics/field_trial_unittest.cc deleted file mode 100644 index 4d55697..0000000 --- a/base/metrics/field_trial_unittest.cc +++ /dev/null
@@ -1,1400 +0,0 @@ -// 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/metrics/field_trial.h" - -#include <stddef.h> - -#include "base/base_switches.h" -#include "base/feature_list.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/message_loop/message_loop.h" -#include "base/metrics/field_trial_param_associator.h" -#include "base/rand_util.h" -#include "base/run_loop.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/stringprintf.h" -#include "base/test/gtest_util.h" -#include "base/test/mock_entropy_provider.h" -#include "base/test/scoped_feature_list.h" -#include "base/test/test_shared_memory_util.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -// Default group name used by several tests. -const char kDefaultGroupName[] = "DefaultGroup"; - -// Call FieldTrialList::FactoryGetFieldTrial() with a future expiry date. -scoped_refptr<FieldTrial> CreateFieldTrial( - const std::string& trial_name, - int total_probability, - const std::string& default_group_name, - int* default_group_number) { - return FieldTrialList::FactoryGetFieldTrial( - trial_name, total_probability, default_group_name, - FieldTrialList::kNoExpirationYear, 1, 1, FieldTrial::SESSION_RANDOMIZED, - default_group_number); -} - -// FieldTrialList::Observer implementation for testing. -class TestFieldTrialObserver : public FieldTrialList::Observer { - public: - enum Type { - ASYNCHRONOUS, - SYNCHRONOUS, - }; - - TestFieldTrialObserver(Type type) : type_(type) { - if (type == SYNCHRONOUS) - FieldTrialList::SetSynchronousObserver(this); - else - FieldTrialList::AddObserver(this); - } - - ~TestFieldTrialObserver() override { - if (type_ == SYNCHRONOUS) - FieldTrialList::RemoveSynchronousObserver(this); - else - FieldTrialList::RemoveObserver(this); - } - - void OnFieldTrialGroupFinalized(const std::string& trial, - const std::string& group) override { - trial_name_ = trial; - group_name_ = group; - } - - const std::string& trial_name() const { return trial_name_; } - const std::string& group_name() const { return group_name_; } - - private: - const Type type_; - std::string trial_name_; - std::string group_name_; - - DISALLOW_COPY_AND_ASSIGN(TestFieldTrialObserver); -}; - -std::string MockEscapeQueryParamValue(const std::string& input) { - return input; -} - -} // namespace - -class FieldTrialTest : public ::testing::Test { - public: - FieldTrialTest() : trial_list_(nullptr) {} - - private: - MessageLoop message_loop_; - FieldTrialList trial_list_; - - DISALLOW_COPY_AND_ASSIGN(FieldTrialTest); -}; - -// Test registration, and also check that destructors are called for trials. -TEST_F(FieldTrialTest, Registration) { - const char name1[] = "name 1 test"; - const char name2[] = "name 2 test"; - EXPECT_FALSE(FieldTrialList::Find(name1)); - EXPECT_FALSE(FieldTrialList::Find(name2)); - - scoped_refptr<FieldTrial> trial1 = - CreateFieldTrial(name1, 10, "default name 1 test", nullptr); - EXPECT_EQ(FieldTrial::kNotFinalized, trial1->group_); - EXPECT_EQ(name1, trial1->trial_name()); - EXPECT_EQ("", trial1->group_name_internal()); - - trial1->AppendGroup(std::string(), 7); - - EXPECT_EQ(trial1.get(), FieldTrialList::Find(name1)); - EXPECT_FALSE(FieldTrialList::Find(name2)); - - scoped_refptr<FieldTrial> trial2 = - CreateFieldTrial(name2, 10, "default name 2 test", nullptr); - EXPECT_EQ(FieldTrial::kNotFinalized, trial2->group_); - EXPECT_EQ(name2, trial2->trial_name()); - EXPECT_EQ("", trial2->group_name_internal()); - - trial2->AppendGroup("a first group", 7); - - EXPECT_EQ(trial1.get(), FieldTrialList::Find(name1)); - EXPECT_EQ(trial2.get(), FieldTrialList::Find(name2)); - // Note: FieldTrialList should delete the objects at shutdown. -} - -TEST_F(FieldTrialTest, AbsoluteProbabilities) { - char always_true[] = " always true"; - char default_always_true[] = " default always true"; - char always_false[] = " always false"; - char default_always_false[] = " default always false"; - for (int i = 1; i < 250; ++i) { - // Try lots of names, by changing the first character of the name. - char c = static_cast<char>(i); - always_true[0] = c; - default_always_true[0] = c; - always_false[0] = c; - default_always_false[0] = c; - - scoped_refptr<FieldTrial> trial_true = - CreateFieldTrial(always_true, 10, default_always_true, nullptr); - const std::string winner = "TheWinner"; - int winner_group = trial_true->AppendGroup(winner, 10); - - EXPECT_EQ(winner_group, trial_true->group()); - EXPECT_EQ(winner, trial_true->group_name()); - - scoped_refptr<FieldTrial> trial_false = - CreateFieldTrial(always_false, 10, default_always_false, nullptr); - int loser_group = trial_false->AppendGroup("ALoser", 0); - - EXPECT_NE(loser_group, trial_false->group()); - } -} - -TEST_F(FieldTrialTest, RemainingProbability) { - // First create a test that hasn't had a winner yet. - const std::string winner = "Winner"; - const std::string loser = "Loser"; - scoped_refptr<FieldTrial> trial; - int counter = 0; - int default_group_number = -1; - do { - std::string name = StringPrintf("trial%d", ++counter); - trial = CreateFieldTrial(name, 10, winner, &default_group_number); - trial->AppendGroup(loser, 5); // 50% chance of not being chosen. - // If a group is not assigned, group_ will be kNotFinalized. - } while (trial->group_ != FieldTrial::kNotFinalized); - - // And that 'default' group (winner) should always win. - EXPECT_EQ(default_group_number, trial->group()); - - // And that winner should ALWAYS win. - EXPECT_EQ(winner, trial->group_name()); -} - -TEST_F(FieldTrialTest, FiftyFiftyProbability) { - // Check that even with small divisors, we have the proper probabilities, and - // all outcomes are possible. Since this is a 50-50 test, it should get both - // outcomes in a few tries, but we'll try no more than 100 times (and be flaky - // with probability around 1 in 2^99). - bool first_winner = false; - bool second_winner = false; - int counter = 0; - do { - std::string name = StringPrintf("FiftyFifty%d", ++counter); - std::string default_group_name = - StringPrintf("Default FiftyFifty%d", ++counter); - scoped_refptr<FieldTrial> trial = - CreateFieldTrial(name, 2, default_group_name, nullptr); - trial->AppendGroup("first", 1); // 50% chance of being chosen. - // If group_ is kNotFinalized, then a group assignement hasn't been done. - if (trial->group_ != FieldTrial::kNotFinalized) { - first_winner = true; - continue; - } - trial->AppendGroup("second", 1); // Always chosen at this point. - EXPECT_NE(FieldTrial::kNotFinalized, trial->group()); - second_winner = true; - } while ((!second_winner || !first_winner) && counter < 100); - EXPECT_TRUE(second_winner); - EXPECT_TRUE(first_winner); -} - -TEST_F(FieldTrialTest, MiddleProbabilities) { - char name[] = " same name"; - char default_group_name[] = " default same name"; - bool false_event_seen = false; - bool true_event_seen = false; - for (int i = 1; i < 250; ++i) { - char c = static_cast<char>(i); - name[0] = c; - default_group_name[0] = c; - scoped_refptr<FieldTrial> trial = - CreateFieldTrial(name, 10, default_group_name, nullptr); - int might_win = trial->AppendGroup("MightWin", 5); - - if (trial->group() == might_win) { - true_event_seen = true; - } else { - false_event_seen = true; - } - if (false_event_seen && true_event_seen) - return; // Successful test!!! - } - // Very surprising to get here. Probability should be around 1 in 2 ** 250. - // One of the following will fail. - EXPECT_TRUE(false_event_seen); - EXPECT_TRUE(true_event_seen); -} - -TEST_F(FieldTrialTest, OneWinner) { - char name[] = "Some name"; - char default_group_name[] = "Default some name"; - int group_count(10); - - int default_group_number = -1; - scoped_refptr<FieldTrial> trial = - CreateFieldTrial(name, group_count, default_group_name, nullptr); - int winner_index(-2); - std::string winner_name; - - for (int i = 1; i <= group_count; ++i) { - int might_win = trial->AppendGroup(std::string(), 1); - - // Because we keep appending groups, we want to see if the last group that - // was added has been assigned or not. - if (trial->group_ == might_win) { - EXPECT_EQ(-2, winner_index); - winner_index = might_win; - StringAppendF(&winner_name, "%d", might_win); - EXPECT_EQ(winner_name, trial->group_name()); - } - } - EXPECT_GE(winner_index, 0); - // Since all groups cover the total probability, we should not have - // chosen the default group. - EXPECT_NE(trial->group(), default_group_number); - EXPECT_EQ(trial->group(), winner_index); - EXPECT_EQ(trial->group_name(), winner_name); -} - -TEST_F(FieldTrialTest, ActiveGroups) { - std::string no_group("No Group"); - scoped_refptr<FieldTrial> trial = - CreateFieldTrial(no_group, 10, "Default", nullptr); - - // There is no winner yet, so no NameGroupId should be returned. - FieldTrial::ActiveGroup active_group; - EXPECT_FALSE(trial->GetActiveGroup(&active_group)); - - // Create a single winning group. - std::string one_winner("One Winner"); - trial = CreateFieldTrial(one_winner, 10, "Default", nullptr); - std::string winner("Winner"); - trial->AppendGroup(winner, 10); - EXPECT_FALSE(trial->GetActiveGroup(&active_group)); - // Finalize the group selection by accessing the selected group. - trial->group(); - EXPECT_TRUE(trial->GetActiveGroup(&active_group)); - EXPECT_EQ(one_winner, active_group.trial_name); - EXPECT_EQ(winner, active_group.group_name); - - std::string multi_group("MultiGroup"); - scoped_refptr<FieldTrial> multi_group_trial = - CreateFieldTrial(multi_group, 9, "Default", nullptr); - - multi_group_trial->AppendGroup("Me", 3); - multi_group_trial->AppendGroup("You", 3); - multi_group_trial->AppendGroup("Them", 3); - EXPECT_FALSE(multi_group_trial->GetActiveGroup(&active_group)); - // Finalize the group selection by accessing the selected group. - multi_group_trial->group(); - EXPECT_TRUE(multi_group_trial->GetActiveGroup(&active_group)); - EXPECT_EQ(multi_group, active_group.trial_name); - EXPECT_EQ(multi_group_trial->group_name(), active_group.group_name); - - // Now check if the list is built properly... - FieldTrial::ActiveGroups active_groups; - FieldTrialList::GetActiveFieldTrialGroups(&active_groups); - EXPECT_EQ(2U, active_groups.size()); - for (size_t i = 0; i < active_groups.size(); ++i) { - // Order is not guaranteed, so check all values. - EXPECT_NE(no_group, active_groups[i].trial_name); - EXPECT_TRUE(one_winner != active_groups[i].trial_name || - winner == active_groups[i].group_name); - EXPECT_TRUE(multi_group != active_groups[i].trial_name || - multi_group_trial->group_name() == active_groups[i].group_name); - } -} - -TEST_F(FieldTrialTest, GetActiveFieldTrialGroupsFromString) { - FieldTrial::ActiveGroups active_groups; - FieldTrialList::GetActiveFieldTrialGroupsFromString("*A/X/B/Y/*C/Z", - &active_groups); - ASSERT_EQ(2U, active_groups.size()); - EXPECT_EQ("A", active_groups[0].trial_name); - EXPECT_EQ("X", active_groups[0].group_name); - EXPECT_EQ("C", active_groups[1].trial_name); - EXPECT_EQ("Z", active_groups[1].group_name); -} - -TEST_F(FieldTrialTest, ActiveGroupsNotFinalized) { - const char kTrialName[] = "TestTrial"; - const char kSecondaryGroupName[] = "SecondaryGroup"; - - int default_group = -1; - scoped_refptr<FieldTrial> trial = - CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group); - const int secondary_group = trial->AppendGroup(kSecondaryGroupName, 50); - - // Before |group()| is called, |GetActiveGroup()| should return false. - FieldTrial::ActiveGroup active_group; - EXPECT_FALSE(trial->GetActiveGroup(&active_group)); - - // |GetActiveFieldTrialGroups()| should also not include the trial. - FieldTrial::ActiveGroups active_groups; - FieldTrialList::GetActiveFieldTrialGroups(&active_groups); - EXPECT_TRUE(active_groups.empty()); - - // After |group()| has been called, both APIs should succeed. - const int chosen_group = trial->group(); - EXPECT_TRUE(chosen_group == default_group || chosen_group == secondary_group); - - EXPECT_TRUE(trial->GetActiveGroup(&active_group)); - EXPECT_EQ(kTrialName, active_group.trial_name); - if (chosen_group == default_group) - EXPECT_EQ(kDefaultGroupName, active_group.group_name); - else - EXPECT_EQ(kSecondaryGroupName, active_group.group_name); - - FieldTrialList::GetActiveFieldTrialGroups(&active_groups); - ASSERT_EQ(1U, active_groups.size()); - EXPECT_EQ(kTrialName, active_groups[0].trial_name); - EXPECT_EQ(active_group.group_name, active_groups[0].group_name); -} - -TEST_F(FieldTrialTest, GetGroupNameWithoutActivation) { - const char kTrialName[] = "TestTrial"; - const char kSecondaryGroupName[] = "SecondaryGroup"; - - int default_group = -1; - scoped_refptr<FieldTrial> trial = - CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group); - trial->AppendGroup(kSecondaryGroupName, 50); - - // The trial should start inactive. - EXPECT_FALSE(FieldTrialList::IsTrialActive(kTrialName)); - - // Calling |GetGroupNameWithoutActivation()| should not activate the trial. - std::string group_name = trial->GetGroupNameWithoutActivation(); - EXPECT_FALSE(group_name.empty()); - EXPECT_FALSE(FieldTrialList::IsTrialActive(kTrialName)); - - // Calling |group_name()| should activate it and return the same group name. - EXPECT_EQ(group_name, trial->group_name()); - EXPECT_TRUE(FieldTrialList::IsTrialActive(kTrialName)); -} - -TEST_F(FieldTrialTest, Save) { - std::string save_string; - - scoped_refptr<FieldTrial> trial = - CreateFieldTrial("Some name", 10, "Default some name", nullptr); - // There is no winner yet, so no textual group name is associated with trial. - // In this case, the trial should not be included. - EXPECT_EQ("", trial->group_name_internal()); - FieldTrialList::StatesToString(&save_string); - EXPECT_EQ("", save_string); - save_string.clear(); - - // Create a winning group. - trial->AppendGroup("Winner", 10); - // Finalize the group selection by accessing the selected group. - trial->group(); - FieldTrialList::StatesToString(&save_string); - EXPECT_EQ("Some name/Winner/", save_string); - save_string.clear(); - - // Create a second trial and winning group. - scoped_refptr<FieldTrial> trial2 = - CreateFieldTrial("xxx", 10, "Default xxx", nullptr); - trial2->AppendGroup("yyyy", 10); - // Finalize the group selection by accessing the selected group. - trial2->group(); - - FieldTrialList::StatesToString(&save_string); - // We assume names are alphabetized... though this is not critical. - EXPECT_EQ("Some name/Winner/xxx/yyyy/", save_string); - save_string.clear(); - - // Create a third trial with only the default group. - scoped_refptr<FieldTrial> trial3 = - CreateFieldTrial("zzz", 10, "default", nullptr); - // Finalize the group selection by accessing the selected group. - trial3->group(); - - FieldTrialList::StatesToString(&save_string); - EXPECT_EQ("Some name/Winner/xxx/yyyy/zzz/default/", save_string); -} - -TEST_F(FieldTrialTest, Restore) { - ASSERT_FALSE(FieldTrialList::TrialExists("Some_name")); - ASSERT_FALSE(FieldTrialList::TrialExists("xxx")); - - FieldTrialList::CreateTrialsFromString("Some_name/Winner/xxx/yyyy/", - std::set<std::string>()); - - FieldTrial* trial = FieldTrialList::Find("Some_name"); - ASSERT_NE(static_cast<FieldTrial*>(nullptr), trial); - EXPECT_EQ("Winner", trial->group_name()); - EXPECT_EQ("Some_name", trial->trial_name()); - - trial = FieldTrialList::Find("xxx"); - ASSERT_NE(static_cast<FieldTrial*>(nullptr), trial); - EXPECT_EQ("yyyy", trial->group_name()); - EXPECT_EQ("xxx", trial->trial_name()); -} - -TEST_F(FieldTrialTest, RestoreNotEndingWithSlash) { - EXPECT_TRUE(FieldTrialList::CreateTrialsFromString("tname/gname", - std::set<std::string>())); - - FieldTrial* trial = FieldTrialList::Find("tname"); - ASSERT_NE(static_cast<FieldTrial*>(nullptr), trial); - EXPECT_EQ("gname", trial->group_name()); - EXPECT_EQ("tname", trial->trial_name()); -} - -TEST_F(FieldTrialTest, BogusRestore) { - EXPECT_FALSE(FieldTrialList::CreateTrialsFromString("MissingSlash", - std::set<std::string>())); - EXPECT_FALSE(FieldTrialList::CreateTrialsFromString("MissingGroupName/", - std::set<std::string>())); - EXPECT_FALSE(FieldTrialList::CreateTrialsFromString("noname, only group/", - std::set<std::string>())); - EXPECT_FALSE(FieldTrialList::CreateTrialsFromString("/emptyname", - std::set<std::string>())); - EXPECT_FALSE(FieldTrialList::CreateTrialsFromString("*/emptyname", - std::set<std::string>())); -} - -TEST_F(FieldTrialTest, DuplicateRestore) { - scoped_refptr<FieldTrial> trial = - CreateFieldTrial("Some name", 10, "Default", nullptr); - trial->AppendGroup("Winner", 10); - // Finalize the group selection by accessing the selected group. - trial->group(); - std::string save_string; - FieldTrialList::StatesToString(&save_string); - EXPECT_EQ("Some name/Winner/", save_string); - - // It is OK if we redundantly specify a winner. - EXPECT_TRUE(FieldTrialList::CreateTrialsFromString(save_string, - std::set<std::string>())); - - // But it is an error to try to change to a different winner. - EXPECT_FALSE(FieldTrialList::CreateTrialsFromString("Some name/Loser/", - std::set<std::string>())); -} - -TEST_F(FieldTrialTest, CreateTrialsFromStringNotActive) { - ASSERT_FALSE(FieldTrialList::TrialExists("Abc")); - ASSERT_FALSE(FieldTrialList::TrialExists("Xyz")); - ASSERT_TRUE(FieldTrialList::CreateTrialsFromString("Abc/def/Xyz/zyx/", - std::set<std::string>())); - - FieldTrial::ActiveGroups active_groups; - FieldTrialList::GetActiveFieldTrialGroups(&active_groups); - ASSERT_TRUE(active_groups.empty()); - - // Check that the values still get returned and querying them activates them. - EXPECT_EQ("def", FieldTrialList::FindFullName("Abc")); - EXPECT_EQ("zyx", FieldTrialList::FindFullName("Xyz")); - - FieldTrialList::GetActiveFieldTrialGroups(&active_groups); - ASSERT_EQ(2U, active_groups.size()); - EXPECT_EQ("Abc", active_groups[0].trial_name); - EXPECT_EQ("def", active_groups[0].group_name); - EXPECT_EQ("Xyz", active_groups[1].trial_name); - EXPECT_EQ("zyx", active_groups[1].group_name); -} - -TEST_F(FieldTrialTest, CreateTrialsFromStringForceActivation) { - ASSERT_FALSE(FieldTrialList::TrialExists("Abc")); - ASSERT_FALSE(FieldTrialList::TrialExists("def")); - ASSERT_FALSE(FieldTrialList::TrialExists("Xyz")); - ASSERT_TRUE(FieldTrialList::CreateTrialsFromString( - "*Abc/cba/def/fed/*Xyz/zyx/", std::set<std::string>())); - - FieldTrial::ActiveGroups active_groups; - FieldTrialList::GetActiveFieldTrialGroups(&active_groups); - ASSERT_EQ(2U, active_groups.size()); - EXPECT_EQ("Abc", active_groups[0].trial_name); - EXPECT_EQ("cba", active_groups[0].group_name); - EXPECT_EQ("Xyz", active_groups[1].trial_name); - EXPECT_EQ("zyx", active_groups[1].group_name); -} - -TEST_F(FieldTrialTest, CreateTrialsFromStringNotActiveObserver) { - ASSERT_FALSE(FieldTrialList::TrialExists("Abc")); - - TestFieldTrialObserver observer(TestFieldTrialObserver::ASYNCHRONOUS); - ASSERT_TRUE(FieldTrialList::CreateTrialsFromString("Abc/def/", - std::set<std::string>())); - RunLoop().RunUntilIdle(); - // Observer shouldn't be notified. - EXPECT_TRUE(observer.trial_name().empty()); - - // Check that the values still get returned and querying them activates them. - EXPECT_EQ("def", FieldTrialList::FindFullName("Abc")); - - RunLoop().RunUntilIdle(); - EXPECT_EQ("Abc", observer.trial_name()); - EXPECT_EQ("def", observer.group_name()); -} - -TEST_F(FieldTrialTest, CreateTrialsFromStringWithIgnoredFieldTrials) { - ASSERT_FALSE(FieldTrialList::TrialExists("Unaccepted1")); - ASSERT_FALSE(FieldTrialList::TrialExists("Foo")); - ASSERT_FALSE(FieldTrialList::TrialExists("Unaccepted2")); - ASSERT_FALSE(FieldTrialList::TrialExists("Bar")); - ASSERT_FALSE(FieldTrialList::TrialExists("Unaccepted3")); - - std::set<std::string> ignored_trial_names; - ignored_trial_names.insert("Unaccepted1"); - ignored_trial_names.insert("Unaccepted2"); - ignored_trial_names.insert("Unaccepted3"); - - FieldTrialList::CreateTrialsFromString( - "Unaccepted1/Unaccepted1_name/" - "Foo/Foo_name/" - "Unaccepted2/Unaccepted2_name/" - "Bar/Bar_name/" - "Unaccepted3/Unaccepted3_name/", - ignored_trial_names); - - EXPECT_FALSE(FieldTrialList::TrialExists("Unaccepted1")); - EXPECT_TRUE(FieldTrialList::TrialExists("Foo")); - EXPECT_FALSE(FieldTrialList::TrialExists("Unaccepted2")); - EXPECT_TRUE(FieldTrialList::TrialExists("Bar")); - EXPECT_FALSE(FieldTrialList::TrialExists("Unaccepted3")); - - FieldTrial::ActiveGroups active_groups; - FieldTrialList::GetActiveFieldTrialGroups(&active_groups); - EXPECT_TRUE(active_groups.empty()); - - FieldTrial* trial = FieldTrialList::Find("Foo"); - ASSERT_NE(static_cast<FieldTrial*>(nullptr), trial); - EXPECT_EQ("Foo", trial->trial_name()); - EXPECT_EQ("Foo_name", trial->group_name()); - - trial = FieldTrialList::Find("Bar"); - ASSERT_NE(static_cast<FieldTrial*>(nullptr), trial); - EXPECT_EQ("Bar", trial->trial_name()); - EXPECT_EQ("Bar_name", trial->group_name()); -} - -TEST_F(FieldTrialTest, CreateFieldTrial) { - ASSERT_FALSE(FieldTrialList::TrialExists("Some_name")); - - FieldTrialList::CreateFieldTrial("Some_name", "Winner"); - - FieldTrial* trial = FieldTrialList::Find("Some_name"); - ASSERT_NE(static_cast<FieldTrial*>(nullptr), trial); - EXPECT_EQ("Winner", trial->group_name()); - EXPECT_EQ("Some_name", trial->trial_name()); -} - -TEST_F(FieldTrialTest, CreateFieldTrialIsNotActive) { - const char kTrialName[] = "CreateFieldTrialIsActiveTrial"; - const char kWinnerGroup[] = "Winner"; - ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName)); - FieldTrialList::CreateFieldTrial(kTrialName, kWinnerGroup); - - FieldTrial::ActiveGroups active_groups; - FieldTrialList::GetActiveFieldTrialGroups(&active_groups); - EXPECT_TRUE(active_groups.empty()); -} - -TEST_F(FieldTrialTest, DuplicateFieldTrial) { - scoped_refptr<FieldTrial> trial = - CreateFieldTrial("Some_name", 10, "Default", nullptr); - trial->AppendGroup("Winner", 10); - - // It is OK if we redundantly specify a winner. - FieldTrial* trial1 = FieldTrialList::CreateFieldTrial("Some_name", "Winner"); - EXPECT_TRUE(trial1 != nullptr); - - // But it is an error to try to change to a different winner. - FieldTrial* trial2 = FieldTrialList::CreateFieldTrial("Some_name", "Loser"); - EXPECT_TRUE(trial2 == nullptr); -} - -TEST_F(FieldTrialTest, DisableImmediately) { - int default_group_number = -1; - scoped_refptr<FieldTrial> trial = - CreateFieldTrial("trial", 100, "default", &default_group_number); - trial->Disable(); - ASSERT_EQ("default", trial->group_name()); - ASSERT_EQ(default_group_number, trial->group()); -} - -TEST_F(FieldTrialTest, DisableAfterInitialization) { - scoped_refptr<FieldTrial> trial = - CreateFieldTrial("trial", 100, "default", nullptr); - trial->AppendGroup("non_default", 100); - trial->Disable(); - ASSERT_EQ("default", trial->group_name()); -} - -TEST_F(FieldTrialTest, ForcedFieldTrials) { - // Validate we keep the forced choice. - FieldTrial* forced_trial = FieldTrialList::CreateFieldTrial("Use the", - "Force"); - EXPECT_STREQ("Force", forced_trial->group_name().c_str()); - - int default_group_number = -1; - scoped_refptr<FieldTrial> factory_trial = - CreateFieldTrial("Use the", 1000, "default", &default_group_number); - EXPECT_EQ(factory_trial.get(), forced_trial); - - int chosen_group = factory_trial->AppendGroup("Force", 100); - EXPECT_EQ(chosen_group, factory_trial->group()); - int not_chosen_group = factory_trial->AppendGroup("Dark Side", 100); - EXPECT_NE(chosen_group, not_chosen_group); - - // Since we didn't force the default group, we should not be returned the - // chosen group as the default group. - EXPECT_NE(default_group_number, chosen_group); - int new_group = factory_trial->AppendGroup("Duck Tape", 800); - EXPECT_NE(chosen_group, new_group); - // The new group should not be the default group either. - EXPECT_NE(default_group_number, new_group); -} - -TEST_F(FieldTrialTest, ForcedFieldTrialsDefaultGroup) { - // Forcing the default should use the proper group ID. - FieldTrial* forced_trial = FieldTrialList::CreateFieldTrial("Trial Name", - "Default"); - int default_group_number = -1; - scoped_refptr<FieldTrial> factory_trial = - CreateFieldTrial("Trial Name", 1000, "Default", &default_group_number); - EXPECT_EQ(forced_trial, factory_trial.get()); - - int other_group = factory_trial->AppendGroup("Not Default", 100); - EXPECT_STREQ("Default", factory_trial->group_name().c_str()); - EXPECT_EQ(default_group_number, factory_trial->group()); - EXPECT_NE(other_group, factory_trial->group()); - - int new_other_group = factory_trial->AppendGroup("Not Default Either", 800); - EXPECT_NE(new_other_group, factory_trial->group()); -} - -TEST_F(FieldTrialTest, SetForced) { - // Start by setting a trial for which we ensure a winner... - int default_group_number = -1; - scoped_refptr<FieldTrial> forced_trial = - CreateFieldTrial("Use the", 1, "default", &default_group_number); - EXPECT_EQ(forced_trial, forced_trial); - - int forced_group = forced_trial->AppendGroup("Force", 1); - EXPECT_EQ(forced_group, forced_trial->group()); - - // Now force it. - forced_trial->SetForced(); - - // Now try to set it up differently as a hard coded registration would. - scoped_refptr<FieldTrial> hard_coded_trial = - CreateFieldTrial("Use the", 1, "default", &default_group_number); - EXPECT_EQ(hard_coded_trial, forced_trial); - - int would_lose_group = hard_coded_trial->AppendGroup("Force", 0); - EXPECT_EQ(forced_group, hard_coded_trial->group()); - EXPECT_EQ(forced_group, would_lose_group); - - // Same thing if we would have done it to win again. - scoped_refptr<FieldTrial> other_hard_coded_trial = - CreateFieldTrial("Use the", 1, "default", &default_group_number); - EXPECT_EQ(other_hard_coded_trial, forced_trial); - - int would_win_group = other_hard_coded_trial->AppendGroup("Force", 1); - EXPECT_EQ(forced_group, other_hard_coded_trial->group()); - EXPECT_EQ(forced_group, would_win_group); -} - -TEST_F(FieldTrialTest, SetForcedDefaultOnly) { - const char kTrialName[] = "SetForcedDefaultOnly"; - ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName)); - - int default_group = -1; - scoped_refptr<FieldTrial> trial = - CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group); - trial->SetForced(); - - trial = CreateFieldTrial(kTrialName, 100, kDefaultGroupName, nullptr); - EXPECT_EQ(default_group, trial->group()); - EXPECT_EQ(kDefaultGroupName, trial->group_name()); -} - -TEST_F(FieldTrialTest, SetForcedDefaultWithExtraGroup) { - const char kTrialName[] = "SetForcedDefaultWithExtraGroup"; - ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName)); - - int default_group = -1; - scoped_refptr<FieldTrial> trial = - CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group); - trial->SetForced(); - - trial = CreateFieldTrial(kTrialName, 100, kDefaultGroupName, nullptr); - const int extra_group = trial->AppendGroup("Extra", 100); - EXPECT_EQ(default_group, trial->group()); - EXPECT_NE(extra_group, trial->group()); - EXPECT_EQ(kDefaultGroupName, trial->group_name()); -} - -TEST_F(FieldTrialTest, SetForcedTurnFeatureOn) { - const char kTrialName[] = "SetForcedTurnFeatureOn"; - const char kExtraGroupName[] = "Extra"; - ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName)); - - // Simulate a server-side (forced) config that turns the feature on when the - // original hard-coded config had it disabled. - scoped_refptr<FieldTrial> forced_trial = - CreateFieldTrial(kTrialName, 100, kDefaultGroupName, nullptr); - forced_trial->AppendGroup(kExtraGroupName, 100); - forced_trial->SetForced(); - - int default_group = -1; - scoped_refptr<FieldTrial> client_trial = - CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group); - const int extra_group = client_trial->AppendGroup(kExtraGroupName, 0); - EXPECT_NE(default_group, extra_group); - - EXPECT_FALSE(client_trial->group_reported_); - EXPECT_EQ(extra_group, client_trial->group()); - EXPECT_TRUE(client_trial->group_reported_); - EXPECT_EQ(kExtraGroupName, client_trial->group_name()); -} - -TEST_F(FieldTrialTest, SetForcedTurnFeatureOff) { - const char kTrialName[] = "SetForcedTurnFeatureOff"; - const char kExtraGroupName[] = "Extra"; - ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName)); - - // Simulate a server-side (forced) config that turns the feature off when the - // original hard-coded config had it enabled. - scoped_refptr<FieldTrial> forced_trial = - CreateFieldTrial(kTrialName, 100, kDefaultGroupName, nullptr); - forced_trial->AppendGroup(kExtraGroupName, 0); - forced_trial->SetForced(); - - int default_group = -1; - scoped_refptr<FieldTrial> client_trial = - CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group); - const int extra_group = client_trial->AppendGroup(kExtraGroupName, 100); - EXPECT_NE(default_group, extra_group); - - EXPECT_FALSE(client_trial->group_reported_); - EXPECT_EQ(default_group, client_trial->group()); - EXPECT_TRUE(client_trial->group_reported_); - EXPECT_EQ(kDefaultGroupName, client_trial->group_name()); -} - -TEST_F(FieldTrialTest, SetForcedChangeDefault_Default) { - const char kTrialName[] = "SetForcedDefaultGroupChange"; - const char kGroupAName[] = "A"; - const char kGroupBName[] = "B"; - ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName)); - - // Simulate a server-side (forced) config that switches which group is default - // and ensures that the non-forced code receives the correct group numbers. - scoped_refptr<FieldTrial> forced_trial = - CreateFieldTrial(kTrialName, 100, kGroupAName, nullptr); - forced_trial->AppendGroup(kGroupBName, 100); - forced_trial->SetForced(); - - int default_group = -1; - scoped_refptr<FieldTrial> client_trial = - CreateFieldTrial(kTrialName, 100, kGroupBName, &default_group); - const int extra_group = client_trial->AppendGroup(kGroupAName, 50); - EXPECT_NE(default_group, extra_group); - - EXPECT_FALSE(client_trial->group_reported_); - EXPECT_EQ(default_group, client_trial->group()); - EXPECT_TRUE(client_trial->group_reported_); - EXPECT_EQ(kGroupBName, client_trial->group_name()); -} - -TEST_F(FieldTrialTest, SetForcedChangeDefault_NonDefault) { - const char kTrialName[] = "SetForcedDefaultGroupChange"; - const char kGroupAName[] = "A"; - const char kGroupBName[] = "B"; - ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName)); - - // Simulate a server-side (forced) config that switches which group is default - // and ensures that the non-forced code receives the correct group numbers. - scoped_refptr<FieldTrial> forced_trial = - CreateFieldTrial(kTrialName, 100, kGroupAName, nullptr); - forced_trial->AppendGroup(kGroupBName, 0); - forced_trial->SetForced(); - - int default_group = -1; - scoped_refptr<FieldTrial> client_trial = - CreateFieldTrial(kTrialName, 100, kGroupBName, &default_group); - const int extra_group = client_trial->AppendGroup(kGroupAName, 50); - EXPECT_NE(default_group, extra_group); - - EXPECT_FALSE(client_trial->group_reported_); - EXPECT_EQ(extra_group, client_trial->group()); - EXPECT_TRUE(client_trial->group_reported_); - EXPECT_EQ(kGroupAName, client_trial->group_name()); -} - -TEST_F(FieldTrialTest, Observe) { - const char kTrialName[] = "TrialToObserve1"; - const char kSecondaryGroupName[] = "SecondaryGroup"; - - TestFieldTrialObserver observer(TestFieldTrialObserver::ASYNCHRONOUS); - int default_group = -1; - scoped_refptr<FieldTrial> trial = - CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group); - const int secondary_group = trial->AppendGroup(kSecondaryGroupName, 50); - const int chosen_group = trial->group(); - EXPECT_TRUE(chosen_group == default_group || chosen_group == secondary_group); - - // Observers are called asynchronously. - EXPECT_TRUE(observer.trial_name().empty()); - EXPECT_TRUE(observer.group_name().empty()); - RunLoop().RunUntilIdle(); - - EXPECT_EQ(kTrialName, observer.trial_name()); - if (chosen_group == default_group) - EXPECT_EQ(kDefaultGroupName, observer.group_name()); - else - EXPECT_EQ(kSecondaryGroupName, observer.group_name()); -} - -TEST_F(FieldTrialTest, SynchronousObserver) { - const char kTrialName[] = "TrialToObserve1"; - const char kSecondaryGroupName[] = "SecondaryGroup"; - - TestFieldTrialObserver observer(TestFieldTrialObserver::SYNCHRONOUS); - int default_group = -1; - scoped_refptr<FieldTrial> trial = - CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group); - const int secondary_group = trial->AppendGroup(kSecondaryGroupName, 50); - const int chosen_group = trial->group(); - EXPECT_TRUE(chosen_group == default_group || chosen_group == secondary_group); - - // The observer should be notified synchronously by the group() call. - EXPECT_EQ(kTrialName, observer.trial_name()); - if (chosen_group == default_group) - EXPECT_EQ(kDefaultGroupName, observer.group_name()); - else - EXPECT_EQ(kSecondaryGroupName, observer.group_name()); -} - -TEST_F(FieldTrialTest, ObserveDisabled) { - const char kTrialName[] = "TrialToObserve2"; - - TestFieldTrialObserver observer(TestFieldTrialObserver::ASYNCHRONOUS); - int default_group = -1; - scoped_refptr<FieldTrial> trial = - CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group); - trial->AppendGroup("A", 25); - trial->AppendGroup("B", 25); - trial->AppendGroup("C", 25); - trial->Disable(); - - // Observer shouldn't be notified of a disabled trial. - RunLoop().RunUntilIdle(); - EXPECT_TRUE(observer.trial_name().empty()); - EXPECT_TRUE(observer.group_name().empty()); - - // Observer shouldn't be notified even after a |group()| call. - EXPECT_EQ(default_group, trial->group()); - RunLoop().RunUntilIdle(); - EXPECT_TRUE(observer.trial_name().empty()); - EXPECT_TRUE(observer.group_name().empty()); -} - -TEST_F(FieldTrialTest, ObserveForcedDisabled) { - const char kTrialName[] = "TrialToObserve3"; - - TestFieldTrialObserver observer(TestFieldTrialObserver::ASYNCHRONOUS); - int default_group = -1; - scoped_refptr<FieldTrial> trial = - CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group); - trial->AppendGroup("A", 25); - trial->AppendGroup("B", 25); - trial->AppendGroup("C", 25); - trial->SetForced(); - trial->Disable(); - - // Observer shouldn't be notified of a disabled trial, even when forced. - RunLoop().RunUntilIdle(); - EXPECT_TRUE(observer.trial_name().empty()); - EXPECT_TRUE(observer.group_name().empty()); - - // Observer shouldn't be notified even after a |group()| call. - EXPECT_EQ(default_group, trial->group()); - RunLoop().RunUntilIdle(); - EXPECT_TRUE(observer.trial_name().empty()); - EXPECT_TRUE(observer.group_name().empty()); -} - -TEST_F(FieldTrialTest, DisabledTrialNotActive) { - const char kTrialName[] = "DisabledTrial"; - ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName)); - - scoped_refptr<FieldTrial> trial = - CreateFieldTrial(kTrialName, 100, kDefaultGroupName, nullptr); - trial->AppendGroup("X", 50); - trial->Disable(); - - // Ensure the trial is not listed as active. - FieldTrial::ActiveGroups active_groups; - FieldTrialList::GetActiveFieldTrialGroups(&active_groups); - EXPECT_TRUE(active_groups.empty()); - - // Ensure the trial is not listed in the |StatesToString()| result. - std::string states; - FieldTrialList::StatesToString(&states); - EXPECT_TRUE(states.empty()); -} - -TEST_F(FieldTrialTest, ExpirationYearNotExpired) { - const char kTrialName[] = "NotExpired"; - const char kGroupName[] = "Group2"; - const int kProbability = 100; - ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName)); - - scoped_refptr<FieldTrial> trial = - CreateFieldTrial(kTrialName, kProbability, kDefaultGroupName, nullptr); - trial->AppendGroup(kGroupName, kProbability); - EXPECT_EQ(kGroupName, trial->group_name()); -} - -TEST_F(FieldTrialTest, FloatBoundariesGiveEqualGroupSizes) { - const int kBucketCount = 100; - - // Try each boundary value |i / 100.0| as the entropy value. - for (int i = 0; i < kBucketCount; ++i) { - const double entropy = i / static_cast<double>(kBucketCount); - - scoped_refptr<FieldTrial> trial( - new FieldTrial("test", kBucketCount, "default", entropy)); - for (int j = 0; j < kBucketCount; ++j) - trial->AppendGroup(IntToString(j), 1); - - EXPECT_EQ(IntToString(i), trial->group_name()); - } -} - -TEST_F(FieldTrialTest, DoesNotSurpassTotalProbability) { - const double kEntropyValue = 1.0 - 1e-9; - ASSERT_LT(kEntropyValue, 1.0); - - scoped_refptr<FieldTrial> trial( - new FieldTrial("test", 2, "default", kEntropyValue)); - trial->AppendGroup("1", 1); - trial->AppendGroup("2", 1); - - EXPECT_EQ("2", trial->group_name()); -} - -TEST_F(FieldTrialTest, CreateSimulatedFieldTrial) { - const char kTrialName[] = "CreateSimulatedFieldTrial"; - ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName)); - - // Different cases to test, e.g. default vs. non default group being chosen. - struct { - double entropy_value; - const char* expected_group; - } test_cases[] = { - { 0.4, "A" }, - { 0.85, "B" }, - { 0.95, kDefaultGroupName }, - }; - - for (size_t i = 0; i < arraysize(test_cases); ++i) { - TestFieldTrialObserver observer(TestFieldTrialObserver::ASYNCHRONOUS); - scoped_refptr<FieldTrial> trial( - FieldTrial::CreateSimulatedFieldTrial(kTrialName, 100, kDefaultGroupName, - test_cases[i].entropy_value)); - trial->AppendGroup("A", 80); - trial->AppendGroup("B", 10); - EXPECT_EQ(test_cases[i].expected_group, trial->group_name()); - - // Field trial shouldn't have been registered with the list. - EXPECT_FALSE(FieldTrialList::TrialExists(kTrialName)); - EXPECT_EQ(0u, FieldTrialList::GetFieldTrialCount()); - - // Observer shouldn't have been notified. - RunLoop().RunUntilIdle(); - EXPECT_TRUE(observer.trial_name().empty()); - - // The trial shouldn't be in the active set of trials. - FieldTrial::ActiveGroups active_groups; - FieldTrialList::GetActiveFieldTrialGroups(&active_groups); - EXPECT_TRUE(active_groups.empty()); - - // The trial shouldn't be listed in the |StatesToString()| result. - std::string states; - FieldTrialList::StatesToString(&states); - EXPECT_TRUE(states.empty()); - } -} - -TEST(FieldTrialTestWithoutList, StatesStringFormat) { - std::string save_string; - - // Scoping the first FieldTrialList, as we need another one to test the - // importing function. - { - FieldTrialList field_trial_list(nullptr); - scoped_refptr<FieldTrial> trial = - CreateFieldTrial("Abc", 10, "Default some name", nullptr); - trial->AppendGroup("cba", 10); - trial->group(); - scoped_refptr<FieldTrial> trial2 = - CreateFieldTrial("Xyz", 10, "Default xxx", nullptr); - trial2->AppendGroup("zyx", 10); - trial2->group(); - scoped_refptr<FieldTrial> trial3 = - CreateFieldTrial("zzz", 10, "default", nullptr); - - FieldTrialList::AllStatesToString(&save_string, false); - } - - // Starting with a new blank FieldTrialList. - FieldTrialList field_trial_list(nullptr); - ASSERT_TRUE(field_trial_list.CreateTrialsFromString(save_string, - std::set<std::string>())); - - FieldTrial::ActiveGroups active_groups; - field_trial_list.GetActiveFieldTrialGroups(&active_groups); - ASSERT_EQ(2U, active_groups.size()); - EXPECT_EQ("Abc", active_groups[0].trial_name); - EXPECT_EQ("cba", active_groups[0].group_name); - EXPECT_EQ("Xyz", active_groups[1].trial_name); - EXPECT_EQ("zyx", active_groups[1].group_name); - EXPECT_TRUE(field_trial_list.TrialExists("zzz")); -} - -TEST(FieldTrialDeathTest, OneTimeRandomizedTrialWithoutFieldTrialList) { - // Trying to instantiate a one-time randomized field trial before the - // FieldTrialList is created should crash. - EXPECT_DEATH_IF_SUPPORTED( - FieldTrialList::FactoryGetFieldTrial( - "OneTimeRandomizedTrialWithoutFieldTrialList", 100, kDefaultGroupName, - FieldTrialList::kNoExpirationYear, 1, 1, - FieldTrial::ONE_TIME_RANDOMIZED, nullptr), - ""); -} - -TEST(FieldTrialListTest, TestCopyFieldTrialStateToFlags) { - constexpr char kFieldTrialHandleSwitch[] = "test-field-trial-handle"; - constexpr char kEnableFeaturesSwitch[] = "test-enable-features"; - constexpr char kDisableFeaturesSwitch[] = "test-disable-features"; - - FieldTrialList field_trial_list(std::make_unique<MockEntropyProvider>()); - - std::unique_ptr<FeatureList> feature_list(new FeatureList); - feature_list->InitializeFromCommandLine("A,B", "C"); - - FieldTrial* trial = FieldTrialList::CreateFieldTrial("Trial1", "Group1"); - feature_list->RegisterFieldTrialOverride( - "MyFeature", FeatureList::OVERRIDE_ENABLE_FEATURE, trial); - - test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitWithFeatureList(std::move(feature_list)); - - FilePath test_file_path = FilePath(FILE_PATH_LITERAL("Program")); - CommandLine command_line = CommandLine(test_file_path); - - FieldTrialList::CopyFieldTrialStateToFlags( - kFieldTrialHandleSwitch, kEnableFeaturesSwitch, kDisableFeaturesSwitch, - &command_line); - EXPECT_TRUE(command_line.HasSwitch(kFieldTrialHandleSwitch)); - - // Explictly specified enabled/disabled features should be specified. - EXPECT_EQ("A,B", command_line.GetSwitchValueASCII(kEnableFeaturesSwitch)); - EXPECT_EQ("C", command_line.GetSwitchValueASCII(kDisableFeaturesSwitch)); -} - -TEST(FieldTrialListTest, InstantiateAllocator) { - test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.Init(); - - FieldTrialList field_trial_list(nullptr); - FieldTrialList::CreateFieldTrial("Trial1", "Group1"); - - FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded(); - void* memory = field_trial_list.field_trial_allocator_->shared_memory(); - size_t used = field_trial_list.field_trial_allocator_->used(); - - // Ensure that the function is idempotent. - FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded(); - void* new_memory = field_trial_list.field_trial_allocator_->shared_memory(); - size_t new_used = field_trial_list.field_trial_allocator_->used(); - EXPECT_EQ(memory, new_memory); - EXPECT_EQ(used, new_used); -} - -TEST(FieldTrialListTest, AddTrialsToAllocator) { - std::string save_string; - SharedMemoryHandle handle; - - // Scoping the first FieldTrialList, as we need another one to test that it - // matches. - { - test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.Init(); - - FieldTrialList field_trial_list(nullptr); - FieldTrialList::CreateFieldTrial("Trial1", "Group1"); - FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded(); - FieldTrialList::AllStatesToString(&save_string, false); - handle = SharedMemory::DuplicateHandle( - field_trial_list.field_trial_allocator_->shared_memory()->handle()); - } - - FieldTrialList field_trial_list2(nullptr); - std::unique_ptr<SharedMemory> shm(new SharedMemory(handle, true)); - // 4 KiB is enough to hold the trials only created for this test. - shm.get()->Map(4 << 10); - FieldTrialList::CreateTrialsFromSharedMemory(std::move(shm)); - std::string check_string; - FieldTrialList::AllStatesToString(&check_string, false); - EXPECT_EQ(save_string, check_string); -} - -TEST(FieldTrialListTest, DoNotAddSimulatedFieldTrialsToAllocator) { - constexpr char kTrialName[] = "trial"; - SharedMemoryHandle handle; - { - test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.Init(); - - // Create a simulated trial and a real trial and call group() on them, which - // should only add the real trial to the field trial allocator. - FieldTrialList field_trial_list(nullptr); - FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded(); - - // This shouldn't add to the allocator. - scoped_refptr<FieldTrial> simulated_trial = - FieldTrial::CreateSimulatedFieldTrial(kTrialName, 100, "Simulated", - 0.95); - simulated_trial->group(); - - // This should add to the allocator. - FieldTrial* real_trial = - FieldTrialList::CreateFieldTrial(kTrialName, "Real"); - real_trial->group(); - - handle = SharedMemory::DuplicateHandle( - field_trial_list.field_trial_allocator_->shared_memory()->handle()); - } - - // Check that there's only one entry in the allocator. - FieldTrialList field_trial_list2(nullptr); - std::unique_ptr<SharedMemory> shm(new SharedMemory(handle, true)); - // 4 KiB is enough to hold the trials only created for this test. - shm.get()->Map(4 << 10); - FieldTrialList::CreateTrialsFromSharedMemory(std::move(shm)); - std::string check_string; - FieldTrialList::AllStatesToString(&check_string, false); - ASSERT_EQ(check_string.find("Simulated"), std::string::npos); -} - -TEST(FieldTrialListTest, AssociateFieldTrialParams) { - test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.Init(); - - std::string trial_name("Trial1"); - std::string group_name("Group1"); - - // Create a field trial with some params. - FieldTrialList field_trial_list(nullptr); - FieldTrialList::CreateFieldTrial(trial_name, group_name); - std::map<std::string, std::string> params; - params["key1"] = "value1"; - params["key2"] = "value2"; - FieldTrialParamAssociator::GetInstance()->AssociateFieldTrialParams( - trial_name, group_name, params); - FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded(); - - // Clear all cached params from the associator. - FieldTrialParamAssociator::GetInstance()->ClearAllCachedParamsForTesting(); - // Check that the params have been cleared from the cache. - std::map<std::string, std::string> cached_params; - FieldTrialParamAssociator::GetInstance()->GetFieldTrialParamsWithoutFallback( - trial_name, group_name, &cached_params); - EXPECT_EQ(0U, cached_params.size()); - - // Check that we fetch the param from shared memory properly. - std::map<std::string, std::string> new_params; - FieldTrialParamAssociator::GetInstance()->GetFieldTrialParams(trial_name, - &new_params); - EXPECT_EQ("value1", new_params["key1"]); - EXPECT_EQ("value2", new_params["key2"]); - EXPECT_EQ(2U, new_params.size()); -} - -TEST(FieldTrialListTest, ClearParamsFromSharedMemory) { - std::string trial_name("Trial1"); - std::string group_name("Group1"); - - SharedMemoryHandle handle; - { - test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.Init(); - - // Create a field trial with some params. - FieldTrialList field_trial_list(nullptr); - FieldTrial* trial = - FieldTrialList::CreateFieldTrial(trial_name, group_name); - std::map<std::string, std::string> params; - params["key1"] = "value1"; - params["key2"] = "value2"; - FieldTrialParamAssociator::GetInstance()->AssociateFieldTrialParams( - trial_name, group_name, params); - FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded(); - - // Clear all params from the associator AND shared memory. The allocated - // segments should be different. - FieldTrial::FieldTrialRef old_ref = trial->ref_; - FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting(); - FieldTrial::FieldTrialRef new_ref = trial->ref_; - EXPECT_NE(old_ref, new_ref); - - // Check that there are no params associated with the field trial anymore. - std::map<std::string, std::string> new_params; - FieldTrialParamAssociator::GetInstance()->GetFieldTrialParams(trial_name, - &new_params); - EXPECT_EQ(0U, new_params.size()); - - // Now duplicate the handle so we can easily check that the trial is still - // in shared memory via AllStatesToString. - handle = SharedMemory::DuplicateHandle( - field_trial_list.field_trial_allocator_->shared_memory()->handle()); - } - - // Check that we have the trial. - FieldTrialList field_trial_list2(nullptr); - std::unique_ptr<SharedMemory> shm(new SharedMemory(handle, true)); - // 4 KiB is enough to hold the trials only created for this test. - shm.get()->Map(4 << 10); - FieldTrialList::CreateTrialsFromSharedMemory(std::move(shm)); - std::string check_string; - FieldTrialList::AllStatesToString(&check_string, false); - EXPECT_EQ("*Trial1/Group1/", check_string); -} - -TEST(FieldTrialListTest, DumpAndFetchFromSharedMemory) { - std::string trial_name("Trial1"); - std::string group_name("Group1"); - - // Create a field trial with some params. - FieldTrialList field_trial_list(nullptr); - FieldTrialList::CreateFieldTrial(trial_name, group_name); - std::map<std::string, std::string> params; - params["key1"] = "value1"; - params["key2"] = "value2"; - FieldTrialParamAssociator::GetInstance()->AssociateFieldTrialParams( - trial_name, group_name, params); - - std::unique_ptr<SharedMemory> shm(new SharedMemory()); - // 4 KiB is enough to hold the trials only created for this test. - shm.get()->CreateAndMapAnonymous(4 << 10); - // We _could_ use PersistentMemoryAllocator, this just has less params. - SharedPersistentMemoryAllocator allocator(std::move(shm), 1, "", false); - - // Dump and subsequently retrieve the field trial to |allocator|. - FieldTrialList::DumpAllFieldTrialsToPersistentAllocator(&allocator); - std::vector<const FieldTrial::FieldTrialEntry*> entries = - FieldTrialList::GetAllFieldTrialsFromPersistentAllocator(allocator); - - // Check that we have the entry we put in. - EXPECT_EQ(1u, entries.size()); - const FieldTrial::FieldTrialEntry* entry = entries[0]; - - // Check that the trial and group names match. - StringPiece shm_trial_name; - StringPiece shm_group_name; - entry->GetTrialAndGroupName(&shm_trial_name, &shm_group_name); - EXPECT_EQ(trial_name, shm_trial_name); - EXPECT_EQ(group_name, shm_group_name); - - // Check that the params match. - std::map<std::string, std::string> shm_params; - entry->GetParams(&shm_params); - EXPECT_EQ(2u, shm_params.size()); - EXPECT_EQ("value1", shm_params["key1"]); - EXPECT_EQ("value2", shm_params["key2"]); -} - -#if !defined(OS_NACL) -TEST(FieldTrialListTest, SerializeSharedMemoryHandleMetadata) { - std::unique_ptr<SharedMemory> shm(new SharedMemory()); - shm->CreateAndMapAnonymous(4 << 10); - - std::string serialized = - FieldTrialList::SerializeSharedMemoryHandleMetadata(shm->handle()); -#if defined(OS_WIN) || defined(OS_FUCHSIA) - SharedMemoryHandle deserialized = - FieldTrialList::DeserializeSharedMemoryHandleMetadata(serialized); -#else - // Use a valid-looking arbitrary number for the file descriptor. It's not - // being used in this unittest, but needs to pass sanity checks in the - // handle's constructor. - SharedMemoryHandle deserialized = - FieldTrialList::DeserializeSharedMemoryHandleMetadata(42, serialized); -#endif - EXPECT_EQ(deserialized.GetGUID(), shm->handle().GetGUID()); - EXPECT_FALSE(deserialized.GetGUID().is_empty()); -} -#endif // !defined(OS_NACL) - -// Verify that the field trial shared memory handle is really read-only, and -// does not allow writable mappings. Test disabled on NaCl, Windows and Fuchsia -// which don't support/implement GetFieldTrialHandle(). For Fuchsia, see -// crbug.com/752368 -#if !defined(OS_NACL) && !defined(OS_WIN) && !defined(OS_FUCHSIA) -TEST(FieldTrialListTest, CheckReadOnlySharedMemoryHandle) { - FieldTrialList field_trial_list(nullptr); - FieldTrialList::CreateFieldTrial("Trial1", "Group1"); - - test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.Init(); - - FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded(); - - SharedMemoryHandle handle = FieldTrialList::GetFieldTrialHandle(); - ASSERT_TRUE(handle.IsValid()); - - ASSERT_TRUE(CheckReadOnlySharedMemoryHandleForTesting(handle)); -} -#endif // !OS_NACL && !OS_WIN && !OS_FUCHSIA - -TEST_F(FieldTrialTest, TestAllParamsToString) { - std::string exptected_output = "t1.g1:p1/v1/p2/v2"; - - // Create study with one group and two params. - std::map<std::string, std::string> params; - params["p1"] = "v1"; - params["p2"] = "v2"; - FieldTrialParamAssociator::GetInstance()->AssociateFieldTrialParams( - "t1", "g1", params); - EXPECT_EQ( - "", FieldTrialList::AllParamsToString(false, &MockEscapeQueryParamValue)); - - scoped_refptr<FieldTrial> trial1 = - CreateFieldTrial("t1", 100, "Default", nullptr); - trial1->AppendGroup("g1", 100); - trial1->group(); - EXPECT_EQ(exptected_output, FieldTrialList::AllParamsToString( - false, &MockEscapeQueryParamValue)); - - // Create study with two groups and params that don't belog to the assigned - // group. This should be in the output. - FieldTrialParamAssociator::GetInstance()->AssociateFieldTrialParams( - "t2", "g2", params); - scoped_refptr<FieldTrial> trial2 = - CreateFieldTrial("t2", 100, "Default", nullptr); - trial2->AppendGroup("g1", 100); - trial2->AppendGroup("g2", 0); - trial2->group(); - EXPECT_EQ(exptected_output, FieldTrialList::AllParamsToString( - false, &MockEscapeQueryParamValue)); -} - -} // namespace base
diff --git a/base/metrics/histogram_base_unittest.cc b/base/metrics/histogram_base_unittest.cc deleted file mode 100644 index e539e5c..0000000 --- a/base/metrics/histogram_base_unittest.cc +++ /dev/null
@@ -1,189 +0,0 @@ -// 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 <vector> - -#include "base/metrics/histogram.h" -#include "base/metrics/histogram_base.h" -#include "base/metrics/sample_vector.h" -#include "base/metrics/sparse_histogram.h" -#include "base/metrics/statistics_recorder.h" -#include "base/pickle.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -class HistogramBaseTest : public testing::Test { - protected: - HistogramBaseTest() { - // Each test will have a clean state (no Histogram / BucketRanges - // registered). - ResetStatisticsRecorder(); - } - - ~HistogramBaseTest() override = default; - - void ResetStatisticsRecorder() { - // It is necessary to fully destruct any existing StatisticsRecorder - // before creating a new one. - statistics_recorder_.reset(); - statistics_recorder_ = StatisticsRecorder::CreateTemporaryForTesting(); - } - - private: - std::unique_ptr<StatisticsRecorder> statistics_recorder_; - - DISALLOW_COPY_AND_ASSIGN(HistogramBaseTest); -}; - -TEST_F(HistogramBaseTest, DeserializeHistogram) { - HistogramBase* histogram = Histogram::FactoryGet( - "TestHistogram", 1, 1000, 10, - (HistogramBase::kUmaTargetedHistogramFlag | - HistogramBase::kIPCSerializationSourceFlag)); - - Pickle pickle; - histogram->SerializeInfo(&pickle); - - PickleIterator iter(pickle); - HistogramBase* deserialized = DeserializeHistogramInfo(&iter); - EXPECT_EQ(histogram, deserialized); - - ResetStatisticsRecorder(); - - PickleIterator iter2(pickle); - deserialized = DeserializeHistogramInfo(&iter2); - EXPECT_TRUE(deserialized); - EXPECT_NE(histogram, deserialized); - EXPECT_EQ("TestHistogram", StringPiece(deserialized->histogram_name())); - EXPECT_TRUE(deserialized->HasConstructionArguments(1, 1000, 10)); - - // kIPCSerializationSourceFlag will be cleared. - EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, deserialized->flags()); -} - -TEST_F(HistogramBaseTest, DeserializeLinearHistogram) { - HistogramBase* histogram = LinearHistogram::FactoryGet( - "TestHistogram", 1, 1000, 10, - HistogramBase::kIPCSerializationSourceFlag); - - Pickle pickle; - histogram->SerializeInfo(&pickle); - - PickleIterator iter(pickle); - HistogramBase* deserialized = DeserializeHistogramInfo(&iter); - EXPECT_EQ(histogram, deserialized); - - ResetStatisticsRecorder(); - - PickleIterator iter2(pickle); - deserialized = DeserializeHistogramInfo(&iter2); - EXPECT_TRUE(deserialized); - EXPECT_NE(histogram, deserialized); - EXPECT_EQ("TestHistogram", StringPiece(deserialized->histogram_name())); - EXPECT_TRUE(deserialized->HasConstructionArguments(1, 1000, 10)); - EXPECT_EQ(0, deserialized->flags()); -} - -TEST_F(HistogramBaseTest, DeserializeBooleanHistogram) { - HistogramBase* histogram = BooleanHistogram::FactoryGet( - "TestHistogram", HistogramBase::kIPCSerializationSourceFlag); - - Pickle pickle; - histogram->SerializeInfo(&pickle); - - PickleIterator iter(pickle); - HistogramBase* deserialized = DeserializeHistogramInfo(&iter); - EXPECT_EQ(histogram, deserialized); - - ResetStatisticsRecorder(); - - PickleIterator iter2(pickle); - deserialized = DeserializeHistogramInfo(&iter2); - EXPECT_TRUE(deserialized); - EXPECT_NE(histogram, deserialized); - EXPECT_EQ("TestHistogram", StringPiece(deserialized->histogram_name())); - EXPECT_TRUE(deserialized->HasConstructionArguments(1, 2, 3)); - EXPECT_EQ(0, deserialized->flags()); -} - -TEST_F(HistogramBaseTest, DeserializeCustomHistogram) { - std::vector<HistogramBase::Sample> ranges; - ranges.push_back(13); - ranges.push_back(5); - ranges.push_back(9); - - HistogramBase* histogram = CustomHistogram::FactoryGet( - "TestHistogram", ranges, HistogramBase::kIPCSerializationSourceFlag); - - Pickle pickle; - histogram->SerializeInfo(&pickle); - - PickleIterator iter(pickle); - HistogramBase* deserialized = DeserializeHistogramInfo(&iter); - EXPECT_EQ(histogram, deserialized); - - ResetStatisticsRecorder(); - - PickleIterator iter2(pickle); - deserialized = DeserializeHistogramInfo(&iter2); - EXPECT_TRUE(deserialized); - EXPECT_NE(histogram, deserialized); - EXPECT_EQ("TestHistogram", StringPiece(deserialized->histogram_name())); - EXPECT_TRUE(deserialized->HasConstructionArguments(5, 13, 4)); - EXPECT_EQ(0, deserialized->flags()); -} - -TEST_F(HistogramBaseTest, DeserializeSparseHistogram) { - HistogramBase* histogram = SparseHistogram::FactoryGet( - "TestHistogram", HistogramBase::kIPCSerializationSourceFlag); - - Pickle pickle; - histogram->SerializeInfo(&pickle); - - PickleIterator iter(pickle); - HistogramBase* deserialized = DeserializeHistogramInfo(&iter); - EXPECT_EQ(histogram, deserialized); - - ResetStatisticsRecorder(); - - PickleIterator iter2(pickle); - deserialized = DeserializeHistogramInfo(&iter2); - EXPECT_TRUE(deserialized); - EXPECT_NE(histogram, deserialized); - EXPECT_EQ("TestHistogram", StringPiece(deserialized->histogram_name())); - EXPECT_EQ(0, deserialized->flags()); -} - -TEST_F(HistogramBaseTest, AddKilo) { - HistogramBase* histogram = - LinearHistogram::FactoryGet("TestAddKiloHistogram", 1, 1000, 100, 0); - - histogram->AddKilo(100, 1000); - histogram->AddKilo(200, 2000); - histogram->AddKilo(300, 1500); - - std::unique_ptr<HistogramSamples> samples = histogram->SnapshotSamples(); - EXPECT_EQ(1, samples->GetCount(100)); - EXPECT_EQ(2, samples->GetCount(200)); - EXPECT_LE(1, samples->GetCount(300)); - EXPECT_GE(2, samples->GetCount(300)); -} - -TEST_F(HistogramBaseTest, AddKiB) { - HistogramBase* histogram = - LinearHistogram::FactoryGet("TestAddKiBHistogram", 1, 1000, 100, 0); - - histogram->AddKiB(100, 1024); - histogram->AddKiB(200, 2048); - histogram->AddKiB(300, 1536); - - std::unique_ptr<HistogramSamples> samples = histogram->SnapshotSamples(); - EXPECT_EQ(1, samples->GetCount(100)); - EXPECT_EQ(2, samples->GetCount(200)); - EXPECT_LE(1, samples->GetCount(300)); - EXPECT_GE(2, samples->GetCount(300)); -} - -} // namespace base
diff --git a/base/metrics/histogram_delta_serialization_unittest.cc b/base/metrics/histogram_delta_serialization_unittest.cc deleted file mode 100644 index 719bc70..0000000 --- a/base/metrics/histogram_delta_serialization_unittest.cc +++ /dev/null
@@ -1,55 +0,0 @@ -// 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/metrics/histogram_delta_serialization.h" - -#include <vector> - -#include "base/metrics/histogram.h" -#include "base/metrics/histogram_base.h" -#include "base/metrics/statistics_recorder.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(HistogramDeltaSerializationTest, DeserializeHistogramAndAddSamples) { - std::unique_ptr<StatisticsRecorder> statistic_recorder( - StatisticsRecorder::CreateTemporaryForTesting()); - HistogramDeltaSerialization serializer("HistogramDeltaSerializationTest"); - std::vector<std::string> deltas; - // Nothing was changed yet. - serializer.PrepareAndSerializeDeltas(&deltas, true); - EXPECT_TRUE(deltas.empty()); - - HistogramBase* histogram = Histogram::FactoryGet( - "TestHistogram", 1, 1000, 10, HistogramBase::kIPCSerializationSourceFlag); - histogram->Add(1); - histogram->Add(10); - histogram->Add(100); - histogram->Add(1000); - - serializer.PrepareAndSerializeDeltas(&deltas, true); - EXPECT_FALSE(deltas.empty()); - - HistogramDeltaSerialization::DeserializeAndAddSamples(deltas); - - // The histogram has kIPCSerializationSourceFlag. So samples will be ignored. - std::unique_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples()); - EXPECT_EQ(1, snapshot->GetCount(1)); - EXPECT_EQ(1, snapshot->GetCount(10)); - EXPECT_EQ(1, snapshot->GetCount(100)); - EXPECT_EQ(1, snapshot->GetCount(1000)); - - // Clear kIPCSerializationSourceFlag to emulate multi-process usage. - histogram->ClearFlags(HistogramBase::kIPCSerializationSourceFlag); - HistogramDeltaSerialization::DeserializeAndAddSamples(deltas); - - std::unique_ptr<HistogramSamples> snapshot2(histogram->SnapshotSamples()); - EXPECT_EQ(2, snapshot2->GetCount(1)); - EXPECT_EQ(2, snapshot2->GetCount(10)); - EXPECT_EQ(2, snapshot2->GetCount(100)); - EXPECT_EQ(2, snapshot2->GetCount(1000)); -} - -} // namespace base
diff --git a/base/metrics/histogram_functions_unittest.cc b/base/metrics/histogram_functions_unittest.cc deleted file mode 100644 index 3720674..0000000 --- a/base/metrics/histogram_functions_unittest.cc +++ /dev/null
@@ -1,127 +0,0 @@ -// 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/metrics/histogram_functions.h" - -#include "base/metrics/histogram_macros.h" -#include "base/test/histogram_tester.h" -#include "base/time/time.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -enum UmaHistogramTestingEnum { - UMA_HISTOGRAM_TESTING_ENUM_FIRST, - UMA_HISTOGRAM_TESTING_ENUM_SECOND, - UMA_HISTOGRAM_TESTING_ENUM_THIRD -}; - -TEST(HistogramFunctionsTest, ExactLinear) { - std::string histogram("Testing.UMA.HistogramExactLinear"); - HistogramTester tester; - UmaHistogramExactLinear(histogram, 10, 100); - tester.ExpectUniqueSample(histogram, 10, 1); - UmaHistogramExactLinear(histogram, 20, 100); - UmaHistogramExactLinear(histogram, 10, 100); - tester.ExpectBucketCount(histogram, 10, 2); - tester.ExpectBucketCount(histogram, 20, 1); - tester.ExpectTotalCount(histogram, 3); - // Test linear buckets overflow. - UmaHistogramExactLinear(histogram, 200, 100); - tester.ExpectBucketCount(histogram, 101, 1); - tester.ExpectTotalCount(histogram, 4); - // Test linear buckets underflow. - UmaHistogramExactLinear(histogram, 0, 100); - tester.ExpectBucketCount(histogram, 0, 1); - tester.ExpectTotalCount(histogram, 5); -} - -TEST(HistogramFunctionsTest, Enumeration) { - std::string histogram("Testing.UMA.HistogramEnumeration"); - HistogramTester tester; - UmaHistogramEnumeration(histogram, UMA_HISTOGRAM_TESTING_ENUM_FIRST, - UMA_HISTOGRAM_TESTING_ENUM_THIRD); - tester.ExpectUniqueSample(histogram, UMA_HISTOGRAM_TESTING_ENUM_FIRST, 1); - - // Verify the overflow & underflow bucket exists. - UMA_HISTOGRAM_ENUMERATION( - histogram, static_cast<int>(UMA_HISTOGRAM_TESTING_ENUM_THIRD) + 10, - static_cast<int>(UMA_HISTOGRAM_TESTING_ENUM_THIRD)); - tester.ExpectBucketCount( - histogram, static_cast<int>(UMA_HISTOGRAM_TESTING_ENUM_THIRD) + 1, 1); - tester.ExpectTotalCount(histogram, 2); -} - -TEST(HistogramFunctionsTest, Boolean) { - std::string histogram("Testing.UMA.HistogramBoolean"); - HistogramTester tester; - UmaHistogramBoolean(histogram, true); - tester.ExpectUniqueSample(histogram, 1, 1); - UmaHistogramBoolean(histogram, false); - tester.ExpectBucketCount(histogram, 0, 1); - tester.ExpectTotalCount(histogram, 2); -} - -TEST(HistogramFunctionsTest, Percentage) { - std::string histogram("Testing.UMA.HistogramPercentage"); - HistogramTester tester; - UmaHistogramPercentage(histogram, 50); - tester.ExpectUniqueSample(histogram, 50, 1); - // Test overflows. - UmaHistogramPercentage(histogram, 110); - tester.ExpectBucketCount(histogram, 101, 1); - tester.ExpectTotalCount(histogram, 2); -} - -TEST(HistogramFunctionsTest, Counts) { - std::string histogram("Testing.UMA.HistogramCount.Custom"); - HistogramTester tester; - UmaHistogramCustomCounts(histogram, 10, 1, 100, 10); - tester.ExpectUniqueSample(histogram, 10, 1); - UmaHistogramCustomCounts(histogram, 20, 1, 100, 10); - UmaHistogramCustomCounts(histogram, 20, 1, 100, 10); - UmaHistogramCustomCounts(histogram, 20, 1, 100, 10); - tester.ExpectBucketCount(histogram, 20, 3); - tester.ExpectTotalCount(histogram, 4); - UmaHistogramCustomCounts(histogram, 110, 1, 100, 10); - tester.ExpectBucketCount(histogram, 101, 1); - tester.ExpectTotalCount(histogram, 5); -} - -TEST(HistogramFunctionsTest, Times) { - std::string histogram("Testing.UMA.HistogramTimes"); - HistogramTester tester; - UmaHistogramTimes(histogram, TimeDelta::FromSeconds(1)); - tester.ExpectTimeBucketCount(histogram, TimeDelta::FromSeconds(1), 1); - tester.ExpectTotalCount(histogram, 1); - UmaHistogramTimes(histogram, TimeDelta::FromSeconds(9)); - tester.ExpectTimeBucketCount(histogram, TimeDelta::FromSeconds(9), 1); - tester.ExpectTotalCount(histogram, 2); - UmaHistogramTimes(histogram, TimeDelta::FromSeconds(10)); // Overflows - tester.ExpectTimeBucketCount(histogram, TimeDelta::FromSeconds(10), 1); - UmaHistogramTimes(histogram, TimeDelta::FromSeconds(20)); // Overflows. - // Check the value by picking any overflow time. - tester.ExpectTimeBucketCount(histogram, TimeDelta::FromSeconds(11), 2); - tester.ExpectTotalCount(histogram, 4); -} - -TEST(HistogramFunctionsTest, Sparse_SupportsLargeRange) { - std::string histogram("Testing.UMA.HistogramSparse"); - HistogramTester tester; - UmaHistogramSparse(histogram, 0); - UmaHistogramSparse(histogram, 123456789); - UmaHistogramSparse(histogram, 123456789); - EXPECT_THAT(tester.GetAllSamples(histogram), - testing::ElementsAre(Bucket(0, 1), Bucket(123456789, 2))); -} - -TEST(HistogramFunctionsTest, Sparse_SupportsNegativeValues) { - std::string histogram("Testing.UMA.HistogramSparse"); - HistogramTester tester; - UmaHistogramSparse(histogram, -1); - tester.ExpectUniqueSample(histogram, -1, 1); -} - -} // namespace base.
diff --git a/base/metrics/histogram_macros_unittest.cc b/base/metrics/histogram_macros_unittest.cc deleted file mode 100644 index 3c592b0..0000000 --- a/base/metrics/histogram_macros_unittest.cc +++ /dev/null
@@ -1,57 +0,0 @@ -// 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/metrics/histogram_macros.h" -#include "base/time/time.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(ScopedHistogramTimer, TwoTimersOneScope) { - SCOPED_UMA_HISTOGRAM_TIMER("TestTimer0"); - SCOPED_UMA_HISTOGRAM_TIMER("TestTimer1"); - SCOPED_UMA_HISTOGRAM_LONG_TIMER("TestLongTimer0"); - SCOPED_UMA_HISTOGRAM_LONG_TIMER("TestLongTimer1"); -} - -// Compile tests for UMA_HISTOGRAM_ENUMERATION with the three different types it -// accepts: -// - integral types -// - unscoped enums -// - scoped enums -TEST(HistogramMacro, IntegralPsuedoEnumeration) { - UMA_HISTOGRAM_ENUMERATION("Test.FauxEnumeration", 1, 10000); -} - -TEST(HistogramMacro, UnscopedEnumeration) { - enum TestEnum : char { - FIRST_VALUE, - SECOND_VALUE, - THIRD_VALUE, - MAX_ENTRIES, - }; - UMA_HISTOGRAM_ENUMERATION("Test.UnscopedEnumeration", SECOND_VALUE, - MAX_ENTRIES); -} - -TEST(HistogramMacro, ScopedEnumeration) { - enum class TestEnum { - FIRST_VALUE, - SECOND_VALUE, - THIRD_VALUE, - kMaxValue = THIRD_VALUE, - }; - UMA_HISTOGRAM_ENUMERATION("Test.ScopedEnumeration", TestEnum::FIRST_VALUE); - - enum class TestEnum2 { - FIRST_VALUE, - SECOND_VALUE, - THIRD_VALUE, - MAX_ENTRIES, - }; - UMA_HISTOGRAM_ENUMERATION("Test.ScopedEnumeration2", TestEnum2::SECOND_VALUE, - TestEnum2::MAX_ENTRIES); -} - -} // namespace base
diff --git a/base/metrics/histogram_samples_unittest.cc b/base/metrics/histogram_samples_unittest.cc deleted file mode 100644 index 74c743b..0000000 --- a/base/metrics/histogram_samples_unittest.cc +++ /dev/null
@@ -1,84 +0,0 @@ -// Copyright (c) 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/metrics/histogram_samples.h" - -#include <limits> - -#include "base/test/gtest_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -using SingleSample = HistogramSamples::SingleSample; -using AtomicSingleSample = HistogramSamples::AtomicSingleSample; - -TEST(SingleSampleTest, Load) { - AtomicSingleSample sample; - ASSERT_TRUE(sample.Accumulate(9, 1)); - - SingleSample s = sample.Load(); - EXPECT_EQ(9U, s.bucket); - EXPECT_EQ(1U, s.count); - - s = sample.Load(); - EXPECT_EQ(9U, s.bucket); - EXPECT_EQ(1U, s.count); -} - -TEST(SingleSampleTest, Extract) { - AtomicSingleSample sample; - ASSERT_TRUE(sample.Accumulate(9, 1)); - - SingleSample s = sample.Extract(/*disable=*/false); - EXPECT_EQ(9U, s.bucket); - EXPECT_EQ(1U, s.count); - - s = sample.Extract(/*disable=*/false); - EXPECT_EQ(0U, s.bucket); - EXPECT_EQ(0U, s.count); -} - -TEST(SingleSampleTest, Disable) { - AtomicSingleSample sample; - EXPECT_EQ(0U, sample.Extract(/*disable=*/false).count); - EXPECT_FALSE(sample.IsDisabled()); - - ASSERT_TRUE(sample.Accumulate(9, 1)); - EXPECT_EQ(1U, sample.Extract(/*disable=*/true).count); - EXPECT_TRUE(sample.IsDisabled()); - - ASSERT_FALSE(sample.Accumulate(9, 1)); - EXPECT_EQ(0U, sample.Extract(/*disable=*/false).count); - EXPECT_FALSE(sample.IsDisabled()); -} - -TEST(SingleSampleTest, Accumulate) { - AtomicSingleSample sample; - - ASSERT_TRUE(sample.Accumulate(9, 1)); - ASSERT_TRUE(sample.Accumulate(9, 2)); - ASSERT_TRUE(sample.Accumulate(9, 4)); - EXPECT_EQ(7U, sample.Extract(/*disable=*/false).count); - - ASSERT_TRUE(sample.Accumulate(9, 4)); - ASSERT_TRUE(sample.Accumulate(9, -2)); - ASSERT_TRUE(sample.Accumulate(9, 1)); - EXPECT_EQ(3U, sample.Extract(/*disable=*/false).count); -} - -TEST(SingleSampleTest, Overflow) { - AtomicSingleSample sample; - - ASSERT_TRUE(sample.Accumulate(9, 1)); - ASSERT_FALSE(sample.Accumulate(9, -2)); - EXPECT_EQ(1U, sample.Extract(/*disable=*/false).count); - - ASSERT_TRUE(sample.Accumulate(9, std::numeric_limits<uint16_t>::max())); - ASSERT_FALSE(sample.Accumulate(9, 1)); - EXPECT_EQ(std::numeric_limits<uint16_t>::max(), - sample.Extract(/*disable=*/false).count); -} - -} // namespace base
diff --git a/base/metrics/histogram_snapshot_manager_unittest.cc b/base/metrics/histogram_snapshot_manager_unittest.cc deleted file mode 100644 index 1e2c599..0000000 --- a/base/metrics/histogram_snapshot_manager_unittest.cc +++ /dev/null
@@ -1,116 +0,0 @@ -// 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/metrics/histogram_snapshot_manager.h" - -#include <string> -#include <vector> - -#include "base/macros.h" -#include "base/metrics/histogram_delta_serialization.h" -#include "base/metrics/histogram_macros.h" -#include "base/metrics/sample_vector.h" -#include "base/metrics/statistics_recorder.h" -#include "base/stl_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -class HistogramFlattenerDeltaRecorder : public HistogramFlattener { - public: - HistogramFlattenerDeltaRecorder() = default; - - void RecordDelta(const HistogramBase& histogram, - const HistogramSamples& snapshot) override { - recorded_delta_histogram_names_.push_back(histogram.histogram_name()); - // Use CHECK instead of ASSERT to get full stack-trace and thus origin. - CHECK(!ContainsKey(recorded_delta_histogram_sum_, - histogram.histogram_name())); - // Keep pointer to snapshot for testing. This really isn't ideal but the - // snapshot-manager keeps the snapshot alive until it's "forgotten". - recorded_delta_histogram_sum_[histogram.histogram_name()] = snapshot.sum(); - } - - void Reset() { - recorded_delta_histogram_names_.clear(); - recorded_delta_histogram_sum_.clear(); - } - - std::vector<std::string> GetRecordedDeltaHistogramNames() { - return recorded_delta_histogram_names_; - } - - int64_t GetRecordedDeltaHistogramSum(const std::string& name) { - EXPECT_TRUE(ContainsKey(recorded_delta_histogram_sum_, name)); - return recorded_delta_histogram_sum_[name]; - } - - private: - std::vector<std::string> recorded_delta_histogram_names_; - std::map<std::string, int64_t> recorded_delta_histogram_sum_; - - DISALLOW_COPY_AND_ASSIGN(HistogramFlattenerDeltaRecorder); -}; - -class HistogramSnapshotManagerTest : public testing::Test { - protected: - HistogramSnapshotManagerTest() - : statistics_recorder_(StatisticsRecorder::CreateTemporaryForTesting()), - histogram_snapshot_manager_(&histogram_flattener_delta_recorder_) {} - - ~HistogramSnapshotManagerTest() override = default; - - std::unique_ptr<StatisticsRecorder> statistics_recorder_; - HistogramFlattenerDeltaRecorder histogram_flattener_delta_recorder_; - HistogramSnapshotManager histogram_snapshot_manager_; -}; - -TEST_F(HistogramSnapshotManagerTest, PrepareDeltasNoFlagsFilter) { - // kNoFlags filter should record all histograms. - UMA_HISTOGRAM_ENUMERATION("UmaHistogram", 1, 4); - UMA_STABILITY_HISTOGRAM_ENUMERATION("UmaStabilityHistogram", 1, 2); - - StatisticsRecorder::PrepareDeltas(false, HistogramBase::kNoFlags, - HistogramBase::kNoFlags, - &histogram_snapshot_manager_); - - const std::vector<std::string>& histograms = - histogram_flattener_delta_recorder_.GetRecordedDeltaHistogramNames(); - EXPECT_EQ(2U, histograms.size()); - EXPECT_EQ("UmaHistogram", histograms[0]); - EXPECT_EQ("UmaStabilityHistogram", histograms[1]); -} - -TEST_F(HistogramSnapshotManagerTest, PrepareDeltasUmaHistogramFlagFilter) { - // Note that kUmaStabilityHistogramFlag includes kUmaTargetedHistogramFlag. - UMA_HISTOGRAM_ENUMERATION("UmaHistogram", 1, 4); - UMA_STABILITY_HISTOGRAM_ENUMERATION("UmaStabilityHistogram", 1, 2); - - StatisticsRecorder::PrepareDeltas(false, HistogramBase::kNoFlags, - HistogramBase::kUmaTargetedHistogramFlag, - &histogram_snapshot_manager_); - - const std::vector<std::string>& histograms = - histogram_flattener_delta_recorder_.GetRecordedDeltaHistogramNames(); - EXPECT_EQ(2U, histograms.size()); - EXPECT_EQ("UmaHistogram", histograms[0]); - EXPECT_EQ("UmaStabilityHistogram", histograms[1]); -} - -TEST_F(HistogramSnapshotManagerTest, - PrepareDeltasUmaStabilityHistogramFlagFilter) { - UMA_HISTOGRAM_ENUMERATION("UmaHistogram", 1, 4); - UMA_STABILITY_HISTOGRAM_ENUMERATION("UmaStabilityHistogram", 1, 2); - - StatisticsRecorder::PrepareDeltas(false, HistogramBase::kNoFlags, - HistogramBase::kUmaStabilityHistogramFlag, - &histogram_snapshot_manager_); - - const std::vector<std::string>& histograms = - histogram_flattener_delta_recorder_.GetRecordedDeltaHistogramNames(); - EXPECT_EQ(1U, histograms.size()); - EXPECT_EQ("UmaStabilityHistogram", histograms[0]); -} - -} // namespace base
diff --git a/base/metrics/histogram_unittest.cc b/base/metrics/histogram_unittest.cc deleted file mode 100644 index b819393..0000000 --- a/base/metrics/histogram_unittest.cc +++ /dev/null
@@ -1,841 +0,0 @@ -// 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/metrics/histogram.h" - -#include <limits.h> -#include <stddef.h> -#include <stdint.h> - -#include <climits> -#include <memory> -#include <string> -#include <vector> - -#include "base/logging.h" -#include "base/metrics/bucket_ranges.h" -#include "base/metrics/dummy_histogram.h" -#include "base/metrics/histogram_macros.h" -#include "base/metrics/metrics_hashes.h" -#include "base/metrics/persistent_histogram_allocator.h" -#include "base/metrics/persistent_memory_allocator.h" -#include "base/metrics/record_histogram_checker.h" -#include "base/metrics/sample_vector.h" -#include "base/metrics/statistics_recorder.h" -#include "base/pickle.h" -#include "base/strings/stringprintf.h" -#include "base/test/gtest_util.h" -#include "base/time/time.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -const char kExpiredHistogramName[] = "ExpiredHistogram"; - -// Test implementation of RecordHistogramChecker interface. -class TestRecordHistogramChecker : public RecordHistogramChecker { - public: - ~TestRecordHistogramChecker() override = default; - - // RecordHistogramChecker: - bool ShouldRecord(uint64_t histogram_hash) const override { - return histogram_hash != HashMetricName(kExpiredHistogramName); - } -}; - -} // namespace - -// Test parameter indicates if a persistent memory allocator should be used -// for histogram allocation. False will allocate histograms from the process -// heap. -class HistogramTest : public testing::TestWithParam<bool> { - protected: - const int32_t kAllocatorMemorySize = 8 << 20; // 8 MiB - - HistogramTest() : use_persistent_histogram_allocator_(GetParam()) {} - - void SetUp() override { - if (use_persistent_histogram_allocator_) - CreatePersistentHistogramAllocator(); - - // Each test will have a clean state (no Histogram / BucketRanges - // registered). - InitializeStatisticsRecorder(); - } - - void TearDown() override { - if (allocator_) { - ASSERT_FALSE(allocator_->IsFull()); - ASSERT_FALSE(allocator_->IsCorrupt()); - } - UninitializeStatisticsRecorder(); - DestroyPersistentHistogramAllocator(); - } - - void InitializeStatisticsRecorder() { - DCHECK(!statistics_recorder_); - statistics_recorder_ = StatisticsRecorder::CreateTemporaryForTesting(); - auto record_checker = std::make_unique<TestRecordHistogramChecker>(); - StatisticsRecorder::SetRecordChecker(std::move(record_checker)); - } - - void UninitializeStatisticsRecorder() { - statistics_recorder_.reset(); - } - - void CreatePersistentHistogramAllocator() { - GlobalHistogramAllocator::CreateWithLocalMemory( - kAllocatorMemorySize, 0, "HistogramAllocatorTest"); - allocator_ = GlobalHistogramAllocator::Get()->memory_allocator(); - } - - void DestroyPersistentHistogramAllocator() { - allocator_ = nullptr; - GlobalHistogramAllocator::ReleaseForTesting(); - } - - const bool use_persistent_histogram_allocator_; - - std::unique_ptr<StatisticsRecorder> statistics_recorder_; - std::unique_ptr<char[]> allocator_memory_; - PersistentMemoryAllocator* allocator_ = nullptr; - - private: - DISALLOW_COPY_AND_ASSIGN(HistogramTest); -}; - -// Run all HistogramTest cases with both heap and persistent memory. -INSTANTIATE_TEST_CASE_P(HeapAndPersistent, HistogramTest, testing::Bool()); - - -// Check for basic syntax and use. -TEST_P(HistogramTest, BasicTest) { - // Try basic construction - HistogramBase* histogram = Histogram::FactoryGet( - "TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags); - EXPECT_TRUE(histogram); - - HistogramBase* linear_histogram = LinearHistogram::FactoryGet( - "TestLinearHistogram", 1, 1000, 10, HistogramBase::kNoFlags); - EXPECT_TRUE(linear_histogram); - - std::vector<int> custom_ranges; - custom_ranges.push_back(1); - custom_ranges.push_back(5); - HistogramBase* custom_histogram = CustomHistogram::FactoryGet( - "TestCustomHistogram", custom_ranges, HistogramBase::kNoFlags); - EXPECT_TRUE(custom_histogram); - - // Macros that create histograms have an internal static variable which will - // continue to point to those from the very first run of this method even - // during subsequent runs. - static bool already_run = false; - if (already_run) - return; - already_run = true; - - // Use standard macros (but with fixed samples) - LOCAL_HISTOGRAM_TIMES("Test2Histogram", TimeDelta::FromDays(1)); - LOCAL_HISTOGRAM_COUNTS("Test3Histogram", 30); - - LOCAL_HISTOGRAM_ENUMERATION("Test6Histogram", 129, 130); -} - -// Check that the macro correctly matches histograms by name and records their -// data together. -TEST_P(HistogramTest, NameMatchTest) { - // Macros that create histograms have an internal static variable which will - // continue to point to those from the very first run of this method even - // during subsequent runs. - static bool already_run = false; - if (already_run) - return; - already_run = true; - - LOCAL_HISTOGRAM_PERCENTAGE("DuplicatedHistogram", 10); - LOCAL_HISTOGRAM_PERCENTAGE("DuplicatedHistogram", 10); - HistogramBase* histogram = LinearHistogram::FactoryGet( - "DuplicatedHistogram", 1, 101, 102, HistogramBase::kNoFlags); - - std::unique_ptr<HistogramSamples> samples = histogram->SnapshotSamples(); - EXPECT_EQ(2, samples->TotalCount()); - EXPECT_EQ(2, samples->GetCount(10)); -} - -// Check that delta calculations work correctly. -TEST_P(HistogramTest, DeltaTest) { - HistogramBase* histogram = - Histogram::FactoryGet("DeltaHistogram", 1, 64, 8, - HistogramBase::kNoFlags); - histogram->Add(1); - histogram->Add(10); - histogram->Add(50); - - std::unique_ptr<HistogramSamples> samples = histogram->SnapshotDelta(); - EXPECT_EQ(3, samples->TotalCount()); - EXPECT_EQ(1, samples->GetCount(1)); - EXPECT_EQ(1, samples->GetCount(10)); - EXPECT_EQ(1, samples->GetCount(50)); - EXPECT_EQ(samples->TotalCount(), samples->redundant_count()); - - samples = histogram->SnapshotDelta(); - EXPECT_EQ(0, samples->TotalCount()); - - histogram->Add(10); - histogram->Add(10); - samples = histogram->SnapshotDelta(); - EXPECT_EQ(2, samples->TotalCount()); - EXPECT_EQ(2, samples->GetCount(10)); - - samples = histogram->SnapshotDelta(); - EXPECT_EQ(0, samples->TotalCount()); -} - -// Check that final-delta calculations work correctly. -TEST_P(HistogramTest, FinalDeltaTest) { - HistogramBase* histogram = - Histogram::FactoryGet("FinalDeltaHistogram", 1, 64, 8, - HistogramBase::kNoFlags); - histogram->Add(1); - histogram->Add(10); - histogram->Add(50); - - std::unique_ptr<HistogramSamples> samples = histogram->SnapshotDelta(); - EXPECT_EQ(3, samples->TotalCount()); - EXPECT_EQ(1, samples->GetCount(1)); - EXPECT_EQ(1, samples->GetCount(10)); - EXPECT_EQ(1, samples->GetCount(50)); - EXPECT_EQ(samples->TotalCount(), samples->redundant_count()); - - histogram->Add(2); - histogram->Add(50); - - samples = histogram->SnapshotFinalDelta(); - EXPECT_EQ(2, samples->TotalCount()); - EXPECT_EQ(1, samples->GetCount(2)); - EXPECT_EQ(1, samples->GetCount(50)); - EXPECT_EQ(samples->TotalCount(), samples->redundant_count()); -} - -TEST_P(HistogramTest, ExponentialRangesTest) { - // Check that we got a nice exponential when there was enough room. - BucketRanges ranges(9); - Histogram::InitializeBucketRanges(1, 64, &ranges); - EXPECT_EQ(0, ranges.range(0)); - int power_of_2 = 1; - for (int i = 1; i < 8; i++) { - EXPECT_EQ(power_of_2, ranges.range(i)); - power_of_2 *= 2; - } - EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges.range(8)); - - // Check the corresponding Histogram will use the correct ranges. - Histogram* histogram = static_cast<Histogram*>( - Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags)); - EXPECT_TRUE(ranges.Equals(histogram->bucket_ranges())); - - // When bucket count is limited, exponential ranges will partially look like - // linear. - BucketRanges ranges2(16); - Histogram::InitializeBucketRanges(1, 32, &ranges2); - - EXPECT_EQ(0, ranges2.range(0)); - EXPECT_EQ(1, ranges2.range(1)); - EXPECT_EQ(2, ranges2.range(2)); - EXPECT_EQ(3, ranges2.range(3)); - EXPECT_EQ(4, ranges2.range(4)); - EXPECT_EQ(5, ranges2.range(5)); - EXPECT_EQ(6, ranges2.range(6)); - EXPECT_EQ(7, ranges2.range(7)); - EXPECT_EQ(9, ranges2.range(8)); - EXPECT_EQ(11, ranges2.range(9)); - EXPECT_EQ(14, ranges2.range(10)); - EXPECT_EQ(17, ranges2.range(11)); - EXPECT_EQ(21, ranges2.range(12)); - EXPECT_EQ(26, ranges2.range(13)); - EXPECT_EQ(32, ranges2.range(14)); - EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges2.range(15)); - - // Check the corresponding Histogram will use the correct ranges. - Histogram* histogram2 = static_cast<Histogram*>( - Histogram::FactoryGet("Histogram2", 1, 32, 15, HistogramBase::kNoFlags)); - EXPECT_TRUE(ranges2.Equals(histogram2->bucket_ranges())); -} - -TEST_P(HistogramTest, LinearRangesTest) { - BucketRanges ranges(9); - LinearHistogram::InitializeBucketRanges(1, 7, &ranges); - // Gets a nice linear set of bucket ranges. - for (int i = 0; i < 8; i++) - EXPECT_EQ(i, ranges.range(i)); - EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges.range(8)); - - // The correspoding LinearHistogram should use the correct ranges. - Histogram* histogram = static_cast<Histogram*>( - LinearHistogram::FactoryGet("Linear", 1, 7, 8, HistogramBase::kNoFlags)); - EXPECT_TRUE(ranges.Equals(histogram->bucket_ranges())); - - // Linear ranges are not divisible. - BucketRanges ranges2(6); - LinearHistogram::InitializeBucketRanges(1, 6, &ranges2); - EXPECT_EQ(0, ranges2.range(0)); - EXPECT_EQ(1, ranges2.range(1)); - EXPECT_EQ(3, ranges2.range(2)); - EXPECT_EQ(4, ranges2.range(3)); - EXPECT_EQ(6, ranges2.range(4)); - EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges2.range(5)); - // The correspoding LinearHistogram should use the correct ranges. - Histogram* histogram2 = static_cast<Histogram*>( - LinearHistogram::FactoryGet("Linear2", 1, 6, 5, HistogramBase::kNoFlags)); - EXPECT_TRUE(ranges2.Equals(histogram2->bucket_ranges())); -} - -TEST_P(HistogramTest, ArrayToCustomEnumRangesTest) { - const HistogramBase::Sample ranges[3] = {5, 10, 20}; - std::vector<HistogramBase::Sample> ranges_vec = - CustomHistogram::ArrayToCustomEnumRanges(ranges); - ASSERT_EQ(6u, ranges_vec.size()); - EXPECT_EQ(5, ranges_vec[0]); - EXPECT_EQ(6, ranges_vec[1]); - EXPECT_EQ(10, ranges_vec[2]); - EXPECT_EQ(11, ranges_vec[3]); - EXPECT_EQ(20, ranges_vec[4]); - EXPECT_EQ(21, ranges_vec[5]); -} - -TEST_P(HistogramTest, CustomHistogramTest) { - // A well prepared custom ranges. - std::vector<HistogramBase::Sample> custom_ranges; - custom_ranges.push_back(1); - custom_ranges.push_back(2); - - Histogram* histogram = static_cast<Histogram*>( - CustomHistogram::FactoryGet("TestCustomHistogram1", custom_ranges, - HistogramBase::kNoFlags)); - const BucketRanges* ranges = histogram->bucket_ranges(); - ASSERT_EQ(4u, ranges->size()); - EXPECT_EQ(0, ranges->range(0)); // Auto added. - EXPECT_EQ(1, ranges->range(1)); - EXPECT_EQ(2, ranges->range(2)); - EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(3)); // Auto added. - - // A unordered custom ranges. - custom_ranges.clear(); - custom_ranges.push_back(2); - custom_ranges.push_back(1); - histogram = static_cast<Histogram*>( - CustomHistogram::FactoryGet("TestCustomHistogram2", custom_ranges, - HistogramBase::kNoFlags)); - ranges = histogram->bucket_ranges(); - ASSERT_EQ(4u, ranges->size()); - EXPECT_EQ(0, ranges->range(0)); - EXPECT_EQ(1, ranges->range(1)); - EXPECT_EQ(2, ranges->range(2)); - EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(3)); - - // A custom ranges with duplicated values. - custom_ranges.clear(); - custom_ranges.push_back(4); - custom_ranges.push_back(1); - custom_ranges.push_back(4); - histogram = static_cast<Histogram*>( - CustomHistogram::FactoryGet("TestCustomHistogram3", custom_ranges, - HistogramBase::kNoFlags)); - ranges = histogram->bucket_ranges(); - ASSERT_EQ(4u, ranges->size()); - EXPECT_EQ(0, ranges->range(0)); - EXPECT_EQ(1, ranges->range(1)); - EXPECT_EQ(4, ranges->range(2)); - EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(3)); -} - -TEST_P(HistogramTest, CustomHistogramWithOnly2Buckets) { - // This test exploits the fact that the CustomHistogram can have 2 buckets, - // while the base class Histogram is *supposed* to have at least 3 buckets. - // We should probably change the restriction on the base class (or not inherit - // the base class!). - - std::vector<HistogramBase::Sample> custom_ranges; - custom_ranges.push_back(4); - - Histogram* histogram = static_cast<Histogram*>( - CustomHistogram::FactoryGet("2BucketsCustomHistogram", custom_ranges, - HistogramBase::kNoFlags)); - const BucketRanges* ranges = histogram->bucket_ranges(); - ASSERT_EQ(3u, ranges->size()); - EXPECT_EQ(0, ranges->range(0)); - EXPECT_EQ(4, ranges->range(1)); - EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(2)); -} - -TEST_P(HistogramTest, AddCountTest) { - const size_t kBucketCount = 50; - Histogram* histogram = static_cast<Histogram*>( - Histogram::FactoryGet("AddCountHistogram", 10, 100, kBucketCount, - HistogramBase::kNoFlags)); - - histogram->AddCount(20, 15); - histogram->AddCount(30, 14); - - std::unique_ptr<HistogramSamples> samples = histogram->SnapshotSamples(); - EXPECT_EQ(29, samples->TotalCount()); - EXPECT_EQ(15, samples->GetCount(20)); - EXPECT_EQ(14, samples->GetCount(30)); - - histogram->AddCount(20, 25); - histogram->AddCount(30, 24); - - std::unique_ptr<HistogramSamples> samples2 = histogram->SnapshotSamples(); - EXPECT_EQ(78, samples2->TotalCount()); - EXPECT_EQ(40, samples2->GetCount(20)); - EXPECT_EQ(38, samples2->GetCount(30)); -} - -TEST_P(HistogramTest, AddCount_LargeValuesDontOverflow) { - const size_t kBucketCount = 50; - Histogram* histogram = static_cast<Histogram*>( - Histogram::FactoryGet("AddCountHistogram", 10, 1000000000, kBucketCount, - HistogramBase::kNoFlags)); - - histogram->AddCount(200000000, 15); - histogram->AddCount(300000000, 14); - - std::unique_ptr<HistogramSamples> samples = histogram->SnapshotSamples(); - EXPECT_EQ(29, samples->TotalCount()); - EXPECT_EQ(15, samples->GetCount(200000000)); - EXPECT_EQ(14, samples->GetCount(300000000)); - - histogram->AddCount(200000000, 25); - histogram->AddCount(300000000, 24); - - std::unique_ptr<HistogramSamples> samples2 = histogram->SnapshotSamples(); - EXPECT_EQ(78, samples2->TotalCount()); - EXPECT_EQ(40, samples2->GetCount(200000000)); - EXPECT_EQ(38, samples2->GetCount(300000000)); - EXPECT_EQ(19400000000LL, samples2->sum()); -} - -// Some metrics are designed so that they are guaranteed not to overflow between -// snapshots, but could overflow over a long-running session. -// Make sure that counts returned by Histogram::SnapshotDelta do not overflow -// even when a total count (returned by Histogram::SnapshotSample) does. -TEST_P(HistogramTest, AddCount_LargeCountsDontOverflow) { - const size_t kBucketCount = 10; - Histogram* histogram = static_cast<Histogram*>(Histogram::FactoryGet( - "AddCountHistogram", 10, 50, kBucketCount, HistogramBase::kNoFlags)); - - const int count = (1 << 30) - 1; - - // Repeat N times to make sure that there is no internal value overflow. - for (int i = 0; i < 10; ++i) { - histogram->AddCount(42, count); - std::unique_ptr<HistogramSamples> samples = histogram->SnapshotDelta(); - EXPECT_EQ(count, samples->TotalCount()); - EXPECT_EQ(count, samples->GetCount(42)); - } -} - -// Make sure histogram handles out-of-bounds data gracefully. -TEST_P(HistogramTest, BoundsTest) { - const size_t kBucketCount = 50; - Histogram* histogram = static_cast<Histogram*>( - Histogram::FactoryGet("Bounded", 10, 100, kBucketCount, - HistogramBase::kNoFlags)); - - // Put two samples "out of bounds" above and below. - histogram->Add(5); - histogram->Add(-50); - - histogram->Add(100); - histogram->Add(10000); - - // Verify they landed in the underflow, and overflow buckets. - std::unique_ptr<SampleVector> samples = histogram->SnapshotAllSamples(); - EXPECT_EQ(2, samples->GetCountAtIndex(0)); - EXPECT_EQ(0, samples->GetCountAtIndex(1)); - size_t array_size = histogram->bucket_count(); - EXPECT_EQ(kBucketCount, array_size); - EXPECT_EQ(0, samples->GetCountAtIndex(array_size - 2)); - EXPECT_EQ(2, samples->GetCountAtIndex(array_size - 1)); - - std::vector<int> custom_ranges; - custom_ranges.push_back(10); - custom_ranges.push_back(50); - custom_ranges.push_back(100); - Histogram* test_custom_histogram = static_cast<Histogram*>( - CustomHistogram::FactoryGet("TestCustomRangeBoundedHistogram", - custom_ranges, HistogramBase::kNoFlags)); - - // Put two samples "out of bounds" above and below. - test_custom_histogram->Add(5); - test_custom_histogram->Add(-50); - test_custom_histogram->Add(100); - test_custom_histogram->Add(1000); - test_custom_histogram->Add(INT_MAX); - - // Verify they landed in the underflow, and overflow buckets. - std::unique_ptr<SampleVector> custom_samples = - test_custom_histogram->SnapshotAllSamples(); - EXPECT_EQ(2, custom_samples->GetCountAtIndex(0)); - EXPECT_EQ(0, custom_samples->GetCountAtIndex(1)); - size_t bucket_count = test_custom_histogram->bucket_count(); - EXPECT_EQ(0, custom_samples->GetCountAtIndex(bucket_count - 2)); - EXPECT_EQ(3, custom_samples->GetCountAtIndex(bucket_count - 1)); -} - -// Check to be sure samples land as expected is "correct" buckets. -TEST_P(HistogramTest, BucketPlacementTest) { - Histogram* histogram = static_cast<Histogram*>( - Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags)); - - // Add i+1 samples to the i'th bucket. - histogram->Add(0); - int power_of_2 = 1; - for (int i = 1; i < 8; i++) { - for (int j = 0; j <= i; j++) - histogram->Add(power_of_2); - power_of_2 *= 2; - } - - // Check to see that the bucket counts reflect our additions. - std::unique_ptr<SampleVector> samples = histogram->SnapshotAllSamples(); - for (int i = 0; i < 8; i++) - EXPECT_EQ(i + 1, samples->GetCountAtIndex(i)); -} - -TEST_P(HistogramTest, CorruptSampleCounts) { - // The internal code creates histograms via macros and thus keeps static - // pointers to them. If those pointers are to persistent memory which will - // be free'd then any following calls to that code will crash with a - // segmentation violation. - if (use_persistent_histogram_allocator_) - return; - - Histogram* histogram = static_cast<Histogram*>( - Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags)); - - // Add some samples. - histogram->Add(20); - histogram->Add(40); - - std::unique_ptr<SampleVector> snapshot = histogram->SnapshotAllSamples(); - EXPECT_EQ(HistogramBase::NO_INCONSISTENCIES, - histogram->FindCorruption(*snapshot)); - EXPECT_EQ(2, snapshot->redundant_count()); - EXPECT_EQ(2, snapshot->TotalCount()); - - snapshot->counts()[3] += 100; // Sample count won't match redundant count. - EXPECT_EQ(HistogramBase::COUNT_LOW_ERROR, - histogram->FindCorruption(*snapshot)); - snapshot->counts()[2] -= 200; - EXPECT_EQ(HistogramBase::COUNT_HIGH_ERROR, - histogram->FindCorruption(*snapshot)); - - // But we can't spot a corruption if it is compensated for. - snapshot->counts()[1] += 100; - EXPECT_EQ(HistogramBase::NO_INCONSISTENCIES, - histogram->FindCorruption(*snapshot)); -} - -TEST_P(HistogramTest, CorruptBucketBounds) { - Histogram* histogram = static_cast<Histogram*>( - Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags)); - - std::unique_ptr<HistogramSamples> snapshot = histogram->SnapshotSamples(); - EXPECT_EQ(HistogramBase::NO_INCONSISTENCIES, - histogram->FindCorruption(*snapshot)); - - BucketRanges* bucket_ranges = - const_cast<BucketRanges*>(histogram->bucket_ranges()); - HistogramBase::Sample tmp = bucket_ranges->range(1); - bucket_ranges->set_range(1, bucket_ranges->range(2)); - bucket_ranges->set_range(2, tmp); - EXPECT_EQ( - HistogramBase::BUCKET_ORDER_ERROR | HistogramBase::RANGE_CHECKSUM_ERROR, - histogram->FindCorruption(*snapshot)); - - bucket_ranges->set_range(2, bucket_ranges->range(1)); - bucket_ranges->set_range(1, tmp); - EXPECT_EQ(0U, histogram->FindCorruption(*snapshot)); - - // Show that two simple changes don't offset each other - bucket_ranges->set_range(3, bucket_ranges->range(3) + 1); - EXPECT_EQ(HistogramBase::RANGE_CHECKSUM_ERROR, - histogram->FindCorruption(*snapshot)); - - bucket_ranges->set_range(4, bucket_ranges->range(4) - 1); - EXPECT_EQ(HistogramBase::RANGE_CHECKSUM_ERROR, - histogram->FindCorruption(*snapshot)); - - // Repair histogram so that destructor won't DCHECK(). - bucket_ranges->set_range(3, bucket_ranges->range(3) - 1); - bucket_ranges->set_range(4, bucket_ranges->range(4) + 1); -} - -TEST_P(HistogramTest, HistogramSerializeInfo) { - Histogram* histogram = static_cast<Histogram*>( - Histogram::FactoryGet("Histogram", 1, 64, 8, - HistogramBase::kIPCSerializationSourceFlag)); - Pickle pickle; - histogram->SerializeInfo(&pickle); - - PickleIterator iter(pickle); - - int type; - EXPECT_TRUE(iter.ReadInt(&type)); - EXPECT_EQ(HISTOGRAM, type); - - std::string name; - EXPECT_TRUE(iter.ReadString(&name)); - EXPECT_EQ("Histogram", name); - - int flag; - EXPECT_TRUE(iter.ReadInt(&flag)); - EXPECT_EQ(HistogramBase::kIPCSerializationSourceFlag, - flag & ~HistogramBase::kIsPersistent); - - int min; - EXPECT_TRUE(iter.ReadInt(&min)); - EXPECT_EQ(1, min); - - int max; - EXPECT_TRUE(iter.ReadInt(&max)); - EXPECT_EQ(64, max); - - uint32_t bucket_count; - EXPECT_TRUE(iter.ReadUInt32(&bucket_count)); - EXPECT_EQ(8u, bucket_count); - - uint32_t checksum; - EXPECT_TRUE(iter.ReadUInt32(&checksum)); - EXPECT_EQ(histogram->bucket_ranges()->checksum(), checksum); - - // No more data in the pickle. - EXPECT_FALSE(iter.SkipBytes(1)); -} - -TEST_P(HistogramTest, CustomHistogramSerializeInfo) { - std::vector<int> custom_ranges; - custom_ranges.push_back(10); - custom_ranges.push_back(100); - - HistogramBase* custom_histogram = CustomHistogram::FactoryGet( - "TestCustomRangeBoundedHistogram", - custom_ranges, - HistogramBase::kNoFlags); - Pickle pickle; - custom_histogram->SerializeInfo(&pickle); - - // Validate the pickle. - PickleIterator iter(pickle); - - int i; - std::string s; - uint32_t bucket_count; - uint32_t ui32; - EXPECT_TRUE(iter.ReadInt(&i) && iter.ReadString(&s) && iter.ReadInt(&i) && - iter.ReadInt(&i) && iter.ReadInt(&i) && - iter.ReadUInt32(&bucket_count) && iter.ReadUInt32(&ui32)); - EXPECT_EQ(3u, bucket_count); - - int range; - EXPECT_TRUE(iter.ReadInt(&range)); - EXPECT_EQ(10, range); - EXPECT_TRUE(iter.ReadInt(&range)); - EXPECT_EQ(100, range); - - // No more data in the pickle. - EXPECT_FALSE(iter.SkipBytes(1)); -} - -TEST_P(HistogramTest, BadConstruction) { - HistogramBase* histogram = Histogram::FactoryGet( - "BadConstruction", 0, 100, 8, HistogramBase::kNoFlags); - EXPECT_TRUE(histogram->HasConstructionArguments(1, 100, 8)); - - // Try to get the same histogram name with different arguments. - HistogramBase* bad_histogram = Histogram::FactoryGet( - "BadConstruction", 0, 100, 7, HistogramBase::kNoFlags); - EXPECT_EQ(DummyHistogram::GetInstance(), bad_histogram); - bad_histogram = Histogram::FactoryGet( - "BadConstruction", 0, 99, 8, HistogramBase::kNoFlags); - EXPECT_EQ(DummyHistogram::GetInstance(), bad_histogram); - - HistogramBase* linear_histogram = LinearHistogram::FactoryGet( - "BadConstructionLinear", 0, 100, 8, HistogramBase::kNoFlags); - EXPECT_TRUE(linear_histogram->HasConstructionArguments(1, 100, 8)); - - // Try to get the same histogram name with different arguments. - bad_histogram = LinearHistogram::FactoryGet( - "BadConstructionLinear", 0, 100, 7, HistogramBase::kNoFlags); - EXPECT_EQ(DummyHistogram::GetInstance(), bad_histogram); - bad_histogram = LinearHistogram::FactoryGet( - "BadConstructionLinear", 10, 100, 8, HistogramBase::kNoFlags); - EXPECT_EQ(DummyHistogram::GetInstance(), bad_histogram); -} - -TEST_P(HistogramTest, FactoryTime) { - const int kTestCreateCount = 1 << 14; // Must be power-of-2. - const int kTestLookupCount = 100000; - const int kTestAddCount = 1000000; - - // Create all histogram names in advance for accurate timing below. - std::vector<std::string> histogram_names; - for (int i = 0; i < kTestCreateCount; ++i) { - histogram_names.push_back( - StringPrintf("TestHistogram.%d", i % kTestCreateCount)); - } - - // Calculate cost of creating histograms. - TimeTicks create_start = TimeTicks::Now(); - for (int i = 0; i < kTestCreateCount; ++i) { - Histogram::FactoryGet(histogram_names[i], 1, 100, 10, - HistogramBase::kNoFlags); - } - TimeDelta create_ticks = TimeTicks::Now() - create_start; - int64_t create_ms = create_ticks.InMilliseconds(); - - VLOG(1) << kTestCreateCount << " histogram creations took " << create_ms - << "ms or about " - << (create_ms * 1000000) / kTestCreateCount - << "ns each."; - - // Calculate cost of looking up existing histograms. - TimeTicks lookup_start = TimeTicks::Now(); - for (int i = 0; i < kTestLookupCount; ++i) { - // 6007 is co-prime with kTestCreateCount and so will do lookups in an - // order less likely to be cacheable (but still hit them all) should the - // underlying storage use the exact histogram name as the key. - const int i_mult = 6007; - static_assert(i_mult < INT_MAX / kTestCreateCount, "Multiplier too big"); - int index = (i * i_mult) & (kTestCreateCount - 1); - Histogram::FactoryGet(histogram_names[index], 1, 100, 10, - HistogramBase::kNoFlags); - } - TimeDelta lookup_ticks = TimeTicks::Now() - lookup_start; - int64_t lookup_ms = lookup_ticks.InMilliseconds(); - - VLOG(1) << kTestLookupCount << " histogram lookups took " << lookup_ms - << "ms or about " - << (lookup_ms * 1000000) / kTestLookupCount - << "ns each."; - - // Calculate cost of accessing histograms. - HistogramBase* histogram = Histogram::FactoryGet( - histogram_names[0], 1, 100, 10, HistogramBase::kNoFlags); - ASSERT_TRUE(histogram); - TimeTicks add_start = TimeTicks::Now(); - for (int i = 0; i < kTestAddCount; ++i) - histogram->Add(i & 127); - TimeDelta add_ticks = TimeTicks::Now() - add_start; - int64_t add_ms = add_ticks.InMilliseconds(); - - VLOG(1) << kTestAddCount << " histogram adds took " << add_ms - << "ms or about " - << (add_ms * 1000000) / kTestAddCount - << "ns each."; -} - -// For Histogram, LinearHistogram and CustomHistogram, the minimum for a -// declared range is 1, while the maximum is (HistogramBase::kSampleType_MAX - -// 1). But we accept ranges exceeding those limits, and silently clamped to -// those limits. This is for backwards compatibility. -TEST(HistogramDeathTest, BadRangesTest) { - HistogramBase* histogram = Histogram::FactoryGet( - "BadRanges", 0, HistogramBase::kSampleType_MAX, 8, - HistogramBase::kNoFlags); - EXPECT_TRUE( - histogram->HasConstructionArguments( - 1, HistogramBase::kSampleType_MAX - 1, 8)); - - HistogramBase* linear_histogram = LinearHistogram::FactoryGet( - "BadRangesLinear", 0, HistogramBase::kSampleType_MAX, 8, - HistogramBase::kNoFlags); - EXPECT_TRUE( - linear_histogram->HasConstructionArguments( - 1, HistogramBase::kSampleType_MAX - 1, 8)); - - std::vector<int> custom_ranges; - custom_ranges.push_back(0); - custom_ranges.push_back(5); - Histogram* custom_histogram = static_cast<Histogram*>( - CustomHistogram::FactoryGet( - "BadRangesCustom", custom_ranges, HistogramBase::kNoFlags)); - const BucketRanges* ranges = custom_histogram->bucket_ranges(); - ASSERT_EQ(3u, ranges->size()); - EXPECT_EQ(0, ranges->range(0)); - EXPECT_EQ(5, ranges->range(1)); - EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(2)); - - // CustomHistogram does not accepts kSampleType_MAX as range. - custom_ranges.push_back(HistogramBase::kSampleType_MAX); - EXPECT_DEATH_IF_SUPPORTED( - CustomHistogram::FactoryGet("BadRangesCustom2", custom_ranges, - HistogramBase::kNoFlags), - ""); - - // CustomHistogram needs at least 1 valid range. - custom_ranges.clear(); - custom_ranges.push_back(0); - EXPECT_DEATH_IF_SUPPORTED( - CustomHistogram::FactoryGet("BadRangesCustom3", custom_ranges, - HistogramBase::kNoFlags), - ""); -} - -TEST_P(HistogramTest, ExpiredHistogramTest) { - HistogramBase* expired = Histogram::FactoryGet(kExpiredHistogramName, 1, 1000, - 10, HistogramBase::kNoFlags); - ASSERT_TRUE(expired); - expired->Add(5); - expired->Add(500); - auto samples = expired->SnapshotDelta(); - EXPECT_EQ(0, samples->TotalCount()); - - HistogramBase* linear_expired = LinearHistogram::FactoryGet( - kExpiredHistogramName, 1, 1000, 10, HistogramBase::kNoFlags); - ASSERT_TRUE(linear_expired); - linear_expired->Add(5); - linear_expired->Add(500); - samples = linear_expired->SnapshotDelta(); - EXPECT_EQ(0, samples->TotalCount()); - - std::vector<int> custom_ranges; - custom_ranges.push_back(1); - custom_ranges.push_back(5); - HistogramBase* custom_expired = CustomHistogram::FactoryGet( - kExpiredHistogramName, custom_ranges, HistogramBase::kNoFlags); - ASSERT_TRUE(custom_expired); - custom_expired->Add(2); - custom_expired->Add(4); - samples = custom_expired->SnapshotDelta(); - EXPECT_EQ(0, samples->TotalCount()); - - HistogramBase* valid = Histogram::FactoryGet("ValidHistogram", 1, 1000, 10, - HistogramBase::kNoFlags); - ASSERT_TRUE(valid); - valid->Add(5); - valid->Add(500); - samples = valid->SnapshotDelta(); - EXPECT_EQ(2, samples->TotalCount()); - - HistogramBase* linear_valid = LinearHistogram::FactoryGet( - "LinearHistogram", 1, 1000, 10, HistogramBase::kNoFlags); - ASSERT_TRUE(linear_valid); - linear_valid->Add(5); - linear_valid->Add(500); - samples = linear_valid->SnapshotDelta(); - EXPECT_EQ(2, samples->TotalCount()); - - HistogramBase* custom_valid = CustomHistogram::FactoryGet( - "CustomHistogram", custom_ranges, HistogramBase::kNoFlags); - ASSERT_TRUE(custom_valid); - custom_valid->Add(2); - custom_valid->Add(4); - samples = custom_valid->SnapshotDelta(); - EXPECT_EQ(2, samples->TotalCount()); -} - -} // namespace base
diff --git a/base/metrics/histogram_unittest.nc b/base/metrics/histogram_unittest.nc deleted file mode 100644 index c9c2657..0000000 --- a/base/metrics/histogram_unittest.nc +++ /dev/null
@@ -1,90 +0,0 @@ -// 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. - -// This is a "No Compile Test" suite. -// http://dev.chromium.org/developers/testing/no-compile-tests - -#include "base/metrics/histogram_functions.h" -#include "base/metrics/histogram_macros.h" - -namespace base { - -#if defined(NCTEST_DIFFERENT_ENUM) // [r"\|sample\| and \|boundary\| shouldn't be of different enums"] - -void WontCompile() { - enum TypeA { A }; - enum TypeB { B }; - UMA_HISTOGRAM_ENUMERATION("", A, B); -} - -#elif defined(NCTEST_DIFFERENT_ENUM_CLASS) // [r"\|sample\| and \|boundary\| shouldn't be of different enums"] - -void WontCompile() { - enum class TypeA { A }; - enum class TypeB { B }; - UMA_HISTOGRAM_ENUMERATION("", TypeA::A, TypeB::B); -} - -#elif defined(NCTEST_DIFFERENT_ENUM_MIXED) // [r"\|sample\| and \|boundary\| shouldn't be of different enums"] - -void WontCompile() { - enum class TypeA { A }; - enum TypeB { B }; - UMA_HISTOGRAM_ENUMERATION("", TypeA::A, B); -} - -#elif defined(NCTEST_NEGATIVE_ENUM_MAX) // [r'static_assert failed "\|boundary\| is out of range of HistogramBase::Sample"'] - -void WontCompile() { - // Buckets for enumeration start from 0, so a boundary < 0 is illegal. - enum class TypeA { A = -1 }; - UMA_HISTOGRAM_ENUMERATION("", TypeA::A, TypeA::A); -} - -#elif defined(NCTEST_ENUM_MAX_OUT_OF_RANGE) // [r'static_assert failed "\|boundary\| is out of range of HistogramBase::Sample"'] - -void WontCompile() { - // HistogramBase::Sample is an int and can't hold larger values. - enum class TypeA : uint32_t { A = 0xffffffff }; - UMA_HISTOGRAM_ENUMERATION("", TypeA::A, TypeA::A); -} - -#elif defined(NCTEST_SAMPLE_NOT_ENUM) // [r'static_assert failed "Unexpected: \|boundary\| is enum, but \|sample\| is not."'] - -void WontCompile() { - enum TypeA { A }; - UMA_HISTOGRAM_ENUMERATION("", 0, TypeA::A); -} - -#elif defined(NCTEST_FUNCTION_INT) // [r"Non enum passed to UmaHistogramEnumeration"] - -void WontCompile() { - UmaHistogramEnumeration("", 1, 2); -} - -#elif defined(NCTEST_FUNCTION_DIFFERENT_ENUM) // [r"no matching function for call to 'UmaHistogramEnumeration'"] - -void WontCompile() { - enum TypeA { A }; - enum TypeB { B }; - UmaHistogramEnumeration("", A, B); -} - -#elif defined(NCTEST_FUNCTION_FIRST_NOT_ENUM) // [r"no matching function for call to 'UmaHistogramEnumeration'"] - -void WontCompile() { - enum TypeB { B }; - UmaHistogramEnumeration("", 1, B); -} - -#elif defined(NCTEST_FUNCTION_SECOND_NOT_ENUM) // [r"no matching function for call to 'UmaHistogramEnumeration'"] - -void WontCompile() { - enum TypeA { A }; - UmaHistogramEnumeration("", A, 2); -} - -#endif - -} // namespace base
diff --git a/base/metrics/metrics_hashes_unittest.cc b/base/metrics/metrics_hashes_unittest.cc deleted file mode 100644 index aea254e..0000000 --- a/base/metrics/metrics_hashes_unittest.cc +++ /dev/null
@@ -1,35 +0,0 @@ -// 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/metrics/metrics_hashes.h" - -#include <stddef.h> -#include <stdint.h> - -#include "base/format_macros.h" -#include "base/macros.h" -#include "base/strings/stringprintf.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -// Make sure our ID hashes are the same as what we see on the server side. -TEST(MetricsUtilTest, HashMetricName) { - static const struct { - std::string input; - std::string output; - } cases[] = { - {"Back", "0x0557fa923dcee4d0"}, - {"Forward", "0x67d2f6740a8eaebf"}, - {"NewTab", "0x290eb683f96572f1"}, - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - uint64_t hash = HashMetricName(cases[i].input); - std::string hash_hex = base::StringPrintf("0x%016" PRIx64, hash); - EXPECT_EQ(cases[i].output, hash_hex); - } -} - -} // namespace metrics
diff --git a/base/metrics/persistent_histogram_allocator_unittest.cc b/base/metrics/persistent_histogram_allocator_unittest.cc deleted file mode 100644 index 7e07386..0000000 --- a/base/metrics/persistent_histogram_allocator_unittest.cc +++ /dev/null
@@ -1,375 +0,0 @@ -// 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/metrics/persistent_histogram_allocator.h" - -#include "base/files/file.h" -#include "base/files/file_util.h" -#include "base/files/scoped_temp_dir.h" -#include "base/logging.h" -#include "base/memory/ptr_util.h" -#include "base/metrics/bucket_ranges.h" -#include "base/metrics/histogram_macros.h" -#include "base/metrics/persistent_memory_allocator.h" -#include "base/metrics/statistics_recorder.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -class PersistentHistogramAllocatorTest : public testing::Test { - protected: - const int32_t kAllocatorMemorySize = 64 << 10; // 64 KiB - - PersistentHistogramAllocatorTest() - : statistics_recorder_(StatisticsRecorder::CreateTemporaryForTesting()) { - CreatePersistentHistogramAllocator(); - } - ~PersistentHistogramAllocatorTest() override { - DestroyPersistentHistogramAllocator(); - } - - void CreatePersistentHistogramAllocator() { - allocator_memory_.reset(new char[kAllocatorMemorySize]); - - GlobalHistogramAllocator::ReleaseForTesting(); - memset(allocator_memory_.get(), 0, kAllocatorMemorySize); - GlobalHistogramAllocator::CreateWithPersistentMemory( - allocator_memory_.get(), kAllocatorMemorySize, 0, 0, - "PersistentHistogramAllocatorTest"); - allocator_ = GlobalHistogramAllocator::Get()->memory_allocator(); - } - - void DestroyPersistentHistogramAllocator() { - allocator_ = nullptr; - GlobalHistogramAllocator::ReleaseForTesting(); - } - - std::unique_ptr<StatisticsRecorder> statistics_recorder_; - std::unique_ptr<char[]> allocator_memory_; - PersistentMemoryAllocator* allocator_ = nullptr; - - private: - DISALLOW_COPY_AND_ASSIGN(PersistentHistogramAllocatorTest); -}; - -TEST_F(PersistentHistogramAllocatorTest, CreateAndIterate) { - PersistentMemoryAllocator::MemoryInfo meminfo0; - allocator_->GetMemoryInfo(&meminfo0); - - // Try basic construction - HistogramBase* histogram = Histogram::FactoryGet( - "TestHistogram", 1, 1000, 10, HistogramBase::kIsPersistent); - EXPECT_TRUE(histogram); - histogram->CheckName("TestHistogram"); - PersistentMemoryAllocator::MemoryInfo meminfo1; - allocator_->GetMemoryInfo(&meminfo1); - EXPECT_GT(meminfo0.free, meminfo1.free); - - HistogramBase* linear_histogram = LinearHistogram::FactoryGet( - "TestLinearHistogram", 1, 1000, 10, HistogramBase::kIsPersistent); - EXPECT_TRUE(linear_histogram); - linear_histogram->CheckName("TestLinearHistogram"); - PersistentMemoryAllocator::MemoryInfo meminfo2; - allocator_->GetMemoryInfo(&meminfo2); - EXPECT_GT(meminfo1.free, meminfo2.free); - - HistogramBase* boolean_histogram = BooleanHistogram::FactoryGet( - "TestBooleanHistogram", HistogramBase::kIsPersistent); - EXPECT_TRUE(boolean_histogram); - boolean_histogram->CheckName("TestBooleanHistogram"); - PersistentMemoryAllocator::MemoryInfo meminfo3; - allocator_->GetMemoryInfo(&meminfo3); - EXPECT_GT(meminfo2.free, meminfo3.free); - - std::vector<int> custom_ranges; - custom_ranges.push_back(1); - custom_ranges.push_back(5); - HistogramBase* custom_histogram = CustomHistogram::FactoryGet( - "TestCustomHistogram", custom_ranges, HistogramBase::kIsPersistent); - EXPECT_TRUE(custom_histogram); - custom_histogram->CheckName("TestCustomHistogram"); - PersistentMemoryAllocator::MemoryInfo meminfo4; - allocator_->GetMemoryInfo(&meminfo4); - EXPECT_GT(meminfo3.free, meminfo4.free); - - PersistentMemoryAllocator::Iterator iter(allocator_); - uint32_t type; - EXPECT_NE(0U, iter.GetNext(&type)); // Histogram - EXPECT_NE(0U, iter.GetNext(&type)); // LinearHistogram - EXPECT_NE(0U, iter.GetNext(&type)); // BooleanHistogram - EXPECT_NE(0U, iter.GetNext(&type)); // CustomHistogram - EXPECT_EQ(0U, iter.GetNext(&type)); - - // Create a second allocator and have it access the memory of the first. - std::unique_ptr<HistogramBase> recovered; - PersistentHistogramAllocator recovery( - std::make_unique<PersistentMemoryAllocator>( - allocator_memory_.get(), kAllocatorMemorySize, 0, 0, "", false)); - PersistentHistogramAllocator::Iterator histogram_iter(&recovery); - - recovered = histogram_iter.GetNext(); - ASSERT_TRUE(recovered); - recovered->CheckName("TestHistogram"); - - recovered = histogram_iter.GetNext(); - ASSERT_TRUE(recovered); - recovered->CheckName("TestLinearHistogram"); - - recovered = histogram_iter.GetNext(); - ASSERT_TRUE(recovered); - recovered->CheckName("TestBooleanHistogram"); - - recovered = histogram_iter.GetNext(); - ASSERT_TRUE(recovered); - recovered->CheckName("TestCustomHistogram"); - - recovered = histogram_iter.GetNext(); - EXPECT_FALSE(recovered); -} - -TEST_F(PersistentHistogramAllocatorTest, ConstructPaths) { - const FilePath dir_path(FILE_PATH_LITERAL("foo/")); - const std::string dir_string = - dir_path.NormalizePathSeparators().AsUTF8Unsafe(); - - FilePath path = GlobalHistogramAllocator::ConstructFilePath(dir_path, "bar"); - EXPECT_EQ(dir_string + "bar.pma", path.AsUTF8Unsafe()); - - std::string name; - Time stamp; - ProcessId pid; - EXPECT_FALSE( - GlobalHistogramAllocator::ParseFilePath(path, &name, nullptr, nullptr)); - EXPECT_FALSE( - GlobalHistogramAllocator::ParseFilePath(path, nullptr, &stamp, nullptr)); - EXPECT_FALSE( - GlobalHistogramAllocator::ParseFilePath(path, nullptr, nullptr, &pid)); - - path = GlobalHistogramAllocator::ConstructFilePathForUploadDir( - dir_path, "bar", Time::FromTimeT(12345), 6789); - EXPECT_EQ(dir_string + "bar-3039-1A85.pma", path.AsUTF8Unsafe()); - ASSERT_TRUE( - GlobalHistogramAllocator::ParseFilePath(path, &name, &stamp, &pid)); - EXPECT_EQ(name, "bar"); - EXPECT_EQ(Time::FromTimeT(12345), stamp); - EXPECT_EQ(static_cast<ProcessId>(6789), pid); -} - -TEST_F(PersistentHistogramAllocatorTest, CreateWithFile) { - const char temp_name[] = "CreateWithFileTest"; - ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - FilePath temp_file = temp_dir.GetPath().AppendASCII(temp_name); - const size_t temp_size = 64 << 10; // 64 KiB - - // Test creation of a new file. - GlobalHistogramAllocator::ReleaseForTesting(); - GlobalHistogramAllocator::CreateWithFile(temp_file, temp_size, 0, temp_name); - EXPECT_EQ(std::string(temp_name), - GlobalHistogramAllocator::Get()->memory_allocator()->Name()); - - // Test re-open of a possibly-existing file. - GlobalHistogramAllocator::ReleaseForTesting(); - GlobalHistogramAllocator::CreateWithFile(temp_file, temp_size, 0, ""); - EXPECT_EQ(std::string(temp_name), - GlobalHistogramAllocator::Get()->memory_allocator()->Name()); - - // Test re-open of an known-existing file. - GlobalHistogramAllocator::ReleaseForTesting(); - GlobalHistogramAllocator::CreateWithFile(temp_file, 0, 0, ""); - EXPECT_EQ(std::string(temp_name), - GlobalHistogramAllocator::Get()->memory_allocator()->Name()); - - // Final release so file and temp-dir can be removed. - GlobalHistogramAllocator::ReleaseForTesting(); -} - -TEST_F(PersistentHistogramAllocatorTest, CreateSpareFile) { - const char temp_name[] = "CreateSpareFileTest.pma"; - ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - FilePath temp_file = temp_dir.GetPath().AppendASCII(temp_name); - const size_t temp_size = 64 << 10; // 64 KiB - - ASSERT_TRUE(GlobalHistogramAllocator::CreateSpareFile(temp_file, temp_size)); - - File file(temp_file, File::FLAG_OPEN | File::FLAG_READ); - ASSERT_TRUE(file.IsValid()); - EXPECT_EQ(static_cast<int64_t>(temp_size), file.GetLength()); - - char buffer[256]; - for (size_t pos = 0; pos < temp_size; pos += sizeof(buffer)) { - ASSERT_EQ(static_cast<int>(sizeof(buffer)), - file.ReadAtCurrentPos(buffer, sizeof(buffer))); - for (size_t i = 0; i < sizeof(buffer); ++i) - EXPECT_EQ(0, buffer[i]); - } -} - -TEST_F(PersistentHistogramAllocatorTest, StatisticsRecorderMerge) { - const char LinearHistogramName[] = "SRTLinearHistogram"; - const char SparseHistogramName[] = "SRTSparseHistogram"; - const size_t starting_sr_count = StatisticsRecorder::GetHistogramCount(); - - // Create a local StatisticsRecorder in which the newly created histogram - // will be recorded. The global allocator must be replaced after because the - // act of releasing will cause the active SR to forget about all histograms - // in the relased memory. - std::unique_ptr<StatisticsRecorder> local_sr = - StatisticsRecorder::CreateTemporaryForTesting(); - EXPECT_EQ(0U, StatisticsRecorder::GetHistogramCount()); - std::unique_ptr<GlobalHistogramAllocator> old_allocator = - GlobalHistogramAllocator::ReleaseForTesting(); - GlobalHistogramAllocator::CreateWithLocalMemory(kAllocatorMemorySize, 0, ""); - ASSERT_TRUE(GlobalHistogramAllocator::Get()); - - // Create a linear histogram for merge testing. - HistogramBase* histogram1 = - LinearHistogram::FactoryGet(LinearHistogramName, 1, 10, 10, 0); - ASSERT_TRUE(histogram1); - EXPECT_EQ(1U, StatisticsRecorder::GetHistogramCount()); - histogram1->Add(3); - histogram1->Add(1); - histogram1->Add(4); - histogram1->AddCount(1, 4); - histogram1->Add(6); - - // Create a sparse histogram for merge testing. - HistogramBase* histogram2 = - SparseHistogram::FactoryGet(SparseHistogramName, 0); - ASSERT_TRUE(histogram2); - EXPECT_EQ(2U, StatisticsRecorder::GetHistogramCount()); - histogram2->Add(3); - histogram2->Add(1); - histogram2->Add(4); - histogram2->AddCount(1, 4); - histogram2->Add(6); - - // Destroy the local SR and ensure that we're back to the initial state and - // restore the global allocator. Histograms created in the local SR will - // become unmanaged. - std::unique_ptr<GlobalHistogramAllocator> new_allocator = - GlobalHistogramAllocator::ReleaseForTesting(); - local_sr.reset(); - EXPECT_EQ(starting_sr_count, StatisticsRecorder::GetHistogramCount()); - GlobalHistogramAllocator::Set(std::move(old_allocator)); - - // Create a "recovery" allocator using the same memory as the local one. - PersistentHistogramAllocator recovery1( - std::make_unique<PersistentMemoryAllocator>( - const_cast<void*>(new_allocator->memory_allocator()->data()), - new_allocator->memory_allocator()->size(), 0, 0, "", false)); - PersistentHistogramAllocator::Iterator histogram_iter1(&recovery1); - - // Get the histograms that were created locally (and forgotten) and merge - // them into the global SR. New objects will be created. - std::unique_ptr<HistogramBase> recovered; - while (true) { - recovered = histogram_iter1.GetNext(); - if (!recovered) - break; - - recovery1.MergeHistogramDeltaToStatisticsRecorder(recovered.get()); - HistogramBase* found = - StatisticsRecorder::FindHistogram(recovered->histogram_name()); - EXPECT_NE(recovered.get(), found); - }; - EXPECT_EQ(starting_sr_count + 2, StatisticsRecorder::GetHistogramCount()); - - // Check the merged histograms for accuracy. - HistogramBase* found = StatisticsRecorder::FindHistogram(LinearHistogramName); - ASSERT_TRUE(found); - std::unique_ptr<HistogramSamples> snapshot = found->SnapshotSamples(); - EXPECT_EQ(found->SnapshotSamples()->TotalCount(), snapshot->TotalCount()); - EXPECT_EQ(1, snapshot->GetCount(3)); - EXPECT_EQ(5, snapshot->GetCount(1)); - EXPECT_EQ(1, snapshot->GetCount(4)); - EXPECT_EQ(1, snapshot->GetCount(6)); - - found = StatisticsRecorder::FindHistogram(SparseHistogramName); - ASSERT_TRUE(found); - snapshot = found->SnapshotSamples(); - EXPECT_EQ(found->SnapshotSamples()->TotalCount(), snapshot->TotalCount()); - EXPECT_EQ(1, snapshot->GetCount(3)); - EXPECT_EQ(5, snapshot->GetCount(1)); - EXPECT_EQ(1, snapshot->GetCount(4)); - EXPECT_EQ(1, snapshot->GetCount(6)); - - // Perform additional histogram increments. - histogram1->AddCount(1, 3); - histogram1->Add(6); - histogram2->AddCount(1, 3); - histogram2->Add(7); - - // Do another merge. - PersistentHistogramAllocator recovery2( - std::make_unique<PersistentMemoryAllocator>( - const_cast<void*>(new_allocator->memory_allocator()->data()), - new_allocator->memory_allocator()->size(), 0, 0, "", false)); - PersistentHistogramAllocator::Iterator histogram_iter2(&recovery2); - while (true) { - recovered = histogram_iter2.GetNext(); - if (!recovered) - break; - recovery2.MergeHistogramDeltaToStatisticsRecorder(recovered.get()); - }; - EXPECT_EQ(starting_sr_count + 2, StatisticsRecorder::GetHistogramCount()); - - // And verify. - found = StatisticsRecorder::FindHistogram(LinearHistogramName); - snapshot = found->SnapshotSamples(); - EXPECT_EQ(found->SnapshotSamples()->TotalCount(), snapshot->TotalCount()); - EXPECT_EQ(1, snapshot->GetCount(3)); - EXPECT_EQ(8, snapshot->GetCount(1)); - EXPECT_EQ(1, snapshot->GetCount(4)); - EXPECT_EQ(2, snapshot->GetCount(6)); - - found = StatisticsRecorder::FindHistogram(SparseHistogramName); - snapshot = found->SnapshotSamples(); - EXPECT_EQ(found->SnapshotSamples()->TotalCount(), snapshot->TotalCount()); - EXPECT_EQ(1, snapshot->GetCount(3)); - EXPECT_EQ(8, snapshot->GetCount(1)); - EXPECT_EQ(1, snapshot->GetCount(4)); - EXPECT_EQ(1, snapshot->GetCount(6)); - EXPECT_EQ(1, snapshot->GetCount(7)); -} - -TEST_F(PersistentHistogramAllocatorTest, RangesDeDuplication) { - // This corresponds to the "ranges_ref" field of the PersistentHistogramData - // structure defined (privately) inside persistent_histogram_allocator.cc. - const int kRangesRefIndex = 5; - - // Create two histograms with the same ranges. - HistogramBase* histogram1 = - Histogram::FactoryGet("TestHistogram1", 1, 1000, 10, 0); - HistogramBase* histogram2 = - Histogram::FactoryGet("TestHistogram2", 1, 1000, 10, 0); - const uint32_t ranges_ref = static_cast<Histogram*>(histogram1) - ->bucket_ranges() - ->persistent_reference(); - ASSERT_NE(0U, ranges_ref); - EXPECT_EQ(ranges_ref, static_cast<Histogram*>(histogram2) - ->bucket_ranges() - ->persistent_reference()); - - // Make sure that the persistent data record is also correct. Two histograms - // will be fetched; other allocations are not "iterable". - PersistentMemoryAllocator::Iterator iter(allocator_); - uint32_t type; - uint32_t ref1 = iter.GetNext(&type); - uint32_t ref2 = iter.GetNext(&type); - EXPECT_EQ(0U, iter.GetNext(&type)); - EXPECT_NE(0U, ref1); - EXPECT_NE(0U, ref2); - EXPECT_NE(ref1, ref2); - - uint32_t* data1 = - allocator_->GetAsArray<uint32_t>(ref1, 0, kRangesRefIndex + 1); - uint32_t* data2 = - allocator_->GetAsArray<uint32_t>(ref2, 0, kRangesRefIndex + 1); - EXPECT_EQ(ranges_ref, data1[kRangesRefIndex]); - EXPECT_EQ(ranges_ref, data2[kRangesRefIndex]); -} - -} // namespace base
diff --git a/base/metrics/persistent_histogram_storage_unittest.cc b/base/metrics/persistent_histogram_storage_unittest.cc deleted file mode 100644 index ed42068..0000000 --- a/base/metrics/persistent_histogram_storage_unittest.cc +++ /dev/null
@@ -1,78 +0,0 @@ -// 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/metrics/persistent_histogram_storage.h" - -#include <memory> - -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/files/scoped_temp_dir.h" -#include "base/metrics/histogram_macros.h" -#include "base/time/time.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -// Name of the allocator for storing histograms. -constexpr char kTestHistogramAllocatorName[] = "TestMetrics"; - -} // namespace - -class PersistentHistogramStorageTest : public testing::Test { - protected: - PersistentHistogramStorageTest() = default; - ~PersistentHistogramStorageTest() override = default; - - // Creates a unique temporary directory, and sets the test storage directory. - void SetUp() override { - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - test_storage_dir_ = - temp_dir_path().AppendASCII(kTestHistogramAllocatorName); - } - - // Gets the path to the temporary directory. - const FilePath& temp_dir_path() { return temp_dir_.GetPath(); } - - const FilePath& test_storage_dir() { return test_storage_dir_; } - - private: - // A temporary directory where all file IO operations take place. - ScopedTempDir temp_dir_; - - // The directory into which metrics files are written. - FilePath test_storage_dir_; - - DISALLOW_COPY_AND_ASSIGN(PersistentHistogramStorageTest); -}; - -// TODO(chengx): Re-enable the test on OS_IOS after issue 836789 is fixed. -// PersistentHistogramStorage is only used on OS_WIN now, so disabling this -// test on OS_IOS is fine. -#if !defined(OS_NACL) && !defined(OS_IOS) -TEST_F(PersistentHistogramStorageTest, HistogramWriteTest) { - auto persistent_histogram_storage = - std::make_unique<PersistentHistogramStorage>( - kTestHistogramAllocatorName, - PersistentHistogramStorage::StorageDirManagement::kCreate); - - persistent_histogram_storage->set_storage_base_dir(temp_dir_path()); - - // Log some random data. - UMA_HISTOGRAM_BOOLEAN("Some.Test.Metric", true); - - // Deleting the object causes the data to be written to the disk. - persistent_histogram_storage.reset(); - - // The storage directory and the histogram file are created during the - // destruction of the PersistentHistogramStorage instance. - EXPECT_TRUE(DirectoryExists(test_storage_dir())); - EXPECT_FALSE(IsDirectoryEmpty(test_storage_dir())); -} -#endif // !defined(OS_NACL) && !defined(OS_IOS) - -} // namespace base
diff --git a/base/metrics/persistent_memory_allocator_unittest.cc b/base/metrics/persistent_memory_allocator_unittest.cc deleted file mode 100644 index 75e4faa..0000000 --- a/base/metrics/persistent_memory_allocator_unittest.cc +++ /dev/null
@@ -1,1001 +0,0 @@ -// 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/metrics/persistent_memory_allocator.h" - -#include <memory> - -#include "base/files/file.h" -#include "base/files/file_util.h" -#include "base/files/memory_mapped_file.h" -#include "base/files/scoped_temp_dir.h" -#include "base/memory/shared_memory.h" -#include "base/metrics/histogram.h" -#include "base/rand_util.h" -#include "base/strings/safe_sprintf.h" -#include "base/strings/stringprintf.h" -#include "base/synchronization/condition_variable.h" -#include "base/synchronization/lock.h" -#include "base/threading/simple_thread.h" -#include "testing/gmock/include/gmock/gmock.h" - -namespace base { - -namespace { - -const uint32_t TEST_MEMORY_SIZE = 1 << 20; // 1 MiB -const uint32_t TEST_MEMORY_PAGE = 64 << 10; // 64 KiB -const uint32_t TEST_ID = 12345; -const char TEST_NAME[] = "TestAllocator"; - -void SetFileLength(const base::FilePath& path, size_t length) { - { - File file(path, File::FLAG_OPEN | File::FLAG_READ | File::FLAG_WRITE); - DCHECK(file.IsValid()); - ASSERT_TRUE(file.SetLength(static_cast<int64_t>(length))); - } - - int64_t actual_length; - DCHECK(GetFileSize(path, &actual_length)); - DCHECK_EQ(length, static_cast<size_t>(actual_length)); -} - -} // namespace - -typedef PersistentMemoryAllocator::Reference Reference; - -class PersistentMemoryAllocatorTest : public testing::Test { - public: - // This can't be statically initialized because it's value isn't defined - // in the PersistentMemoryAllocator header file. Instead, it's simply set - // in the constructor. - uint32_t kAllocAlignment; - - struct TestObject1 { - static constexpr uint32_t kPersistentTypeId = 1; - static constexpr size_t kExpectedInstanceSize = 4 + 1 + 3; - int32_t onething; - char oranother; - }; - - struct TestObject2 { - static constexpr uint32_t kPersistentTypeId = 2; - static constexpr size_t kExpectedInstanceSize = 8 + 4 + 4 + 8 + 8; - int64_t thiis; - int32_t that; - float andthe; - double other; - char thing[8]; - }; - - PersistentMemoryAllocatorTest() { - kAllocAlignment = GetAllocAlignment(); - mem_segment_.reset(new char[TEST_MEMORY_SIZE]); - } - - void SetUp() override { - allocator_.reset(); - ::memset(mem_segment_.get(), 0, TEST_MEMORY_SIZE); - allocator_.reset(new PersistentMemoryAllocator( - mem_segment_.get(), TEST_MEMORY_SIZE, TEST_MEMORY_PAGE, - TEST_ID, TEST_NAME, false)); - } - - void TearDown() override { - allocator_.reset(); - } - - unsigned CountIterables() { - PersistentMemoryAllocator::Iterator iter(allocator_.get()); - uint32_t type; - unsigned count = 0; - while (iter.GetNext(&type) != 0) { - ++count; - } - return count; - } - - static uint32_t GetAllocAlignment() { - return PersistentMemoryAllocator::kAllocAlignment; - } - - protected: - std::unique_ptr<char[]> mem_segment_; - std::unique_ptr<PersistentMemoryAllocator> allocator_; -}; - -TEST_F(PersistentMemoryAllocatorTest, AllocateAndIterate) { - allocator_->CreateTrackingHistograms(allocator_->Name()); - - std::string base_name(TEST_NAME); - EXPECT_EQ(TEST_ID, allocator_->Id()); - EXPECT_TRUE(allocator_->used_histogram_); - EXPECT_EQ("UMA.PersistentAllocator." + base_name + ".UsedPct", - allocator_->used_histogram_->histogram_name()); - EXPECT_EQ(PersistentMemoryAllocator::MEMORY_INITIALIZED, - allocator_->GetMemoryState()); - - // Get base memory info for later comparison. - PersistentMemoryAllocator::MemoryInfo meminfo0; - allocator_->GetMemoryInfo(&meminfo0); - EXPECT_EQ(TEST_MEMORY_SIZE, meminfo0.total); - EXPECT_GT(meminfo0.total, meminfo0.free); - - // Validate allocation of test object and make sure it can be referenced - // and all metadata looks correct. - TestObject1* obj1 = allocator_->New<TestObject1>(); - ASSERT_TRUE(obj1); - Reference block1 = allocator_->GetAsReference(obj1); - ASSERT_NE(0U, block1); - EXPECT_NE(nullptr, allocator_->GetAsObject<TestObject1>(block1)); - EXPECT_EQ(nullptr, allocator_->GetAsObject<TestObject2>(block1)); - EXPECT_LE(sizeof(TestObject1), allocator_->GetAllocSize(block1)); - EXPECT_GT(sizeof(TestObject1) + kAllocAlignment, - allocator_->GetAllocSize(block1)); - PersistentMemoryAllocator::MemoryInfo meminfo1; - allocator_->GetMemoryInfo(&meminfo1); - EXPECT_EQ(meminfo0.total, meminfo1.total); - EXPECT_GT(meminfo0.free, meminfo1.free); - - // Verify that pointers can be turned back into references and that invalid - // addresses return null. - char* memory1 = allocator_->GetAsArray<char>(block1, 1, 1); - ASSERT_TRUE(memory1); - EXPECT_EQ(block1, allocator_->GetAsReference(memory1, 0)); - EXPECT_EQ(block1, allocator_->GetAsReference(memory1, 1)); - EXPECT_EQ(0U, allocator_->GetAsReference(memory1, 2)); - EXPECT_EQ(0U, allocator_->GetAsReference(memory1 + 1, 0)); - EXPECT_EQ(0U, allocator_->GetAsReference(memory1 + 16, 0)); - EXPECT_EQ(0U, allocator_->GetAsReference(nullptr, 0)); - EXPECT_EQ(0U, allocator_->GetAsReference(&base_name, 0)); - - // Ensure that the test-object can be made iterable. - PersistentMemoryAllocator::Iterator iter1a(allocator_.get()); - EXPECT_EQ(0U, iter1a.GetLast()); - uint32_t type; - EXPECT_EQ(0U, iter1a.GetNext(&type)); - allocator_->MakeIterable(block1); - EXPECT_EQ(block1, iter1a.GetNext(&type)); - EXPECT_EQ(1U, type); - EXPECT_EQ(block1, iter1a.GetLast()); - EXPECT_EQ(0U, iter1a.GetNext(&type)); - EXPECT_EQ(block1, iter1a.GetLast()); - - // Create second test-object and ensure everything is good and it cannot - // be confused with test-object of another type. - TestObject2* obj2 = allocator_->New<TestObject2>(); - ASSERT_TRUE(obj2); - Reference block2 = allocator_->GetAsReference(obj2); - ASSERT_NE(0U, block2); - EXPECT_NE(nullptr, allocator_->GetAsObject<TestObject2>(block2)); - EXPECT_EQ(nullptr, allocator_->GetAsObject<TestObject1>(block2)); - EXPECT_LE(sizeof(TestObject2), allocator_->GetAllocSize(block2)); - EXPECT_GT(sizeof(TestObject2) + kAllocAlignment, - allocator_->GetAllocSize(block2)); - PersistentMemoryAllocator::MemoryInfo meminfo2; - allocator_->GetMemoryInfo(&meminfo2); - EXPECT_EQ(meminfo1.total, meminfo2.total); - EXPECT_GT(meminfo1.free, meminfo2.free); - - // Ensure that second test-object can also be made iterable. - allocator_->MakeIterable(obj2); - EXPECT_EQ(block2, iter1a.GetNext(&type)); - EXPECT_EQ(2U, type); - EXPECT_EQ(block2, iter1a.GetLast()); - EXPECT_EQ(0U, iter1a.GetNext(&type)); - EXPECT_EQ(block2, iter1a.GetLast()); - - // Check that the iterator can be reset to the beginning. - iter1a.Reset(); - EXPECT_EQ(0U, iter1a.GetLast()); - EXPECT_EQ(block1, iter1a.GetNext(&type)); - EXPECT_EQ(block1, iter1a.GetLast()); - EXPECT_EQ(block2, iter1a.GetNext(&type)); - EXPECT_EQ(block2, iter1a.GetLast()); - EXPECT_EQ(0U, iter1a.GetNext(&type)); - - // Check that the iterator can be reset to an arbitrary location. - iter1a.Reset(block1); - EXPECT_EQ(block1, iter1a.GetLast()); - EXPECT_EQ(block2, iter1a.GetNext(&type)); - EXPECT_EQ(block2, iter1a.GetLast()); - EXPECT_EQ(0U, iter1a.GetNext(&type)); - - // Check that iteration can begin after an arbitrary location. - PersistentMemoryAllocator::Iterator iter1b(allocator_.get(), block1); - EXPECT_EQ(block2, iter1b.GetNext(&type)); - EXPECT_EQ(0U, iter1b.GetNext(&type)); - - // Ensure nothing has gone noticably wrong. - EXPECT_FALSE(allocator_->IsFull()); - EXPECT_FALSE(allocator_->IsCorrupt()); - - // Check the internal histogram record of used memory. - allocator_->UpdateTrackingHistograms(); - std::unique_ptr<HistogramSamples> used_samples( - allocator_->used_histogram_->SnapshotSamples()); - EXPECT_TRUE(used_samples); - EXPECT_EQ(1, used_samples->TotalCount()); - - // Check that an object's type can be changed. - EXPECT_EQ(2U, allocator_->GetType(block2)); - allocator_->ChangeType(block2, 3, 2, false); - EXPECT_EQ(3U, allocator_->GetType(block2)); - allocator_->New<TestObject2>(block2, 3, false); - EXPECT_EQ(2U, allocator_->GetType(block2)); - - // Create second allocator (read/write) using the same memory segment. - std::unique_ptr<PersistentMemoryAllocator> allocator2( - new PersistentMemoryAllocator(mem_segment_.get(), TEST_MEMORY_SIZE, - TEST_MEMORY_PAGE, 0, "", false)); - EXPECT_EQ(TEST_ID, allocator2->Id()); - EXPECT_FALSE(allocator2->used_histogram_); - - // Ensure that iteration and access through second allocator works. - PersistentMemoryAllocator::Iterator iter2(allocator2.get()); - EXPECT_EQ(block1, iter2.GetNext(&type)); - EXPECT_EQ(block2, iter2.GetNext(&type)); - EXPECT_EQ(0U, iter2.GetNext(&type)); - EXPECT_NE(nullptr, allocator2->GetAsObject<TestObject1>(block1)); - EXPECT_NE(nullptr, allocator2->GetAsObject<TestObject2>(block2)); - - // Create a third allocator (read-only) using the same memory segment. - std::unique_ptr<const PersistentMemoryAllocator> allocator3( - new PersistentMemoryAllocator(mem_segment_.get(), TEST_MEMORY_SIZE, - TEST_MEMORY_PAGE, 0, "", true)); - EXPECT_EQ(TEST_ID, allocator3->Id()); - EXPECT_FALSE(allocator3->used_histogram_); - - // Ensure that iteration and access through third allocator works. - PersistentMemoryAllocator::Iterator iter3(allocator3.get()); - EXPECT_EQ(block1, iter3.GetNext(&type)); - EXPECT_EQ(block2, iter3.GetNext(&type)); - EXPECT_EQ(0U, iter3.GetNext(&type)); - EXPECT_NE(nullptr, allocator3->GetAsObject<TestObject1>(block1)); - EXPECT_NE(nullptr, allocator3->GetAsObject<TestObject2>(block2)); - - // Ensure that GetNextOfType works. - PersistentMemoryAllocator::Iterator iter1c(allocator_.get()); - EXPECT_EQ(block2, iter1c.GetNextOfType<TestObject2>()); - EXPECT_EQ(0U, iter1c.GetNextOfType(2)); - - // Ensure that GetNextOfObject works. - PersistentMemoryAllocator::Iterator iter1d(allocator_.get()); - EXPECT_EQ(obj2, iter1d.GetNextOfObject<TestObject2>()); - EXPECT_EQ(nullptr, iter1d.GetNextOfObject<TestObject2>()); - - // Ensure that deleting an object works. - allocator_->Delete(obj2); - PersistentMemoryAllocator::Iterator iter1z(allocator_.get()); - EXPECT_EQ(nullptr, iter1z.GetNextOfObject<TestObject2>()); - - // Ensure that the memory state can be set. - allocator_->SetMemoryState(PersistentMemoryAllocator::MEMORY_DELETED); - EXPECT_EQ(PersistentMemoryAllocator::MEMORY_DELETED, - allocator_->GetMemoryState()); -} - -TEST_F(PersistentMemoryAllocatorTest, PageTest) { - // This allocation will go into the first memory page. - Reference block1 = allocator_->Allocate(TEST_MEMORY_PAGE / 2, 1); - EXPECT_LT(0U, block1); - EXPECT_GT(TEST_MEMORY_PAGE, block1); - - // This allocation won't fit in same page as previous block. - Reference block2 = - allocator_->Allocate(TEST_MEMORY_PAGE - 2 * kAllocAlignment, 2); - EXPECT_EQ(TEST_MEMORY_PAGE, block2); - - // This allocation will also require a new page. - Reference block3 = allocator_->Allocate(2 * kAllocAlignment + 99, 3); - EXPECT_EQ(2U * TEST_MEMORY_PAGE, block3); -} - -// A simple thread that takes an allocator and repeatedly allocates random- -// sized chunks from it until no more can be done. -class AllocatorThread : public SimpleThread { - public: - AllocatorThread(const std::string& name, - void* base, - uint32_t size, - uint32_t page_size) - : SimpleThread(name, Options()), - count_(0), - iterable_(0), - allocator_(base, size, page_size, 0, std::string(), false) {} - - void Run() override { - for (;;) { - uint32_t size = RandInt(1, 99); - uint32_t type = RandInt(100, 999); - Reference block = allocator_.Allocate(size, type); - if (!block) - break; - - count_++; - if (RandInt(0, 1)) { - allocator_.MakeIterable(block); - iterable_++; - } - } - } - - unsigned iterable() { return iterable_; } - unsigned count() { return count_; } - - private: - unsigned count_; - unsigned iterable_; - PersistentMemoryAllocator allocator_; -}; - -// Test parallel allocation/iteration and ensure consistency across all -// instances. -TEST_F(PersistentMemoryAllocatorTest, ParallelismTest) { - void* memory = mem_segment_.get(); - AllocatorThread t1("t1", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE); - AllocatorThread t2("t2", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE); - AllocatorThread t3("t3", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE); - AllocatorThread t4("t4", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE); - AllocatorThread t5("t5", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE); - - t1.Start(); - t2.Start(); - t3.Start(); - t4.Start(); - t5.Start(); - - unsigned last_count = 0; - do { - unsigned count = CountIterables(); - EXPECT_LE(last_count, count); - } while (!allocator_->IsCorrupt() && !allocator_->IsFull()); - - t1.Join(); - t2.Join(); - t3.Join(); - t4.Join(); - t5.Join(); - - EXPECT_FALSE(allocator_->IsCorrupt()); - EXPECT_TRUE(allocator_->IsFull()); - EXPECT_EQ(CountIterables(), - t1.iterable() + t2.iterable() + t3.iterable() + t4.iterable() + - t5.iterable()); -} - -// A simple thread that counts objects by iterating through an allocator. -class CounterThread : public SimpleThread { - public: - CounterThread(const std::string& name, - PersistentMemoryAllocator::Iterator* iterator, - Lock* lock, - ConditionVariable* condition, - bool* wake_up) - : SimpleThread(name, Options()), - iterator_(iterator), - lock_(lock), - condition_(condition), - count_(0), - wake_up_(wake_up) {} - - void Run() override { - // Wait so all threads can start at approximately the same time. - // Best performance comes from releasing a single worker which then - // releases the next, etc., etc. - { - AutoLock autolock(*lock_); - - // Before calling Wait(), make sure that the wake up condition - // has not already passed. Also, since spurious signal events - // are possible, check the condition in a while loop to make - // sure that the wake up condition is met when this thread - // returns from the Wait(). - // See usage comments in src/base/synchronization/condition_variable.h. - while (!*wake_up_) { - condition_->Wait(); - condition_->Signal(); - } - } - - uint32_t type; - while (iterator_->GetNext(&type) != 0) { - ++count_; - } - } - - unsigned count() { return count_; } - - private: - PersistentMemoryAllocator::Iterator* iterator_; - Lock* lock_; - ConditionVariable* condition_; - unsigned count_; - bool* wake_up_; - - DISALLOW_COPY_AND_ASSIGN(CounterThread); -}; - -// Ensure that parallel iteration returns the same number of objects as -// single-threaded iteration. -TEST_F(PersistentMemoryAllocatorTest, IteratorParallelismTest) { - // Fill the memory segment with random allocations. - unsigned iterable_count = 0; - for (;;) { - uint32_t size = RandInt(1, 99); - uint32_t type = RandInt(100, 999); - Reference block = allocator_->Allocate(size, type); - if (!block) - break; - allocator_->MakeIterable(block); - ++iterable_count; - } - EXPECT_FALSE(allocator_->IsCorrupt()); - EXPECT_TRUE(allocator_->IsFull()); - EXPECT_EQ(iterable_count, CountIterables()); - - PersistentMemoryAllocator::Iterator iter(allocator_.get()); - Lock lock; - ConditionVariable condition(&lock); - bool wake_up = false; - - CounterThread t1("t1", &iter, &lock, &condition, &wake_up); - CounterThread t2("t2", &iter, &lock, &condition, &wake_up); - CounterThread t3("t3", &iter, &lock, &condition, &wake_up); - CounterThread t4("t4", &iter, &lock, &condition, &wake_up); - CounterThread t5("t5", &iter, &lock, &condition, &wake_up); - - t1.Start(); - t2.Start(); - t3.Start(); - t4.Start(); - t5.Start(); - - // Take the lock and set the wake up condition to true. This helps to - // avoid a race condition where the Signal() event is called before - // all the threads have reached the Wait() and thus never get woken up. - { - AutoLock autolock(lock); - wake_up = true; - } - - // This will release all the waiting threads. - condition.Signal(); - - t1.Join(); - t2.Join(); - t3.Join(); - t4.Join(); - t5.Join(); - - EXPECT_EQ(iterable_count, - t1.count() + t2.count() + t3.count() + t4.count() + t5.count()); - -#if 0 - // These ensure that the threads don't run sequentially. It shouldn't be - // enabled in general because it could lead to a flaky test if it happens - // simply by chance but it is useful during development to ensure that the - // test is working correctly. - EXPECT_NE(iterable_count, t1.count()); - EXPECT_NE(iterable_count, t2.count()); - EXPECT_NE(iterable_count, t3.count()); - EXPECT_NE(iterable_count, t4.count()); - EXPECT_NE(iterable_count, t5.count()); -#endif -} - -TEST_F(PersistentMemoryAllocatorTest, DelayedAllocationTest) { - std::atomic<Reference> ref1, ref2; - ref1.store(0, std::memory_order_relaxed); - ref2.store(0, std::memory_order_relaxed); - DelayedPersistentAllocation da1(allocator_.get(), &ref1, 1001, 100, true); - DelayedPersistentAllocation da2a(allocator_.get(), &ref2, 2002, 200, 0, true); - DelayedPersistentAllocation da2b(allocator_.get(), &ref2, 2002, 200, 5, true); - - // Nothing should yet have been allocated. - uint32_t type; - PersistentMemoryAllocator::Iterator iter(allocator_.get()); - EXPECT_EQ(0U, iter.GetNext(&type)); - - // Do first delayed allocation and check that a new persistent object exists. - EXPECT_EQ(0U, da1.reference()); - void* mem1 = da1.Get(); - ASSERT_TRUE(mem1); - EXPECT_NE(0U, da1.reference()); - EXPECT_EQ(allocator_->GetAsReference(mem1, 1001), - ref1.load(std::memory_order_relaxed)); - EXPECT_NE(0U, iter.GetNext(&type)); - EXPECT_EQ(1001U, type); - EXPECT_EQ(0U, iter.GetNext(&type)); - - // Do second delayed allocation and check. - void* mem2a = da2a.Get(); - ASSERT_TRUE(mem2a); - EXPECT_EQ(allocator_->GetAsReference(mem2a, 2002), - ref2.load(std::memory_order_relaxed)); - EXPECT_NE(0U, iter.GetNext(&type)); - EXPECT_EQ(2002U, type); - EXPECT_EQ(0U, iter.GetNext(&type)); - - // Third allocation should just return offset into second allocation. - void* mem2b = da2b.Get(); - ASSERT_TRUE(mem2b); - EXPECT_EQ(0U, iter.GetNext(&type)); - EXPECT_EQ(reinterpret_cast<uintptr_t>(mem2a) + 5, - reinterpret_cast<uintptr_t>(mem2b)); -} - -// This test doesn't verify anything other than it doesn't crash. Its goal -// is to find coding errors that aren't otherwise tested for, much like a -// "fuzzer" would. -// This test is suppsoed to fail on TSAN bot (crbug.com/579867). -#if defined(THREAD_SANITIZER) -#define MAYBE_CorruptionTest DISABLED_CorruptionTest -#else -#define MAYBE_CorruptionTest CorruptionTest -#endif -TEST_F(PersistentMemoryAllocatorTest, MAYBE_CorruptionTest) { - char* memory = mem_segment_.get(); - AllocatorThread t1("t1", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE); - AllocatorThread t2("t2", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE); - AllocatorThread t3("t3", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE); - AllocatorThread t4("t4", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE); - AllocatorThread t5("t5", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE); - - t1.Start(); - t2.Start(); - t3.Start(); - t4.Start(); - t5.Start(); - - do { - size_t offset = RandInt(0, TEST_MEMORY_SIZE - 1); - char value = RandInt(0, 255); - memory[offset] = value; - } while (!allocator_->IsCorrupt() && !allocator_->IsFull()); - - t1.Join(); - t2.Join(); - t3.Join(); - t4.Join(); - t5.Join(); - - CountIterables(); -} - -// Attempt to cause crashes or loops by expressly creating dangerous conditions. -TEST_F(PersistentMemoryAllocatorTest, MaliciousTest) { - Reference block1 = allocator_->Allocate(sizeof(TestObject1), 1); - Reference block2 = allocator_->Allocate(sizeof(TestObject1), 2); - Reference block3 = allocator_->Allocate(sizeof(TestObject1), 3); - Reference block4 = allocator_->Allocate(sizeof(TestObject1), 3); - Reference block5 = allocator_->Allocate(sizeof(TestObject1), 3); - allocator_->MakeIterable(block1); - allocator_->MakeIterable(block2); - allocator_->MakeIterable(block3); - allocator_->MakeIterable(block4); - allocator_->MakeIterable(block5); - EXPECT_EQ(5U, CountIterables()); - EXPECT_FALSE(allocator_->IsCorrupt()); - - // Create loop in iterable list and ensure it doesn't hang. The return value - // from CountIterables() in these cases is unpredictable. If there is a - // failure, the call will hang and the test killed for taking too long. - uint32_t* header4 = (uint32_t*)(mem_segment_.get() + block4); - EXPECT_EQ(block5, header4[3]); - header4[3] = block4; - CountIterables(); // loop: 1-2-3-4-4 - EXPECT_TRUE(allocator_->IsCorrupt()); - - // Test where loop goes back to previous block. - header4[3] = block3; - CountIterables(); // loop: 1-2-3-4-3 - - // Test where loop goes back to the beginning. - header4[3] = block1; - CountIterables(); // loop: 1-2-3-4-1 -} - - -//----- LocalPersistentMemoryAllocator ----------------------------------------- - -TEST(LocalPersistentMemoryAllocatorTest, CreationTest) { - LocalPersistentMemoryAllocator allocator(TEST_MEMORY_SIZE, 42, ""); - EXPECT_EQ(42U, allocator.Id()); - EXPECT_NE(0U, allocator.Allocate(24, 1)); - EXPECT_FALSE(allocator.IsFull()); - EXPECT_FALSE(allocator.IsCorrupt()); -} - - -//----- SharedPersistentMemoryAllocator ---------------------------------------- - -TEST(SharedPersistentMemoryAllocatorTest, CreationTest) { - SharedMemoryHandle shared_handle_1; - SharedMemoryHandle shared_handle_2; - - PersistentMemoryAllocator::MemoryInfo meminfo1; - Reference r123, r456, r789; - { - std::unique_ptr<SharedMemory> shmem1(new SharedMemory()); - ASSERT_TRUE(shmem1->CreateAndMapAnonymous(TEST_MEMORY_SIZE)); - SharedPersistentMemoryAllocator local(std::move(shmem1), TEST_ID, "", - false); - EXPECT_FALSE(local.IsReadonly()); - r123 = local.Allocate(123, 123); - r456 = local.Allocate(456, 456); - r789 = local.Allocate(789, 789); - local.MakeIterable(r123); - local.ChangeType(r456, 654, 456, false); - local.MakeIterable(r789); - local.GetMemoryInfo(&meminfo1); - EXPECT_FALSE(local.IsFull()); - EXPECT_FALSE(local.IsCorrupt()); - - shared_handle_1 = local.shared_memory()->handle().Duplicate(); - ASSERT_TRUE(shared_handle_1.IsValid()); - shared_handle_2 = local.shared_memory()->handle().Duplicate(); - ASSERT_TRUE(shared_handle_2.IsValid()); - } - - // Read-only test. - std::unique_ptr<SharedMemory> shmem2(new SharedMemory(shared_handle_1, - /*readonly=*/true)); - ASSERT_TRUE(shmem2->Map(TEST_MEMORY_SIZE)); - - SharedPersistentMemoryAllocator shalloc2(std::move(shmem2), 0, "", true); - EXPECT_TRUE(shalloc2.IsReadonly()); - EXPECT_EQ(TEST_ID, shalloc2.Id()); - EXPECT_FALSE(shalloc2.IsFull()); - EXPECT_FALSE(shalloc2.IsCorrupt()); - - PersistentMemoryAllocator::Iterator iter2(&shalloc2); - uint32_t type; - EXPECT_EQ(r123, iter2.GetNext(&type)); - EXPECT_EQ(r789, iter2.GetNext(&type)); - EXPECT_EQ(0U, iter2.GetNext(&type)); - - EXPECT_EQ(123U, shalloc2.GetType(r123)); - EXPECT_EQ(654U, shalloc2.GetType(r456)); - EXPECT_EQ(789U, shalloc2.GetType(r789)); - - PersistentMemoryAllocator::MemoryInfo meminfo2; - shalloc2.GetMemoryInfo(&meminfo2); - EXPECT_EQ(meminfo1.total, meminfo2.total); - EXPECT_EQ(meminfo1.free, meminfo2.free); - - // Read/write test. - std::unique_ptr<SharedMemory> shmem3(new SharedMemory(shared_handle_2, - /*readonly=*/false)); - ASSERT_TRUE(shmem3->Map(TEST_MEMORY_SIZE)); - - SharedPersistentMemoryAllocator shalloc3(std::move(shmem3), 0, "", false); - EXPECT_FALSE(shalloc3.IsReadonly()); - EXPECT_EQ(TEST_ID, shalloc3.Id()); - EXPECT_FALSE(shalloc3.IsFull()); - EXPECT_FALSE(shalloc3.IsCorrupt()); - - PersistentMemoryAllocator::Iterator iter3(&shalloc3); - EXPECT_EQ(r123, iter3.GetNext(&type)); - EXPECT_EQ(r789, iter3.GetNext(&type)); - EXPECT_EQ(0U, iter3.GetNext(&type)); - - EXPECT_EQ(123U, shalloc3.GetType(r123)); - EXPECT_EQ(654U, shalloc3.GetType(r456)); - EXPECT_EQ(789U, shalloc3.GetType(r789)); - - PersistentMemoryAllocator::MemoryInfo meminfo3; - shalloc3.GetMemoryInfo(&meminfo3); - EXPECT_EQ(meminfo1.total, meminfo3.total); - EXPECT_EQ(meminfo1.free, meminfo3.free); - - // Interconnectivity test. - Reference obj = shalloc3.Allocate(42, 42); - ASSERT_TRUE(obj); - shalloc3.MakeIterable(obj); - EXPECT_EQ(obj, iter2.GetNext(&type)); - EXPECT_EQ(42U, type); - - // Clear-on-change test. - Reference data_ref = shalloc3.Allocate(sizeof(int) * 4, 911); - int* data = shalloc3.GetAsArray<int>(data_ref, 911, 4); - ASSERT_TRUE(data); - data[0] = 0; - data[1] = 1; - data[2] = 2; - data[3] = 3; - ASSERT_TRUE(shalloc3.ChangeType(data_ref, 119, 911, false)); - EXPECT_EQ(0, data[0]); - EXPECT_EQ(1, data[1]); - EXPECT_EQ(2, data[2]); - EXPECT_EQ(3, data[3]); - ASSERT_TRUE(shalloc3.ChangeType(data_ref, 191, 119, true)); - EXPECT_EQ(0, data[0]); - EXPECT_EQ(0, data[1]); - EXPECT_EQ(0, data[2]); - EXPECT_EQ(0, data[3]); -} - - -#if !defined(OS_NACL) -//----- FilePersistentMemoryAllocator ------------------------------------------ - -TEST(FilePersistentMemoryAllocatorTest, CreationTest) { - ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - FilePath file_path = temp_dir.GetPath().AppendASCII("persistent_memory"); - - PersistentMemoryAllocator::MemoryInfo meminfo1; - Reference r123, r456, r789; - { - LocalPersistentMemoryAllocator local(TEST_MEMORY_SIZE, TEST_ID, ""); - EXPECT_FALSE(local.IsReadonly()); - r123 = local.Allocate(123, 123); - r456 = local.Allocate(456, 456); - r789 = local.Allocate(789, 789); - local.MakeIterable(r123); - local.ChangeType(r456, 654, 456, false); - local.MakeIterable(r789); - local.GetMemoryInfo(&meminfo1); - EXPECT_FALSE(local.IsFull()); - EXPECT_FALSE(local.IsCorrupt()); - - File writer(file_path, File::FLAG_CREATE | File::FLAG_WRITE); - ASSERT_TRUE(writer.IsValid()); - writer.Write(0, (const char*)local.data(), local.used()); - } - - std::unique_ptr<MemoryMappedFile> mmfile(new MemoryMappedFile()); - mmfile->Initialize(file_path); - EXPECT_TRUE(mmfile->IsValid()); - const size_t mmlength = mmfile->length(); - EXPECT_GE(meminfo1.total, mmlength); - - FilePersistentMemoryAllocator file(std::move(mmfile), 0, 0, "", false); - EXPECT_FALSE(file.IsReadonly()); - EXPECT_EQ(TEST_ID, file.Id()); - EXPECT_FALSE(file.IsFull()); - EXPECT_FALSE(file.IsCorrupt()); - - PersistentMemoryAllocator::Iterator iter(&file); - uint32_t type; - EXPECT_EQ(r123, iter.GetNext(&type)); - EXPECT_EQ(r789, iter.GetNext(&type)); - EXPECT_EQ(0U, iter.GetNext(&type)); - - EXPECT_EQ(123U, file.GetType(r123)); - EXPECT_EQ(654U, file.GetType(r456)); - EXPECT_EQ(789U, file.GetType(r789)); - - PersistentMemoryAllocator::MemoryInfo meminfo2; - file.GetMemoryInfo(&meminfo2); - EXPECT_GE(meminfo1.total, meminfo2.total); - EXPECT_GE(meminfo1.free, meminfo2.free); - EXPECT_EQ(mmlength, meminfo2.total); - EXPECT_EQ(0U, meminfo2.free); - - // There's no way of knowing if Flush actually does anything but at least - // verify that it runs without CHECK violations. - file.Flush(false); - file.Flush(true); -} - -TEST(FilePersistentMemoryAllocatorTest, ExtendTest) { - ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - FilePath file_path = temp_dir.GetPath().AppendASCII("extend_test"); - MemoryMappedFile::Region region = {0, 16 << 10}; // 16KiB maximum size. - - // Start with a small but valid file of persistent data. - ASSERT_FALSE(PathExists(file_path)); - { - LocalPersistentMemoryAllocator local(TEST_MEMORY_SIZE, TEST_ID, ""); - local.Allocate(1, 1); - local.Allocate(11, 11); - - File writer(file_path, File::FLAG_CREATE | File::FLAG_WRITE); - ASSERT_TRUE(writer.IsValid()); - writer.Write(0, (const char*)local.data(), local.used()); - } - ASSERT_TRUE(PathExists(file_path)); - int64_t before_size; - ASSERT_TRUE(GetFileSize(file_path, &before_size)); - - // Map it as an extendable read/write file and append to it. - { - std::unique_ptr<MemoryMappedFile> mmfile(new MemoryMappedFile()); - mmfile->Initialize( - File(file_path, File::FLAG_OPEN | File::FLAG_READ | File::FLAG_WRITE), - region, MemoryMappedFile::READ_WRITE_EXTEND); - FilePersistentMemoryAllocator allocator(std::move(mmfile), region.size, 0, - "", false); - EXPECT_EQ(static_cast<size_t>(before_size), allocator.used()); - - allocator.Allocate(111, 111); - EXPECT_LT(static_cast<size_t>(before_size), allocator.used()); - } - - // Validate that append worked. - int64_t after_size; - ASSERT_TRUE(GetFileSize(file_path, &after_size)); - EXPECT_LT(before_size, after_size); - - // Verify that it's still an acceptable file. - { - std::unique_ptr<MemoryMappedFile> mmfile(new MemoryMappedFile()); - mmfile->Initialize( - File(file_path, File::FLAG_OPEN | File::FLAG_READ | File::FLAG_WRITE), - region, MemoryMappedFile::READ_WRITE_EXTEND); - EXPECT_TRUE(FilePersistentMemoryAllocator::IsFileAcceptable(*mmfile, true)); - EXPECT_TRUE( - FilePersistentMemoryAllocator::IsFileAcceptable(*mmfile, false)); - } -} - -TEST(FilePersistentMemoryAllocatorTest, AcceptableTest) { - const uint32_t kAllocAlignment = - PersistentMemoryAllocatorTest::GetAllocAlignment(); - ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - - LocalPersistentMemoryAllocator local(TEST_MEMORY_SIZE, TEST_ID, ""); - local.MakeIterable(local.Allocate(1, 1)); - local.MakeIterable(local.Allocate(11, 11)); - const size_t minsize = local.used(); - std::unique_ptr<char[]> garbage(new char[minsize]); - RandBytes(garbage.get(), minsize); - - std::unique_ptr<MemoryMappedFile> mmfile; - char filename[100]; - for (size_t filesize = minsize; filesize > 0; --filesize) { - strings::SafeSPrintf(filename, "memory_%d_A", filesize); - FilePath file_path = temp_dir.GetPath().AppendASCII(filename); - ASSERT_FALSE(PathExists(file_path)); - { - File writer(file_path, File::FLAG_CREATE | File::FLAG_WRITE); - ASSERT_TRUE(writer.IsValid()); - writer.Write(0, (const char*)local.data(), filesize); - } - ASSERT_TRUE(PathExists(file_path)); - - // Request read/write access for some sizes that are a multple of the - // allocator's alignment size. The allocator is strict about file size - // being a multiple of its internal alignment when doing read/write access. - const bool read_only = (filesize % (2 * kAllocAlignment)) != 0; - const uint32_t file_flags = - File::FLAG_OPEN | File::FLAG_READ | (read_only ? 0 : File::FLAG_WRITE); - const MemoryMappedFile::Access map_access = - read_only ? MemoryMappedFile::READ_ONLY : MemoryMappedFile::READ_WRITE; - - mmfile.reset(new MemoryMappedFile()); - mmfile->Initialize(File(file_path, file_flags), map_access); - EXPECT_EQ(filesize, mmfile->length()); - if (FilePersistentMemoryAllocator::IsFileAcceptable(*mmfile, read_only)) { - // Make sure construction doesn't crash. It will, however, cause - // error messages warning about about a corrupted memory segment. - FilePersistentMemoryAllocator allocator(std::move(mmfile), 0, 0, "", - read_only); - // Also make sure that iteration doesn't crash. - PersistentMemoryAllocator::Iterator iter(&allocator); - uint32_t type_id; - Reference ref; - while ((ref = iter.GetNext(&type_id)) != 0) { - const char* data = allocator.GetAsArray<char>( - ref, 0, PersistentMemoryAllocator::kSizeAny); - uint32_t type = allocator.GetType(ref); - size_t size = allocator.GetAllocSize(ref); - // Ensure compiler can't optimize-out above variables. - (void)data; - (void)type; - (void)size; - } - - // Ensure that short files are detected as corrupt and full files are not. - EXPECT_EQ(filesize != minsize, allocator.IsCorrupt()); - } else { - // For filesize >= minsize, the file must be acceptable. This - // else clause (file-not-acceptable) should be reached only if - // filesize < minsize. - EXPECT_LT(filesize, minsize); - } - - strings::SafeSPrintf(filename, "memory_%d_B", filesize); - file_path = temp_dir.GetPath().AppendASCII(filename); - ASSERT_FALSE(PathExists(file_path)); - { - File writer(file_path, File::FLAG_CREATE | File::FLAG_WRITE); - ASSERT_TRUE(writer.IsValid()); - writer.Write(0, (const char*)garbage.get(), filesize); - } - ASSERT_TRUE(PathExists(file_path)); - - mmfile.reset(new MemoryMappedFile()); - mmfile->Initialize(File(file_path, file_flags), map_access); - EXPECT_EQ(filesize, mmfile->length()); - if (FilePersistentMemoryAllocator::IsFileAcceptable(*mmfile, read_only)) { - // Make sure construction doesn't crash. It will, however, cause - // error messages warning about about a corrupted memory segment. - FilePersistentMemoryAllocator allocator(std::move(mmfile), 0, 0, "", - read_only); - EXPECT_TRUE(allocator.IsCorrupt()); // Garbage data so it should be. - } else { - // For filesize >= minsize, the file must be acceptable. This - // else clause (file-not-acceptable) should be reached only if - // filesize < minsize. - EXPECT_GT(minsize, filesize); - } - } -} - -TEST_F(PersistentMemoryAllocatorTest, TruncateTest) { - ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - FilePath file_path = temp_dir.GetPath().AppendASCII("truncate_test"); - - // Start with a small but valid file of persistent data. Keep the "used" - // amount for both allocations. - Reference a1_ref; - Reference a2_ref; - size_t a1_used; - size_t a2_used; - ASSERT_FALSE(PathExists(file_path)); - { - LocalPersistentMemoryAllocator allocator(TEST_MEMORY_SIZE, TEST_ID, ""); - a1_ref = allocator.Allocate(100 << 10, 1); - allocator.MakeIterable(a1_ref); - a1_used = allocator.used(); - a2_ref = allocator.Allocate(200 << 10, 11); - allocator.MakeIterable(a2_ref); - a2_used = allocator.used(); - - File writer(file_path, File::FLAG_CREATE | File::FLAG_WRITE); - ASSERT_TRUE(writer.IsValid()); - writer.Write(0, static_cast<const char*>(allocator.data()), - allocator.size()); - } - ASSERT_TRUE(PathExists(file_path)); - EXPECT_LE(a1_used, a2_ref); - - // Truncate the file to include everything and make sure it can be read, both - // with read-write and read-only access. - for (size_t file_length : {a2_used, a1_used, a1_used / 2}) { - SCOPED_TRACE(StringPrintf("file_length=%zu", file_length)); - SetFileLength(file_path, file_length); - - for (bool read_only : {false, true}) { - SCOPED_TRACE(StringPrintf("read_only=%s", read_only ? "true" : "false")); - - std::unique_ptr<MemoryMappedFile> mmfile(new MemoryMappedFile()); - mmfile->Initialize( - File(file_path, File::FLAG_OPEN | - (read_only ? File::FLAG_READ - : File::FLAG_READ | File::FLAG_WRITE)), - read_only ? MemoryMappedFile::READ_ONLY - : MemoryMappedFile::READ_WRITE); - ASSERT_TRUE( - FilePersistentMemoryAllocator::IsFileAcceptable(*mmfile, read_only)); - - FilePersistentMemoryAllocator allocator(std::move(mmfile), 0, 0, "", - read_only); - - PersistentMemoryAllocator::Iterator iter(&allocator); - uint32_t type_id; - EXPECT_EQ(file_length >= a1_used ? a1_ref : 0U, iter.GetNext(&type_id)); - EXPECT_EQ(file_length >= a2_used ? a2_ref : 0U, iter.GetNext(&type_id)); - EXPECT_EQ(0U, iter.GetNext(&type_id)); - - // Ensure that short files are detected as corrupt and full files are not. - EXPECT_EQ(file_length < a2_used, allocator.IsCorrupt()); - } - - // Ensure that file length was not adjusted. - int64_t actual_length; - ASSERT_TRUE(GetFileSize(file_path, &actual_length)); - EXPECT_EQ(file_length, static_cast<size_t>(actual_length)); - } -} - -#endif // !defined(OS_NACL) - -} // namespace base
diff --git a/base/metrics/persistent_sample_map_unittest.cc b/base/metrics/persistent_sample_map_unittest.cc deleted file mode 100644 index b25f582..0000000 --- a/base/metrics/persistent_sample_map_unittest.cc +++ /dev/null
@@ -1,260 +0,0 @@ -// Copyright (c) 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/metrics/persistent_sample_map.h" - -#include <memory> - -#include "base/memory/ptr_util.h" -#include "base/metrics/persistent_histogram_allocator.h" -#include "base/test/gtest_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -std::unique_ptr<PersistentHistogramAllocator> CreateHistogramAllocator( - size_t bytes) { - return std::make_unique<PersistentHistogramAllocator>( - std::make_unique<LocalPersistentMemoryAllocator>(bytes, 0, "")); -} - -std::unique_ptr<PersistentHistogramAllocator> DuplicateHistogramAllocator( - PersistentHistogramAllocator* original) { - return std::make_unique<PersistentHistogramAllocator>( - std::make_unique<PersistentMemoryAllocator>( - const_cast<void*>(original->data()), original->length(), 0, - original->Id(), original->Name(), false)); -} - -TEST(PersistentSampleMapTest, AccumulateTest) { - std::unique_ptr<PersistentHistogramAllocator> allocator = - CreateHistogramAllocator(64 << 10); // 64 KiB - HistogramSamples::LocalMetadata meta; - PersistentSampleMap samples(1, allocator.get(), &meta); - - samples.Accumulate(1, 100); - samples.Accumulate(2, 200); - samples.Accumulate(1, -200); - EXPECT_EQ(-100, samples.GetCount(1)); - EXPECT_EQ(200, samples.GetCount(2)); - - EXPECT_EQ(300, samples.sum()); - EXPECT_EQ(100, samples.TotalCount()); - EXPECT_EQ(samples.redundant_count(), samples.TotalCount()); -} - -TEST(PersistentSampleMapTest, Accumulate_LargeValuesDontOverflow) { - std::unique_ptr<PersistentHistogramAllocator> allocator = - CreateHistogramAllocator(64 << 10); // 64 KiB - HistogramSamples::LocalMetadata meta; - PersistentSampleMap samples(1, allocator.get(), &meta); - - samples.Accumulate(250000000, 100); - samples.Accumulate(500000000, 200); - samples.Accumulate(250000000, -200); - EXPECT_EQ(-100, samples.GetCount(250000000)); - EXPECT_EQ(200, samples.GetCount(500000000)); - - EXPECT_EQ(75000000000LL, samples.sum()); - EXPECT_EQ(100, samples.TotalCount()); - EXPECT_EQ(samples.redundant_count(), samples.TotalCount()); -} - -TEST(PersistentSampleMapTest, AddSubtractTest) { - std::unique_ptr<PersistentHistogramAllocator> allocator1 = - CreateHistogramAllocator(64 << 10); // 64 KiB - HistogramSamples::LocalMetadata meta1; - PersistentSampleMap samples1(1, allocator1.get(), &meta1); - samples1.Accumulate(1, 100); - samples1.Accumulate(2, 100); - samples1.Accumulate(3, 100); - - std::unique_ptr<PersistentHistogramAllocator> allocator2 = - DuplicateHistogramAllocator(allocator1.get()); - HistogramSamples::LocalMetadata meta2; - PersistentSampleMap samples2(2, allocator2.get(), &meta2); - samples2.Accumulate(1, 200); - samples2.Accumulate(2, 200); - samples2.Accumulate(4, 200); - - samples1.Add(samples2); - EXPECT_EQ(300, samples1.GetCount(1)); - EXPECT_EQ(300, samples1.GetCount(2)); - EXPECT_EQ(100, samples1.GetCount(3)); - EXPECT_EQ(200, samples1.GetCount(4)); - EXPECT_EQ(2000, samples1.sum()); - EXPECT_EQ(900, samples1.TotalCount()); - EXPECT_EQ(samples1.redundant_count(), samples1.TotalCount()); - - samples1.Subtract(samples2); - EXPECT_EQ(100, samples1.GetCount(1)); - EXPECT_EQ(100, samples1.GetCount(2)); - EXPECT_EQ(100, samples1.GetCount(3)); - EXPECT_EQ(0, samples1.GetCount(4)); - EXPECT_EQ(600, samples1.sum()); - EXPECT_EQ(300, samples1.TotalCount()); - EXPECT_EQ(samples1.redundant_count(), samples1.TotalCount()); -} - -TEST(PersistentSampleMapTest, PersistenceTest) { - std::unique_ptr<PersistentHistogramAllocator> allocator1 = - CreateHistogramAllocator(64 << 10); // 64 KiB - HistogramSamples::LocalMetadata meta12; - PersistentSampleMap samples1(12, allocator1.get(), &meta12); - samples1.Accumulate(1, 100); - samples1.Accumulate(2, 200); - samples1.Accumulate(1, -200); - samples1.Accumulate(-1, 1); - EXPECT_EQ(-100, samples1.GetCount(1)); - EXPECT_EQ(200, samples1.GetCount(2)); - EXPECT_EQ(1, samples1.GetCount(-1)); - EXPECT_EQ(299, samples1.sum()); - EXPECT_EQ(101, samples1.TotalCount()); - EXPECT_EQ(samples1.redundant_count(), samples1.TotalCount()); - - std::unique_ptr<PersistentHistogramAllocator> allocator2 = - DuplicateHistogramAllocator(allocator1.get()); - PersistentSampleMap samples2(12, allocator2.get(), &meta12); - EXPECT_EQ(samples1.id(), samples2.id()); - EXPECT_EQ(samples1.sum(), samples2.sum()); - EXPECT_EQ(samples1.redundant_count(), samples2.redundant_count()); - EXPECT_EQ(samples1.TotalCount(), samples2.TotalCount()); - EXPECT_EQ(-100, samples2.GetCount(1)); - EXPECT_EQ(200, samples2.GetCount(2)); - EXPECT_EQ(1, samples2.GetCount(-1)); - EXPECT_EQ(299, samples2.sum()); - EXPECT_EQ(101, samples2.TotalCount()); - EXPECT_EQ(samples2.redundant_count(), samples2.TotalCount()); - - samples1.Accumulate(-1, -1); - EXPECT_EQ(0, samples2.GetCount(3)); - EXPECT_EQ(0, samples1.GetCount(3)); - samples2.Accumulate(3, 300); - EXPECT_EQ(300, samples2.GetCount(3)); - EXPECT_EQ(300, samples1.GetCount(3)); - EXPECT_EQ(samples1.sum(), samples2.sum()); - EXPECT_EQ(samples1.redundant_count(), samples2.redundant_count()); - EXPECT_EQ(samples1.TotalCount(), samples2.TotalCount()); - - EXPECT_EQ(0, samples2.GetCount(4)); - EXPECT_EQ(0, samples1.GetCount(4)); - samples1.Accumulate(4, 400); - EXPECT_EQ(400, samples2.GetCount(4)); - EXPECT_EQ(400, samples1.GetCount(4)); - samples2.Accumulate(4, 4000); - EXPECT_EQ(4400, samples2.GetCount(4)); - EXPECT_EQ(4400, samples1.GetCount(4)); - EXPECT_EQ(samples1.sum(), samples2.sum()); - EXPECT_EQ(samples1.redundant_count(), samples2.redundant_count()); - EXPECT_EQ(samples1.TotalCount(), samples2.TotalCount()); -} - -TEST(PersistentSampleMapIteratorTest, IterateTest) { - std::unique_ptr<PersistentHistogramAllocator> allocator = - CreateHistogramAllocator(64 << 10); // 64 KiB - HistogramSamples::LocalMetadata meta; - PersistentSampleMap samples(1, allocator.get(), &meta); - samples.Accumulate(1, 100); - samples.Accumulate(2, 200); - samples.Accumulate(4, -300); - samples.Accumulate(5, 0); - - std::unique_ptr<SampleCountIterator> it = samples.Iterator(); - - HistogramBase::Sample min; - int64_t max; - HistogramBase::Count count; - - it->Get(&min, &max, &count); - EXPECT_EQ(1, min); - EXPECT_EQ(2, max); - EXPECT_EQ(100, count); - EXPECT_FALSE(it->GetBucketIndex(nullptr)); - - it->Next(); - it->Get(&min, &max, &count); - EXPECT_EQ(2, min); - EXPECT_EQ(3, max); - EXPECT_EQ(200, count); - - it->Next(); - it->Get(&min, &max, &count); - EXPECT_EQ(4, min); - EXPECT_EQ(5, max); - EXPECT_EQ(-300, count); - - it->Next(); - EXPECT_TRUE(it->Done()); -} - -TEST(PersistentSampleMapIteratorTest, SkipEmptyRanges) { - std::unique_ptr<PersistentHistogramAllocator> allocator1 = - CreateHistogramAllocator(64 << 10); // 64 KiB - HistogramSamples::LocalMetadata meta1; - PersistentSampleMap samples1(1, allocator1.get(), &meta1); - samples1.Accumulate(5, 1); - samples1.Accumulate(10, 2); - samples1.Accumulate(15, 3); - samples1.Accumulate(20, 4); - samples1.Accumulate(25, 5); - - std::unique_ptr<PersistentHistogramAllocator> allocator2 = - DuplicateHistogramAllocator(allocator1.get()); - HistogramSamples::LocalMetadata meta2; - PersistentSampleMap samples2(2, allocator2.get(), &meta2); - samples2.Accumulate(5, 1); - samples2.Accumulate(20, 4); - samples2.Accumulate(25, 5); - - samples1.Subtract(samples2); - - std::unique_ptr<SampleCountIterator> it = samples1.Iterator(); - EXPECT_FALSE(it->Done()); - - HistogramBase::Sample min; - int64_t max; - HistogramBase::Count count; - - it->Get(&min, &max, &count); - EXPECT_EQ(10, min); - EXPECT_EQ(11, max); - EXPECT_EQ(2, count); - - it->Next(); - EXPECT_FALSE(it->Done()); - - it->Get(&min, &max, &count); - EXPECT_EQ(15, min); - EXPECT_EQ(16, max); - EXPECT_EQ(3, count); - - it->Next(); - EXPECT_TRUE(it->Done()); -} - -TEST(PersistentSampleMapIteratorDeathTest, IterateDoneTest) { - std::unique_ptr<PersistentHistogramAllocator> allocator = - CreateHistogramAllocator(64 << 10); // 64 KiB - HistogramSamples::LocalMetadata meta; - PersistentSampleMap samples(1, allocator.get(), &meta); - - std::unique_ptr<SampleCountIterator> it = samples.Iterator(); - - EXPECT_TRUE(it->Done()); - - HistogramBase::Sample min; - int64_t max; - HistogramBase::Count count; - EXPECT_DCHECK_DEATH(it->Get(&min, &max, &count)); - - EXPECT_DCHECK_DEATH(it->Next()); - - samples.Accumulate(1, 100); - it = samples.Iterator(); - EXPECT_FALSE(it->Done()); -} - -} // namespace -} // namespace base
diff --git a/base/metrics/sample_map_unittest.cc b/base/metrics/sample_map_unittest.cc deleted file mode 100644 index 83db56f..0000000 --- a/base/metrics/sample_map_unittest.cc +++ /dev/null
@@ -1,168 +0,0 @@ -// 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/metrics/sample_map.h" - -#include <memory> - -#include "base/test/gtest_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -TEST(SampleMapTest, AccumulateTest) { - SampleMap samples(1); - - samples.Accumulate(1, 100); - samples.Accumulate(2, 200); - samples.Accumulate(1, -200); - EXPECT_EQ(-100, samples.GetCount(1)); - EXPECT_EQ(200, samples.GetCount(2)); - - EXPECT_EQ(300, samples.sum()); - EXPECT_EQ(100, samples.TotalCount()); - EXPECT_EQ(samples.redundant_count(), samples.TotalCount()); -} - -TEST(SampleMapTest, Accumulate_LargeValuesDontOverflow) { - SampleMap samples(1); - - samples.Accumulate(250000000, 100); - samples.Accumulate(500000000, 200); - samples.Accumulate(250000000, -200); - EXPECT_EQ(-100, samples.GetCount(250000000)); - EXPECT_EQ(200, samples.GetCount(500000000)); - - EXPECT_EQ(75000000000LL, samples.sum()); - EXPECT_EQ(100, samples.TotalCount()); - EXPECT_EQ(samples.redundant_count(), samples.TotalCount()); -} - -TEST(SampleMapTest, AddSubtractTest) { - SampleMap samples1(1); - SampleMap samples2(2); - - samples1.Accumulate(1, 100); - samples1.Accumulate(2, 100); - samples1.Accumulate(3, 100); - - samples2.Accumulate(1, 200); - samples2.Accumulate(2, 200); - samples2.Accumulate(4, 200); - - samples1.Add(samples2); - EXPECT_EQ(300, samples1.GetCount(1)); - EXPECT_EQ(300, samples1.GetCount(2)); - EXPECT_EQ(100, samples1.GetCount(3)); - EXPECT_EQ(200, samples1.GetCount(4)); - EXPECT_EQ(2000, samples1.sum()); - EXPECT_EQ(900, samples1.TotalCount()); - EXPECT_EQ(samples1.redundant_count(), samples1.TotalCount()); - - samples1.Subtract(samples2); - EXPECT_EQ(100, samples1.GetCount(1)); - EXPECT_EQ(100, samples1.GetCount(2)); - EXPECT_EQ(100, samples1.GetCount(3)); - EXPECT_EQ(0, samples1.GetCount(4)); - EXPECT_EQ(600, samples1.sum()); - EXPECT_EQ(300, samples1.TotalCount()); - EXPECT_EQ(samples1.redundant_count(), samples1.TotalCount()); -} - -TEST(SampleMapIteratorTest, IterateTest) { - SampleMap samples(1); - samples.Accumulate(1, 100); - samples.Accumulate(2, 200); - samples.Accumulate(4, -300); - samples.Accumulate(5, 0); - - std::unique_ptr<SampleCountIterator> it = samples.Iterator(); - - HistogramBase::Sample min; - int64_t max; - HistogramBase::Count count; - - it->Get(&min, &max, &count); - EXPECT_EQ(1, min); - EXPECT_EQ(2, max); - EXPECT_EQ(100, count); - EXPECT_FALSE(it->GetBucketIndex(nullptr)); - - it->Next(); - it->Get(&min, &max, &count); - EXPECT_EQ(2, min); - EXPECT_EQ(3, max); - EXPECT_EQ(200, count); - - it->Next(); - it->Get(&min, &max, &count); - EXPECT_EQ(4, min); - EXPECT_EQ(5, max); - EXPECT_EQ(-300, count); - - it->Next(); - EXPECT_TRUE(it->Done()); -} - -TEST(SampleMapIteratorTest, SkipEmptyRanges) { - SampleMap samples(1); - samples.Accumulate(5, 1); - samples.Accumulate(10, 2); - samples.Accumulate(15, 3); - samples.Accumulate(20, 4); - samples.Accumulate(25, 5); - - SampleMap samples2(2); - samples2.Accumulate(5, 1); - samples2.Accumulate(20, 4); - samples2.Accumulate(25, 5); - - samples.Subtract(samples2); - - std::unique_ptr<SampleCountIterator> it = samples.Iterator(); - EXPECT_FALSE(it->Done()); - - HistogramBase::Sample min; - int64_t max; - HistogramBase::Count count; - - it->Get(&min, &max, &count); - EXPECT_EQ(10, min); - EXPECT_EQ(11, max); - EXPECT_EQ(2, count); - - it->Next(); - EXPECT_FALSE(it->Done()); - - it->Get(&min, &max, &count); - EXPECT_EQ(15, min); - EXPECT_EQ(16, max); - EXPECT_EQ(3, count); - - it->Next(); - EXPECT_TRUE(it->Done()); -} - -TEST(SampleMapIteratorDeathTest, IterateDoneTest) { - SampleMap samples(1); - - std::unique_ptr<SampleCountIterator> it = samples.Iterator(); - - EXPECT_TRUE(it->Done()); - - HistogramBase::Sample min; - int64_t max; - HistogramBase::Count count; - EXPECT_DCHECK_DEATH(it->Get(&min, &max, &count)); - - EXPECT_DCHECK_DEATH(it->Next()); - - samples.Accumulate(1, 100); - it = samples.Iterator(); - EXPECT_FALSE(it->Done()); -} - -} // namespace -} // namespace base
diff --git a/base/metrics/sample_vector_unittest.cc b/base/metrics/sample_vector_unittest.cc deleted file mode 100644 index 4921802..0000000 --- a/base/metrics/sample_vector_unittest.cc +++ /dev/null
@@ -1,545 +0,0 @@ -// 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/metrics/sample_vector.h" - -#include <limits.h> -#include <stddef.h> - -#include <atomic> -#include <memory> -#include <vector> - -#include "base/metrics/bucket_ranges.h" -#include "base/metrics/histogram.h" -#include "base/metrics/persistent_memory_allocator.h" -#include "base/test/gtest_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -// This framework class has "friend" access to the SampleVector for accessing -// non-public methods and fields. -class SampleVectorTest : public testing::Test { - public: - const HistogramBase::AtomicCount* GetSamplesCounts( - const SampleVectorBase& samples) { - return samples.counts(); - } -}; - -TEST_F(SampleVectorTest, Accumulate) { - // Custom buckets: [1, 5) [5, 10) - BucketRanges ranges(3); - ranges.set_range(0, 1); - ranges.set_range(1, 5); - ranges.set_range(2, 10); - SampleVector samples(1, &ranges); - - samples.Accumulate(1, 200); - samples.Accumulate(2, -300); - EXPECT_EQ(-100, samples.GetCountAtIndex(0)); - - samples.Accumulate(5, 200); - EXPECT_EQ(200, samples.GetCountAtIndex(1)); - - EXPECT_EQ(600, samples.sum()); - EXPECT_EQ(100, samples.redundant_count()); - EXPECT_EQ(samples.TotalCount(), samples.redundant_count()); - - samples.Accumulate(5, -100); - EXPECT_EQ(100, samples.GetCountAtIndex(1)); - - EXPECT_EQ(100, samples.sum()); - EXPECT_EQ(0, samples.redundant_count()); - EXPECT_EQ(samples.TotalCount(), samples.redundant_count()); -} - -TEST_F(SampleVectorTest, Accumulate_LargeValuesDontOverflow) { - // Custom buckets: [1, 250000000) [250000000, 500000000) - BucketRanges ranges(3); - ranges.set_range(0, 1); - ranges.set_range(1, 250000000); - ranges.set_range(2, 500000000); - SampleVector samples(1, &ranges); - - samples.Accumulate(240000000, 200); - samples.Accumulate(249999999, -300); - EXPECT_EQ(-100, samples.GetCountAtIndex(0)); - - samples.Accumulate(250000000, 200); - EXPECT_EQ(200, samples.GetCountAtIndex(1)); - - EXPECT_EQ(23000000300LL, samples.sum()); - EXPECT_EQ(100, samples.redundant_count()); - EXPECT_EQ(samples.TotalCount(), samples.redundant_count()); - - samples.Accumulate(250000000, -100); - EXPECT_EQ(100, samples.GetCountAtIndex(1)); - - EXPECT_EQ(-1999999700LL, samples.sum()); - EXPECT_EQ(0, samples.redundant_count()); - EXPECT_EQ(samples.TotalCount(), samples.redundant_count()); -} - -TEST_F(SampleVectorTest, AddSubtract) { - // Custom buckets: [0, 1) [1, 2) [2, 3) [3, INT_MAX) - BucketRanges ranges(5); - ranges.set_range(0, 0); - ranges.set_range(1, 1); - ranges.set_range(2, 2); - ranges.set_range(3, 3); - ranges.set_range(4, INT_MAX); - - SampleVector samples1(1, &ranges); - samples1.Accumulate(0, 100); - samples1.Accumulate(2, 100); - samples1.Accumulate(4, 100); - EXPECT_EQ(600, samples1.sum()); - EXPECT_EQ(300, samples1.TotalCount()); - EXPECT_EQ(samples1.redundant_count(), samples1.TotalCount()); - - SampleVector samples2(2, &ranges); - samples2.Accumulate(1, 200); - samples2.Accumulate(2, 200); - samples2.Accumulate(4, 200); - EXPECT_EQ(1400, samples2.sum()); - EXPECT_EQ(600, samples2.TotalCount()); - EXPECT_EQ(samples2.redundant_count(), samples2.TotalCount()); - - samples1.Add(samples2); - EXPECT_EQ(100, samples1.GetCountAtIndex(0)); - EXPECT_EQ(200, samples1.GetCountAtIndex(1)); - EXPECT_EQ(300, samples1.GetCountAtIndex(2)); - EXPECT_EQ(300, samples1.GetCountAtIndex(3)); - EXPECT_EQ(2000, samples1.sum()); - EXPECT_EQ(900, samples1.TotalCount()); - EXPECT_EQ(samples1.redundant_count(), samples1.TotalCount()); - - samples1.Subtract(samples2); - EXPECT_EQ(100, samples1.GetCountAtIndex(0)); - EXPECT_EQ(0, samples1.GetCountAtIndex(1)); - EXPECT_EQ(100, samples1.GetCountAtIndex(2)); - EXPECT_EQ(100, samples1.GetCountAtIndex(3)); - EXPECT_EQ(600, samples1.sum()); - EXPECT_EQ(300, samples1.TotalCount()); - EXPECT_EQ(samples1.redundant_count(), samples1.TotalCount()); -} - -TEST_F(SampleVectorTest, BucketIndexDeath) { - // 8 buckets with exponential layout: - // [0, 1) [1, 2) [2, 4) [4, 8) [8, 16) [16, 32) [32, 64) [64, INT_MAX) - BucketRanges ranges(9); - Histogram::InitializeBucketRanges(1, 64, &ranges); - SampleVector samples(1, &ranges); - - // Normal case - samples.Accumulate(0, 1); - samples.Accumulate(3, 2); - samples.Accumulate(64, 3); - EXPECT_EQ(1, samples.GetCount(0)); - EXPECT_EQ(2, samples.GetCount(2)); - EXPECT_EQ(3, samples.GetCount(65)); - - // Extreme case. - EXPECT_DEATH_IF_SUPPORTED(samples.Accumulate(INT_MIN, 100), ""); - EXPECT_DEATH_IF_SUPPORTED(samples.Accumulate(-1, 100), ""); - EXPECT_DEATH_IF_SUPPORTED(samples.Accumulate(INT_MAX, 100), ""); - - // Custom buckets: [1, 5) [5, 10) - // Note, this is not a valid BucketRanges for Histogram because it does not - // have overflow buckets. - BucketRanges ranges2(3); - ranges2.set_range(0, 1); - ranges2.set_range(1, 5); - ranges2.set_range(2, 10); - SampleVector samples2(2, &ranges2); - - // Normal case. - samples2.Accumulate(1, 1); - samples2.Accumulate(4, 1); - samples2.Accumulate(5, 2); - samples2.Accumulate(9, 2); - EXPECT_EQ(2, samples2.GetCount(1)); - EXPECT_EQ(4, samples2.GetCount(5)); - - // Extreme case. - EXPECT_DEATH_IF_SUPPORTED(samples2.Accumulate(0, 100), ""); - EXPECT_DEATH_IF_SUPPORTED(samples2.Accumulate(10, 100), ""); -} - -TEST_F(SampleVectorTest, AddSubtractBucketNotMatchDeath) { - // Custom buckets 1: [1, 3) [3, 5) - BucketRanges ranges1(3); - ranges1.set_range(0, 1); - ranges1.set_range(1, 3); - ranges1.set_range(2, 5); - SampleVector samples1(1, &ranges1); - - // Custom buckets 2: [0, 1) [1, 3) [3, 6) [6, 7) - BucketRanges ranges2(5); - ranges2.set_range(0, 0); - ranges2.set_range(1, 1); - ranges2.set_range(2, 3); - ranges2.set_range(3, 6); - ranges2.set_range(4, 7); - SampleVector samples2(2, &ranges2); - - samples2.Accumulate(1, 100); - samples1.Add(samples2); - EXPECT_EQ(100, samples1.GetCountAtIndex(0)); - - // Extra bucket in the beginning. These should CHECK in GetBucketIndex. - samples2.Accumulate(0, 100); - EXPECT_DEATH_IF_SUPPORTED(samples1.Add(samples2), ""); - EXPECT_DEATH_IF_SUPPORTED(samples1.Subtract(samples2), ""); - - // Extra bucket in the end. These should cause AddSubtractImpl to fail, and - // Add to DCHECK as a result. - samples2.Accumulate(0, -100); - samples2.Accumulate(6, 100); - EXPECT_DCHECK_DEATH(samples1.Add(samples2)); - EXPECT_DCHECK_DEATH(samples1.Subtract(samples2)); - - // Bucket not match: [3, 5) VS [3, 6). These should cause AddSubtractImpl to - // DCHECK. - samples2.Accumulate(6, -100); - samples2.Accumulate(3, 100); - EXPECT_DCHECK_DEATH(samples1.Add(samples2)); - EXPECT_DCHECK_DEATH(samples1.Subtract(samples2)); -} - -TEST_F(SampleVectorTest, Iterate) { - BucketRanges ranges(5); - ranges.set_range(0, 0); - ranges.set_range(1, 1); - ranges.set_range(2, 2); - ranges.set_range(3, 3); - ranges.set_range(4, 4); - - std::vector<HistogramBase::Count> counts(3); - counts[0] = 1; - counts[1] = 0; // Iterator will bypass this empty bucket. - counts[2] = 2; - - // BucketRanges can have larger size than counts. - SampleVectorIterator it(&counts, &ranges); - size_t index; - - HistogramBase::Sample min; - int64_t max; - HistogramBase::Count count; - it.Get(&min, &max, &count); - EXPECT_EQ(0, min); - EXPECT_EQ(1, max); - EXPECT_EQ(1, count); - EXPECT_TRUE(it.GetBucketIndex(&index)); - EXPECT_EQ(0u, index); - - it.Next(); - it.Get(&min, &max, &count); - EXPECT_EQ(2, min); - EXPECT_EQ(3, max); - EXPECT_EQ(2, count); - EXPECT_TRUE(it.GetBucketIndex(&index)); - EXPECT_EQ(2u, index); - - it.Next(); - EXPECT_TRUE(it.Done()); - - // Create iterator from SampleVector. - SampleVector samples(1, &ranges); - samples.Accumulate(0, 0); - samples.Accumulate(1, 1); - samples.Accumulate(2, 2); - samples.Accumulate(3, 3); - std::unique_ptr<SampleCountIterator> it2 = samples.Iterator(); - - int i; - for (i = 1; !it2->Done(); i++, it2->Next()) { - it2->Get(&min, &max, &count); - EXPECT_EQ(i, min); - EXPECT_EQ(i + 1, max); - EXPECT_EQ(i, count); - - size_t index; - EXPECT_TRUE(it2->GetBucketIndex(&index)); - EXPECT_EQ(static_cast<size_t>(i), index); - } - EXPECT_EQ(4, i); -} - -TEST_F(SampleVectorTest, IterateDoneDeath) { - BucketRanges ranges(5); - ranges.set_range(0, 0); - ranges.set_range(1, 1); - ranges.set_range(2, 2); - ranges.set_range(3, 3); - ranges.set_range(4, INT_MAX); - SampleVector samples(1, &ranges); - - std::unique_ptr<SampleCountIterator> it = samples.Iterator(); - - EXPECT_TRUE(it->Done()); - - HistogramBase::Sample min; - int64_t max; - HistogramBase::Count count; - EXPECT_DCHECK_DEATH(it->Get(&min, &max, &count)); - - EXPECT_DCHECK_DEATH(it->Next()); - - samples.Accumulate(2, 100); - it = samples.Iterator(); - EXPECT_FALSE(it->Done()); -} - -TEST_F(SampleVectorTest, SingleSample) { - // Custom buckets: [1, 5) [5, 10) - BucketRanges ranges(3); - ranges.set_range(0, 1); - ranges.set_range(1, 5); - ranges.set_range(2, 10); - SampleVector samples(&ranges); - - // Ensure that a single value accumulates correctly. - EXPECT_FALSE(GetSamplesCounts(samples)); - samples.Accumulate(3, 200); - EXPECT_EQ(200, samples.GetCount(3)); - EXPECT_FALSE(GetSamplesCounts(samples)); - samples.Accumulate(3, 400); - EXPECT_EQ(600, samples.GetCount(3)); - EXPECT_FALSE(GetSamplesCounts(samples)); - EXPECT_EQ(3 * 600, samples.sum()); - EXPECT_EQ(600, samples.TotalCount()); - EXPECT_EQ(600, samples.redundant_count()); - - // Ensure that the iterator returns only one value. - HistogramBase::Sample min; - int64_t max; - HistogramBase::Count count; - std::unique_ptr<SampleCountIterator> it = samples.Iterator(); - ASSERT_FALSE(it->Done()); - it->Get(&min, &max, &count); - EXPECT_EQ(1, min); - EXPECT_EQ(5, max); - EXPECT_EQ(600, count); - it->Next(); - EXPECT_TRUE(it->Done()); - - // Ensure that it can be merged to another single-sample vector. - SampleVector samples_copy(&ranges); - samples_copy.Add(samples); - EXPECT_FALSE(GetSamplesCounts(samples_copy)); - EXPECT_EQ(3 * 600, samples_copy.sum()); - EXPECT_EQ(600, samples_copy.TotalCount()); - EXPECT_EQ(600, samples_copy.redundant_count()); - - // A different value should cause creation of the counts array. - samples.Accumulate(8, 100); - EXPECT_TRUE(GetSamplesCounts(samples)); - EXPECT_EQ(600, samples.GetCount(3)); - EXPECT_EQ(100, samples.GetCount(8)); - EXPECT_EQ(3 * 600 + 8 * 100, samples.sum()); - EXPECT_EQ(600 + 100, samples.TotalCount()); - EXPECT_EQ(600 + 100, samples.redundant_count()); - - // The iterator should now return both values. - it = samples.Iterator(); - ASSERT_FALSE(it->Done()); - it->Get(&min, &max, &count); - EXPECT_EQ(1, min); - EXPECT_EQ(5, max); - EXPECT_EQ(600, count); - it->Next(); - ASSERT_FALSE(it->Done()); - it->Get(&min, &max, &count); - EXPECT_EQ(5, min); - EXPECT_EQ(10, max); - EXPECT_EQ(100, count); - it->Next(); - EXPECT_TRUE(it->Done()); - - // Ensure that it can merged to a single-sample vector. - samples_copy.Add(samples); - EXPECT_TRUE(GetSamplesCounts(samples_copy)); - EXPECT_EQ(3 * 1200 + 8 * 100, samples_copy.sum()); - EXPECT_EQ(1200 + 100, samples_copy.TotalCount()); - EXPECT_EQ(1200 + 100, samples_copy.redundant_count()); -} - -TEST_F(SampleVectorTest, PersistentSampleVector) { - LocalPersistentMemoryAllocator allocator(64 << 10, 0, ""); - std::atomic<PersistentMemoryAllocator::Reference> samples_ref; - samples_ref.store(0, std::memory_order_relaxed); - HistogramSamples::Metadata samples_meta; - memset(&samples_meta, 0, sizeof(samples_meta)); - - // Custom buckets: [1, 5) [5, 10) - BucketRanges ranges(3); - ranges.set_range(0, 1); - ranges.set_range(1, 5); - ranges.set_range(2, 10); - - // Persistent allocation. - const size_t counts_bytes = - sizeof(HistogramBase::AtomicCount) * ranges.bucket_count(); - const DelayedPersistentAllocation allocation(&allocator, &samples_ref, 1, - counts_bytes, false); - - PersistentSampleVector samples1(0, &ranges, &samples_meta, allocation); - EXPECT_FALSE(GetSamplesCounts(samples1)); - samples1.Accumulate(3, 200); - EXPECT_EQ(200, samples1.GetCount(3)); - EXPECT_FALSE(GetSamplesCounts(samples1)); - EXPECT_EQ(0, samples1.GetCount(8)); - EXPECT_FALSE(GetSamplesCounts(samples1)); - - PersistentSampleVector samples2(0, &ranges, &samples_meta, allocation); - EXPECT_EQ(200, samples2.GetCount(3)); - EXPECT_FALSE(GetSamplesCounts(samples2)); - - HistogramBase::Sample min; - int64_t max; - HistogramBase::Count count; - std::unique_ptr<SampleCountIterator> it = samples2.Iterator(); - ASSERT_FALSE(it->Done()); - it->Get(&min, &max, &count); - EXPECT_EQ(1, min); - EXPECT_EQ(5, max); - EXPECT_EQ(200, count); - it->Next(); - EXPECT_TRUE(it->Done()); - - samples1.Accumulate(8, 100); - EXPECT_TRUE(GetSamplesCounts(samples1)); - - EXPECT_FALSE(GetSamplesCounts(samples2)); - EXPECT_EQ(200, samples2.GetCount(3)); - EXPECT_EQ(100, samples2.GetCount(8)); - EXPECT_TRUE(GetSamplesCounts(samples2)); - EXPECT_EQ(3 * 200 + 8 * 100, samples2.sum()); - EXPECT_EQ(300, samples2.TotalCount()); - EXPECT_EQ(300, samples2.redundant_count()); - - it = samples2.Iterator(); - ASSERT_FALSE(it->Done()); - it->Get(&min, &max, &count); - EXPECT_EQ(1, min); - EXPECT_EQ(5, max); - EXPECT_EQ(200, count); - it->Next(); - ASSERT_FALSE(it->Done()); - it->Get(&min, &max, &count); - EXPECT_EQ(5, min); - EXPECT_EQ(10, max); - EXPECT_EQ(100, count); - it->Next(); - EXPECT_TRUE(it->Done()); - - PersistentSampleVector samples3(0, &ranges, &samples_meta, allocation); - EXPECT_TRUE(GetSamplesCounts(samples2)); - EXPECT_EQ(200, samples3.GetCount(3)); - EXPECT_EQ(100, samples3.GetCount(8)); - EXPECT_EQ(3 * 200 + 8 * 100, samples3.sum()); - EXPECT_EQ(300, samples3.TotalCount()); - EXPECT_EQ(300, samples3.redundant_count()); - - it = samples3.Iterator(); - ASSERT_FALSE(it->Done()); - it->Get(&min, &max, &count); - EXPECT_EQ(1, min); - EXPECT_EQ(5, max); - EXPECT_EQ(200, count); - it->Next(); - ASSERT_FALSE(it->Done()); - it->Get(&min, &max, &count); - EXPECT_EQ(5, min); - EXPECT_EQ(10, max); - EXPECT_EQ(100, count); - it->Next(); - EXPECT_TRUE(it->Done()); -} - -TEST_F(SampleVectorTest, PersistentSampleVectorTestWithOutsideAlloc) { - LocalPersistentMemoryAllocator allocator(64 << 10, 0, ""); - std::atomic<PersistentMemoryAllocator::Reference> samples_ref; - samples_ref.store(0, std::memory_order_relaxed); - HistogramSamples::Metadata samples_meta; - memset(&samples_meta, 0, sizeof(samples_meta)); - - // Custom buckets: [1, 5) [5, 10) - BucketRanges ranges(3); - ranges.set_range(0, 1); - ranges.set_range(1, 5); - ranges.set_range(2, 10); - - // Persistent allocation. - const size_t counts_bytes = - sizeof(HistogramBase::AtomicCount) * ranges.bucket_count(); - const DelayedPersistentAllocation allocation(&allocator, &samples_ref, 1, - counts_bytes, false); - - PersistentSampleVector samples1(0, &ranges, &samples_meta, allocation); - EXPECT_FALSE(GetSamplesCounts(samples1)); - samples1.Accumulate(3, 200); - EXPECT_EQ(200, samples1.GetCount(3)); - EXPECT_FALSE(GetSamplesCounts(samples1)); - - // Because the delayed allocation can be shared with other objects (the - // |offset| parameter allows concatinating multiple data blocks into the - // same allocation), it's possible that the allocation gets realized from - // the outside even though the data block being accessed is all zero. - allocation.Get(); - EXPECT_EQ(200, samples1.GetCount(3)); - EXPECT_FALSE(GetSamplesCounts(samples1)); - - HistogramBase::Sample min; - int64_t max; - HistogramBase::Count count; - std::unique_ptr<SampleCountIterator> it = samples1.Iterator(); - ASSERT_FALSE(it->Done()); - it->Get(&min, &max, &count); - EXPECT_EQ(1, min); - EXPECT_EQ(5, max); - EXPECT_EQ(200, count); - it->Next(); - EXPECT_TRUE(it->Done()); - - // A duplicate samples object should still see the single-sample entry even - // when storage is available. - PersistentSampleVector samples2(0, &ranges, &samples_meta, allocation); - EXPECT_EQ(200, samples2.GetCount(3)); - - // New accumulations, in both directions, of the existing value should work. - samples1.Accumulate(3, 50); - EXPECT_EQ(250, samples1.GetCount(3)); - EXPECT_EQ(250, samples2.GetCount(3)); - samples2.Accumulate(3, 50); - EXPECT_EQ(300, samples1.GetCount(3)); - EXPECT_EQ(300, samples2.GetCount(3)); - - it = samples1.Iterator(); - ASSERT_FALSE(it->Done()); - it->Get(&min, &max, &count); - EXPECT_EQ(1, min); - EXPECT_EQ(5, max); - EXPECT_EQ(300, count); - it->Next(); - EXPECT_TRUE(it->Done()); - - samples1.Accumulate(8, 100); - EXPECT_TRUE(GetSamplesCounts(samples1)); - EXPECT_EQ(300, samples1.GetCount(3)); - EXPECT_EQ(300, samples2.GetCount(3)); - EXPECT_EQ(100, samples1.GetCount(8)); - EXPECT_EQ(100, samples2.GetCount(8)); - samples2.Accumulate(8, 100); - EXPECT_EQ(300, samples1.GetCount(3)); - EXPECT_EQ(300, samples2.GetCount(3)); - EXPECT_EQ(200, samples1.GetCount(8)); - EXPECT_EQ(200, samples2.GetCount(8)); -} - -} // namespace base
diff --git a/base/metrics/single_sample_metrics_unittest.cc b/base/metrics/single_sample_metrics_unittest.cc deleted file mode 100644 index 5a6d159..0000000 --- a/base/metrics/single_sample_metrics_unittest.cc +++ /dev/null
@@ -1,124 +0,0 @@ -// 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/metrics/single_sample_metrics.h" - -#include "base/memory/ptr_util.h" -#include "base/metrics/dummy_histogram.h" -#include "base/test/gtest_util.h" -#include "base/test/histogram_tester.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -const HistogramBase::Sample kMin = 1; -const HistogramBase::Sample kMax = 10; -const uint32_t kBucketCount = 10; -const char kMetricName[] = "Single.Sample.Metric"; - -class SingleSampleMetricsTest : public testing::Test { - public: - SingleSampleMetricsTest() = default; - - ~SingleSampleMetricsTest() override { - // Ensure we cleanup after ourselves. - SingleSampleMetricsFactory::DeleteFactoryForTesting(); - } - - private: - DISALLOW_COPY_AND_ASSIGN(SingleSampleMetricsTest); -}; - -} // namespace - -TEST_F(SingleSampleMetricsTest, DefaultFactoryGetSet) { - SingleSampleMetricsFactory* factory = SingleSampleMetricsFactory::Get(); - ASSERT_TRUE(factory); - - // Same factory should be returned evermore. - EXPECT_EQ(factory, SingleSampleMetricsFactory::Get()); - - // Setting a factory after the default has been instantiated should fail. - EXPECT_DCHECK_DEATH(SingleSampleMetricsFactory::SetFactory( - WrapUnique<SingleSampleMetricsFactory>(nullptr))); -} - -TEST_F(SingleSampleMetricsTest, CustomFactoryGetSet) { - SingleSampleMetricsFactory* factory = new DefaultSingleSampleMetricsFactory(); - SingleSampleMetricsFactory::SetFactory(WrapUnique(factory)); - EXPECT_EQ(factory, SingleSampleMetricsFactory::Get()); -} - -TEST_F(SingleSampleMetricsTest, DefaultSingleSampleMetricNoValue) { - SingleSampleMetricsFactory* factory = SingleSampleMetricsFactory::Get(); - - HistogramTester tester; - std::unique_ptr<SingleSampleMetric> metric = - factory->CreateCustomCountsMetric(kMetricName, kMin, kMax, kBucketCount); - metric.reset(); - - // Verify that no sample is recorded if SetSample() is never called. - tester.ExpectTotalCount(kMetricName, 0); -} - -TEST_F(SingleSampleMetricsTest, DefaultSingleSampleMetricWithValue) { - SingleSampleMetricsFactory* factory = SingleSampleMetricsFactory::Get(); - - HistogramTester tester; - std::unique_ptr<SingleSampleMetric> metric = - factory->CreateCustomCountsMetric(kMetricName, kMin, kMax, kBucketCount); - - const HistogramBase::Sample kLastSample = 9; - metric->SetSample(1); - metric->SetSample(3); - metric->SetSample(5); - metric->SetSample(kLastSample); - metric.reset(); - - // Verify only the last sample sent to SetSample() is recorded. - tester.ExpectUniqueSample(kMetricName, kLastSample, 1); - - // Verify construction implicitly by requesting a histogram with the same - // parameters; this test relies on the fact that histogram objects are unique - // per name. Different parameters will result in a Dummy histogram returned. - EXPECT_EQ( - DummyHistogram::GetInstance(), - Histogram::FactoryGet(kMetricName, 1, 3, 3, HistogramBase::kNoFlags)); - EXPECT_NE(DummyHistogram::GetInstance(), - Histogram::FactoryGet(kMetricName, kMin, kMax, kBucketCount, - HistogramBase::kUmaTargetedHistogramFlag)); -} - -TEST_F(SingleSampleMetricsTest, MultipleMetricsAreDistinct) { - SingleSampleMetricsFactory* factory = SingleSampleMetricsFactory::Get(); - - HistogramTester tester; - std::unique_ptr<SingleSampleMetric> metric = - factory->CreateCustomCountsMetric(kMetricName, kMin, kMax, kBucketCount); - std::unique_ptr<SingleSampleMetric> metric2 = - factory->CreateCustomCountsMetric(kMetricName, kMin, kMax, kBucketCount); - const char kMetricName2[] = "Single.Sample.Metric.2"; - std::unique_ptr<SingleSampleMetric> metric3 = - factory->CreateCustomCountsMetric(kMetricName2, kMin, kMax, kBucketCount); - - const HistogramBase::Sample kSample1 = 5; - metric->SetSample(kSample1); - metric2->SetSample(kSample1); - - const HistogramBase::Sample kSample2 = 7; - metric3->SetSample(kSample2); - - metric.reset(); - tester.ExpectUniqueSample(kMetricName, kSample1, 1); - - metric2.reset(); - tester.ExpectUniqueSample(kMetricName, kSample1, 2); - - metric3.reset(); - tester.ExpectUniqueSample(kMetricName2, kSample2, 1); -} - -} // namespace base
diff --git a/base/metrics/sparse_histogram_unittest.cc b/base/metrics/sparse_histogram_unittest.cc deleted file mode 100644 index 72dd905..0000000 --- a/base/metrics/sparse_histogram_unittest.cc +++ /dev/null
@@ -1,388 +0,0 @@ -// 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/metrics/sparse_histogram.h" - -#include <memory> -#include <string> - -#include "base/metrics/histogram_base.h" -#include "base/metrics/histogram_functions.h" -#include "base/metrics/histogram_samples.h" -#include "base/metrics/metrics_hashes.h" -#include "base/metrics/persistent_histogram_allocator.h" -#include "base/metrics/persistent_memory_allocator.h" -#include "base/metrics/sample_map.h" -#include "base/metrics/statistics_recorder.h" -#include "base/pickle.h" -#include "base/strings/stringprintf.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -// Test parameter indicates if a persistent memory allocator should be used -// for histogram allocation. False will allocate histograms from the process -// heap. -class SparseHistogramTest : public testing::TestWithParam<bool> { - protected: - const int32_t kAllocatorMemorySize = 8 << 20; // 8 MiB - - SparseHistogramTest() : use_persistent_histogram_allocator_(GetParam()) {} - - void SetUp() override { - if (use_persistent_histogram_allocator_) - CreatePersistentMemoryAllocator(); - - // Each test will have a clean state (no Histogram / BucketRanges - // registered). - InitializeStatisticsRecorder(); - } - - void TearDown() override { - if (allocator_) { - ASSERT_FALSE(allocator_->IsFull()); - ASSERT_FALSE(allocator_->IsCorrupt()); - } - UninitializeStatisticsRecorder(); - DestroyPersistentMemoryAllocator(); - } - - void InitializeStatisticsRecorder() { - DCHECK(!statistics_recorder_); - statistics_recorder_ = StatisticsRecorder::CreateTemporaryForTesting(); - } - - void UninitializeStatisticsRecorder() { - statistics_recorder_.reset(); - } - - void CreatePersistentMemoryAllocator() { - GlobalHistogramAllocator::CreateWithLocalMemory( - kAllocatorMemorySize, 0, "SparseHistogramAllocatorTest"); - allocator_ = GlobalHistogramAllocator::Get()->memory_allocator(); - } - - void DestroyPersistentMemoryAllocator() { - allocator_ = nullptr; - GlobalHistogramAllocator::ReleaseForTesting(); - } - - std::unique_ptr<SparseHistogram> NewSparseHistogram(const char* name) { - // std::make_unique can't access protected ctor so do it manually. This - // test class is a friend so can access it. - return std::unique_ptr<SparseHistogram>(new SparseHistogram(name)); - } - - const bool use_persistent_histogram_allocator_; - - std::unique_ptr<StatisticsRecorder> statistics_recorder_; - PersistentMemoryAllocator* allocator_ = nullptr; - - private: - DISALLOW_COPY_AND_ASSIGN(SparseHistogramTest); -}; - -// Run all HistogramTest cases with both heap and persistent memory. -INSTANTIATE_TEST_CASE_P(HeapAndPersistent, - SparseHistogramTest, - testing::Bool()); - - -TEST_P(SparseHistogramTest, BasicTest) { - std::unique_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse")); - std::unique_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples()); - EXPECT_EQ(0, snapshot->TotalCount()); - EXPECT_EQ(0, snapshot->sum()); - - histogram->Add(100); - std::unique_ptr<HistogramSamples> snapshot1(histogram->SnapshotSamples()); - EXPECT_EQ(1, snapshot1->TotalCount()); - EXPECT_EQ(1, snapshot1->GetCount(100)); - - histogram->Add(100); - histogram->Add(101); - std::unique_ptr<HistogramSamples> snapshot2(histogram->SnapshotSamples()); - EXPECT_EQ(3, snapshot2->TotalCount()); - EXPECT_EQ(2, snapshot2->GetCount(100)); - EXPECT_EQ(1, snapshot2->GetCount(101)); -} - -TEST_P(SparseHistogramTest, BasicTestAddCount) { - std::unique_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse")); - std::unique_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples()); - EXPECT_EQ(0, snapshot->TotalCount()); - EXPECT_EQ(0, snapshot->sum()); - - histogram->AddCount(100, 15); - std::unique_ptr<HistogramSamples> snapshot1(histogram->SnapshotSamples()); - EXPECT_EQ(15, snapshot1->TotalCount()); - EXPECT_EQ(15, snapshot1->GetCount(100)); - - histogram->AddCount(100, 15); - histogram->AddCount(101, 25); - std::unique_ptr<HistogramSamples> snapshot2(histogram->SnapshotSamples()); - EXPECT_EQ(55, snapshot2->TotalCount()); - EXPECT_EQ(30, snapshot2->GetCount(100)); - EXPECT_EQ(25, snapshot2->GetCount(101)); -} - -TEST_P(SparseHistogramTest, AddCount_LargeValuesDontOverflow) { - std::unique_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse")); - std::unique_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples()); - EXPECT_EQ(0, snapshot->TotalCount()); - EXPECT_EQ(0, snapshot->sum()); - - histogram->AddCount(1000000000, 15); - std::unique_ptr<HistogramSamples> snapshot1(histogram->SnapshotSamples()); - EXPECT_EQ(15, snapshot1->TotalCount()); - EXPECT_EQ(15, snapshot1->GetCount(1000000000)); - - histogram->AddCount(1000000000, 15); - histogram->AddCount(1010000000, 25); - std::unique_ptr<HistogramSamples> snapshot2(histogram->SnapshotSamples()); - EXPECT_EQ(55, snapshot2->TotalCount()); - EXPECT_EQ(30, snapshot2->GetCount(1000000000)); - EXPECT_EQ(25, snapshot2->GetCount(1010000000)); - EXPECT_EQ(55250000000LL, snapshot2->sum()); -} - -// Make sure that counts returned by Histogram::SnapshotDelta do not overflow -// even when a total count (returned by Histogram::SnapshotSample) does. -TEST_P(SparseHistogramTest, AddCount_LargeCountsDontOverflow) { - std::unique_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse")); - std::unique_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples()); - EXPECT_EQ(0, snapshot->TotalCount()); - EXPECT_EQ(0, snapshot->sum()); - - const int count = (1 << 30) - 1; - - // Repeat N times to make sure that there is no internal value overflow. - for (int i = 0; i < 10; ++i) { - histogram->AddCount(42, count); - std::unique_ptr<HistogramSamples> samples = histogram->SnapshotDelta(); - EXPECT_EQ(count, samples->TotalCount()); - EXPECT_EQ(count, samples->GetCount(42)); - } -} - -TEST_P(SparseHistogramTest, MacroBasicTest) { - UmaHistogramSparse("Sparse", 100); - UmaHistogramSparse("Sparse", 200); - UmaHistogramSparse("Sparse", 100); - - const StatisticsRecorder::Histograms histograms = - StatisticsRecorder::GetHistograms(); - - ASSERT_THAT(histograms, testing::SizeIs(1)); - const HistogramBase* const sparse_histogram = histograms[0]; - - EXPECT_EQ(SPARSE_HISTOGRAM, sparse_histogram->GetHistogramType()); - EXPECT_EQ("Sparse", StringPiece(sparse_histogram->histogram_name())); - EXPECT_EQ( - HistogramBase::kUmaTargetedHistogramFlag | - (use_persistent_histogram_allocator_ ? HistogramBase::kIsPersistent - : 0), - sparse_histogram->flags()); - - std::unique_ptr<HistogramSamples> samples = - sparse_histogram->SnapshotSamples(); - EXPECT_EQ(3, samples->TotalCount()); - EXPECT_EQ(2, samples->GetCount(100)); - EXPECT_EQ(1, samples->GetCount(200)); -} - -TEST_P(SparseHistogramTest, MacroInLoopTest) { - // Unlike the macros in histogram.h, SparseHistogram macros can have a - // variable as histogram name. - for (int i = 0; i < 2; i++) { - UmaHistogramSparse(StringPrintf("Sparse%d", i), 100); - } - - const StatisticsRecorder::Histograms histograms = - StatisticsRecorder::Sort(StatisticsRecorder::GetHistograms()); - ASSERT_THAT(histograms, testing::SizeIs(2)); - EXPECT_STREQ(histograms[0]->histogram_name(), "Sparse0"); - EXPECT_STREQ(histograms[1]->histogram_name(), "Sparse1"); -} - -TEST_P(SparseHistogramTest, Serialize) { - std::unique_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse")); - histogram->SetFlags(HistogramBase::kIPCSerializationSourceFlag); - - Pickle pickle; - histogram->SerializeInfo(&pickle); - - PickleIterator iter(pickle); - - int type; - EXPECT_TRUE(iter.ReadInt(&type)); - EXPECT_EQ(SPARSE_HISTOGRAM, type); - - std::string name; - EXPECT_TRUE(iter.ReadString(&name)); - EXPECT_EQ("Sparse", name); - - int flag; - EXPECT_TRUE(iter.ReadInt(&flag)); - EXPECT_EQ(HistogramBase::kIPCSerializationSourceFlag, flag); - - // No more data in the pickle. - EXPECT_FALSE(iter.SkipBytes(1)); -} - -// Ensure that race conditions that cause multiple, identical sparse histograms -// to be created will safely resolve to a single one. -TEST_P(SparseHistogramTest, DuplicationSafety) { - const char histogram_name[] = "Duplicated"; - size_t histogram_count = StatisticsRecorder::GetHistogramCount(); - - // Create a histogram that we will later duplicate. - HistogramBase* original = - SparseHistogram::FactoryGet(histogram_name, HistogramBase::kNoFlags); - ++histogram_count; - DCHECK_EQ(histogram_count, StatisticsRecorder::GetHistogramCount()); - original->Add(1); - - // Create a duplicate. This has to happen differently depending on where the - // memory is taken from. - if (use_persistent_histogram_allocator_) { - // To allocate from persistent memory, clear the last_created reference in - // the GlobalHistogramAllocator. This will cause an Import to recreate - // the just-created histogram which will then be released as a duplicate. - GlobalHistogramAllocator::Get()->ClearLastCreatedReferenceForTesting(); - // Creating a different histogram will first do an Import to ensure it - // hasn't been created elsewhere, triggering the duplication and release. - SparseHistogram::FactoryGet("something.new", HistogramBase::kNoFlags); - ++histogram_count; - } else { - // To allocate from the heap, just call the (private) constructor directly. - // Delete it immediately like would have happened within FactoryGet(); - std::unique_ptr<SparseHistogram> something = - NewSparseHistogram(histogram_name); - DCHECK_NE(original, something.get()); - } - DCHECK_EQ(histogram_count, StatisticsRecorder::GetHistogramCount()); - - // Re-creating the histogram via FactoryGet() will return the same one. - HistogramBase* duplicate = - SparseHistogram::FactoryGet(histogram_name, HistogramBase::kNoFlags); - DCHECK_EQ(original, duplicate); - DCHECK_EQ(histogram_count, StatisticsRecorder::GetHistogramCount()); - duplicate->Add(2); - - // Ensure that original histograms are still cross-functional. - original->Add(2); - duplicate->Add(1); - std::unique_ptr<HistogramSamples> snapshot_orig = original->SnapshotSamples(); - std::unique_ptr<HistogramSamples> snapshot_dup = duplicate->SnapshotSamples(); - DCHECK_EQ(2, snapshot_orig->GetCount(2)); - DCHECK_EQ(2, snapshot_dup->GetCount(1)); -} - -TEST_P(SparseHistogramTest, FactoryTime) { - const int kTestCreateCount = 1 << 10; // Must be power-of-2. - const int kTestLookupCount = 100000; - const int kTestAddCount = 100000; - - // Create all histogram names in advance for accurate timing below. - std::vector<std::string> histogram_names; - for (int i = 0; i < kTestCreateCount; ++i) { - histogram_names.push_back( - StringPrintf("TestHistogram.%d", i % kTestCreateCount)); - } - - // Calculate cost of creating histograms. - TimeTicks create_start = TimeTicks::Now(); - for (int i = 0; i < kTestCreateCount; ++i) - SparseHistogram::FactoryGet(histogram_names[i], HistogramBase::kNoFlags); - TimeDelta create_ticks = TimeTicks::Now() - create_start; - int64_t create_ms = create_ticks.InMilliseconds(); - - VLOG(1) << kTestCreateCount << " histogram creations took " << create_ms - << "ms or about " - << (create_ms * 1000000) / kTestCreateCount - << "ns each."; - - // Calculate cost of looking up existing histograms. - TimeTicks lookup_start = TimeTicks::Now(); - for (int i = 0; i < kTestLookupCount; ++i) { - // 6007 is co-prime with kTestCreateCount and so will do lookups in an - // order less likely to be cacheable (but still hit them all) should the - // underlying storage use the exact histogram name as the key. - const int i_mult = 6007; - static_assert(i_mult < INT_MAX / kTestCreateCount, "Multiplier too big"); - int index = (i * i_mult) & (kTestCreateCount - 1); - SparseHistogram::FactoryGet(histogram_names[index], - HistogramBase::kNoFlags); - } - TimeDelta lookup_ticks = TimeTicks::Now() - lookup_start; - int64_t lookup_ms = lookup_ticks.InMilliseconds(); - - VLOG(1) << kTestLookupCount << " histogram lookups took " << lookup_ms - << "ms or about " - << (lookup_ms * 1000000) / kTestLookupCount - << "ns each."; - - // Calculate cost of accessing histograms. - HistogramBase* histogram = - SparseHistogram::FactoryGet(histogram_names[0], HistogramBase::kNoFlags); - ASSERT_TRUE(histogram); - TimeTicks add_start = TimeTicks::Now(); - for (int i = 0; i < kTestAddCount; ++i) - histogram->Add(i & 127); - TimeDelta add_ticks = TimeTicks::Now() - add_start; - int64_t add_ms = add_ticks.InMilliseconds(); - - VLOG(1) << kTestAddCount << " histogram adds took " << add_ms - << "ms or about " - << (add_ms * 1000000) / kTestAddCount - << "ns each."; -} - -TEST_P(SparseHistogramTest, ExtremeValues) { - static const struct { - Histogram::Sample sample; - int64_t expected_max; - } cases[] = { - // Note: We use -2147483647 - 1 rather than -2147483648 because the later - // is interpreted as - operator applied to 2147483648 and the latter can't - // be represented as an int32 and causes a warning. - {-2147483647 - 1, -2147483647LL}, - {0, 1}, - {2147483647, 2147483648LL}, - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - HistogramBase* histogram = - SparseHistogram::FactoryGet(StringPrintf("ExtremeValues_%zu", i), - HistogramBase::kUmaTargetedHistogramFlag); - histogram->Add(cases[i].sample); - - std::unique_ptr<HistogramSamples> snapshot = histogram->SnapshotSamples(); - std::unique_ptr<SampleCountIterator> it = snapshot->Iterator(); - ASSERT_FALSE(it->Done()); - - base::Histogram::Sample min; - int64_t max; - base::Histogram::Count count; - it->Get(&min, &max, &count); - - EXPECT_EQ(1, count); - EXPECT_EQ(cases[i].sample, min); - EXPECT_EQ(cases[i].expected_max, max); - - it->Next(); - EXPECT_TRUE(it->Done()); - } -} - -TEST_P(SparseHistogramTest, HistogramNameHash) { - const char kName[] = "TestName"; - HistogramBase* histogram = SparseHistogram::FactoryGet( - kName, HistogramBase::kUmaTargetedHistogramFlag); - EXPECT_EQ(histogram->name_hash(), HashMetricName(kName)); -} - -} // namespace base
diff --git a/base/metrics/statistics_recorder_unittest.cc b/base/metrics/statistics_recorder_unittest.cc deleted file mode 100644 index 63ba136..0000000 --- a/base/metrics/statistics_recorder_unittest.cc +++ /dev/null
@@ -1,718 +0,0 @@ -// 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/metrics/statistics_recorder.h" - -#include <stddef.h> - -#include <memory> -#include <utility> -#include <vector> - -#include "base/bind.h" -#include "base/json/json_reader.h" -#include "base/logging.h" -#include "base/memory/weak_ptr.h" -#include "base/metrics/histogram_base.h" -#include "base/metrics/histogram_macros.h" -#include "base/metrics/persistent_histogram_allocator.h" -#include "base/metrics/record_histogram_checker.h" -#include "base/metrics/sparse_histogram.h" -#include "base/values.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -// Class to make sure any manipulations we do to the min log level are -// contained (i.e., do not affect other unit tests). -class LogStateSaver { - public: - LogStateSaver() : old_min_log_level_(logging::GetMinLogLevel()) {} - - ~LogStateSaver() { logging::SetMinLogLevel(old_min_log_level_); } - - private: - int old_min_log_level_; - - DISALLOW_COPY_AND_ASSIGN(LogStateSaver); -}; - -// Test implementation of RecordHistogramChecker interface. -class OddRecordHistogramChecker : public base::RecordHistogramChecker { - public: - ~OddRecordHistogramChecker() override = default; - - // base::RecordHistogramChecker: - bool ShouldRecord(uint64_t histogram_hash) const override { - return histogram_hash % 2; - } -}; - -} // namespace - -namespace base { - -using testing::IsEmpty; -using testing::SizeIs; -using testing::UnorderedElementsAre; - -class StatisticsRecorderTest : public testing::TestWithParam<bool> { - protected: - const int32_t kAllocatorMemorySize = 64 << 10; // 64 KiB - - StatisticsRecorderTest() : use_persistent_histogram_allocator_(GetParam()) { - // Each test will have a clean state (no Histogram / BucketRanges - // registered). - InitializeStatisticsRecorder(); - - // Use persistent memory for histograms if so indicated by test parameter. - if (use_persistent_histogram_allocator_) { - GlobalHistogramAllocator::CreateWithLocalMemory(kAllocatorMemorySize, 0, - "StatisticsRecorderTest"); - } - } - - ~StatisticsRecorderTest() override { - GlobalHistogramAllocator::ReleaseForTesting(); - UninitializeStatisticsRecorder(); - } - - void InitializeStatisticsRecorder() { - DCHECK(!statistics_recorder_); - statistics_recorder_ = StatisticsRecorder::CreateTemporaryForTesting(); - } - - // Deletes the global recorder if there is any. This is used by test - // NotInitialized to ensure a clean global state. - void UninitializeStatisticsRecorder() { - statistics_recorder_.reset(); - delete StatisticsRecorder::top_; - DCHECK(!StatisticsRecorder::top_); - } - - bool HasGlobalRecorder() { return StatisticsRecorder::top_ != nullptr; } - - Histogram* CreateHistogram(const char* name, - HistogramBase::Sample min, - HistogramBase::Sample max, - size_t bucket_count) { - BucketRanges* ranges = new BucketRanges(bucket_count + 1); - Histogram::InitializeBucketRanges(min, max, ranges); - const BucketRanges* registered_ranges = - StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); - return new Histogram(name, min, max, registered_ranges); - } - - void InitLogOnShutdown() { StatisticsRecorder::InitLogOnShutdown(); } - - bool IsVLogInitialized() { return StatisticsRecorder::is_vlog_initialized_; } - - void ResetVLogInitialized() { - UninitializeStatisticsRecorder(); - StatisticsRecorder::is_vlog_initialized_ = false; - } - - const bool use_persistent_histogram_allocator_; - - std::unique_ptr<StatisticsRecorder> statistics_recorder_; - std::unique_ptr<GlobalHistogramAllocator> old_global_allocator_; - - private: - LogStateSaver log_state_saver_; - - DISALLOW_COPY_AND_ASSIGN(StatisticsRecorderTest); -}; - -// Run all HistogramTest cases with both heap and persistent memory. -INSTANTIATE_TEST_CASE_P(Allocator, StatisticsRecorderTest, testing::Bool()); - -TEST_P(StatisticsRecorderTest, NotInitialized) { - UninitializeStatisticsRecorder(); - EXPECT_FALSE(HasGlobalRecorder()); - - HistogramBase* const histogram = - CreateHistogram("TestHistogram", 1, 1000, 10); - EXPECT_EQ(StatisticsRecorder::RegisterOrDeleteDuplicate(histogram), - histogram); - EXPECT_TRUE(HasGlobalRecorder()); - EXPECT_THAT(StatisticsRecorder::GetHistograms(), - UnorderedElementsAre(histogram)); - - UninitializeStatisticsRecorder(); - EXPECT_FALSE(HasGlobalRecorder()); - - BucketRanges* const ranges = new BucketRanges(3); - ranges->ResetChecksum(); - EXPECT_EQ(StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges), - ranges); - EXPECT_TRUE(HasGlobalRecorder()); - EXPECT_THAT(StatisticsRecorder::GetBucketRanges(), - UnorderedElementsAre(ranges)); -} - -TEST_P(StatisticsRecorderTest, RegisterBucketRanges) { - std::vector<const BucketRanges*> registered_ranges; - - BucketRanges* ranges1 = new BucketRanges(3); - ranges1->ResetChecksum(); - BucketRanges* ranges2 = new BucketRanges(4); - ranges2->ResetChecksum(); - - // Register new ranges. - EXPECT_EQ(ranges1, - StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges1)); - EXPECT_EQ(ranges2, - StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges2)); - EXPECT_THAT(StatisticsRecorder::GetBucketRanges(), - UnorderedElementsAre(ranges1, ranges2)); - - // Register some ranges again. - EXPECT_EQ(ranges1, - StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges1)); - EXPECT_THAT(StatisticsRecorder::GetBucketRanges(), - UnorderedElementsAre(ranges1, ranges2)); - - // Make sure the ranges is still the one we know. - ASSERT_EQ(3u, ranges1->size()); - EXPECT_EQ(0, ranges1->range(0)); - EXPECT_EQ(0, ranges1->range(1)); - EXPECT_EQ(0, ranges1->range(2)); - - // Register ranges with same values. - BucketRanges* ranges3 = new BucketRanges(3); - ranges3->ResetChecksum(); - EXPECT_EQ(ranges1, // returning ranges1 - StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges3)); - EXPECT_THAT(StatisticsRecorder::GetBucketRanges(), - UnorderedElementsAre(ranges1, ranges2)); -} - -TEST_P(StatisticsRecorderTest, RegisterHistogram) { - // Create a Histogram that was not registered. - Histogram* const histogram1 = CreateHistogram("TestHistogram1", 1, 1000, 10); - - EXPECT_THAT(StatisticsRecorder::GetHistograms(), IsEmpty()); - - // Register the Histogram. - EXPECT_EQ(histogram1, - StatisticsRecorder::RegisterOrDeleteDuplicate(histogram1)); - EXPECT_THAT(StatisticsRecorder::GetHistograms(), - UnorderedElementsAre(histogram1)); - - // Register the same Histogram again. - EXPECT_EQ(histogram1, - StatisticsRecorder::RegisterOrDeleteDuplicate(histogram1)); - EXPECT_THAT(StatisticsRecorder::GetHistograms(), - UnorderedElementsAre(histogram1)); - - // Register another Histogram with the same name. - Histogram* const histogram2 = CreateHistogram("TestHistogram1", 1, 1000, 10); - EXPECT_NE(histogram1, histogram2); - EXPECT_EQ(histogram1, - StatisticsRecorder::RegisterOrDeleteDuplicate(histogram2)); - EXPECT_THAT(StatisticsRecorder::GetHistograms(), - UnorderedElementsAre(histogram1)); - - // Register another Histogram with a different name. - Histogram* const histogram3 = CreateHistogram("TestHistogram0", 1, 1000, 10); - EXPECT_NE(histogram1, histogram3); - EXPECT_EQ(histogram3, - StatisticsRecorder::RegisterOrDeleteDuplicate(histogram3)); - EXPECT_THAT(StatisticsRecorder::GetHistograms(), - UnorderedElementsAre(histogram1, histogram3)); -} - -TEST_P(StatisticsRecorderTest, FindHistogram) { - HistogramBase* histogram1 = Histogram::FactoryGet( - "TestHistogram1", 1, 1000, 10, HistogramBase::kNoFlags); - HistogramBase* histogram2 = Histogram::FactoryGet( - "TestHistogram2", 1, 1000, 10, HistogramBase::kNoFlags); - - EXPECT_EQ(histogram1, StatisticsRecorder::FindHistogram("TestHistogram1")); - EXPECT_EQ(histogram2, StatisticsRecorder::FindHistogram("TestHistogram2")); - EXPECT_FALSE(StatisticsRecorder::FindHistogram("TestHistogram")); - - // Create a new global allocator using the same memory as the old one. Any - // old one is kept around so the memory doesn't get released. - old_global_allocator_ = GlobalHistogramAllocator::ReleaseForTesting(); - if (use_persistent_histogram_allocator_) { - GlobalHistogramAllocator::CreateWithPersistentMemory( - const_cast<void*>(old_global_allocator_->data()), - old_global_allocator_->length(), 0, old_global_allocator_->Id(), - old_global_allocator_->Name()); - } - - // Reset statistics-recorder to validate operation from a clean start. - UninitializeStatisticsRecorder(); - InitializeStatisticsRecorder(); - - if (use_persistent_histogram_allocator_) { - EXPECT_TRUE(StatisticsRecorder::FindHistogram("TestHistogram1")); - EXPECT_TRUE(StatisticsRecorder::FindHistogram("TestHistogram2")); - } else { - EXPECT_FALSE(StatisticsRecorder::FindHistogram("TestHistogram1")); - EXPECT_FALSE(StatisticsRecorder::FindHistogram("TestHistogram2")); - } - EXPECT_FALSE(StatisticsRecorder::FindHistogram("TestHistogram")); -} - -TEST_P(StatisticsRecorderTest, WithName) { - Histogram::FactoryGet("TestHistogram1", 1, 1000, 10, Histogram::kNoFlags); - Histogram::FactoryGet("TestHistogram2", 1, 1000, 10, Histogram::kNoFlags); - Histogram::FactoryGet("TestHistogram3", 1, 1000, 10, Histogram::kNoFlags); - - const auto histograms = StatisticsRecorder::GetHistograms(); - EXPECT_THAT(histograms, SizeIs(3)); - EXPECT_THAT(StatisticsRecorder::WithName(histograms, ""), SizeIs(3)); - EXPECT_THAT(StatisticsRecorder::WithName(histograms, "Test"), SizeIs(3)); - EXPECT_THAT(StatisticsRecorder::WithName(histograms, "1"), SizeIs(1)); - EXPECT_THAT(StatisticsRecorder::WithName(histograms, "hello"), IsEmpty()); -} - -TEST_P(StatisticsRecorderTest, RegisterHistogramWithFactoryGet) { - EXPECT_THAT(StatisticsRecorder::GetHistograms(), IsEmpty()); - - // Create a histogram. - HistogramBase* const histogram1 = Histogram::FactoryGet( - "TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags); - EXPECT_THAT(StatisticsRecorder::GetHistograms(), - UnorderedElementsAre(histogram1)); - - // Get an existing histogram. - HistogramBase* const histogram2 = Histogram::FactoryGet( - "TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags); - EXPECT_EQ(histogram1, histogram2); - EXPECT_THAT(StatisticsRecorder::GetHistograms(), - UnorderedElementsAre(histogram1)); - - // Create a LinearHistogram. - HistogramBase* const histogram3 = LinearHistogram::FactoryGet( - "TestLinearHistogram", 1, 1000, 10, HistogramBase::kNoFlags); - EXPECT_THAT(StatisticsRecorder::GetHistograms(), - UnorderedElementsAre(histogram1, histogram3)); - - // Create a BooleanHistogram. - HistogramBase* const histogram4 = BooleanHistogram::FactoryGet( - "TestBooleanHistogram", HistogramBase::kNoFlags); - EXPECT_THAT(StatisticsRecorder::GetHistograms(), - UnorderedElementsAre(histogram1, histogram3, histogram4)); - - // Create a CustomHistogram. - std::vector<int> custom_ranges; - custom_ranges.push_back(1); - custom_ranges.push_back(5); - HistogramBase* const histogram5 = CustomHistogram::FactoryGet( - "TestCustomHistogram", custom_ranges, HistogramBase::kNoFlags); - EXPECT_THAT( - StatisticsRecorder::GetHistograms(), - UnorderedElementsAre(histogram1, histogram3, histogram4, histogram5)); -} - -TEST_P(StatisticsRecorderTest, RegisterHistogramWithMacros) { - // Macros cache pointers and so tests that use them can only be run once. - // Stop immediately if this test has run previously. - static bool already_run = false; - if (already_run) - return; - already_run = true; - - StatisticsRecorder::Histograms registered_histograms; - - HistogramBase* histogram = Histogram::FactoryGet( - "TestHistogramCounts", 1, 1000000, 50, HistogramBase::kNoFlags); - - // The histogram we got from macro is the same as from FactoryGet. - LOCAL_HISTOGRAM_COUNTS("TestHistogramCounts", 30); - registered_histograms = StatisticsRecorder::GetHistograms(); - ASSERT_EQ(1u, registered_histograms.size()); - EXPECT_EQ(histogram, registered_histograms[0]); - - LOCAL_HISTOGRAM_TIMES("TestHistogramTimes", TimeDelta::FromDays(1)); - LOCAL_HISTOGRAM_ENUMERATION("TestHistogramEnumeration", 20, 200); - - EXPECT_THAT(StatisticsRecorder::GetHistograms(), SizeIs(3)); -} - -TEST_P(StatisticsRecorderTest, BucketRangesSharing) { - EXPECT_THAT(StatisticsRecorder::GetBucketRanges(), IsEmpty()); - - Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags); - Histogram::FactoryGet("Histogram2", 1, 64, 8, HistogramBase::kNoFlags); - EXPECT_THAT(StatisticsRecorder::GetBucketRanges(), SizeIs(1)); - - Histogram::FactoryGet("Histogram3", 1, 64, 16, HistogramBase::kNoFlags); - EXPECT_THAT(StatisticsRecorder::GetBucketRanges(), SizeIs(2)); -} - -TEST_P(StatisticsRecorderTest, ToJSON) { - Histogram::FactoryGet("TestHistogram1", 1, 1000, 50, HistogramBase::kNoFlags) - ->Add(30); - Histogram::FactoryGet("TestHistogram1", 1, 1000, 50, HistogramBase::kNoFlags) - ->Add(40); - Histogram::FactoryGet("TestHistogram2", 1, 1000, 50, HistogramBase::kNoFlags) - ->Add(30); - Histogram::FactoryGet("TestHistogram2", 1, 1000, 50, HistogramBase::kNoFlags) - ->Add(40); - - std::string json(StatisticsRecorder::ToJSON(JSON_VERBOSITY_LEVEL_FULL)); - - // Check for valid JSON. - std::unique_ptr<Value> root = JSONReader::Read(json); - ASSERT_TRUE(root.get()); - - DictionaryValue* root_dict = nullptr; - ASSERT_TRUE(root->GetAsDictionary(&root_dict)); - - // No query should be set. - ASSERT_FALSE(root_dict->HasKey("query")); - - ListValue* histogram_list = nullptr; - ASSERT_TRUE(root_dict->GetList("histograms", &histogram_list)); - ASSERT_EQ(2u, histogram_list->GetSize()); - - // Examine the first histogram. - DictionaryValue* histogram_dict = nullptr; - ASSERT_TRUE(histogram_list->GetDictionary(0, &histogram_dict)); - - int sample_count; - ASSERT_TRUE(histogram_dict->GetInteger("count", &sample_count)); - EXPECT_EQ(2, sample_count); - - ListValue* buckets_list = nullptr; - ASSERT_TRUE(histogram_dict->GetList("buckets", &buckets_list)); - EXPECT_EQ(2u, buckets_list->GetList().size()); - - // Check the serialized JSON with a different verbosity level. - json = StatisticsRecorder::ToJSON(JSON_VERBOSITY_LEVEL_OMIT_BUCKETS); - root = JSONReader::Read(json); - ASSERT_TRUE(root.get()); - root_dict = nullptr; - ASSERT_TRUE(root->GetAsDictionary(&root_dict)); - histogram_list = nullptr; - ASSERT_TRUE(root_dict->GetList("histograms", &histogram_list)); - ASSERT_EQ(2u, histogram_list->GetSize()); - histogram_dict = nullptr; - ASSERT_TRUE(histogram_list->GetDictionary(0, &histogram_dict)); - sample_count = 0; - ASSERT_TRUE(histogram_dict->GetInteger("count", &sample_count)); - EXPECT_EQ(2, sample_count); - buckets_list = nullptr; - // Bucket information should be omitted. - ASSERT_FALSE(histogram_dict->GetList("buckets", &buckets_list)); -} - -TEST_P(StatisticsRecorderTest, IterationTest) { - Histogram::FactoryGet("IterationTest1", 1, 64, 16, HistogramBase::kNoFlags); - Histogram::FactoryGet("IterationTest2", 1, 64, 16, HistogramBase::kNoFlags); - - auto histograms = StatisticsRecorder::GetHistograms(); - EXPECT_THAT(histograms, SizeIs(2)); - histograms = StatisticsRecorder::NonPersistent(std::move(histograms)); - EXPECT_THAT(histograms, SizeIs(use_persistent_histogram_allocator_ ? 0 : 2)); - - // Create a new global allocator using the same memory as the old one. Any - // old one is kept around so the memory doesn't get released. - old_global_allocator_ = GlobalHistogramAllocator::ReleaseForTesting(); - if (use_persistent_histogram_allocator_) { - GlobalHistogramAllocator::CreateWithPersistentMemory( - const_cast<void*>(old_global_allocator_->data()), - old_global_allocator_->length(), 0, old_global_allocator_->Id(), - old_global_allocator_->Name()); - } - - // Reset statistics-recorder to validate operation from a clean start. - UninitializeStatisticsRecorder(); - InitializeStatisticsRecorder(); - - histograms = StatisticsRecorder::GetHistograms(); - EXPECT_THAT(histograms, SizeIs(use_persistent_histogram_allocator_ ? 2 : 0)); - histograms = StatisticsRecorder::NonPersistent(std::move(histograms)); - EXPECT_THAT(histograms, IsEmpty()); -} - -namespace { - -// CallbackCheckWrapper is simply a convenient way to check and store that -// a callback was actually run. -struct CallbackCheckWrapper { - CallbackCheckWrapper() : called(false), last_histogram_value(0) {} - - void OnHistogramChanged(base::HistogramBase::Sample histogram_value) { - called = true; - last_histogram_value = histogram_value; - } - - bool called; - base::HistogramBase::Sample last_histogram_value; -}; - -} // namespace - -// Check that you can't overwrite the callback with another. -TEST_P(StatisticsRecorderTest, SetCallbackFailsWithoutHistogramTest) { - CallbackCheckWrapper callback_wrapper; - - bool result = base::StatisticsRecorder::SetCallback( - "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged, - base::Unretained(&callback_wrapper))); - EXPECT_TRUE(result); - - result = base::StatisticsRecorder::SetCallback( - "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged, - base::Unretained(&callback_wrapper))); - EXPECT_FALSE(result); -} - -// Check that you can't overwrite the callback with another. -TEST_P(StatisticsRecorderTest, SetCallbackFailsWithHistogramTest) { - HistogramBase* histogram = Histogram::FactoryGet("TestHistogram", 1, 1000, 10, - HistogramBase::kNoFlags); - EXPECT_TRUE(histogram); - - CallbackCheckWrapper callback_wrapper; - - bool result = base::StatisticsRecorder::SetCallback( - "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged, - base::Unretained(&callback_wrapper))); - EXPECT_TRUE(result); - EXPECT_EQ(histogram->flags() & base::HistogramBase::kCallbackExists, - base::HistogramBase::kCallbackExists); - - result = base::StatisticsRecorder::SetCallback( - "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged, - base::Unretained(&callback_wrapper))); - EXPECT_FALSE(result); - EXPECT_EQ(histogram->flags() & base::HistogramBase::kCallbackExists, - base::HistogramBase::kCallbackExists); - - histogram->Add(1); - - EXPECT_TRUE(callback_wrapper.called); -} - -// Check that you can't overwrite the callback with another. -TEST_P(StatisticsRecorderTest, ClearCallbackSuceedsWithHistogramTest) { - HistogramBase* histogram = Histogram::FactoryGet("TestHistogram", 1, 1000, 10, - HistogramBase::kNoFlags); - EXPECT_TRUE(histogram); - - CallbackCheckWrapper callback_wrapper; - - bool result = base::StatisticsRecorder::SetCallback( - "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged, - base::Unretained(&callback_wrapper))); - EXPECT_TRUE(result); - EXPECT_EQ(histogram->flags() & base::HistogramBase::kCallbackExists, - base::HistogramBase::kCallbackExists); - - base::StatisticsRecorder::ClearCallback("TestHistogram"); - EXPECT_EQ(histogram->flags() & base::HistogramBase::kCallbackExists, 0); - - histogram->Add(1); - - EXPECT_FALSE(callback_wrapper.called); -} - -// Check that callback is used. -TEST_P(StatisticsRecorderTest, CallbackUsedTest) { - { - HistogramBase* histogram = Histogram::FactoryGet( - "TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags); - EXPECT_TRUE(histogram); - - CallbackCheckWrapper callback_wrapper; - - base::StatisticsRecorder::SetCallback( - "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged, - base::Unretained(&callback_wrapper))); - - histogram->Add(1); - - EXPECT_TRUE(callback_wrapper.called); - EXPECT_EQ(callback_wrapper.last_histogram_value, 1); - } - - { - HistogramBase* linear_histogram = LinearHistogram::FactoryGet( - "TestLinearHistogram", 1, 1000, 10, HistogramBase::kNoFlags); - - CallbackCheckWrapper callback_wrapper; - - base::StatisticsRecorder::SetCallback( - "TestLinearHistogram", - base::Bind(&CallbackCheckWrapper::OnHistogramChanged, - base::Unretained(&callback_wrapper))); - - linear_histogram->Add(1); - - EXPECT_TRUE(callback_wrapper.called); - EXPECT_EQ(callback_wrapper.last_histogram_value, 1); - } - - { - std::vector<int> custom_ranges; - custom_ranges.push_back(1); - custom_ranges.push_back(5); - HistogramBase* custom_histogram = CustomHistogram::FactoryGet( - "TestCustomHistogram", custom_ranges, HistogramBase::kNoFlags); - - CallbackCheckWrapper callback_wrapper; - - base::StatisticsRecorder::SetCallback( - "TestCustomHistogram", - base::Bind(&CallbackCheckWrapper::OnHistogramChanged, - base::Unretained(&callback_wrapper))); - - custom_histogram->Add(1); - - EXPECT_TRUE(callback_wrapper.called); - EXPECT_EQ(callback_wrapper.last_histogram_value, 1); - } - - { - HistogramBase* custom_histogram = SparseHistogram::FactoryGet( - "TestSparseHistogram", HistogramBase::kNoFlags); - - CallbackCheckWrapper callback_wrapper; - - base::StatisticsRecorder::SetCallback( - "TestSparseHistogram", - base::Bind(&CallbackCheckWrapper::OnHistogramChanged, - base::Unretained(&callback_wrapper))); - - custom_histogram->Add(1); - - EXPECT_TRUE(callback_wrapper.called); - EXPECT_EQ(callback_wrapper.last_histogram_value, 1); - } -} - -// Check that setting a callback before the histogram exists works. -TEST_P(StatisticsRecorderTest, CallbackUsedBeforeHistogramCreatedTest) { - CallbackCheckWrapper callback_wrapper; - - base::StatisticsRecorder::SetCallback( - "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged, - base::Unretained(&callback_wrapper))); - - HistogramBase* histogram = Histogram::FactoryGet("TestHistogram", 1, 1000, 10, - HistogramBase::kNoFlags); - EXPECT_TRUE(histogram); - histogram->Add(1); - - EXPECT_TRUE(callback_wrapper.called); - EXPECT_EQ(callback_wrapper.last_histogram_value, 1); -} - -TEST_P(StatisticsRecorderTest, LogOnShutdownNotInitialized) { - ResetVLogInitialized(); - logging::SetMinLogLevel(logging::LOG_WARNING); - InitializeStatisticsRecorder(); - EXPECT_FALSE(VLOG_IS_ON(1)); - EXPECT_FALSE(IsVLogInitialized()); - InitLogOnShutdown(); - EXPECT_FALSE(IsVLogInitialized()); -} - -TEST_P(StatisticsRecorderTest, LogOnShutdownInitializedExplicitly) { - ResetVLogInitialized(); - logging::SetMinLogLevel(logging::LOG_WARNING); - InitializeStatisticsRecorder(); - EXPECT_FALSE(VLOG_IS_ON(1)); - EXPECT_FALSE(IsVLogInitialized()); - logging::SetMinLogLevel(logging::LOG_VERBOSE); - EXPECT_TRUE(VLOG_IS_ON(1)); - InitLogOnShutdown(); - EXPECT_TRUE(IsVLogInitialized()); -} - -TEST_P(StatisticsRecorderTest, LogOnShutdownInitialized) { - ResetVLogInitialized(); - logging::SetMinLogLevel(logging::LOG_VERBOSE); - InitializeStatisticsRecorder(); - EXPECT_TRUE(VLOG_IS_ON(1)); - EXPECT_TRUE(IsVLogInitialized()); -} - -class TestHistogramProvider : public StatisticsRecorder::HistogramProvider { - public: - TestHistogramProvider(std::unique_ptr<PersistentHistogramAllocator> allocator) - : allocator_(std::move(allocator)), weak_factory_(this) { - StatisticsRecorder::RegisterHistogramProvider(weak_factory_.GetWeakPtr()); - } - - void MergeHistogramDeltas() override { - PersistentHistogramAllocator::Iterator hist_iter(allocator_.get()); - while (true) { - std::unique_ptr<base::HistogramBase> histogram = hist_iter.GetNext(); - if (!histogram) - break; - allocator_->MergeHistogramDeltaToStatisticsRecorder(histogram.get()); - } - } - - private: - std::unique_ptr<PersistentHistogramAllocator> allocator_; - WeakPtrFactory<TestHistogramProvider> weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(TestHistogramProvider); -}; - -TEST_P(StatisticsRecorderTest, ImportHistogramsTest) { - // Create a second SR to create some histograms for later import. - std::unique_ptr<StatisticsRecorder> temp_sr = - StatisticsRecorder::CreateTemporaryForTesting(); - - // Extract any existing global allocator so a new one can be created. - std::unique_ptr<GlobalHistogramAllocator> old_allocator = - GlobalHistogramAllocator::ReleaseForTesting(); - - // Create a histogram inside a new allocator for testing. - GlobalHistogramAllocator::CreateWithLocalMemory(kAllocatorMemorySize, 0, ""); - HistogramBase* histogram = LinearHistogram::FactoryGet("Foo", 1, 10, 11, 0); - histogram->Add(3); - - // Undo back to the starting point. - std::unique_ptr<GlobalHistogramAllocator> new_allocator = - GlobalHistogramAllocator::ReleaseForTesting(); - GlobalHistogramAllocator::Set(std::move(old_allocator)); - temp_sr.reset(); - - // Create a provider that can supply histograms to the current SR. - TestHistogramProvider provider(std::move(new_allocator)); - - // Verify that the created histogram is no longer known. - ASSERT_FALSE(StatisticsRecorder::FindHistogram(histogram->histogram_name())); - - // Now test that it merges. - StatisticsRecorder::ImportProvidedHistograms(); - HistogramBase* found = - StatisticsRecorder::FindHistogram(histogram->histogram_name()); - ASSERT_TRUE(found); - EXPECT_NE(histogram, found); - std::unique_ptr<HistogramSamples> snapshot = found->SnapshotSamples(); - EXPECT_EQ(1, snapshot->TotalCount()); - EXPECT_EQ(1, snapshot->GetCount(3)); - - // Finally, verify that updates can also be merged. - histogram->Add(3); - histogram->Add(5); - StatisticsRecorder::ImportProvidedHistograms(); - snapshot = found->SnapshotSamples(); - EXPECT_EQ(3, snapshot->TotalCount()); - EXPECT_EQ(2, snapshot->GetCount(3)); - EXPECT_EQ(1, snapshot->GetCount(5)); -} - -TEST_P(StatisticsRecorderTest, RecordHistogramChecker) { - // Record checker isn't set - EXPECT_TRUE(base::StatisticsRecorder::ShouldRecordHistogram(0)); - auto record_checker = std::make_unique<OddRecordHistogramChecker>(); - base::StatisticsRecorder::SetRecordChecker(std::move(record_checker)); - EXPECT_TRUE(base::StatisticsRecorder::ShouldRecordHistogram(1)); - EXPECT_FALSE(base::StatisticsRecorder::ShouldRecordHistogram(2)); -} - -} // namespace base
diff --git a/base/native_library_unittest.cc b/base/native_library_unittest.cc deleted file mode 100644 index ac8ec5c..0000000 --- a/base/native_library_unittest.cc +++ /dev/null
@@ -1,166 +0,0 @@ -// 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/files/file_path.h" -#include "base/macros.h" -#include "base/native_library.h" -#include "base/path_service.h" -#include "base/test/native_library_test_utils.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -const FilePath::CharType kDummyLibraryPath[] = - FILE_PATH_LITERAL("dummy_library"); - -TEST(NativeLibraryTest, LoadFailure) { - NativeLibraryLoadError error; - EXPECT_FALSE(LoadNativeLibrary(FilePath(kDummyLibraryPath), &error)); - EXPECT_FALSE(error.ToString().empty()); -} - -// |error| is optional and can be null. -TEST(NativeLibraryTest, LoadFailureWithNullError) { - EXPECT_FALSE(LoadNativeLibrary(FilePath(kDummyLibraryPath), nullptr)); -} - -TEST(NativeLibraryTest, GetNativeLibraryName) { - const char kExpectedName[] = -#if defined(OS_WIN) - "mylib.dll"; -#elif defined(OS_IOS) - "mylib"; -#elif defined(OS_MACOSX) - "libmylib.dylib"; -#elif defined(OS_POSIX) || defined(OS_FUCHSIA) - "libmylib.so"; -#endif - EXPECT_EQ(kExpectedName, GetNativeLibraryName("mylib")); -} - -TEST(NativeLibraryTest, GetLoadableModuleName) { - const char kExpectedName[] = -#if defined(OS_WIN) - "mylib.dll"; -#elif defined(OS_IOS) - "mylib"; -#elif defined(OS_MACOSX) - "mylib.so"; -#elif defined(OS_POSIX) || defined(OS_FUCHSIA) - "libmylib.so"; -#endif - EXPECT_EQ(kExpectedName, GetLoadableModuleName("mylib")); -} - -// We don't support dynamic loading on iOS, and ASAN will complain about our -// intentional ODR violation because of |g_native_library_exported_value| being -// defined globally both here and in the shared library. -#if !defined(OS_IOS) && !defined(ADDRESS_SANITIZER) - -const char kTestLibraryName[] = -#if defined(OS_WIN) - "test_shared_library.dll"; -#elif defined(OS_MACOSX) - "libtest_shared_library.dylib"; -#elif defined(OS_ANDROID) && defined(COMPONENT_BUILD) - "libtest_shared_library.cr.so"; -#elif defined(OS_POSIX) || defined(OS_FUCHSIA) - "libtest_shared_library.so"; -#endif - -class TestLibrary { - public: - TestLibrary() : TestLibrary(NativeLibraryOptions()) {} - - explicit TestLibrary(const NativeLibraryOptions& options) - : library_(nullptr) { - base::FilePath exe_path; - -#if !defined(OS_FUCHSIA) - // Libraries do not sit alongside the executable in Fuchsia. NativeLibrary - // is aware of this and is able to resolve library paths correctly. - CHECK(base::PathService::Get(base::DIR_EXE, &exe_path)); -#endif - - library_ = LoadNativeLibraryWithOptions( - exe_path.AppendASCII(kTestLibraryName), options, nullptr); - CHECK(library_); - } - - ~TestLibrary() { - UnloadNativeLibrary(library_); - } - - template <typename ReturnType, typename... Args> - ReturnType Call(const char* function_name, Args... args) { - return reinterpret_cast<ReturnType(*)(Args...)>( - GetFunctionPointerFromNativeLibrary(library_, function_name))(args...); - } - - private: - NativeLibrary library_; - - DISALLOW_COPY_AND_ASSIGN(TestLibrary); -}; - -// NativeLibraaryTest.LoadLibrary is failing on M tablets only. -// crbug/641309 -#if !defined(OS_ANDROID) - -// Verifies that we can load a native library and resolve its exported symbols. -TEST(NativeLibraryTest, LoadLibrary) { - TestLibrary library; - EXPECT_EQ(5, library.Call<int>("GetSimpleTestValue")); -} - -#endif // !defined(OS_ANDROID) - -// Android dlopen() requires further investigation, as it might vary across -// versions with respect to symbol resolution scope. -// TSan and MSan error out on RTLD_DEEPBIND, https://crbug.com/705255 -#if !defined(OS_ANDROID) && !defined(THREAD_SANITIZER) && \ - !defined(MEMORY_SANITIZER) - -// Verifies that the |prefer_own_symbols| option satisfies its guarantee that -// a loaded library will always prefer local symbol resolution before -// considering global symbols. -TEST(NativeLibraryTest, LoadLibraryPreferOwnSymbols) { - NativeLibraryOptions options; - options.prefer_own_symbols = true; - TestLibrary library(options); - - // Verify that this binary and the DSO use different storage for - // |g_native_library_exported_value|. - g_native_library_exported_value = 1; - library.Call<void>("SetExportedValue", 2); - EXPECT_EQ(1, g_native_library_exported_value); - g_native_library_exported_value = 3; - EXPECT_EQ(2, library.Call<int>("GetExportedValue")); - - // Both this binary and the library link against the - // native_library_test_utils source library, which in turn exports the - // NativeLibraryTestIncrement() function whose return value depends on some - // static internal state. - // - // The DSO's GetIncrementValue() forwards to that function inside the DSO. - // - // Here we verify that direct calls to NativeLibraryTestIncrement() in this - // binary return a sequence of values independent from the sequence returned - // by GetIncrementValue(), ensuring that the DSO is calling its own local - // definition of NativeLibraryTestIncrement(). - EXPECT_EQ(1, library.Call<int>("GetIncrementValue")); - EXPECT_EQ(1, NativeLibraryTestIncrement()); - EXPECT_EQ(2, library.Call<int>("GetIncrementValue")); - EXPECT_EQ(3, library.Call<int>("GetIncrementValue")); - EXPECT_EQ(4, library.Call<int>("NativeLibraryTestIncrement")); - EXPECT_EQ(2, NativeLibraryTestIncrement()); - EXPECT_EQ(3, NativeLibraryTestIncrement()); -} - -#endif // !defined(OS_ANDROID) - -#endif // !defined(OS_IOS) && !defined(ADDRESS_SANITIZER) - -} // namespace base
diff --git a/base/nix/xdg_util_unittest.cc b/base/nix/xdg_util_unittest.cc deleted file mode 100644 index e195303..0000000 --- a/base/nix/xdg_util_unittest.cc +++ /dev/null
@@ -1,181 +0,0 @@ -// 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/nix/xdg_util.h" - -#include "base/environment.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using ::testing::_; -using ::testing::Eq; -using ::testing::Return; -using ::testing::SetArgPointee; - -namespace base { -namespace nix { - -namespace { - -class MockEnvironment : public Environment { - public: - MOCK_METHOD2(GetVar, bool(StringPiece, std::string* result)); - MOCK_METHOD2(SetVar, bool(StringPiece, const std::string& new_value)); - MOCK_METHOD1(UnSetVar, bool(StringPiece)); -}; - -// Needs to be const char* to make gmock happy. -const char* const kDesktopGnome = "gnome"; -const char* const kDesktopGnomeFallback = "gnome-fallback"; -const char* const kDesktopMATE = "mate"; -const char* const kDesktopKDE4 = "kde4"; -const char* const kDesktopKDE = "kde"; -const char* const kDesktopXFCE = "xfce"; -const char* const kXdgDesktopCinnamon = "X-Cinnamon"; -const char* const kXdgDesktopGNOME = "GNOME"; -const char* const kXdgDesktopKDE = "KDE"; -const char* const kXdgDesktopPantheon = "Pantheon"; -const char* const kXdgDesktopUnity = "Unity"; -const char* const kXdgDesktopUnity7 = "Unity:Unity7"; -const char* const kXdgDesktopUnity8 = "Unity:Unity8"; -const char* const kKDESessionKDE5 = "5"; - -const char kDesktopSession[] = "DESKTOP_SESSION"; -const char kKDESession[] = "KDE_SESSION_VERSION"; -const char kXdgDesktop[] = "XDG_CURRENT_DESKTOP"; - -} // namespace - -TEST(XDGUtilTest, GetDesktopEnvironmentGnome) { - MockEnvironment getter; - EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false)); - EXPECT_CALL(getter, GetVar(Eq(kDesktopSession), _)) - .WillOnce(DoAll(SetArgPointee<1>(kDesktopGnome), Return(true))); - - EXPECT_EQ(DESKTOP_ENVIRONMENT_GNOME, GetDesktopEnvironment(&getter)); -} - -TEST(XDGUtilTest, GetDesktopEnvironmentMATE) { - MockEnvironment getter; - EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false)); - EXPECT_CALL(getter, GetVar(Eq(kDesktopSession), _)) - .WillOnce(DoAll(SetArgPointee<1>(kDesktopMATE), Return(true))); - - EXPECT_EQ(DESKTOP_ENVIRONMENT_GNOME, GetDesktopEnvironment(&getter)); -} - -TEST(XDGUtilTest, GetDesktopEnvironmentKDE4) { - MockEnvironment getter; - EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false)); - EXPECT_CALL(getter, GetVar(Eq(kDesktopSession), _)) - .WillOnce(DoAll(SetArgPointee<1>(kDesktopKDE4), Return(true))); - - EXPECT_EQ(DESKTOP_ENVIRONMENT_KDE4, GetDesktopEnvironment(&getter)); -} - -TEST(XDGUtilTest, GetDesktopEnvironmentKDE3) { - MockEnvironment getter; - EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false)); - EXPECT_CALL(getter, GetVar(Eq(kDesktopSession), _)) - .WillOnce(DoAll(SetArgPointee<1>(kDesktopKDE), Return(true))); - - EXPECT_EQ(DESKTOP_ENVIRONMENT_KDE3, GetDesktopEnvironment(&getter)); -} - -TEST(XDGUtilTest, GetDesktopEnvironmentXFCE) { - MockEnvironment getter; - EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false)); - EXPECT_CALL(getter, GetVar(Eq(kDesktopSession), _)) - .WillOnce(DoAll(SetArgPointee<1>(kDesktopXFCE), Return(true))); - - EXPECT_EQ(DESKTOP_ENVIRONMENT_XFCE, GetDesktopEnvironment(&getter)); -} - -TEST(XDGUtilTest, GetXdgDesktopCinnamon) { - MockEnvironment getter; - EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false)); - EXPECT_CALL(getter, GetVar(Eq(kXdgDesktop), _)) - .WillOnce(DoAll(SetArgPointee<1>(kXdgDesktopCinnamon), Return(true))); - - EXPECT_EQ(DESKTOP_ENVIRONMENT_CINNAMON, GetDesktopEnvironment(&getter)); -} - -TEST(XDGUtilTest, GetXdgDesktopGnome) { - MockEnvironment getter; - EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false)); - EXPECT_CALL(getter, GetVar(Eq(kXdgDesktop), _)) - .WillOnce(DoAll(SetArgPointee<1>(kXdgDesktopGNOME), Return(true))); - - EXPECT_EQ(DESKTOP_ENVIRONMENT_GNOME, GetDesktopEnvironment(&getter)); -} - -TEST(XDGUtilTest, GetXdgDesktopGnomeFallback) { - MockEnvironment getter; - EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false)); - EXPECT_CALL(getter, GetVar(Eq(kXdgDesktop), _)) - .WillOnce(DoAll(SetArgPointee<1>(kXdgDesktopUnity), Return(true))); - EXPECT_CALL(getter, GetVar(Eq(kDesktopSession), _)) - .WillOnce(DoAll(SetArgPointee<1>(kDesktopGnomeFallback), Return(true))); - - EXPECT_EQ(DESKTOP_ENVIRONMENT_GNOME, GetDesktopEnvironment(&getter)); -} - -TEST(XDGUtilTest, GetXdgDesktopKDE5) { - MockEnvironment getter; - EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false)); - EXPECT_CALL(getter, GetVar(Eq(kXdgDesktop), _)) - .WillOnce(DoAll(SetArgPointee<1>(kXdgDesktopKDE), Return(true))); - EXPECT_CALL(getter, GetVar(Eq(kKDESession), _)) - .WillOnce(DoAll(SetArgPointee<1>(kKDESessionKDE5), Return(true))); - - EXPECT_EQ(DESKTOP_ENVIRONMENT_KDE5, GetDesktopEnvironment(&getter)); -} - -TEST(XDGUtilTest, GetXdgDesktopKDE4) { - MockEnvironment getter; - EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false)); - EXPECT_CALL(getter, GetVar(Eq(kXdgDesktop), _)) - .WillOnce(DoAll(SetArgPointee<1>(kXdgDesktopKDE), Return(true))); - - EXPECT_EQ(DESKTOP_ENVIRONMENT_KDE4, GetDesktopEnvironment(&getter)); -} - -TEST(XDGUtilTest, GetXdgDesktopPantheon) { - MockEnvironment getter; - EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false)); - EXPECT_CALL(getter, GetVar(Eq(kXdgDesktop), _)) - .WillOnce(DoAll(SetArgPointee<1>(kXdgDesktopPantheon), Return(true))); - - EXPECT_EQ(DESKTOP_ENVIRONMENT_PANTHEON, GetDesktopEnvironment(&getter)); -} - -TEST(XDGUtilTest, GetXdgDesktopUnity) { - MockEnvironment getter; - EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false)); - EXPECT_CALL(getter, GetVar(Eq(kXdgDesktop), _)) - .WillOnce(DoAll(SetArgPointee<1>(kXdgDesktopUnity), Return(true))); - - EXPECT_EQ(DESKTOP_ENVIRONMENT_UNITY, GetDesktopEnvironment(&getter)); -} - -TEST(XDGUtilTest, GetXdgDesktopUnity7) { - MockEnvironment getter; - EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false)); - EXPECT_CALL(getter, GetVar(Eq(kXdgDesktop), _)) - .WillOnce(DoAll(SetArgPointee<1>(kXdgDesktopUnity7), Return(true))); - - EXPECT_EQ(DESKTOP_ENVIRONMENT_UNITY, GetDesktopEnvironment(&getter)); -} - -TEST(XDGUtilTest, GetXdgDesktopUnity8) { - MockEnvironment getter; - EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false)); - EXPECT_CALL(getter, GetVar(Eq(kXdgDesktop), _)) - .WillOnce(DoAll(SetArgPointee<1>(kXdgDesktopUnity8), Return(true))); - - EXPECT_EQ(DESKTOP_ENVIRONMENT_UNITY, GetDesktopEnvironment(&getter)); -} - -} // namespace nix -} // namespace base
diff --git a/base/no_destructor_unittest.cc b/base/no_destructor_unittest.cc deleted file mode 100644 index c552a92..0000000 --- a/base/no_destructor_unittest.cc +++ /dev/null
@@ -1,76 +0,0 @@ -// 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/no_destructor.h" - -#include <string> -#include <utility> - -#include "base/logging.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -struct CheckOnDestroy { - ~CheckOnDestroy() { CHECK(false); } -}; - -TEST(NoDestructorTest, SkipsDestructors) { - NoDestructor<CheckOnDestroy> destructor_should_not_run; -} - -struct CopyOnly { - CopyOnly() = default; - - CopyOnly(const CopyOnly&) = default; - CopyOnly& operator=(const CopyOnly&) = default; - - CopyOnly(CopyOnly&&) = delete; - CopyOnly& operator=(CopyOnly&&) = delete; -}; - -struct MoveOnly { - MoveOnly() = default; - - MoveOnly(const MoveOnly&) = delete; - MoveOnly& operator=(const MoveOnly&) = delete; - - MoveOnly(MoveOnly&&) = default; - MoveOnly& operator=(MoveOnly&&) = default; -}; - -struct ForwardingTestStruct { - ForwardingTestStruct(const CopyOnly&, MoveOnly&&) {} -}; - -TEST(NoDestructorTest, ForwardsArguments) { - CopyOnly copy_only; - MoveOnly move_only; - - static NoDestructor<ForwardingTestStruct> test_forwarding( - copy_only, std::move(move_only)); -} - -TEST(NoDestructorTest, Accessors) { - static NoDestructor<std::string> awesome("awesome"); - - EXPECT_EQ("awesome", *awesome); - EXPECT_EQ(0, awesome->compare("awesome")); - EXPECT_EQ(0, awesome.get()->compare("awesome")); -} - -// Passing initializer list to a NoDestructor like in this test -// is ambiguous in GCC. -// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84849 -#if !defined(COMPILER_GCC) && !defined(__clang__) -TEST(NoDestructorTest, InitializerList) { - static NoDestructor<std::vector<std::string>> vector({"a", "b", "c"}); -} -#endif -} // namespace - -} // namespace base
diff --git a/base/numerics/BUILD.gn b/base/numerics/BUILD.gn deleted file mode 100644 index 0bb8dd1..0000000 --- a/base/numerics/BUILD.gn +++ /dev/null
@@ -1,28 +0,0 @@ -# Copyright (c) 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. - -# This is a dependency-free, header-only, library, and it needs to stay that -# way to facilitate pulling it into various third-party projects. So, this -# file is here to protect against accidentally introducing external -# dependencies or depending on internal implementation details. -source_set("base_numerics") { - visibility = [ "//base/*" ] - sources = [ - "checked_math_impl.h", - "clamped_math_impl.h", - "safe_conversions_arm_impl.h", - "safe_conversions_impl.h", - "safe_math_arm_impl.h", - "safe_math_clang_gcc_impl.h", - "safe_math_shared_impl.h", - ] - public = [ - "checked_math.h", - "clamped_math.h", - "math_constants.h", - "ranges.h", - "safe_conversions.h", - "safe_math.h", - ] -}
diff --git a/base/observer_list_unittest.cc b/base/observer_list_unittest.cc deleted file mode 100644 index 37629ef..0000000 --- a/base/observer_list_unittest.cc +++ /dev/null
@@ -1,1276 +0,0 @@ -// 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/observer_list.h" -#include "base/observer_list_threadsafe.h" - -#include <memory> -#include <utility> -#include <vector> - -#include "base/bind.h" -#include "base/compiler_specific.h" -#include "base/location.h" -#include "base/memory/weak_ptr.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "base/sequenced_task_runner.h" -#include "base/single_thread_task_runner.h" -#include "base/synchronization/waitable_event.h" -#include "base/task_scheduler/post_task.h" -#include "base/task_scheduler/task_scheduler.h" -#include "base/test/gtest_util.h" -#include "base/test/scoped_task_environment.h" -#include "base/threading/platform_thread.h" -#include "base/threading/thread_restrictions.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -class Foo { - public: - virtual void Observe(int x) = 0; - virtual ~Foo() = default; - virtual int GetValue() const { return 0; } -}; - -class Adder : public Foo { - public: - explicit Adder(int scaler) : total(0), scaler_(scaler) {} - ~Adder() override = default; - - void Observe(int x) override { total += x * scaler_; } - int GetValue() const override { return total; } - - int total; - - private: - int scaler_; -}; - -class Disrupter : public Foo { - public: - Disrupter(ObserverList<Foo>* list, Foo* doomed, bool remove_self) - : list_(list), doomed_(doomed), remove_self_(remove_self) {} - Disrupter(ObserverList<Foo>* list, Foo* doomed) - : Disrupter(list, doomed, false) {} - Disrupter(ObserverList<Foo>* list, bool remove_self) - : Disrupter(list, nullptr, remove_self) {} - - ~Disrupter() override = default; - - void Observe(int x) override { - if (remove_self_) - list_->RemoveObserver(this); - if (doomed_) - list_->RemoveObserver(doomed_); - } - - void SetDoomed(Foo* doomed) { doomed_ = doomed; } - - private: - ObserverList<Foo>* list_; - Foo* doomed_; - bool remove_self_; -}; - -template <typename ObserverListType> -class AddInObserve : public Foo { - public: - explicit AddInObserve(ObserverListType* observer_list) - : observer_list(observer_list), to_add_() {} - - void SetToAdd(Foo* to_add) { to_add_ = to_add; } - - void Observe(int x) override { - if (to_add_) { - observer_list->AddObserver(to_add_); - to_add_ = nullptr; - } - } - - ObserverListType* observer_list; - Foo* to_add_; -}; - - -static const int kThreadRunTime = 2000; // ms to run the multi-threaded test. - -// A thread for use in the ThreadSafeObserver test -// which will add and remove itself from the notification -// list repeatedly. -class AddRemoveThread : public PlatformThread::Delegate, - public Foo { - public: - AddRemoveThread(ObserverListThreadSafe<Foo>* list, - bool notify, - WaitableEvent* ready) - : list_(list), - loop_(nullptr), - in_list_(false), - start_(Time::Now()), - count_observes_(0), - count_addtask_(0), - do_notifies_(notify), - ready_(ready), - weak_factory_(this) {} - - ~AddRemoveThread() override = default; - - void ThreadMain() override { - loop_ = new MessageLoop(); // Fire up a message loop. - loop_->task_runner()->PostTask( - FROM_HERE, - base::BindOnce(&AddRemoveThread::AddTask, weak_factory_.GetWeakPtr())); - ready_->Signal(); - // After ready_ is signaled, loop_ is only accessed by the main test thread - // (i.e. not this thread) in particular by Quit() which causes Run() to - // return, and we "control" loop_ again. - RunLoop().Run(); - delete loop_; - loop_ = reinterpret_cast<MessageLoop*>(0xdeadbeef); - delete this; - } - - // This task just keeps posting to itself in an attempt - // to race with the notifier. - void AddTask() { - count_addtask_++; - - if ((Time::Now() - start_).InMilliseconds() > kThreadRunTime) { - VLOG(1) << "DONE!"; - return; - } - - if (!in_list_) { - list_->AddObserver(this); - in_list_ = true; - } - - if (do_notifies_) { - list_->Notify(FROM_HERE, &Foo::Observe, 10); - } - - loop_->task_runner()->PostTask( - FROM_HERE, - base::BindOnce(&AddRemoveThread::AddTask, weak_factory_.GetWeakPtr())); - } - - // This function is only callable from the main thread. - void Quit() { - loop_->task_runner()->PostTask( - FROM_HERE, RunLoop::QuitCurrentWhenIdleClosureDeprecated()); - } - - void Observe(int x) override { - count_observes_++; - - // If we're getting called after we removed ourselves from - // the list, that is very bad! - DCHECK(in_list_); - - // This callback should fire on the appropriate thread - EXPECT_EQ(loop_, MessageLoop::current()); - - list_->RemoveObserver(this); - in_list_ = false; - } - - private: - ObserverListThreadSafe<Foo>* list_; - MessageLoop* loop_; - bool in_list_; // Are we currently registered for notifications. - // in_list_ is only used on |this| thread. - Time start_; // The time we started the test. - - int count_observes_; // Number of times we observed. - int count_addtask_; // Number of times thread AddTask was called - bool do_notifies_; // Whether these threads should do notifications. - WaitableEvent* ready_; - - base::WeakPtrFactory<AddRemoveThread> weak_factory_; -}; - -} // namespace - -TEST(ObserverListTest, BasicTest) { - ObserverList<Foo> observer_list; - const ObserverList<Foo>& const_observer_list = observer_list; - - { - const ObserverList<Foo>::const_iterator it1 = const_observer_list.begin(); - EXPECT_EQ(it1, const_observer_list.end()); - // Iterator copy. - const ObserverList<Foo>::const_iterator it2 = it1; - EXPECT_EQ(it2, it1); - // Iterator assignment. - ObserverList<Foo>::const_iterator it3; - it3 = it2; - EXPECT_EQ(it3, it1); - EXPECT_EQ(it3, it2); - // Self assignment. - it3 = *&it3; // The *& defeats Clang's -Wself-assign warning. - EXPECT_EQ(it3, it1); - EXPECT_EQ(it3, it2); - } - - { - const ObserverList<Foo>::iterator it1 = observer_list.begin(); - EXPECT_EQ(it1, observer_list.end()); - // Iterator copy. - const ObserverList<Foo>::iterator it2 = it1; - EXPECT_EQ(it2, it1); - // Iterator assignment. - ObserverList<Foo>::iterator it3; - it3 = it2; - EXPECT_EQ(it3, it1); - EXPECT_EQ(it3, it2); - // Self assignment. - it3 = *&it3; // The *& defeats Clang's -Wself-assign warning. - EXPECT_EQ(it3, it1); - EXPECT_EQ(it3, it2); - } - - Adder a(1), b(-1), c(1), d(-1), e(-1); - Disrupter evil(&observer_list, &c); - - observer_list.AddObserver(&a); - observer_list.AddObserver(&b); - - EXPECT_TRUE(const_observer_list.HasObserver(&a)); - EXPECT_FALSE(const_observer_list.HasObserver(&c)); - - { - const ObserverList<Foo>::const_iterator it1 = const_observer_list.begin(); - EXPECT_NE(it1, const_observer_list.end()); - // Iterator copy. - const ObserverList<Foo>::const_iterator it2 = it1; - EXPECT_EQ(it2, it1); - EXPECT_NE(it2, const_observer_list.end()); - // Iterator assignment. - ObserverList<Foo>::const_iterator it3; - it3 = it2; - EXPECT_EQ(it3, it1); - EXPECT_EQ(it3, it2); - // Self assignment. - it3 = *&it3; // The *& defeats Clang's -Wself-assign warning. - EXPECT_EQ(it3, it1); - EXPECT_EQ(it3, it2); - // Iterator post increment. - ObserverList<Foo>::const_iterator it4 = it3++; - EXPECT_EQ(it4, it1); - EXPECT_EQ(it4, it2); - EXPECT_NE(it4, it3); - } - - { - const ObserverList<Foo>::iterator it1 = observer_list.begin(); - EXPECT_NE(it1, observer_list.end()); - // Iterator copy. - const ObserverList<Foo>::iterator it2 = it1; - EXPECT_EQ(it2, it1); - EXPECT_NE(it2, observer_list.end()); - // Iterator assignment. - ObserverList<Foo>::iterator it3; - it3 = it2; - EXPECT_EQ(it3, it1); - EXPECT_EQ(it3, it2); - // Self assignment. - it3 = *&it3; // The *& defeats Clang's -Wself-assign warning. - EXPECT_EQ(it3, it1); - EXPECT_EQ(it3, it2); - // Iterator post increment. - ObserverList<Foo>::iterator it4 = it3++; - EXPECT_EQ(it4, it1); - EXPECT_EQ(it4, it2); - EXPECT_NE(it4, it3); - } - - for (auto& observer : observer_list) - observer.Observe(10); - - observer_list.AddObserver(&evil); - observer_list.AddObserver(&c); - observer_list.AddObserver(&d); - - // Removing an observer not in the list should do nothing. - observer_list.RemoveObserver(&e); - - for (auto& observer : observer_list) - observer.Observe(10); - - EXPECT_EQ(20, a.total); - EXPECT_EQ(-20, b.total); - EXPECT_EQ(0, c.total); - EXPECT_EQ(-10, d.total); - EXPECT_EQ(0, e.total); -} - -TEST(ObserverListTest, CompactsWhenNoActiveIterator) { - ObserverList<const Foo> ol; - const ObserverList<const Foo>& col = ol; - - const Adder a(1); - const Adder b(2); - const Adder c(3); - - ol.AddObserver(&a); - ol.AddObserver(&b); - - EXPECT_TRUE(col.HasObserver(&a)); - EXPECT_FALSE(col.HasObserver(&c)); - - EXPECT_TRUE(col.might_have_observers()); - - using It = ObserverList<const Foo>::const_iterator; - - { - It it = col.begin(); - EXPECT_NE(it, col.end()); - It ita = it; - EXPECT_EQ(ita, it); - EXPECT_NE(++it, col.end()); - EXPECT_NE(ita, it); - It itb = it; - EXPECT_EQ(itb, it); - EXPECT_EQ(++it, col.end()); - - EXPECT_TRUE(col.might_have_observers()); - EXPECT_EQ(&*ita, &a); - EXPECT_EQ(&*itb, &b); - - ol.RemoveObserver(&a); - EXPECT_TRUE(col.might_have_observers()); - EXPECT_FALSE(col.HasObserver(&a)); - EXPECT_EQ(&*itb, &b); - - ol.RemoveObserver(&b); - EXPECT_TRUE(col.might_have_observers()); - EXPECT_FALSE(col.HasObserver(&a)); - EXPECT_FALSE(col.HasObserver(&b)); - - it = It(); - ita = It(); - EXPECT_TRUE(col.might_have_observers()); - ita = itb; - itb = It(); - EXPECT_TRUE(col.might_have_observers()); - ita = It(); - EXPECT_FALSE(col.might_have_observers()); - } - - ol.AddObserver(&a); - ol.AddObserver(&b); - EXPECT_TRUE(col.might_have_observers()); - ol.Clear(); - EXPECT_FALSE(col.might_have_observers()); - - ol.AddObserver(&a); - ol.AddObserver(&b); - EXPECT_TRUE(col.might_have_observers()); - { - const It it = col.begin(); - ol.Clear(); - EXPECT_TRUE(col.might_have_observers()); - } - EXPECT_FALSE(col.might_have_observers()); -} - -TEST(ObserverListTest, DisruptSelf) { - ObserverList<Foo> observer_list; - Adder a(1), b(-1), c(1), d(-1); - Disrupter evil(&observer_list, true); - - observer_list.AddObserver(&a); - observer_list.AddObserver(&b); - - for (auto& observer : observer_list) - observer.Observe(10); - - observer_list.AddObserver(&evil); - observer_list.AddObserver(&c); - observer_list.AddObserver(&d); - - for (auto& observer : observer_list) - observer.Observe(10); - - EXPECT_EQ(20, a.total); - EXPECT_EQ(-20, b.total); - EXPECT_EQ(10, c.total); - EXPECT_EQ(-10, d.total); -} - -TEST(ObserverListTest, DisruptBefore) { - ObserverList<Foo> observer_list; - Adder a(1), b(-1), c(1), d(-1); - Disrupter evil(&observer_list, &b); - - observer_list.AddObserver(&a); - observer_list.AddObserver(&b); - observer_list.AddObserver(&evil); - observer_list.AddObserver(&c); - observer_list.AddObserver(&d); - - for (auto& observer : observer_list) - observer.Observe(10); - for (auto& observer : observer_list) - observer.Observe(10); - - EXPECT_EQ(20, a.total); - EXPECT_EQ(-10, b.total); - EXPECT_EQ(20, c.total); - EXPECT_EQ(-20, d.total); -} - -TEST(ObserverListThreadSafeTest, BasicTest) { - MessageLoop loop; - - scoped_refptr<ObserverListThreadSafe<Foo> > observer_list( - new ObserverListThreadSafe<Foo>); - Adder a(1); - Adder b(-1); - Adder c(1); - Adder d(-1); - - observer_list->AddObserver(&a); - observer_list->AddObserver(&b); - - observer_list->Notify(FROM_HERE, &Foo::Observe, 10); - RunLoop().RunUntilIdle(); - - observer_list->AddObserver(&c); - observer_list->AddObserver(&d); - - observer_list->Notify(FROM_HERE, &Foo::Observe, 10); - observer_list->RemoveObserver(&c); - RunLoop().RunUntilIdle(); - - EXPECT_EQ(20, a.total); - EXPECT_EQ(-20, b.total); - EXPECT_EQ(0, c.total); - EXPECT_EQ(-10, d.total); -} - -TEST(ObserverListThreadSafeTest, RemoveObserver) { - MessageLoop loop; - - scoped_refptr<ObserverListThreadSafe<Foo> > observer_list( - new ObserverListThreadSafe<Foo>); - Adder a(1), b(1); - - // A workaround for the compiler bug. See http://crbug.com/121960. - EXPECT_NE(&a, &b); - - // Should do nothing. - observer_list->RemoveObserver(&a); - observer_list->RemoveObserver(&b); - - observer_list->Notify(FROM_HERE, &Foo::Observe, 10); - RunLoop().RunUntilIdle(); - - EXPECT_EQ(0, a.total); - EXPECT_EQ(0, b.total); - - observer_list->AddObserver(&a); - - // Should also do nothing. - observer_list->RemoveObserver(&b); - - observer_list->Notify(FROM_HERE, &Foo::Observe, 10); - RunLoop().RunUntilIdle(); - - EXPECT_EQ(10, a.total); - EXPECT_EQ(0, b.total); -} - -TEST(ObserverListThreadSafeTest, WithoutSequence) { - scoped_refptr<ObserverListThreadSafe<Foo> > observer_list( - new ObserverListThreadSafe<Foo>); - - Adder a(1), b(1), c(1); - - // No sequence, so these should not be added. - observer_list->AddObserver(&a); - observer_list->AddObserver(&b); - - { - // Add c when there's a sequence. - MessageLoop loop; - observer_list->AddObserver(&c); - - observer_list->Notify(FROM_HERE, &Foo::Observe, 10); - RunLoop().RunUntilIdle(); - - EXPECT_EQ(0, a.total); - EXPECT_EQ(0, b.total); - EXPECT_EQ(10, c.total); - - // Now add a when there's a sequence. - observer_list->AddObserver(&a); - - // Remove c when there's a sequence. - observer_list->RemoveObserver(&c); - - // Notify again. - observer_list->Notify(FROM_HERE, &Foo::Observe, 20); - RunLoop().RunUntilIdle(); - - EXPECT_EQ(20, a.total); - EXPECT_EQ(0, b.total); - EXPECT_EQ(10, c.total); - } - - // Removing should always succeed with or without a sequence. - observer_list->RemoveObserver(&a); - - // Notifying should not fail but should also be a no-op. - MessageLoop loop; - observer_list->AddObserver(&b); - observer_list->Notify(FROM_HERE, &Foo::Observe, 30); - RunLoop().RunUntilIdle(); - - EXPECT_EQ(20, a.total); - EXPECT_EQ(30, b.total); - EXPECT_EQ(10, c.total); -} - -class FooRemover : public Foo { - public: - explicit FooRemover(ObserverListThreadSafe<Foo>* list) : list_(list) {} - ~FooRemover() override = default; - - void AddFooToRemove(Foo* foo) { - foos_.push_back(foo); - } - - void Observe(int x) override { - std::vector<Foo*> tmp; - tmp.swap(foos_); - for (std::vector<Foo*>::iterator it = tmp.begin(); - it != tmp.end(); ++it) { - list_->RemoveObserver(*it); - } - } - - private: - const scoped_refptr<ObserverListThreadSafe<Foo> > list_; - std::vector<Foo*> foos_; -}; - -TEST(ObserverListThreadSafeTest, RemoveMultipleObservers) { - MessageLoop loop; - scoped_refptr<ObserverListThreadSafe<Foo> > observer_list( - new ObserverListThreadSafe<Foo>); - - FooRemover a(observer_list.get()); - Adder b(1); - - observer_list->AddObserver(&a); - observer_list->AddObserver(&b); - - a.AddFooToRemove(&a); - a.AddFooToRemove(&b); - - observer_list->Notify(FROM_HERE, &Foo::Observe, 1); - RunLoop().RunUntilIdle(); -} - -// A test driver for a multi-threaded notification loop. Runs a number -// of observer threads, each of which constantly adds/removes itself -// from the observer list. Optionally, if cross_thread_notifies is set -// to true, the observer threads will also trigger notifications to -// all observers. -static void ThreadSafeObserverHarness(int num_threads, - bool cross_thread_notifies) { - MessageLoop loop; - - scoped_refptr<ObserverListThreadSafe<Foo> > observer_list( - new ObserverListThreadSafe<Foo>); - Adder a(1); - Adder b(-1); - - observer_list->AddObserver(&a); - observer_list->AddObserver(&b); - - std::vector<AddRemoveThread*> threaded_observer; - std::vector<base::PlatformThreadHandle> threads(num_threads); - std::vector<std::unique_ptr<base::WaitableEvent>> ready; - threaded_observer.reserve(num_threads); - ready.reserve(num_threads); - for (int index = 0; index < num_threads; index++) { - ready.push_back(std::make_unique<WaitableEvent>( - WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED)); - threaded_observer.push_back(new AddRemoveThread( - observer_list.get(), cross_thread_notifies, ready.back().get())); - EXPECT_TRUE( - PlatformThread::Create(0, threaded_observer.back(), &threads[index])); - } - ASSERT_EQ(static_cast<size_t>(num_threads), threaded_observer.size()); - ASSERT_EQ(static_cast<size_t>(num_threads), ready.size()); - - // This makes sure that threaded_observer has gotten to set loop_, so that we - // can call Quit() below safe-ish-ly. - for (int i = 0; i < num_threads; ++i) - ready[i]->Wait(); - - Time start = Time::Now(); - while (true) { - if ((Time::Now() - start).InMilliseconds() > kThreadRunTime) - break; - - observer_list->Notify(FROM_HERE, &Foo::Observe, 10); - - RunLoop().RunUntilIdle(); - } - - for (int index = 0; index < num_threads; index++) { - threaded_observer[index]->Quit(); - PlatformThread::Join(threads[index]); - } -} - -TEST(ObserverListThreadSafeTest, CrossThreadObserver) { - // Use 7 observer threads. Notifications only come from - // the main thread. - ThreadSafeObserverHarness(7, false); -} - -TEST(ObserverListThreadSafeTest, CrossThreadNotifications) { - // Use 3 observer threads. Notifications will fire from - // the main thread and all 3 observer threads. - ThreadSafeObserverHarness(3, true); -} - -TEST(ObserverListThreadSafeTest, OutlivesMessageLoop) { - MessageLoop* loop = new MessageLoop; - scoped_refptr<ObserverListThreadSafe<Foo> > observer_list( - new ObserverListThreadSafe<Foo>); - - Adder a(1); - observer_list->AddObserver(&a); - delete loop; - // Test passes if we don't crash here. - observer_list->Notify(FROM_HERE, &Foo::Observe, 1); -} - -namespace { - -class SequenceVerificationObserver : public Foo { - public: - explicit SequenceVerificationObserver( - scoped_refptr<SequencedTaskRunner> task_runner) - : task_runner_(std::move(task_runner)) {} - ~SequenceVerificationObserver() override = default; - - void Observe(int x) override { - called_on_valid_sequence_ = task_runner_->RunsTasksInCurrentSequence(); - } - - bool called_on_valid_sequence() const { return called_on_valid_sequence_; } - - private: - const scoped_refptr<SequencedTaskRunner> task_runner_; - bool called_on_valid_sequence_ = false; - - DISALLOW_COPY_AND_ASSIGN(SequenceVerificationObserver); -}; - -} // namespace - -// Verify that observers are notified on the correct sequence. -TEST(ObserverListThreadSafeTest, NotificationOnValidSequence) { - test::ScopedTaskEnvironment scoped_task_environment; - - auto task_runner_1 = CreateSequencedTaskRunnerWithTraits(TaskTraits()); - auto task_runner_2 = CreateSequencedTaskRunnerWithTraits(TaskTraits()); - - auto observer_list = MakeRefCounted<ObserverListThreadSafe<Foo>>(); - - SequenceVerificationObserver observer_1(task_runner_1); - SequenceVerificationObserver observer_2(task_runner_2); - - task_runner_1->PostTask(FROM_HERE, - BindOnce(&ObserverListThreadSafe<Foo>::AddObserver, - observer_list, Unretained(&observer_1))); - task_runner_2->PostTask(FROM_HERE, - BindOnce(&ObserverListThreadSafe<Foo>::AddObserver, - observer_list, Unretained(&observer_2))); - - TaskScheduler::GetInstance()->FlushForTesting(); - - observer_list->Notify(FROM_HERE, &Foo::Observe, 1); - - TaskScheduler::GetInstance()->FlushForTesting(); - - EXPECT_TRUE(observer_1.called_on_valid_sequence()); - EXPECT_TRUE(observer_2.called_on_valid_sequence()); -} - -// Verify that when an observer is added to a NOTIFY_ALL ObserverListThreadSafe -// from a notification, it is itself notified. -TEST(ObserverListThreadSafeTest, AddObserverFromNotificationNotifyAll) { - test::ScopedTaskEnvironment scoped_task_environment; - auto observer_list = MakeRefCounted<ObserverListThreadSafe<Foo>>(); - - Adder observer_added_from_notification(1); - - AddInObserve<ObserverListThreadSafe<Foo>> initial_observer( - observer_list.get()); - initial_observer.SetToAdd(&observer_added_from_notification); - observer_list->AddObserver(&initial_observer); - - observer_list->Notify(FROM_HERE, &Foo::Observe, 1); - - base::RunLoop().RunUntilIdle(); - - EXPECT_EQ(1, observer_added_from_notification.GetValue()); -} - -namespace { - -class RemoveWhileNotificationIsRunningObserver : public Foo { - public: - RemoveWhileNotificationIsRunningObserver() - : notification_running_(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED), - barrier_(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED) {} - ~RemoveWhileNotificationIsRunningObserver() override = default; - - void Observe(int x) override { - notification_running_.Signal(); - ScopedAllowBaseSyncPrimitivesForTesting allow_base_sync_primitives; - barrier_.Wait(); - } - - void WaitForNotificationRunning() { notification_running_.Wait(); } - void Unblock() { barrier_.Signal(); } - - private: - WaitableEvent notification_running_; - WaitableEvent barrier_; - - DISALLOW_COPY_AND_ASSIGN(RemoveWhileNotificationIsRunningObserver); -}; - -} // namespace - -// Verify that there is no crash when an observer is removed while it is being -// notified. -TEST(ObserverListThreadSafeTest, RemoveWhileNotificationIsRunning) { - auto observer_list = MakeRefCounted<ObserverListThreadSafe<Foo>>(); - RemoveWhileNotificationIsRunningObserver observer; - - WaitableEvent task_running(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - WaitableEvent barrier(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - - // This must be after the declaration of |barrier| so that tasks posted to - // TaskScheduler can safely use |barrier|. - test::ScopedTaskEnvironment scoped_task_environment; - - CreateSequencedTaskRunnerWithTraits({})->PostTask( - FROM_HERE, base::BindOnce(&ObserverListThreadSafe<Foo>::AddObserver, - observer_list, Unretained(&observer))); - TaskScheduler::GetInstance()->FlushForTesting(); - - observer_list->Notify(FROM_HERE, &Foo::Observe, 1); - observer.WaitForNotificationRunning(); - observer_list->RemoveObserver(&observer); - - observer.Unblock(); -} - -TEST(ObserverListTest, Existing) { - ObserverList<Foo> observer_list(ObserverListPolicy::EXISTING_ONLY); - Adder a(1); - AddInObserve<ObserverList<Foo> > b(&observer_list); - Adder c(1); - b.SetToAdd(&c); - - observer_list.AddObserver(&a); - observer_list.AddObserver(&b); - - for (auto& observer : observer_list) - observer.Observe(1); - - EXPECT_FALSE(b.to_add_); - // B's adder should not have been notified because it was added during - // notification. - EXPECT_EQ(0, c.total); - - // Notify again to make sure b's adder is notified. - for (auto& observer : observer_list) - observer.Observe(1); - EXPECT_EQ(1, c.total); -} - -// Same as above, but for ObserverListThreadSafe -TEST(ObserverListThreadSafeTest, Existing) { - MessageLoop loop; - scoped_refptr<ObserverListThreadSafe<Foo>> observer_list( - new ObserverListThreadSafe<Foo>(ObserverListPolicy::EXISTING_ONLY)); - Adder a(1); - AddInObserve<ObserverListThreadSafe<Foo> > b(observer_list.get()); - Adder c(1); - b.SetToAdd(&c); - - observer_list->AddObserver(&a); - observer_list->AddObserver(&b); - - observer_list->Notify(FROM_HERE, &Foo::Observe, 1); - RunLoop().RunUntilIdle(); - - EXPECT_FALSE(b.to_add_); - // B's adder should not have been notified because it was added during - // notification. - EXPECT_EQ(0, c.total); - - // Notify again to make sure b's adder is notified. - observer_list->Notify(FROM_HERE, &Foo::Observe, 1); - RunLoop().RunUntilIdle(); - EXPECT_EQ(1, c.total); -} - -class AddInClearObserve : public Foo { - public: - explicit AddInClearObserve(ObserverList<Foo>* list) - : list_(list), added_(false), adder_(1) {} - - void Observe(int /* x */) override { - list_->Clear(); - list_->AddObserver(&adder_); - added_ = true; - } - - bool added() const { return added_; } - const Adder& adder() const { return adder_; } - - private: - ObserverList<Foo>* const list_; - - bool added_; - Adder adder_; -}; - -TEST(ObserverListTest, ClearNotifyAll) { - ObserverList<Foo> observer_list; - AddInClearObserve a(&observer_list); - - observer_list.AddObserver(&a); - - for (auto& observer : observer_list) - observer.Observe(1); - EXPECT_TRUE(a.added()); - EXPECT_EQ(1, a.adder().total) - << "Adder should observe once and have sum of 1."; -} - -TEST(ObserverListTest, ClearNotifyExistingOnly) { - ObserverList<Foo> observer_list(ObserverListPolicy::EXISTING_ONLY); - AddInClearObserve a(&observer_list); - - observer_list.AddObserver(&a); - - for (auto& observer : observer_list) - observer.Observe(1); - EXPECT_TRUE(a.added()); - EXPECT_EQ(0, a.adder().total) - << "Adder should not observe, so sum should still be 0."; -} - -class ListDestructor : public Foo { - public: - explicit ListDestructor(ObserverList<Foo>* list) : list_(list) {} - ~ListDestructor() override = default; - - void Observe(int x) override { delete list_; } - - private: - ObserverList<Foo>* list_; -}; - - -TEST(ObserverListTest, IteratorOutlivesList) { - ObserverList<Foo>* observer_list = new ObserverList<Foo>; - ListDestructor a(observer_list); - observer_list->AddObserver(&a); - - for (auto& observer : *observer_list) - observer.Observe(0); - - // There are no EXPECT* statements for this test, if we catch - // use-after-free errors for observer_list (eg with ASan) then - // this test has failed. See http://crbug.com/85296. -} - -TEST(ObserverListTest, BasicStdIterator) { - using FooList = ObserverList<Foo>; - FooList observer_list; - - // An optimization: begin() and end() do not involve weak pointers on - // empty list. - EXPECT_FALSE(observer_list.begin().list_); - EXPECT_FALSE(observer_list.end().list_); - - // Iterate over empty list: no effect, no crash. - for (auto& i : observer_list) - i.Observe(10); - - Adder a(1), b(-1), c(1), d(-1); - - observer_list.AddObserver(&a); - observer_list.AddObserver(&b); - observer_list.AddObserver(&c); - observer_list.AddObserver(&d); - - for (FooList::iterator i = observer_list.begin(), e = observer_list.end(); - i != e; ++i) - i->Observe(1); - - EXPECT_EQ(1, a.total); - EXPECT_EQ(-1, b.total); - EXPECT_EQ(1, c.total); - EXPECT_EQ(-1, d.total); - - // Check an iteration over a 'const view' for a given container. - const FooList& const_list = observer_list; - for (FooList::const_iterator i = const_list.begin(), e = const_list.end(); - i != e; ++i) { - EXPECT_EQ(1, std::abs(i->GetValue())); - } - - for (const auto& o : const_list) - EXPECT_EQ(1, std::abs(o.GetValue())); -} - -TEST(ObserverListTest, StdIteratorRemoveItself) { - ObserverList<Foo> observer_list; - Adder a(1), b(-1), c(1), d(-1); - Disrupter disrupter(&observer_list, true); - - observer_list.AddObserver(&a); - observer_list.AddObserver(&b); - observer_list.AddObserver(&disrupter); - observer_list.AddObserver(&c); - observer_list.AddObserver(&d); - - for (auto& o : observer_list) - o.Observe(1); - - for (auto& o : observer_list) - o.Observe(10); - - EXPECT_EQ(11, a.total); - EXPECT_EQ(-11, b.total); - EXPECT_EQ(11, c.total); - EXPECT_EQ(-11, d.total); -} - -TEST(ObserverListTest, StdIteratorRemoveBefore) { - ObserverList<Foo> observer_list; - Adder a(1), b(-1), c(1), d(-1); - Disrupter disrupter(&observer_list, &b); - - observer_list.AddObserver(&a); - observer_list.AddObserver(&b); - observer_list.AddObserver(&disrupter); - observer_list.AddObserver(&c); - observer_list.AddObserver(&d); - - for (auto& o : observer_list) - o.Observe(1); - - for (auto& o : observer_list) - o.Observe(10); - - EXPECT_EQ(11, a.total); - EXPECT_EQ(-1, b.total); - EXPECT_EQ(11, c.total); - EXPECT_EQ(-11, d.total); -} - -TEST(ObserverListTest, StdIteratorRemoveAfter) { - ObserverList<Foo> observer_list; - Adder a(1), b(-1), c(1), d(-1); - Disrupter disrupter(&observer_list, &c); - - observer_list.AddObserver(&a); - observer_list.AddObserver(&b); - observer_list.AddObserver(&disrupter); - observer_list.AddObserver(&c); - observer_list.AddObserver(&d); - - for (auto& o : observer_list) - o.Observe(1); - - for (auto& o : observer_list) - o.Observe(10); - - EXPECT_EQ(11, a.total); - EXPECT_EQ(-11, b.total); - EXPECT_EQ(0, c.total); - EXPECT_EQ(-11, d.total); -} - -TEST(ObserverListTest, StdIteratorRemoveAfterFront) { - ObserverList<Foo> observer_list; - Adder a(1), b(-1), c(1), d(-1); - Disrupter disrupter(&observer_list, &a); - - observer_list.AddObserver(&a); - observer_list.AddObserver(&disrupter); - observer_list.AddObserver(&b); - observer_list.AddObserver(&c); - observer_list.AddObserver(&d); - - for (auto& o : observer_list) - o.Observe(1); - - for (auto& o : observer_list) - o.Observe(10); - - EXPECT_EQ(1, a.total); - EXPECT_EQ(-11, b.total); - EXPECT_EQ(11, c.total); - EXPECT_EQ(-11, d.total); -} - -TEST(ObserverListTest, StdIteratorRemoveBeforeBack) { - ObserverList<Foo> observer_list; - Adder a(1), b(-1), c(1), d(-1); - Disrupter disrupter(&observer_list, &d); - - observer_list.AddObserver(&a); - observer_list.AddObserver(&b); - observer_list.AddObserver(&c); - observer_list.AddObserver(&disrupter); - observer_list.AddObserver(&d); - - for (auto& o : observer_list) - o.Observe(1); - - for (auto& o : observer_list) - o.Observe(10); - - EXPECT_EQ(11, a.total); - EXPECT_EQ(-11, b.total); - EXPECT_EQ(11, c.total); - EXPECT_EQ(0, d.total); -} - -TEST(ObserverListTest, StdIteratorRemoveFront) { - using FooList = ObserverList<Foo>; - FooList observer_list; - Adder a(1), b(-1), c(1), d(-1); - Disrupter disrupter(&observer_list, true); - - observer_list.AddObserver(&disrupter); - observer_list.AddObserver(&a); - observer_list.AddObserver(&b); - observer_list.AddObserver(&c); - observer_list.AddObserver(&d); - - bool test_disruptor = true; - for (FooList::iterator i = observer_list.begin(), e = observer_list.end(); - i != e; ++i) { - i->Observe(1); - // Check that second call to i->Observe() would crash here. - if (test_disruptor) { - EXPECT_FALSE(i.GetCurrent()); - test_disruptor = false; - } - } - - for (auto& o : observer_list) - o.Observe(10); - - EXPECT_EQ(11, a.total); - EXPECT_EQ(-11, b.total); - EXPECT_EQ(11, c.total); - EXPECT_EQ(-11, d.total); -} - -TEST(ObserverListTest, StdIteratorRemoveBack) { - ObserverList<Foo> observer_list; - Adder a(1), b(-1), c(1), d(-1); - Disrupter disrupter(&observer_list, true); - - observer_list.AddObserver(&a); - observer_list.AddObserver(&b); - observer_list.AddObserver(&c); - observer_list.AddObserver(&d); - observer_list.AddObserver(&disrupter); - - for (auto& o : observer_list) - o.Observe(1); - - for (auto& o : observer_list) - o.Observe(10); - - EXPECT_EQ(11, a.total); - EXPECT_EQ(-11, b.total); - EXPECT_EQ(11, c.total); - EXPECT_EQ(-11, d.total); -} - -TEST(ObserverListTest, NestedLoop) { - ObserverList<Foo> observer_list; - Adder a(1), b(-1), c(1), d(-1); - Disrupter disrupter(&observer_list, true); - - observer_list.AddObserver(&disrupter); - observer_list.AddObserver(&a); - observer_list.AddObserver(&b); - observer_list.AddObserver(&c); - observer_list.AddObserver(&d); - - for (auto& o : observer_list) { - o.Observe(10); - - for (auto& o : observer_list) - o.Observe(1); - } - - EXPECT_EQ(15, a.total); - EXPECT_EQ(-15, b.total); - EXPECT_EQ(15, c.total); - EXPECT_EQ(-15, d.total); -} - -TEST(ObserverListTest, NonCompactList) { - ObserverList<Foo> observer_list; - Adder a(1), b(-1); - - Disrupter disrupter1(&observer_list, true); - Disrupter disrupter2(&observer_list, true); - - // Disrupt itself and another one. - disrupter1.SetDoomed(&disrupter2); - - observer_list.AddObserver(&disrupter1); - observer_list.AddObserver(&disrupter2); - observer_list.AddObserver(&a); - observer_list.AddObserver(&b); - - for (auto& o : observer_list) { - // Get the { nullptr, nullptr, &a, &b } non-compact list - // on the first inner pass. - o.Observe(10); - - for (auto& o : observer_list) - o.Observe(1); - } - - EXPECT_EQ(13, a.total); - EXPECT_EQ(-13, b.total); -} - -TEST(ObserverListTest, BecomesEmptyThanNonEmpty) { - ObserverList<Foo> observer_list; - Adder a(1), b(-1); - - Disrupter disrupter1(&observer_list, true); - Disrupter disrupter2(&observer_list, true); - - // Disrupt itself and another one. - disrupter1.SetDoomed(&disrupter2); - - observer_list.AddObserver(&disrupter1); - observer_list.AddObserver(&disrupter2); - - bool add_observers = true; - for (auto& o : observer_list) { - // Get the { nullptr, nullptr } empty list on the first inner pass. - o.Observe(10); - - for (auto& o : observer_list) - o.Observe(1); - - if (add_observers) { - observer_list.AddObserver(&a); - observer_list.AddObserver(&b); - add_observers = false; - } - } - - EXPECT_EQ(12, a.total); - EXPECT_EQ(-12, b.total); -} - -TEST(ObserverListTest, AddObserverInTheLastObserve) { - using FooList = ObserverList<Foo>; - FooList observer_list; - - AddInObserve<FooList> a(&observer_list); - Adder b(-1); - - a.SetToAdd(&b); - observer_list.AddObserver(&a); - - auto it = observer_list.begin(); - while (it != observer_list.end()) { - auto& observer = *it; - // Intentionally increment the iterator before calling Observe(). The - // ObserverList starts with only one observer, and it == observer_list.end() - // should be true after the next line. - ++it; - // However, the first Observe() call will add a second observer: at this - // point, it != observer_list.end() should be true, and Observe() should be - // called on the newly added observer on the next iteration of the loop. - observer.Observe(10); - } - - EXPECT_EQ(-10, b.total); -} - -class MockLogAssertHandler { - public: - MOCK_METHOD4( - HandleLogAssert, - void(const char*, int, const base::StringPiece, const base::StringPiece)); -}; - -#if DCHECK_IS_ON() -TEST(ObserverListTest, NonReentrantObserverList) { - using ::testing::_; - - ObserverList<Foo, /*check_empty=*/false, /*allow_reentrancy=*/false> - non_reentrant_observer_list; - Adder a(1); - non_reentrant_observer_list.AddObserver(&a); - - EXPECT_DCHECK_DEATH({ - for (const Foo& a : non_reentrant_observer_list) { - for (const Foo& b : non_reentrant_observer_list) { - std::ignore = a; - std::ignore = b; - } - } - }); -} - -TEST(ObserverListTest, ReentrantObserverList) { - using ::testing::_; - - ReentrantObserverList<Foo> reentrant_observer_list; - Adder a(1); - reentrant_observer_list.AddObserver(&a); - bool passed = false; - for (const Foo& a : reentrant_observer_list) { - for (const Foo& b : reentrant_observer_list) { - std::ignore = a; - std::ignore = b; - passed = true; - } - } - EXPECT_TRUE(passed); -} -#endif - -} // namespace base
diff --git a/base/optional_unittest.cc b/base/optional_unittest.cc deleted file mode 100644 index 7bdb46b..0000000 --- a/base/optional_unittest.cc +++ /dev/null
@@ -1,2185 +0,0 @@ -// 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/optional.h" - -#include <memory> -#include <set> -#include <string> -#include <vector> - -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using ::testing::ElementsAre; - -namespace base { - -namespace { - -// Object used to test complex object with Optional<T> in addition of the move -// semantics. -class TestObject { - public: - enum class State { - DEFAULT_CONSTRUCTED, - VALUE_CONSTRUCTED, - COPY_CONSTRUCTED, - MOVE_CONSTRUCTED, - MOVED_FROM, - COPY_ASSIGNED, - MOVE_ASSIGNED, - SWAPPED, - }; - - TestObject() : foo_(0), bar_(0.0), state_(State::DEFAULT_CONSTRUCTED) {} - - TestObject(int foo, double bar) - : foo_(foo), bar_(bar), state_(State::VALUE_CONSTRUCTED) {} - - TestObject(const TestObject& other) - : foo_(other.foo_), - bar_(other.bar_), - state_(State::COPY_CONSTRUCTED), - move_ctors_count_(other.move_ctors_count_) {} - - TestObject(TestObject&& other) - : foo_(std::move(other.foo_)), - bar_(std::move(other.bar_)), - state_(State::MOVE_CONSTRUCTED), - move_ctors_count_(other.move_ctors_count_ + 1) { - other.state_ = State::MOVED_FROM; - } - - TestObject& operator=(const TestObject& other) { - foo_ = other.foo_; - bar_ = other.bar_; - state_ = State::COPY_ASSIGNED; - move_ctors_count_ = other.move_ctors_count_; - return *this; - } - - TestObject& operator=(TestObject&& other) { - foo_ = other.foo_; - bar_ = other.bar_; - state_ = State::MOVE_ASSIGNED; - move_ctors_count_ = other.move_ctors_count_; - other.state_ = State::MOVED_FROM; - return *this; - } - - void Swap(TestObject* other) { - using std::swap; - swap(foo_, other->foo_); - swap(bar_, other->bar_); - swap(move_ctors_count_, other->move_ctors_count_); - state_ = State::SWAPPED; - other->state_ = State::SWAPPED; - } - - bool operator==(const TestObject& other) const { - return std::tie(foo_, bar_) == std::tie(other.foo_, other.bar_); - } - - bool operator!=(const TestObject& other) const { return !(*this == other); } - - int foo() const { return foo_; } - State state() const { return state_; } - int move_ctors_count() const { return move_ctors_count_; } - - private: - int foo_; - double bar_; - State state_; - int move_ctors_count_ = 0; -}; - -// Implementing Swappable concept. -void swap(TestObject& lhs, TestObject& rhs) { - lhs.Swap(&rhs); -} - -class NonTriviallyDestructible { - ~NonTriviallyDestructible() {} -}; - -class DeletedDefaultConstructor { - public: - DeletedDefaultConstructor() = delete; - DeletedDefaultConstructor(int foo) : foo_(foo) {} - - int foo() const { return foo_; } - - private: - int foo_; -}; - -class DeletedCopy { - public: - explicit DeletedCopy(int foo) : foo_(foo) {} - DeletedCopy(const DeletedCopy&) = delete; - DeletedCopy(DeletedCopy&&) = default; - - DeletedCopy& operator=(const DeletedCopy&) = delete; - DeletedCopy& operator=(DeletedCopy&&) = default; - - int foo() const { return foo_; } - - private: - int foo_; -}; - -class DeletedMove { - public: - explicit DeletedMove(int foo) : foo_(foo) {} - DeletedMove(const DeletedMove&) = default; - DeletedMove(DeletedMove&&) = delete; - - DeletedMove& operator=(const DeletedMove&) = default; - DeletedMove& operator=(DeletedMove&&) = delete; - - int foo() const { return foo_; } - - private: - int foo_; -}; - -class NonTriviallyDestructibleDeletedCopyConstructor { - public: - explicit NonTriviallyDestructibleDeletedCopyConstructor(int foo) - : foo_(foo) {} - NonTriviallyDestructibleDeletedCopyConstructor( - const NonTriviallyDestructibleDeletedCopyConstructor&) = delete; - NonTriviallyDestructibleDeletedCopyConstructor( - NonTriviallyDestructibleDeletedCopyConstructor&&) = default; - - ~NonTriviallyDestructibleDeletedCopyConstructor() {} - - int foo() const { return foo_; } - - private: - int foo_; -}; - -class DeleteNewOperators { - public: - void* operator new(size_t) = delete; - void* operator new(size_t, void*) = delete; - void* operator new[](size_t) = delete; - void* operator new[](size_t, void*) = delete; -}; - -} // anonymous namespace - -static_assert(std::is_trivially_destructible<Optional<int>>::value, - "OptionalIsTriviallyDestructible"); - -static_assert( - !std::is_trivially_destructible<Optional<NonTriviallyDestructible>>::value, - "OptionalIsTriviallyDestructible"); - -static_assert(sizeof(Optional<int>) == sizeof(internal::OptionalBase<int>), - "internal::{Copy,Move}{Constructible,Assignable} structs " - "should be 0-sized"); - -TEST(OptionalTest, DefaultConstructor) { - { - constexpr Optional<float> o; - EXPECT_FALSE(o); - } - - { - Optional<std::string> o; - EXPECT_FALSE(o); - } - - { - Optional<TestObject> o; - EXPECT_FALSE(o); - } -} - -TEST(OptionalTest, CopyConstructor) { - { - constexpr Optional<float> first(0.1f); - constexpr Optional<float> other(first); - - EXPECT_TRUE(other); - EXPECT_EQ(other.value(), 0.1f); - EXPECT_EQ(first, other); - } - - { - Optional<std::string> first("foo"); - Optional<std::string> other(first); - - EXPECT_TRUE(other); - EXPECT_EQ(other.value(), "foo"); - EXPECT_EQ(first, other); - } - - { - const Optional<std::string> first("foo"); - Optional<std::string> other(first); - - EXPECT_TRUE(other); - EXPECT_EQ(other.value(), "foo"); - EXPECT_EQ(first, other); - } - - { - Optional<TestObject> first(TestObject(3, 0.1)); - Optional<TestObject> other(first); - - EXPECT_TRUE(!!other); - EXPECT_TRUE(other.value() == TestObject(3, 0.1)); - EXPECT_TRUE(first == other); - } -} - -TEST(OptionalTest, ValueConstructor) { - { - constexpr float value = 0.1f; - constexpr Optional<float> o(value); - - EXPECT_TRUE(o); - EXPECT_EQ(value, o.value()); - } - - { - std::string value("foo"); - Optional<std::string> o(value); - - EXPECT_TRUE(o); - EXPECT_EQ(value, o.value()); - } - - { - TestObject value(3, 0.1); - Optional<TestObject> o(value); - - EXPECT_TRUE(o); - EXPECT_EQ(TestObject::State::COPY_CONSTRUCTED, o->state()); - EXPECT_EQ(value, o.value()); - } -} - -TEST(OptionalTest, MoveConstructor) { - { - constexpr Optional<float> first(0.1f); - constexpr Optional<float> second(std::move(first)); - - EXPECT_TRUE(second.has_value()); - EXPECT_EQ(second.value(), 0.1f); - - EXPECT_TRUE(first.has_value()); - } - - { - Optional<std::string> first("foo"); - Optional<std::string> second(std::move(first)); - - EXPECT_TRUE(second.has_value()); - EXPECT_EQ("foo", second.value()); - - EXPECT_TRUE(first.has_value()); - } - - { - Optional<TestObject> first(TestObject(3, 0.1)); - Optional<TestObject> second(std::move(first)); - - EXPECT_TRUE(second.has_value()); - EXPECT_EQ(TestObject::State::MOVE_CONSTRUCTED, second->state()); - EXPECT_TRUE(TestObject(3, 0.1) == second.value()); - - EXPECT_TRUE(first.has_value()); - EXPECT_EQ(TestObject::State::MOVED_FROM, first->state()); - } - - // Even if copy constructor is deleted, move constructor needs to work. - // Note that it couldn't be constexpr. - { - Optional<DeletedCopy> first(in_place, 42); - Optional<DeletedCopy> second(std::move(first)); - - EXPECT_TRUE(second.has_value()); - EXPECT_EQ(42, second->foo()); - - EXPECT_TRUE(first.has_value()); - } - - { - Optional<DeletedMove> first(in_place, 42); - Optional<DeletedMove> second(std::move(first)); - - EXPECT_TRUE(second.has_value()); - EXPECT_EQ(42, second->foo()); - - EXPECT_TRUE(first.has_value()); - } - - { - Optional<NonTriviallyDestructibleDeletedCopyConstructor> first(in_place, - 42); - Optional<NonTriviallyDestructibleDeletedCopyConstructor> second( - std::move(first)); - - EXPECT_TRUE(second.has_value()); - EXPECT_EQ(42, second->foo()); - - EXPECT_TRUE(first.has_value()); - } -} - -TEST(OptionalTest, MoveValueConstructor) { - { - constexpr float value = 0.1f; - constexpr Optional<float> o(std::move(value)); - - EXPECT_TRUE(o); - EXPECT_EQ(0.1f, o.value()); - } - - { - float value = 0.1f; - Optional<float> o(std::move(value)); - - EXPECT_TRUE(o); - EXPECT_EQ(0.1f, o.value()); - } - - { - std::string value("foo"); - Optional<std::string> o(std::move(value)); - - EXPECT_TRUE(o); - EXPECT_EQ("foo", o.value()); - } - - { - TestObject value(3, 0.1); - Optional<TestObject> o(std::move(value)); - - EXPECT_TRUE(o); - EXPECT_EQ(TestObject::State::MOVE_CONSTRUCTED, o->state()); - EXPECT_EQ(TestObject(3, 0.1), o.value()); - } -} - -TEST(OptionalTest, ConvertingCopyConstructor) { - { - Optional<int> first(1); - Optional<double> second(first); - EXPECT_TRUE(second.has_value()); - EXPECT_EQ(1.0, second.value()); - } - - // Make sure explicit is not marked for convertible case. - { - Optional<int> o(1); - ignore_result<Optional<double>>(o); - } -} - -TEST(OptionalTest, ConvertingMoveConstructor) { - { - Optional<int> first(1); - Optional<double> second(std::move(first)); - EXPECT_TRUE(second.has_value()); - EXPECT_EQ(1.0, second.value()); - } - - // Make sure explicit is not marked for convertible case. - { - Optional<int> o(1); - ignore_result<Optional<double>>(std::move(o)); - } - - { - class Test1 { - public: - explicit Test1(int foo) : foo_(foo) {} - - int foo() const { return foo_; } - - private: - int foo_; - }; - - // Not copyable but convertible from Test1. - class Test2 { - public: - Test2(const Test2&) = delete; - explicit Test2(Test1&& other) : bar_(other.foo()) {} - - double bar() const { return bar_; } - - private: - double bar_; - }; - - Optional<Test1> first(in_place, 42); - Optional<Test2> second(std::move(first)); - EXPECT_TRUE(second.has_value()); - EXPECT_EQ(42.0, second->bar()); - } -} - -TEST(OptionalTest, ConstructorForwardArguments) { - { - constexpr Optional<float> a(base::in_place, 0.1f); - EXPECT_TRUE(a); - EXPECT_EQ(0.1f, a.value()); - } - - { - Optional<float> a(base::in_place, 0.1f); - EXPECT_TRUE(a); - EXPECT_EQ(0.1f, a.value()); - } - - { - Optional<std::string> a(base::in_place, "foo"); - EXPECT_TRUE(a); - EXPECT_EQ("foo", a.value()); - } - - { - Optional<TestObject> a(base::in_place, 0, 0.1); - EXPECT_TRUE(!!a); - EXPECT_TRUE(TestObject(0, 0.1) == a.value()); - } -} - -TEST(OptionalTest, ConstructorForwardInitListAndArguments) { - { - Optional<std::vector<int>> opt(in_place, {3, 1}); - EXPECT_TRUE(opt); - EXPECT_THAT(*opt, ElementsAre(3, 1)); - EXPECT_EQ(2u, opt->size()); - } - - { - Optional<std::vector<int>> opt(in_place, {3, 1}, std::allocator<int>()); - EXPECT_TRUE(opt); - EXPECT_THAT(*opt, ElementsAre(3, 1)); - EXPECT_EQ(2u, opt->size()); - } -} - -TEST(OptionalTest, ForwardConstructor) { - { - Optional<double> a(1); - EXPECT_TRUE(a.has_value()); - EXPECT_EQ(1.0, a.value()); - } - - // Test that default type of 'U' is value_type. - { - struct TestData { - int a; - double b; - bool c; - }; - - Optional<TestData> a({1, 2.0, true}); - EXPECT_TRUE(a.has_value()); - EXPECT_EQ(1, a->a); - EXPECT_EQ(2.0, a->b); - EXPECT_TRUE(a->c); - } - - // If T has a constructor with a param Optional<U>, and another ctor with a - // param U, then T(Optional<U>) should be used for Optional<T>(Optional<U>) - // constructor. - { - enum class ParamType { - DEFAULT_CONSTRUCTED, - COPY_CONSTRUCTED, - MOVE_CONSTRUCTED, - INT, - IN_PLACE, - OPTIONAL_INT, - }; - struct Test { - Test() : param_type(ParamType::DEFAULT_CONSTRUCTED) {} - Test(const Test& param) : param_type(ParamType::COPY_CONSTRUCTED) {} - Test(Test&& param) : param_type(ParamType::MOVE_CONSTRUCTED) {} - explicit Test(int param) : param_type(ParamType::INT) {} - explicit Test(in_place_t param) : param_type(ParamType::IN_PLACE) {} - explicit Test(Optional<int> param) - : param_type(ParamType::OPTIONAL_INT) {} - - ParamType param_type; - }; - - // Overload resolution with copy-conversion constructor. - { - const Optional<int> arg(in_place, 1); - Optional<Test> testee(arg); - EXPECT_EQ(ParamType::OPTIONAL_INT, testee->param_type); - } - - // Overload resolution with move conversion constructor. - { - Optional<Test> testee(Optional<int>(in_place, 1)); - EXPECT_EQ(ParamType::OPTIONAL_INT, testee->param_type); - } - - // Default constructor should be used. - { - Optional<Test> testee(in_place); - EXPECT_EQ(ParamType::DEFAULT_CONSTRUCTED, testee->param_type); - } - } - - { - struct Test { - Test(int a) {} // NOLINT(runtime/explicit) - }; - // If T is convertible from U, it is not marked as explicit. - static_assert(std::is_convertible<int, Test>::value, - "Int should be convertible to Test."); - ([](Optional<Test> param) {})(1); - } -} - -TEST(OptionalTest, NulloptConstructor) { - constexpr Optional<int> a(base::nullopt); - EXPECT_FALSE(a); -} - -TEST(OptionalTest, AssignValue) { - { - Optional<float> a; - EXPECT_FALSE(a); - a = 0.1f; - EXPECT_TRUE(a); - - Optional<float> b(0.1f); - EXPECT_TRUE(a == b); - } - - { - Optional<std::string> a; - EXPECT_FALSE(a); - a = std::string("foo"); - EXPECT_TRUE(a); - - Optional<std::string> b(std::string("foo")); - EXPECT_EQ(a, b); - } - - { - Optional<TestObject> a; - EXPECT_FALSE(!!a); - a = TestObject(3, 0.1); - EXPECT_TRUE(!!a); - - Optional<TestObject> b(TestObject(3, 0.1)); - EXPECT_TRUE(a == b); - } - - { - Optional<TestObject> a = TestObject(4, 1.0); - EXPECT_TRUE(!!a); - a = TestObject(3, 0.1); - EXPECT_TRUE(!!a); - - Optional<TestObject> b(TestObject(3, 0.1)); - EXPECT_TRUE(a == b); - } -} - -TEST(OptionalTest, AssignObject) { - { - Optional<float> a; - Optional<float> b(0.1f); - a = b; - - EXPECT_TRUE(a); - EXPECT_EQ(a.value(), 0.1f); - EXPECT_EQ(a, b); - } - - { - Optional<std::string> a; - Optional<std::string> b("foo"); - a = b; - - EXPECT_TRUE(a); - EXPECT_EQ(a.value(), "foo"); - EXPECT_EQ(a, b); - } - - { - Optional<TestObject> a; - Optional<TestObject> b(TestObject(3, 0.1)); - a = b; - - EXPECT_TRUE(!!a); - EXPECT_TRUE(a.value() == TestObject(3, 0.1)); - EXPECT_TRUE(a == b); - } - - { - Optional<TestObject> a(TestObject(4, 1.0)); - Optional<TestObject> b(TestObject(3, 0.1)); - a = b; - - EXPECT_TRUE(!!a); - EXPECT_TRUE(a.value() == TestObject(3, 0.1)); - EXPECT_TRUE(a == b); - } - - { - Optional<DeletedMove> a(in_place, 42); - Optional<DeletedMove> b; - b = a; - - EXPECT_TRUE(!!a); - EXPECT_TRUE(!!b); - EXPECT_EQ(a->foo(), b->foo()); - } - - { - Optional<DeletedMove> a(in_place, 42); - Optional<DeletedMove> b(in_place, 1); - b = a; - - EXPECT_TRUE(!!a); - EXPECT_TRUE(!!b); - EXPECT_EQ(a->foo(), b->foo()); - } - - // Converting assignment. - { - Optional<int> a(in_place, 1); - Optional<double> b; - b = a; - - EXPECT_TRUE(!!a); - EXPECT_TRUE(!!b); - EXPECT_EQ(1, a.value()); - EXPECT_EQ(1.0, b.value()); - } - - { - Optional<int> a(in_place, 42); - Optional<double> b(in_place, 1); - b = a; - - EXPECT_TRUE(!!a); - EXPECT_TRUE(!!b); - EXPECT_EQ(42, a.value()); - EXPECT_EQ(42.0, b.value()); - } - - { - Optional<int> a; - Optional<double> b(in_place, 1); - b = a; - EXPECT_FALSE(!!a); - EXPECT_FALSE(!!b); - } -} - -TEST(OptionalTest, AssignObject_rvalue) { - { - Optional<float> a; - Optional<float> b(0.1f); - a = std::move(b); - - EXPECT_TRUE(a); - EXPECT_TRUE(b); - EXPECT_EQ(0.1f, a.value()); - } - - { - Optional<std::string> a; - Optional<std::string> b("foo"); - a = std::move(b); - - EXPECT_TRUE(a); - EXPECT_TRUE(b); - EXPECT_EQ("foo", a.value()); - } - - { - Optional<TestObject> a; - Optional<TestObject> b(TestObject(3, 0.1)); - a = std::move(b); - - EXPECT_TRUE(!!a); - EXPECT_TRUE(!!b); - EXPECT_TRUE(TestObject(3, 0.1) == a.value()); - - EXPECT_EQ(TestObject::State::MOVE_CONSTRUCTED, a->state()); - EXPECT_EQ(TestObject::State::MOVED_FROM, b->state()); - } - - { - Optional<TestObject> a(TestObject(4, 1.0)); - Optional<TestObject> b(TestObject(3, 0.1)); - a = std::move(b); - - EXPECT_TRUE(!!a); - EXPECT_TRUE(!!b); - EXPECT_TRUE(TestObject(3, 0.1) == a.value()); - - EXPECT_EQ(TestObject::State::MOVE_ASSIGNED, a->state()); - EXPECT_EQ(TestObject::State::MOVED_FROM, b->state()); - } - - { - Optional<DeletedMove> a(in_place, 42); - Optional<DeletedMove> b; - b = std::move(a); - - EXPECT_TRUE(!!a); - EXPECT_TRUE(!!b); - EXPECT_EQ(42, b->foo()); - } - - { - Optional<DeletedMove> a(in_place, 42); - Optional<DeletedMove> b(in_place, 1); - b = std::move(a); - - EXPECT_TRUE(!!a); - EXPECT_TRUE(!!b); - EXPECT_EQ(42, b->foo()); - } - - // Converting assignment. - { - Optional<int> a(in_place, 1); - Optional<double> b; - b = std::move(a); - - EXPECT_TRUE(!!a); - EXPECT_TRUE(!!b); - EXPECT_EQ(1.0, b.value()); - } - - { - Optional<int> a(in_place, 42); - Optional<double> b(in_place, 1); - b = std::move(a); - - EXPECT_TRUE(!!a); - EXPECT_TRUE(!!b); - EXPECT_EQ(42.0, b.value()); - } - - { - Optional<int> a; - Optional<double> b(in_place, 1); - b = std::move(a); - - EXPECT_FALSE(!!a); - EXPECT_FALSE(!!b); - } -} - -TEST(OptionalTest, AssignNull) { - { - Optional<float> a(0.1f); - Optional<float> b(0.2f); - a = base::nullopt; - b = base::nullopt; - EXPECT_EQ(a, b); - } - - { - Optional<std::string> a("foo"); - Optional<std::string> b("bar"); - a = base::nullopt; - b = base::nullopt; - EXPECT_EQ(a, b); - } - - { - Optional<TestObject> a(TestObject(3, 0.1)); - Optional<TestObject> b(TestObject(4, 1.0)); - a = base::nullopt; - b = base::nullopt; - EXPECT_TRUE(a == b); - } -} - -TEST(OptionalTest, AssignOverload) { - struct Test1 { - enum class State { - CONSTRUCTED, - MOVED, - }; - State state = State::CONSTRUCTED; - }; - - // Here, Optional<Test2> can be assigned from Optioanl<Test1>. - // In case of move, marks MOVED to Test1 instance. - struct Test2 { - enum class State { - DEFAULT_CONSTRUCTED, - COPY_CONSTRUCTED_FROM_TEST1, - MOVE_CONSTRUCTED_FROM_TEST1, - COPY_ASSIGNED_FROM_TEST1, - MOVE_ASSIGNED_FROM_TEST1, - }; - - Test2() = default; - explicit Test2(const Test1& test1) - : state(State::COPY_CONSTRUCTED_FROM_TEST1) {} - explicit Test2(Test1&& test1) : state(State::MOVE_CONSTRUCTED_FROM_TEST1) { - test1.state = Test1::State::MOVED; - } - Test2& operator=(const Test1& test1) { - state = State::COPY_ASSIGNED_FROM_TEST1; - return *this; - } - Test2& operator=(Test1&& test1) { - state = State::MOVE_ASSIGNED_FROM_TEST1; - test1.state = Test1::State::MOVED; - return *this; - } - - State state = State::DEFAULT_CONSTRUCTED; - }; - - { - Optional<Test1> a(in_place); - Optional<Test2> b; - - b = a; - EXPECT_TRUE(!!a); - EXPECT_TRUE(!!b); - EXPECT_EQ(Test1::State::CONSTRUCTED, a->state); - EXPECT_EQ(Test2::State::COPY_CONSTRUCTED_FROM_TEST1, b->state); - } - - { - Optional<Test1> a(in_place); - Optional<Test2> b(in_place); - - b = a; - EXPECT_TRUE(!!a); - EXPECT_TRUE(!!b); - EXPECT_EQ(Test1::State::CONSTRUCTED, a->state); - EXPECT_EQ(Test2::State::COPY_ASSIGNED_FROM_TEST1, b->state); - } - - { - Optional<Test1> a(in_place); - Optional<Test2> b; - - b = std::move(a); - EXPECT_TRUE(!!a); - EXPECT_TRUE(!!b); - EXPECT_EQ(Test1::State::MOVED, a->state); - EXPECT_EQ(Test2::State::MOVE_CONSTRUCTED_FROM_TEST1, b->state); - } - - { - Optional<Test1> a(in_place); - Optional<Test2> b(in_place); - - b = std::move(a); - EXPECT_TRUE(!!a); - EXPECT_TRUE(!!b); - EXPECT_EQ(Test1::State::MOVED, a->state); - EXPECT_EQ(Test2::State::MOVE_ASSIGNED_FROM_TEST1, b->state); - } - - // Similar to Test2, but Test3 also has copy/move ctor and assign operators - // from Optional<Test1>, too. In this case, for a = b where a is - // Optional<Test3> and b is Optional<Test1>, - // Optional<T>::operator=(U&&) where U is Optional<Test1> should be used - // rather than Optional<T>::operator=(Optional<U>&&) where U is Test1. - struct Test3 { - enum class State { - DEFAULT_CONSTRUCTED, - COPY_CONSTRUCTED_FROM_TEST1, - MOVE_CONSTRUCTED_FROM_TEST1, - COPY_CONSTRUCTED_FROM_OPTIONAL_TEST1, - MOVE_CONSTRUCTED_FROM_OPTIONAL_TEST1, - COPY_ASSIGNED_FROM_TEST1, - MOVE_ASSIGNED_FROM_TEST1, - COPY_ASSIGNED_FROM_OPTIONAL_TEST1, - MOVE_ASSIGNED_FROM_OPTIONAL_TEST1, - }; - - Test3() = default; - explicit Test3(const Test1& test1) - : state(State::COPY_CONSTRUCTED_FROM_TEST1) {} - explicit Test3(Test1&& test1) : state(State::MOVE_CONSTRUCTED_FROM_TEST1) { - test1.state = Test1::State::MOVED; - } - explicit Test3(const Optional<Test1>& test1) - : state(State::COPY_CONSTRUCTED_FROM_OPTIONAL_TEST1) {} - explicit Test3(Optional<Test1>&& test1) - : state(State::MOVE_CONSTRUCTED_FROM_OPTIONAL_TEST1) { - // In the following senarios, given |test1| should always have value. - DCHECK(test1.has_value()); - test1->state = Test1::State::MOVED; - } - Test3& operator=(const Test1& test1) { - state = State::COPY_ASSIGNED_FROM_TEST1; - return *this; - } - Test3& operator=(Test1&& test1) { - state = State::MOVE_ASSIGNED_FROM_TEST1; - test1.state = Test1::State::MOVED; - return *this; - } - Test3& operator=(const Optional<Test1>& test1) { - state = State::COPY_ASSIGNED_FROM_OPTIONAL_TEST1; - return *this; - } - Test3& operator=(Optional<Test1>&& test1) { - state = State::MOVE_ASSIGNED_FROM_OPTIONAL_TEST1; - // In the following senarios, given |test1| should always have value. - DCHECK(test1.has_value()); - test1->state = Test1::State::MOVED; - return *this; - } - - State state = State::DEFAULT_CONSTRUCTED; - }; - - { - Optional<Test1> a(in_place); - Optional<Test3> b; - - b = a; - EXPECT_TRUE(!!a); - EXPECT_TRUE(!!b); - EXPECT_EQ(Test1::State::CONSTRUCTED, a->state); - EXPECT_EQ(Test3::State::COPY_CONSTRUCTED_FROM_OPTIONAL_TEST1, b->state); - } - - { - Optional<Test1> a(in_place); - Optional<Test3> b(in_place); - - b = a; - EXPECT_TRUE(!!a); - EXPECT_TRUE(!!b); - EXPECT_EQ(Test1::State::CONSTRUCTED, a->state); - EXPECT_EQ(Test3::State::COPY_ASSIGNED_FROM_OPTIONAL_TEST1, b->state); - } - - { - Optional<Test1> a(in_place); - Optional<Test3> b; - - b = std::move(a); - EXPECT_TRUE(!!a); - EXPECT_TRUE(!!b); - EXPECT_EQ(Test1::State::MOVED, a->state); - EXPECT_EQ(Test3::State::MOVE_CONSTRUCTED_FROM_OPTIONAL_TEST1, b->state); - } - - { - Optional<Test1> a(in_place); - Optional<Test3> b(in_place); - - b = std::move(a); - EXPECT_TRUE(!!a); - EXPECT_TRUE(!!b); - EXPECT_EQ(Test1::State::MOVED, a->state); - EXPECT_EQ(Test3::State::MOVE_ASSIGNED_FROM_OPTIONAL_TEST1, b->state); - } -} - -TEST(OptionalTest, OperatorStar) { - { - Optional<float> a(0.1f); - EXPECT_EQ(a.value(), *a); - } - - { - Optional<std::string> a("foo"); - EXPECT_EQ(a.value(), *a); - } - - { - Optional<TestObject> a(TestObject(3, 0.1)); - EXPECT_EQ(a.value(), *a); - } -} - -TEST(OptionalTest, OperatorStar_rvalue) { - EXPECT_EQ(0.1f, *Optional<float>(0.1f)); - EXPECT_EQ(std::string("foo"), *Optional<std::string>("foo")); - EXPECT_TRUE(TestObject(3, 0.1) == *Optional<TestObject>(TestObject(3, 0.1))); -} - -TEST(OptionalTest, OperatorArrow) { - Optional<TestObject> a(TestObject(3, 0.1)); - EXPECT_EQ(a->foo(), 3); -} - -TEST(OptionalTest, Value_rvalue) { - EXPECT_EQ(0.1f, Optional<float>(0.1f).value()); - EXPECT_EQ(std::string("foo"), Optional<std::string>("foo").value()); - EXPECT_TRUE(TestObject(3, 0.1) == - Optional<TestObject>(TestObject(3, 0.1)).value()); -} - -TEST(OptionalTest, ValueOr) { - { - Optional<float> a; - EXPECT_EQ(0.0f, a.value_or(0.0f)); - - a = 0.1f; - EXPECT_EQ(0.1f, a.value_or(0.0f)); - - a = base::nullopt; - EXPECT_EQ(0.0f, a.value_or(0.0f)); - } - - // value_or() can be constexpr. - { - constexpr Optional<int> a(in_place, 1); - constexpr int value = a.value_or(10); - EXPECT_EQ(1, value); - } - { - constexpr Optional<int> a; - constexpr int value = a.value_or(10); - EXPECT_EQ(10, value); - } - - { - Optional<std::string> a; - EXPECT_EQ("bar", a.value_or("bar")); - - a = std::string("foo"); - EXPECT_EQ(std::string("foo"), a.value_or("bar")); - - a = base::nullopt; - EXPECT_EQ(std::string("bar"), a.value_or("bar")); - } - - { - Optional<TestObject> a; - EXPECT_TRUE(a.value_or(TestObject(1, 0.3)) == TestObject(1, 0.3)); - - a = TestObject(3, 0.1); - EXPECT_TRUE(a.value_or(TestObject(1, 0.3)) == TestObject(3, 0.1)); - - a = base::nullopt; - EXPECT_TRUE(a.value_or(TestObject(1, 0.3)) == TestObject(1, 0.3)); - } -} - -TEST(OptionalTest, Swap_bothNoValue) { - Optional<TestObject> a, b; - a.swap(b); - - EXPECT_FALSE(a); - EXPECT_FALSE(b); - EXPECT_TRUE(TestObject(42, 0.42) == a.value_or(TestObject(42, 0.42))); - EXPECT_TRUE(TestObject(42, 0.42) == b.value_or(TestObject(42, 0.42))); -} - -TEST(OptionalTest, Swap_inHasValue) { - Optional<TestObject> a(TestObject(1, 0.3)); - Optional<TestObject> b; - a.swap(b); - - EXPECT_FALSE(a); - - EXPECT_TRUE(!!b); - EXPECT_TRUE(TestObject(42, 0.42) == a.value_or(TestObject(42, 0.42))); - EXPECT_TRUE(TestObject(1, 0.3) == b.value_or(TestObject(42, 0.42))); -} - -TEST(OptionalTest, Swap_outHasValue) { - Optional<TestObject> a; - Optional<TestObject> b(TestObject(1, 0.3)); - a.swap(b); - - EXPECT_TRUE(!!a); - EXPECT_FALSE(!!b); - EXPECT_TRUE(TestObject(1, 0.3) == a.value_or(TestObject(42, 0.42))); - EXPECT_TRUE(TestObject(42, 0.42) == b.value_or(TestObject(42, 0.42))); -} - -TEST(OptionalTest, Swap_bothValue) { - Optional<TestObject> a(TestObject(0, 0.1)); - Optional<TestObject> b(TestObject(1, 0.3)); - a.swap(b); - - EXPECT_TRUE(!!a); - EXPECT_TRUE(!!b); - EXPECT_TRUE(TestObject(1, 0.3) == a.value_or(TestObject(42, 0.42))); - EXPECT_TRUE(TestObject(0, 0.1) == b.value_or(TestObject(42, 0.42))); - EXPECT_EQ(TestObject::State::SWAPPED, a->state()); - EXPECT_EQ(TestObject::State::SWAPPED, b->state()); -} - -TEST(OptionalTest, Emplace) { - { - Optional<float> a(0.1f); - EXPECT_EQ(0.3f, a.emplace(0.3f)); - - EXPECT_TRUE(a); - EXPECT_EQ(0.3f, a.value()); - } - - { - Optional<std::string> a("foo"); - EXPECT_EQ("bar", a.emplace("bar")); - - EXPECT_TRUE(a); - EXPECT_EQ("bar", a.value()); - } - - { - Optional<TestObject> a(TestObject(0, 0.1)); - EXPECT_EQ(TestObject(1, 0.2), a.emplace(TestObject(1, 0.2))); - - EXPECT_TRUE(!!a); - EXPECT_TRUE(TestObject(1, 0.2) == a.value()); - } - - { - Optional<std::vector<int>> a; - auto& ref = a.emplace({2, 3}); - static_assert(std::is_same<std::vector<int>&, decltype(ref)>::value, ""); - EXPECT_TRUE(a); - EXPECT_THAT(*a, ElementsAre(2, 3)); - EXPECT_EQ(&ref, &*a); - } - - { - Optional<std::vector<int>> a; - auto& ref = a.emplace({4, 5}, std::allocator<int>()); - static_assert(std::is_same<std::vector<int>&, decltype(ref)>::value, ""); - EXPECT_TRUE(a); - EXPECT_THAT(*a, ElementsAre(4, 5)); - EXPECT_EQ(&ref, &*a); - } -} - -TEST(OptionalTest, Equals_TwoEmpty) { - Optional<int> a; - Optional<int> b; - - EXPECT_TRUE(a == b); -} - -TEST(OptionalTest, Equals_TwoEquals) { - Optional<int> a(1); - Optional<int> b(1); - - EXPECT_TRUE(a == b); -} - -TEST(OptionalTest, Equals_OneEmpty) { - Optional<int> a; - Optional<int> b(1); - - EXPECT_FALSE(a == b); -} - -TEST(OptionalTest, Equals_TwoDifferent) { - Optional<int> a(0); - Optional<int> b(1); - - EXPECT_FALSE(a == b); -} - -TEST(OptionalTest, Equals_DifferentType) { - Optional<int> a(0); - Optional<double> b(0); - - EXPECT_TRUE(a == b); -} - -TEST(OptionalTest, NotEquals_TwoEmpty) { - Optional<int> a; - Optional<int> b; - - EXPECT_FALSE(a != b); -} - -TEST(OptionalTest, NotEquals_TwoEquals) { - Optional<int> a(1); - Optional<int> b(1); - - EXPECT_FALSE(a != b); -} - -TEST(OptionalTest, NotEquals_OneEmpty) { - Optional<int> a; - Optional<int> b(1); - - EXPECT_TRUE(a != b); -} - -TEST(OptionalTest, NotEquals_TwoDifferent) { - Optional<int> a(0); - Optional<int> b(1); - - EXPECT_TRUE(a != b); -} - -TEST(OptionalTest, NotEquals_DifferentType) { - Optional<int> a(0); - Optional<double> b(0.0); - - EXPECT_FALSE(a != b); -} - -TEST(OptionalTest, Less_LeftEmpty) { - Optional<int> l; - Optional<int> r(1); - - EXPECT_TRUE(l < r); -} - -TEST(OptionalTest, Less_RightEmpty) { - Optional<int> l(1); - Optional<int> r; - - EXPECT_FALSE(l < r); -} - -TEST(OptionalTest, Less_BothEmpty) { - Optional<int> l; - Optional<int> r; - - EXPECT_FALSE(l < r); -} - -TEST(OptionalTest, Less_BothValues) { - { - Optional<int> l(1); - Optional<int> r(2); - - EXPECT_TRUE(l < r); - } - { - Optional<int> l(2); - Optional<int> r(1); - - EXPECT_FALSE(l < r); - } - { - Optional<int> l(1); - Optional<int> r(1); - - EXPECT_FALSE(l < r); - } -} - -TEST(OptionalTest, Less_DifferentType) { - Optional<int> l(1); - Optional<double> r(2.0); - - EXPECT_TRUE(l < r); -} - -TEST(OptionalTest, LessEq_LeftEmpty) { - Optional<int> l; - Optional<int> r(1); - - EXPECT_TRUE(l <= r); -} - -TEST(OptionalTest, LessEq_RightEmpty) { - Optional<int> l(1); - Optional<int> r; - - EXPECT_FALSE(l <= r); -} - -TEST(OptionalTest, LessEq_BothEmpty) { - Optional<int> l; - Optional<int> r; - - EXPECT_TRUE(l <= r); -} - -TEST(OptionalTest, LessEq_BothValues) { - { - Optional<int> l(1); - Optional<int> r(2); - - EXPECT_TRUE(l <= r); - } - { - Optional<int> l(2); - Optional<int> r(1); - - EXPECT_FALSE(l <= r); - } - { - Optional<int> l(1); - Optional<int> r(1); - - EXPECT_TRUE(l <= r); - } -} - -TEST(OptionalTest, LessEq_DifferentType) { - Optional<int> l(1); - Optional<double> r(2.0); - - EXPECT_TRUE(l <= r); -} - -TEST(OptionalTest, Greater_BothEmpty) { - Optional<int> l; - Optional<int> r; - - EXPECT_FALSE(l > r); -} - -TEST(OptionalTest, Greater_LeftEmpty) { - Optional<int> l; - Optional<int> r(1); - - EXPECT_FALSE(l > r); -} - -TEST(OptionalTest, Greater_RightEmpty) { - Optional<int> l(1); - Optional<int> r; - - EXPECT_TRUE(l > r); -} - -TEST(OptionalTest, Greater_BothValue) { - { - Optional<int> l(1); - Optional<int> r(2); - - EXPECT_FALSE(l > r); - } - { - Optional<int> l(2); - Optional<int> r(1); - - EXPECT_TRUE(l > r); - } - { - Optional<int> l(1); - Optional<int> r(1); - - EXPECT_FALSE(l > r); - } -} - -TEST(OptionalTest, Greater_DifferentType) { - Optional<int> l(1); - Optional<double> r(2.0); - - EXPECT_FALSE(l > r); -} - -TEST(OptionalTest, GreaterEq_BothEmpty) { - Optional<int> l; - Optional<int> r; - - EXPECT_TRUE(l >= r); -} - -TEST(OptionalTest, GreaterEq_LeftEmpty) { - Optional<int> l; - Optional<int> r(1); - - EXPECT_FALSE(l >= r); -} - -TEST(OptionalTest, GreaterEq_RightEmpty) { - Optional<int> l(1); - Optional<int> r; - - EXPECT_TRUE(l >= r); -} - -TEST(OptionalTest, GreaterEq_BothValue) { - { - Optional<int> l(1); - Optional<int> r(2); - - EXPECT_FALSE(l >= r); - } - { - Optional<int> l(2); - Optional<int> r(1); - - EXPECT_TRUE(l >= r); - } - { - Optional<int> l(1); - Optional<int> r(1); - - EXPECT_TRUE(l >= r); - } -} - -TEST(OptionalTest, GreaterEq_DifferentType) { - Optional<int> l(1); - Optional<double> r(2.0); - - EXPECT_FALSE(l >= r); -} - -TEST(OptionalTest, OptNullEq) { - { - Optional<int> opt; - EXPECT_TRUE(opt == base::nullopt); - } - { - Optional<int> opt(1); - EXPECT_FALSE(opt == base::nullopt); - } -} - -TEST(OptionalTest, NullOptEq) { - { - Optional<int> opt; - EXPECT_TRUE(base::nullopt == opt); - } - { - Optional<int> opt(1); - EXPECT_FALSE(base::nullopt == opt); - } -} - -TEST(OptionalTest, OptNullNotEq) { - { - Optional<int> opt; - EXPECT_FALSE(opt != base::nullopt); - } - { - Optional<int> opt(1); - EXPECT_TRUE(opt != base::nullopt); - } -} - -TEST(OptionalTest, NullOptNotEq) { - { - Optional<int> opt; - EXPECT_FALSE(base::nullopt != opt); - } - { - Optional<int> opt(1); - EXPECT_TRUE(base::nullopt != opt); - } -} - -TEST(OptionalTest, OptNullLower) { - { - Optional<int> opt; - EXPECT_FALSE(opt < base::nullopt); - } - { - Optional<int> opt(1); - EXPECT_FALSE(opt < base::nullopt); - } -} - -TEST(OptionalTest, NullOptLower) { - { - Optional<int> opt; - EXPECT_FALSE(base::nullopt < opt); - } - { - Optional<int> opt(1); - EXPECT_TRUE(base::nullopt < opt); - } -} - -TEST(OptionalTest, OptNullLowerEq) { - { - Optional<int> opt; - EXPECT_TRUE(opt <= base::nullopt); - } - { - Optional<int> opt(1); - EXPECT_FALSE(opt <= base::nullopt); - } -} - -TEST(OptionalTest, NullOptLowerEq) { - { - Optional<int> opt; - EXPECT_TRUE(base::nullopt <= opt); - } - { - Optional<int> opt(1); - EXPECT_TRUE(base::nullopt <= opt); - } -} - -TEST(OptionalTest, OptNullGreater) { - { - Optional<int> opt; - EXPECT_FALSE(opt > base::nullopt); - } - { - Optional<int> opt(1); - EXPECT_TRUE(opt > base::nullopt); - } -} - -TEST(OptionalTest, NullOptGreater) { - { - Optional<int> opt; - EXPECT_FALSE(base::nullopt > opt); - } - { - Optional<int> opt(1); - EXPECT_FALSE(base::nullopt > opt); - } -} - -TEST(OptionalTest, OptNullGreaterEq) { - { - Optional<int> opt; - EXPECT_TRUE(opt >= base::nullopt); - } - { - Optional<int> opt(1); - EXPECT_TRUE(opt >= base::nullopt); - } -} - -TEST(OptionalTest, NullOptGreaterEq) { - { - Optional<int> opt; - EXPECT_TRUE(base::nullopt >= opt); - } - { - Optional<int> opt(1); - EXPECT_FALSE(base::nullopt >= opt); - } -} - -TEST(OptionalTest, ValueEq_Empty) { - Optional<int> opt; - EXPECT_FALSE(opt == 1); -} - -TEST(OptionalTest, ValueEq_NotEmpty) { - { - Optional<int> opt(0); - EXPECT_FALSE(opt == 1); - } - { - Optional<int> opt(1); - EXPECT_TRUE(opt == 1); - } -} - -TEST(OptionalTest, ValueEq_DifferentType) { - Optional<int> opt(0); - EXPECT_TRUE(opt == 0.0); -} - -TEST(OptionalTest, EqValue_Empty) { - Optional<int> opt; - EXPECT_FALSE(1 == opt); -} - -TEST(OptionalTest, EqValue_NotEmpty) { - { - Optional<int> opt(0); - EXPECT_FALSE(1 == opt); - } - { - Optional<int> opt(1); - EXPECT_TRUE(1 == opt); - } -} - -TEST(OptionalTest, EqValue_DifferentType) { - Optional<int> opt(0); - EXPECT_TRUE(0.0 == opt); -} - -TEST(OptionalTest, ValueNotEq_Empty) { - Optional<int> opt; - EXPECT_TRUE(opt != 1); -} - -TEST(OptionalTest, ValueNotEq_NotEmpty) { - { - Optional<int> opt(0); - EXPECT_TRUE(opt != 1); - } - { - Optional<int> opt(1); - EXPECT_FALSE(opt != 1); - } -} - -TEST(OPtionalTest, ValueNotEq_DifferentType) { - Optional<int> opt(0); - EXPECT_FALSE(opt != 0.0); -} - -TEST(OptionalTest, NotEqValue_Empty) { - Optional<int> opt; - EXPECT_TRUE(1 != opt); -} - -TEST(OptionalTest, NotEqValue_NotEmpty) { - { - Optional<int> opt(0); - EXPECT_TRUE(1 != opt); - } - { - Optional<int> opt(1); - EXPECT_FALSE(1 != opt); - } -} - -TEST(OptionalTest, NotEqValue_DifferentType) { - Optional<int> opt(0); - EXPECT_FALSE(0.0 != opt); -} - -TEST(OptionalTest, ValueLess_Empty) { - Optional<int> opt; - EXPECT_TRUE(opt < 1); -} - -TEST(OptionalTest, ValueLess_NotEmpty) { - { - Optional<int> opt(0); - EXPECT_TRUE(opt < 1); - } - { - Optional<int> opt(1); - EXPECT_FALSE(opt < 1); - } - { - Optional<int> opt(2); - EXPECT_FALSE(opt < 1); - } -} - -TEST(OPtionalTest, ValueLess_DifferentType) { - Optional<int> opt(0); - EXPECT_TRUE(opt < 1.0); -} - -TEST(OptionalTest, LessValue_Empty) { - Optional<int> opt; - EXPECT_FALSE(1 < opt); -} - -TEST(OptionalTest, LessValue_NotEmpty) { - { - Optional<int> opt(0); - EXPECT_FALSE(1 < opt); - } - { - Optional<int> opt(1); - EXPECT_FALSE(1 < opt); - } - { - Optional<int> opt(2); - EXPECT_TRUE(1 < opt); - } -} - -TEST(OptionalTest, LessValue_DifferentType) { - Optional<int> opt(0); - EXPECT_FALSE(0.0 < opt); -} - -TEST(OptionalTest, ValueLessEq_Empty) { - Optional<int> opt; - EXPECT_TRUE(opt <= 1); -} - -TEST(OptionalTest, ValueLessEq_NotEmpty) { - { - Optional<int> opt(0); - EXPECT_TRUE(opt <= 1); - } - { - Optional<int> opt(1); - EXPECT_TRUE(opt <= 1); - } - { - Optional<int> opt(2); - EXPECT_FALSE(opt <= 1); - } -} - -TEST(OptionalTest, ValueLessEq_DifferentType) { - Optional<int> opt(0); - EXPECT_TRUE(opt <= 0.0); -} - -TEST(OptionalTest, LessEqValue_Empty) { - Optional<int> opt; - EXPECT_FALSE(1 <= opt); -} - -TEST(OptionalTest, LessEqValue_NotEmpty) { - { - Optional<int> opt(0); - EXPECT_FALSE(1 <= opt); - } - { - Optional<int> opt(1); - EXPECT_TRUE(1 <= opt); - } - { - Optional<int> opt(2); - EXPECT_TRUE(1 <= opt); - } -} - -TEST(OptionalTest, LessEqValue_DifferentType) { - Optional<int> opt(0); - EXPECT_TRUE(0.0 <= opt); -} - -TEST(OptionalTest, ValueGreater_Empty) { - Optional<int> opt; - EXPECT_FALSE(opt > 1); -} - -TEST(OptionalTest, ValueGreater_NotEmpty) { - { - Optional<int> opt(0); - EXPECT_FALSE(opt > 1); - } - { - Optional<int> opt(1); - EXPECT_FALSE(opt > 1); - } - { - Optional<int> opt(2); - EXPECT_TRUE(opt > 1); - } -} - -TEST(OptionalTest, ValueGreater_DifferentType) { - Optional<int> opt(0); - EXPECT_FALSE(opt > 0.0); -} - -TEST(OptionalTest, GreaterValue_Empty) { - Optional<int> opt; - EXPECT_TRUE(1 > opt); -} - -TEST(OptionalTest, GreaterValue_NotEmpty) { - { - Optional<int> opt(0); - EXPECT_TRUE(1 > opt); - } - { - Optional<int> opt(1); - EXPECT_FALSE(1 > opt); - } - { - Optional<int> opt(2); - EXPECT_FALSE(1 > opt); - } -} - -TEST(OptionalTest, GreaterValue_DifferentType) { - Optional<int> opt(0); - EXPECT_FALSE(0.0 > opt); -} - -TEST(OptionalTest, ValueGreaterEq_Empty) { - Optional<int> opt; - EXPECT_FALSE(opt >= 1); -} - -TEST(OptionalTest, ValueGreaterEq_NotEmpty) { - { - Optional<int> opt(0); - EXPECT_FALSE(opt >= 1); - } - { - Optional<int> opt(1); - EXPECT_TRUE(opt >= 1); - } - { - Optional<int> opt(2); - EXPECT_TRUE(opt >= 1); - } -} - -TEST(OptionalTest, ValueGreaterEq_DifferentType) { - Optional<int> opt(0); - EXPECT_TRUE(opt <= 0.0); -} - -TEST(OptionalTest, GreaterEqValue_Empty) { - Optional<int> opt; - EXPECT_TRUE(1 >= opt); -} - -TEST(OptionalTest, GreaterEqValue_NotEmpty) { - { - Optional<int> opt(0); - EXPECT_TRUE(1 >= opt); - } - { - Optional<int> opt(1); - EXPECT_TRUE(1 >= opt); - } - { - Optional<int> opt(2); - EXPECT_FALSE(1 >= opt); - } -} - -TEST(OptionalTest, GreaterEqValue_DifferentType) { - Optional<int> opt(0); - EXPECT_TRUE(0.0 >= opt); -} - -TEST(OptionalTest, NotEquals) { - { - Optional<float> a(0.1f); - Optional<float> b(0.2f); - EXPECT_NE(a, b); - } - - { - Optional<std::string> a("foo"); - Optional<std::string> b("bar"); - EXPECT_NE(a, b); - } - - { - Optional<int> a(1); - Optional<double> b(2); - EXPECT_NE(a, b); - } - - { - Optional<TestObject> a(TestObject(3, 0.1)); - Optional<TestObject> b(TestObject(4, 1.0)); - EXPECT_TRUE(a != b); - } -} - -TEST(OptionalTest, NotEqualsNull) { - { - Optional<float> a(0.1f); - Optional<float> b(0.1f); - b = base::nullopt; - EXPECT_NE(a, b); - } - - { - Optional<std::string> a("foo"); - Optional<std::string> b("foo"); - b = base::nullopt; - EXPECT_NE(a, b); - } - - { - Optional<TestObject> a(TestObject(3, 0.1)); - Optional<TestObject> b(TestObject(3, 0.1)); - b = base::nullopt; - EXPECT_TRUE(a != b); - } -} - -TEST(OptionalTest, MakeOptional) { - { - Optional<float> o = make_optional(32.f); - EXPECT_TRUE(o); - EXPECT_EQ(32.f, *o); - - float value = 3.f; - o = make_optional(std::move(value)); - EXPECT_TRUE(o); - EXPECT_EQ(3.f, *o); - } - - { - Optional<std::string> o = make_optional(std::string("foo")); - EXPECT_TRUE(o); - EXPECT_EQ("foo", *o); - - std::string value = "bar"; - o = make_optional(std::move(value)); - EXPECT_TRUE(o); - EXPECT_EQ(std::string("bar"), *o); - } - - { - Optional<TestObject> o = make_optional(TestObject(3, 0.1)); - EXPECT_TRUE(!!o); - EXPECT_TRUE(TestObject(3, 0.1) == *o); - - TestObject value = TestObject(0, 0.42); - o = make_optional(std::move(value)); - EXPECT_TRUE(!!o); - EXPECT_TRUE(TestObject(0, 0.42) == *o); - EXPECT_EQ(TestObject::State::MOVED_FROM, value.state()); - EXPECT_EQ(TestObject::State::MOVE_ASSIGNED, o->state()); - - EXPECT_EQ(TestObject::State::MOVE_CONSTRUCTED, - base::make_optional(std::move(value))->state()); - } - - { - struct Test { - Test(int a, double b, bool c) : a(a), b(b), c(c) {} - - int a; - double b; - bool c; - }; - - Optional<Test> o = make_optional<Test>(1, 2.0, true); - EXPECT_TRUE(!!o); - EXPECT_EQ(1, o->a); - EXPECT_EQ(2.0, o->b); - EXPECT_TRUE(o->c); - } - - { - auto str1 = make_optional<std::string>({'1', '2', '3'}); - EXPECT_EQ("123", *str1); - - auto str2 = - make_optional<std::string>({'a', 'b', 'c'}, std::allocator<char>()); - EXPECT_EQ("abc", *str2); - } -} - -TEST(OptionalTest, NonMemberSwap_bothNoValue) { - Optional<TestObject> a, b; - base::swap(a, b); - - EXPECT_FALSE(!!a); - EXPECT_FALSE(!!b); - EXPECT_TRUE(TestObject(42, 0.42) == a.value_or(TestObject(42, 0.42))); - EXPECT_TRUE(TestObject(42, 0.42) == b.value_or(TestObject(42, 0.42))); -} - -TEST(OptionalTest, NonMemberSwap_inHasValue) { - Optional<TestObject> a(TestObject(1, 0.3)); - Optional<TestObject> b; - base::swap(a, b); - - EXPECT_FALSE(!!a); - EXPECT_TRUE(!!b); - EXPECT_TRUE(TestObject(42, 0.42) == a.value_or(TestObject(42, 0.42))); - EXPECT_TRUE(TestObject(1, 0.3) == b.value_or(TestObject(42, 0.42))); -} - -TEST(OptionalTest, NonMemberSwap_outHasValue) { - Optional<TestObject> a; - Optional<TestObject> b(TestObject(1, 0.3)); - base::swap(a, b); - - EXPECT_TRUE(!!a); - EXPECT_FALSE(!!b); - EXPECT_TRUE(TestObject(1, 0.3) == a.value_or(TestObject(42, 0.42))); - EXPECT_TRUE(TestObject(42, 0.42) == b.value_or(TestObject(42, 0.42))); -} - -TEST(OptionalTest, NonMemberSwap_bothValue) { - Optional<TestObject> a(TestObject(0, 0.1)); - Optional<TestObject> b(TestObject(1, 0.3)); - base::swap(a, b); - - EXPECT_TRUE(!!a); - EXPECT_TRUE(!!b); - EXPECT_TRUE(TestObject(1, 0.3) == a.value_or(TestObject(42, 0.42))); - EXPECT_TRUE(TestObject(0, 0.1) == b.value_or(TestObject(42, 0.42))); - EXPECT_EQ(TestObject::State::SWAPPED, a->state()); - EXPECT_EQ(TestObject::State::SWAPPED, b->state()); -} - -TEST(OptionalTest, Hash_OptionalReflectsInternal) { - { - std::hash<int> int_hash; - std::hash<Optional<int>> opt_int_hash; - - EXPECT_EQ(int_hash(1), opt_int_hash(Optional<int>(1))); - } - - { - std::hash<std::string> str_hash; - std::hash<Optional<std::string>> opt_str_hash; - - EXPECT_EQ(str_hash(std::string("foobar")), - opt_str_hash(Optional<std::string>(std::string("foobar")))); - } -} - -TEST(OptionalTest, Hash_NullOptEqualsNullOpt) { - std::hash<Optional<int>> opt_int_hash; - std::hash<Optional<std::string>> opt_str_hash; - - EXPECT_EQ(opt_str_hash(Optional<std::string>()), - opt_int_hash(Optional<int>())); -} - -TEST(OptionalTest, Hash_UseInSet) { - std::set<Optional<int>> setOptInt; - - EXPECT_EQ(setOptInt.end(), setOptInt.find(42)); - - setOptInt.insert(Optional<int>(3)); - EXPECT_EQ(setOptInt.end(), setOptInt.find(42)); - EXPECT_NE(setOptInt.end(), setOptInt.find(3)); -} - -TEST(OptionalTest, HasValue) { - Optional<int> a; - EXPECT_FALSE(a.has_value()); - - a = 42; - EXPECT_TRUE(a.has_value()); - - a = nullopt; - EXPECT_FALSE(a.has_value()); - - a = 0; - EXPECT_TRUE(a.has_value()); - - a = Optional<int>(); - EXPECT_FALSE(a.has_value()); -} - -TEST(OptionalTest, Reset_int) { - Optional<int> a(0); - EXPECT_TRUE(a.has_value()); - EXPECT_EQ(0, a.value()); - - a.reset(); - EXPECT_FALSE(a.has_value()); - EXPECT_EQ(-1, a.value_or(-1)); -} - -TEST(OptionalTest, Reset_Object) { - Optional<TestObject> a(TestObject(0, 0.1)); - EXPECT_TRUE(a.has_value()); - EXPECT_EQ(TestObject(0, 0.1), a.value()); - - a.reset(); - EXPECT_FALSE(a.has_value()); - EXPECT_EQ(TestObject(42, 0.0), a.value_or(TestObject(42, 0.0))); -} - -TEST(OptionalTest, Reset_NoOp) { - Optional<int> a; - EXPECT_FALSE(a.has_value()); - - a.reset(); - EXPECT_FALSE(a.has_value()); -} - -TEST(OptionalTest, AssignFromRValue) { - Optional<TestObject> a; - EXPECT_FALSE(a.has_value()); - - TestObject obj; - a = std::move(obj); - EXPECT_TRUE(a.has_value()); - EXPECT_EQ(1, a->move_ctors_count()); -} - -TEST(OptionalTest, DontCallDefaultCtor) { - Optional<DeletedDefaultConstructor> a; - EXPECT_FALSE(a.has_value()); - - a = base::make_optional<DeletedDefaultConstructor>(42); - EXPECT_TRUE(a.has_value()); - EXPECT_EQ(42, a->foo()); -} - -TEST(OptionalTest, DontCallNewMemberFunction) { - Optional<DeleteNewOperators> a; - EXPECT_FALSE(a.has_value()); - - a = DeleteNewOperators(); - EXPECT_TRUE(a.has_value()); -} - -TEST(OptionalTest, Noexcept) { - // Trivial copy ctor, non-trivial move ctor, nothrow move assign. - struct Test1 { - Test1(const Test1&) = default; - Test1(Test1&&) {} - Test1& operator=(Test1&&) = default; - }; - // Non-trivial copy ctor, trivial move ctor, throw move assign. - struct Test2 { - Test2(const Test2&) {} - Test2(Test2&&) = default; - Test2& operator=(Test2&&) { return *this; } - }; - // Trivial copy ctor, non-trivial nothrow move ctor. - struct Test3 { - Test3(const Test3&) = default; - Test3(Test3&&) noexcept {} - }; - // Non-trivial copy ctor, non-trivial nothrow move ctor. - struct Test4 { - Test4(const Test4&) {} - Test4(Test4&&) noexcept {} - }; - // Non-trivial copy ctor, non-trivial move ctor. - struct Test5 { - Test5(const Test5&) {} - Test5(Test5&&) {} - }; - - static_assert( - noexcept(Optional<int>(std::declval<Optional<int>>())), - "move constructor for noexcept move-constructible T must be noexcept " - "(trivial copy, trivial move)"); - static_assert( - !noexcept(Optional<Test1>(std::declval<Optional<Test1>>())), - "move constructor for non-noexcept move-constructible T must not be " - "noexcept (trivial copy)"); - static_assert( - noexcept(Optional<Test2>(std::declval<Optional<Test2>>())), - "move constructor for noexcept move-constructible T must be noexcept " - "(non-trivial copy, trivial move)"); - static_assert( - noexcept(Optional<Test3>(std::declval<Optional<Test3>>())), - "move constructor for noexcept move-constructible T must be noexcept " - "(trivial copy, non-trivial move)"); - static_assert( - noexcept(Optional<Test4>(std::declval<Optional<Test4>>())), - "move constructor for noexcept move-constructible T must be noexcept " - "(non-trivial copy, non-trivial move)"); - static_assert( - !noexcept(Optional<Test5>(std::declval<Optional<Test5>>())), - "move constructor for non-noexcept move-constructible T must not be " - "noexcept (non-trivial copy)"); - - static_assert( - noexcept(std::declval<Optional<int>>() = std::declval<Optional<int>>()), - "move assign for noexcept move-constructible/move-assignable T " - "must be noexcept"); - static_assert( - !noexcept(std::declval<Optional<Test1>>() = - std::declval<Optional<Test1>>()), - "move assign for non-noexcept move-constructible T must not be noexcept"); - static_assert( - !noexcept(std::declval<Optional<Test2>>() = - std::declval<Optional<Test2>>()), - "move assign for non-noexcept move-assignable T must not be noexcept"); -} - -} // namespace base
diff --git a/base/optional_unittest.nc b/base/optional_unittest.nc deleted file mode 100644 index 62c0196..0000000 --- a/base/optional_unittest.nc +++ /dev/null
@@ -1,65 +0,0 @@ -// 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. - -// This is a "No Compile Test" suite. -// http://dev.chromium.org/developers/testing/no-compile-tests - -#include <type_traits> - -#include "base/optional.h" - -namespace base { - -#if defined(NCTEST_EXPLICIT_CONVERTING_COPY_CONSTRUCTOR) // [r"fatal error: no matching function for call to object of type"] - -// Optional<T>(const Optional<U>& arg) constructor is marked explicit if -// T is not convertible from "const U&". -void WontCompile() { - struct Test { - // Declares as explicit so that Test is still constructible from int, - // but not convertible. - explicit Test(int a) {} - }; - - static_assert(!std::is_convertible<const int&, Test>::value, - "const int& to Test is convertible"); - const Optional<int> arg(in_place, 1); - ([](Optional<Test> param) {})(arg); -} - -#elif defined(NCTEST_EXPLICIT_CONVERTING_MOVE_CONSTRUCTOR) // [r"fatal error: no matching function for call to object of type"] - -// Optional<T>(Optional<U>&& arg) constructor is marked explicit if -// T is not convertible from "U&&". -void WontCompile() { - struct Test { - // Declares as explicit so that Test is still constructible from int, - // but not convertible. - explicit Test(int a) {} - }; - - static_assert(!std::is_convertible<int&&, Test>::value, - "int&& to Test is convertible"); - ([](Optional<Test> param) {})(Optional<int>(in_place, 1)); -} - -#elif defined(NCTEST_EXPLICIT_VALUE_FORWARD_CONSTRUCTOR) // [r"fatal error: no matching function for call to object of type"] - -// Optional<T>(U&&) constructor is marked explicit if T is not convertible -// from U&&. -void WontCompile() { - struct Test { - // Declares as explicit so that Test is still constructible from int, - // but not convertible. - explicit Test(int a) {} - }; - - static_assert(!std::is_convertible<int&&, Test>::value, - "int&& to Test is convertible"); - ([](Optional<Test> param) {})(1); -} - -#endif - -} // namespace base
diff --git a/base/os_compat_android_unittest.cc b/base/os_compat_android_unittest.cc deleted file mode 100644 index 7fbdc6d..0000000 --- a/base/os_compat_android_unittest.cc +++ /dev/null
@@ -1,41 +0,0 @@ -// 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/os_compat_android.h" - -#include "base/files/file_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -typedef testing::Test OsCompatAndroidTest; - -// Keep this Unittest DISABLED_ , because it actually creates a directory in the -// device and it may be source of flakyness. For any changes in the mkdtemp -// function, you should run this unittest in your local machine to check if it -// passes. -TEST_F(OsCompatAndroidTest, DISABLED_TestMkdTemp) { - FilePath tmp_dir; - EXPECT_TRUE(base::GetTempDir(&tmp_dir)); - - // Not six XXXXXX at the suffix of the path. - FilePath sub_dir = tmp_dir.Append("XX"); - std::string sub_dir_string = sub_dir.value(); - // this should be OK since mkdtemp just replaces characters in place - char* buffer = const_cast<char*>(sub_dir_string.c_str()); - EXPECT_EQ(NULL, mkdtemp(buffer)); - - // Directory does not exist - char invalid_path2[] = "doesntoexist/foobarXXXXXX"; - EXPECT_EQ(NULL, mkdtemp(invalid_path2)); - - // Successfully create a tmp dir. - FilePath sub_dir2 = tmp_dir.Append("XXXXXX"); - std::string sub_dir2_string = sub_dir2.value(); - // this should be OK since mkdtemp just replaces characters in place - char* buffer2 = const_cast<char*>(sub_dir2_string.c_str()); - EXPECT_TRUE(mkdtemp(buffer2) != NULL); -} - -} // namespace base
diff --git a/base/path_service_unittest.cc b/base/path_service_unittest.cc deleted file mode 100644 index 378064a..0000000 --- a/base/path_service_unittest.cc +++ /dev/null
@@ -1,278 +0,0 @@ -// 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/path_service.h" - -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/files/scoped_temp_dir.h" -#include "base/strings/string_util.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest-spi.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/platform_test.h" - -#if defined(OS_WIN) -#include "base/win/windows_version.h" -#endif - -namespace base { - -namespace { - -// Returns true if PathService::Get returns true and sets the path parameter -// to non-empty for the given PathService::DirType enumeration value. -bool ReturnsValidPath(int dir_type) { - FilePath path; - bool result = PathService::Get(dir_type, &path); - - // Some paths might not exist on some platforms in which case confirming - // |result| is true and !path.empty() is the best we can do. - bool check_path_exists = true; -#if defined(OS_POSIX) && !defined(OS_FUCHSIA) - // If chromium has never been started on this account, the cache path may not - // exist. - if (dir_type == DIR_CACHE) - check_path_exists = false; -#endif -#if defined(OS_LINUX) - // On the linux try-bots: a path is returned (e.g. /home/chrome-bot/Desktop), - // but it doesn't exist. - if (dir_type == DIR_USER_DESKTOP) - check_path_exists = false; -#endif -#if defined(OS_IOS) - // Bundled unittests on iOS may not have Resources directory in the bundle. - if (dir_type == DIR_ASSETS) - check_path_exists = false; -#endif -#if defined(OS_MACOSX) - if (dir_type != DIR_EXE && dir_type != DIR_MODULE && dir_type != FILE_EXE && - dir_type != FILE_MODULE) { - if (path.ReferencesParent()) - return false; - } -#else - if (path.ReferencesParent()) - return false; -#endif - return result && !path.empty() && (!check_path_exists || PathExists(path)); -} - -#if defined(OS_WIN) -// Function to test any directory keys that are not supported on some versions -// of Windows. Checks that the function fails and that the returned path is -// empty. -bool ReturnsInvalidPath(int dir_type) { - FilePath path; - bool result = PathService::Get(dir_type, &path); - return !result && path.empty(); -} -#endif - -} // namespace - -// On the Mac this winds up using some autoreleased objects, so we need to -// be a PlatformTest. -typedef PlatformTest PathServiceTest; - -// Test that all PathService::Get calls return a value and a true result -// in the development environment. (This test was created because a few -// later changes to Get broke the semantics of the function and yielded the -// correct value while returning false.) -TEST_F(PathServiceTest, Get) { - for (int key = PATH_START + 1; key < PATH_END; ++key) { -#if defined(OS_ANDROID) - if (key == FILE_MODULE || key == DIR_USER_DESKTOP || - key == DIR_HOME) - continue; // Android doesn't implement these. -#elif defined(OS_IOS) - if (key == DIR_USER_DESKTOP) - continue; // iOS doesn't implement DIR_USER_DESKTOP. -#elif defined(OS_FUCHSIA) - if (key == DIR_USER_DESKTOP || key == FILE_MODULE || key == DIR_MODULE) - continue; // Fuchsia doesn't implement DIR_USER_DESKTOP, FILE_MODULE and - // DIR_MODULE. -#endif - EXPECT_PRED1(ReturnsValidPath, key); - } -#if defined(OS_WIN) - for (int key = PATH_WIN_START + 1; key < PATH_WIN_END; ++key) { - bool valid = true; - if (key == DIR_APP_SHORTCUTS) - valid = base::win::GetVersion() >= base::win::VERSION_WIN8; - - if (valid) - EXPECT_TRUE(ReturnsValidPath(key)) << key; - else - EXPECT_TRUE(ReturnsInvalidPath(key)) << key; - } -#elif defined(OS_MACOSX) - for (int key = PATH_MAC_START + 1; key < PATH_MAC_END; ++key) { - EXPECT_PRED1(ReturnsValidPath, key); - } -#elif defined(OS_ANDROID) - for (int key = PATH_ANDROID_START + 1; key < PATH_ANDROID_END; - ++key) { - EXPECT_PRED1(ReturnsValidPath, key); - } -#elif defined(OS_POSIX) && !defined(OS_FUCHSIA) - for (int key = PATH_POSIX_START + 1; key < PATH_POSIX_END; - ++key) { - EXPECT_PRED1(ReturnsValidPath, key); - } -#endif -} - -// Test that all versions of the Override function of PathService do what they -// are supposed to do. -TEST_F(PathServiceTest, Override) { - int my_special_key = 666; - ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - FilePath fake_cache_dir(temp_dir.GetPath().AppendASCII("cache")); - // PathService::Override should always create the path provided if it doesn't - // exist. - EXPECT_TRUE(PathService::Override(my_special_key, fake_cache_dir)); - EXPECT_TRUE(PathExists(fake_cache_dir)); - - FilePath fake_cache_dir2(temp_dir.GetPath().AppendASCII("cache2")); - // PathService::OverrideAndCreateIfNeeded should obey the |create| parameter. - PathService::OverrideAndCreateIfNeeded(my_special_key, - fake_cache_dir2, - false, - false); - EXPECT_FALSE(PathExists(fake_cache_dir2)); - EXPECT_TRUE(PathService::OverrideAndCreateIfNeeded(my_special_key, - fake_cache_dir2, - false, - true)); - EXPECT_TRUE(PathExists(fake_cache_dir2)); - -#if defined(OS_POSIX) - FilePath non_existent( - MakeAbsoluteFilePath(temp_dir.GetPath()).AppendASCII("non_existent")); - EXPECT_TRUE(non_existent.IsAbsolute()); - EXPECT_FALSE(PathExists(non_existent)); -#if !defined(OS_ANDROID) - // This fails because MakeAbsoluteFilePath fails for non-existent files. - // Earlier versions of Bionic libc don't fail for non-existent files, so - // skip this check on Android. - EXPECT_FALSE(PathService::OverrideAndCreateIfNeeded(my_special_key, - non_existent, - false, - false)); -#endif - // This works because indicating that |non_existent| is absolute skips the - // internal MakeAbsoluteFilePath call. - EXPECT_TRUE(PathService::OverrideAndCreateIfNeeded(my_special_key, - non_existent, - true, - false)); - // Check that the path has been overridden and no directory was created. - EXPECT_FALSE(PathExists(non_existent)); - FilePath path; - EXPECT_TRUE(PathService::Get(my_special_key, &path)); - EXPECT_EQ(non_existent, path); -#endif -} - -// Check if multiple overrides can co-exist. -TEST_F(PathServiceTest, OverrideMultiple) { - int my_special_key = 666; - ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - FilePath fake_cache_dir1(temp_dir.GetPath().AppendASCII("1")); - EXPECT_TRUE(PathService::Override(my_special_key, fake_cache_dir1)); - EXPECT_TRUE(PathExists(fake_cache_dir1)); - ASSERT_EQ(1, WriteFile(fake_cache_dir1.AppendASCII("t1"), ".", 1)); - - FilePath fake_cache_dir2(temp_dir.GetPath().AppendASCII("2")); - EXPECT_TRUE(PathService::Override(my_special_key + 1, fake_cache_dir2)); - EXPECT_TRUE(PathExists(fake_cache_dir2)); - ASSERT_EQ(1, WriteFile(fake_cache_dir2.AppendASCII("t2"), ".", 1)); - - FilePath result; - EXPECT_TRUE(PathService::Get(my_special_key, &result)); - // Override might have changed the path representation but our test file - // should be still there. - EXPECT_TRUE(PathExists(result.AppendASCII("t1"))); - EXPECT_TRUE(PathService::Get(my_special_key + 1, &result)); - EXPECT_TRUE(PathExists(result.AppendASCII("t2"))); -} - -TEST_F(PathServiceTest, RemoveOverride) { - // Before we start the test we have to call RemoveOverride at least once to - // clear any overrides that might have been left from other tests. - PathService::RemoveOverride(DIR_TEMP); - - FilePath original_user_data_dir; - EXPECT_TRUE(PathService::Get(DIR_TEMP, &original_user_data_dir)); - EXPECT_FALSE(PathService::RemoveOverride(DIR_TEMP)); - - ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - EXPECT_TRUE(PathService::Override(DIR_TEMP, temp_dir.GetPath())); - FilePath new_user_data_dir; - EXPECT_TRUE(PathService::Get(DIR_TEMP, &new_user_data_dir)); - EXPECT_NE(original_user_data_dir, new_user_data_dir); - - EXPECT_TRUE(PathService::RemoveOverride(DIR_TEMP)); - EXPECT_TRUE(PathService::Get(DIR_TEMP, &new_user_data_dir)); - EXPECT_EQ(original_user_data_dir, new_user_data_dir); -} - -#if defined(OS_WIN) -TEST_F(PathServiceTest, GetProgramFiles) { - FilePath programfiles_dir; -#if defined(_WIN64) - // 64-bit on 64-bit. - EXPECT_TRUE(PathService::Get(DIR_PROGRAM_FILES, - &programfiles_dir)); - EXPECT_EQ(programfiles_dir.value(), - FILE_PATH_LITERAL("C:\\Program Files")); - EXPECT_TRUE(PathService::Get(DIR_PROGRAM_FILESX86, - &programfiles_dir)); - EXPECT_EQ(programfiles_dir.value(), - FILE_PATH_LITERAL("C:\\Program Files (x86)")); - EXPECT_TRUE(PathService::Get(DIR_PROGRAM_FILES6432, - &programfiles_dir)); - EXPECT_EQ(programfiles_dir.value(), - FILE_PATH_LITERAL("C:\\Program Files")); -#else - if (base::win::OSInfo::GetInstance()->wow64_status() == - base::win::OSInfo::WOW64_ENABLED) { - // 32-bit on 64-bit. - EXPECT_TRUE(PathService::Get(DIR_PROGRAM_FILES, - &programfiles_dir)); - EXPECT_EQ(programfiles_dir.value(), - FILE_PATH_LITERAL("C:\\Program Files (x86)")); - EXPECT_TRUE(PathService::Get(DIR_PROGRAM_FILESX86, - &programfiles_dir)); - EXPECT_EQ(programfiles_dir.value(), - FILE_PATH_LITERAL("C:\\Program Files (x86)")); - EXPECT_TRUE(PathService::Get(DIR_PROGRAM_FILES6432, - &programfiles_dir)); - EXPECT_EQ(programfiles_dir.value(), - FILE_PATH_LITERAL("C:\\Program Files")); - } else { - // 32-bit on 32-bit. - EXPECT_TRUE(PathService::Get(DIR_PROGRAM_FILES, - &programfiles_dir)); - EXPECT_EQ(programfiles_dir.value(), - FILE_PATH_LITERAL("C:\\Program Files")); - EXPECT_TRUE(PathService::Get(DIR_PROGRAM_FILESX86, - &programfiles_dir)); - EXPECT_EQ(programfiles_dir.value(), - FILE_PATH_LITERAL("C:\\Program Files")); - EXPECT_TRUE(PathService::Get(DIR_PROGRAM_FILES6432, - &programfiles_dir)); - EXPECT_EQ(programfiles_dir.value(), - FILE_PATH_LITERAL("C:\\Program Files")); - } -#endif -} -#endif - -} // namespace base
diff --git a/base/pickle_unittest.cc b/base/pickle_unittest.cc deleted file mode 100644 index 4563047..0000000 --- a/base/pickle_unittest.cc +++ /dev/null
@@ -1,573 +0,0 @@ -// 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/pickle.h" - -#include <limits.h> -#include <stddef.h> -#include <stdint.h> - -#include <memory> -#include <string> - -#include "base/macros.h" -#include "base/strings/string16.h" -#include "base/strings/utf_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -const bool testbool1 = false; -const bool testbool2 = true; -const int testint = 2'093'847'192; -const long testlong = 1'093'847'192; -const uint16_t testuint16 = 32123; -const uint32_t testuint32 = 1593847192; -const int64_t testint64 = -0x7E8CA925'3104BDFCLL; -const uint64_t testuint64 = 0xCE8CA925'3104BDF7ULL; -const float testfloat = 3.1415926935f; -const double testdouble = 2.71828182845904523; -const std::string teststring("Hello world"); // note non-aligned string length -const std::wstring testwstring(L"Hello, world"); -const string16 teststring16(ASCIIToUTF16("Hello, world")); -const char testrawstring[] = "Hello new world"; // Test raw string writing -// Test raw char16 writing, assumes UTF16 encoding is ANSI for alpha chars. -const char16 testrawstring16[] = {'A', 'l', 'o', 'h', 'a', 0}; -const char testdata[] = "AAA\0BBB\0"; -const int testdatalen = arraysize(testdata) - 1; - -// checks that the results can be read correctly from the Pickle -void VerifyResult(const Pickle& pickle) { - PickleIterator iter(pickle); - - bool outbool; - EXPECT_TRUE(iter.ReadBool(&outbool)); - EXPECT_FALSE(outbool); - EXPECT_TRUE(iter.ReadBool(&outbool)); - EXPECT_TRUE(outbool); - - int outint; - EXPECT_TRUE(iter.ReadInt(&outint)); - EXPECT_EQ(testint, outint); - - long outlong; - EXPECT_TRUE(iter.ReadLong(&outlong)); - EXPECT_EQ(testlong, outlong); - - uint16_t outuint16; - EXPECT_TRUE(iter.ReadUInt16(&outuint16)); - EXPECT_EQ(testuint16, outuint16); - - uint32_t outuint32; - EXPECT_TRUE(iter.ReadUInt32(&outuint32)); - EXPECT_EQ(testuint32, outuint32); - - int64_t outint64; - EXPECT_TRUE(iter.ReadInt64(&outint64)); - EXPECT_EQ(testint64, outint64); - - uint64_t outuint64; - EXPECT_TRUE(iter.ReadUInt64(&outuint64)); - EXPECT_EQ(testuint64, outuint64); - - float outfloat; - EXPECT_TRUE(iter.ReadFloat(&outfloat)); - EXPECT_EQ(testfloat, outfloat); - - double outdouble; - EXPECT_TRUE(iter.ReadDouble(&outdouble)); - EXPECT_EQ(testdouble, outdouble); - - std::string outstring; - EXPECT_TRUE(iter.ReadString(&outstring)); - EXPECT_EQ(teststring, outstring); - - string16 outstring16; - EXPECT_TRUE(iter.ReadString16(&outstring16)); - EXPECT_EQ(teststring16, outstring16); - - StringPiece outstringpiece; - EXPECT_TRUE(iter.ReadStringPiece(&outstringpiece)); - EXPECT_EQ(testrawstring, outstringpiece); - - StringPiece16 outstringpiece16; - EXPECT_TRUE(iter.ReadStringPiece16(&outstringpiece16)); - EXPECT_EQ(testrawstring16, outstringpiece16); - - const char* outdata; - int outdatalen; - EXPECT_TRUE(iter.ReadData(&outdata, &outdatalen)); - EXPECT_EQ(testdatalen, outdatalen); - EXPECT_EQ(memcmp(testdata, outdata, outdatalen), 0); - - // reads past the end should fail - EXPECT_FALSE(iter.ReadInt(&outint)); -} - -} // namespace - -TEST(PickleTest, EncodeDecode) { - Pickle pickle; - - pickle.WriteBool(testbool1); - pickle.WriteBool(testbool2); - pickle.WriteInt(testint); - pickle.WriteLong(testlong); - pickle.WriteUInt16(testuint16); - pickle.WriteUInt32(testuint32); - pickle.WriteInt64(testint64); - pickle.WriteUInt64(testuint64); - pickle.WriteFloat(testfloat); - pickle.WriteDouble(testdouble); - pickle.WriteString(teststring); - pickle.WriteString16(teststring16); - pickle.WriteString(testrawstring); - pickle.WriteString16(testrawstring16); - pickle.WriteData(testdata, testdatalen); - VerifyResult(pickle); - - // test copy constructor - Pickle pickle2(pickle); - VerifyResult(pickle2); - - // test operator= - Pickle pickle3; - pickle3 = pickle; - VerifyResult(pickle3); -} - -// Tests that reading/writing a long works correctly when the source process -// is 64-bit. We rely on having both 32- and 64-bit trybots to validate both -// arms of the conditional in this test. -TEST(PickleTest, LongFrom64Bit) { - Pickle pickle; - // Under the hood long is always written as a 64-bit value, so simulate a - // 64-bit long even on 32-bit architectures by explicitly writing an int64_t. - pickle.WriteInt64(testint64); - - PickleIterator iter(pickle); - long outlong; - if (sizeof(long) < sizeof(int64_t)) { - // ReadLong() should return false when the original written value can't be - // represented as a long. -#if GTEST_HAS_DEATH_TEST - EXPECT_DEATH(ignore_result(iter.ReadLong(&outlong)), ""); -#endif - } else { - EXPECT_TRUE(iter.ReadLong(&outlong)); - EXPECT_EQ(testint64, outlong); - } -} - -// Tests that we can handle really small buffers. -TEST(PickleTest, SmallBuffer) { - std::unique_ptr<char[]> buffer(new char[1]); - - // We should not touch the buffer. - Pickle pickle(buffer.get(), 1); - - PickleIterator iter(pickle); - int data; - EXPECT_FALSE(iter.ReadInt(&data)); -} - -// Tests that we can handle improper headers. -TEST(PickleTest, BigSize) { - int buffer[] = { 0x56035200, 25, 40, 50 }; - - Pickle pickle(reinterpret_cast<char*>(buffer), sizeof(buffer)); - - PickleIterator iter(pickle); - int data; - EXPECT_FALSE(iter.ReadInt(&data)); -} - -TEST(PickleTest, UnalignedSize) { - int buffer[] = { 10, 25, 40, 50 }; - - Pickle pickle(reinterpret_cast<char*>(buffer), sizeof(buffer)); - - PickleIterator iter(pickle); - int data; - EXPECT_FALSE(iter.ReadInt(&data)); -} - -TEST(PickleTest, ZeroLenStr) { - Pickle pickle; - pickle.WriteString(std::string()); - - PickleIterator iter(pickle); - std::string outstr; - EXPECT_TRUE(iter.ReadString(&outstr)); - EXPECT_EQ("", outstr); -} - -TEST(PickleTest, ZeroLenStr16) { - Pickle pickle; - pickle.WriteString16(string16()); - - PickleIterator iter(pickle); - std::string outstr; - EXPECT_TRUE(iter.ReadString(&outstr)); - EXPECT_EQ("", outstr); -} - -TEST(PickleTest, BadLenStr) { - Pickle pickle; - pickle.WriteInt(-2); - - PickleIterator iter(pickle); - std::string outstr; - EXPECT_FALSE(iter.ReadString(&outstr)); -} - -TEST(PickleTest, BadLenStr16) { - Pickle pickle; - pickle.WriteInt(-1); - - PickleIterator iter(pickle); - string16 outstr; - EXPECT_FALSE(iter.ReadString16(&outstr)); -} - -TEST(PickleTest, PeekNext) { - struct CustomHeader : base::Pickle::Header { - int cookies[10]; - }; - - Pickle pickle(sizeof(CustomHeader)); - - pickle.WriteString("Goooooooooooogle"); - - const char* pickle_data = static_cast<const char*>(pickle.data()); - - size_t pickle_size; - - // Data range doesn't contain header - EXPECT_FALSE(Pickle::PeekNext( - sizeof(CustomHeader), - pickle_data, - pickle_data + sizeof(CustomHeader) - 1, - &pickle_size)); - - // Data range contains header - EXPECT_TRUE(Pickle::PeekNext( - sizeof(CustomHeader), - pickle_data, - pickle_data + sizeof(CustomHeader), - &pickle_size)); - EXPECT_EQ(pickle_size, pickle.size()); - - // Data range contains header and some other data - EXPECT_TRUE(Pickle::PeekNext( - sizeof(CustomHeader), - pickle_data, - pickle_data + sizeof(CustomHeader) + 1, - &pickle_size)); - EXPECT_EQ(pickle_size, pickle.size()); - - // Data range contains full pickle - EXPECT_TRUE(Pickle::PeekNext( - sizeof(CustomHeader), - pickle_data, - pickle_data + pickle.size(), - &pickle_size)); - EXPECT_EQ(pickle_size, pickle.size()); -} - -TEST(PickleTest, PeekNextOverflow) { - struct CustomHeader : base::Pickle::Header { - int cookies[10]; - }; - - CustomHeader header; - - // Check if we can wrap around at all - if (sizeof(size_t) > sizeof(header.payload_size)) - return; - - const char* pickle_data = reinterpret_cast<const char*>(&header); - - size_t pickle_size; - - // Wrapping around is detected and reported as maximum size_t value - header.payload_size = static_cast<uint32_t>( - 1 - static_cast<int32_t>(sizeof(CustomHeader))); - EXPECT_TRUE(Pickle::PeekNext( - sizeof(CustomHeader), - pickle_data, - pickle_data + sizeof(CustomHeader), - &pickle_size)); - EXPECT_EQ(pickle_size, std::numeric_limits<size_t>::max()); - - // Ridiculous pickle sizes are fine (callers are supposed to - // verify them) - header.payload_size = - std::numeric_limits<uint32_t>::max() / 2 - sizeof(CustomHeader); - EXPECT_TRUE(Pickle::PeekNext( - sizeof(CustomHeader), - pickle_data, - pickle_data + sizeof(CustomHeader), - &pickle_size)); - EXPECT_EQ(pickle_size, std::numeric_limits<uint32_t>::max() / 2); -} - -TEST(PickleTest, FindNext) { - Pickle pickle; - pickle.WriteInt(1); - pickle.WriteString("Domo"); - - const char* start = reinterpret_cast<const char*>(pickle.data()); - const char* end = start + pickle.size(); - - EXPECT_EQ(end, Pickle::FindNext(pickle.header_size_, start, end)); - EXPECT_EQ(nullptr, Pickle::FindNext(pickle.header_size_, start, end - 1)); - EXPECT_EQ(end, Pickle::FindNext(pickle.header_size_, start, end + 1)); -} - -TEST(PickleTest, FindNextWithIncompleteHeader) { - size_t header_size = sizeof(Pickle::Header); - std::unique_ptr<char[]> buffer(new char[header_size - 1]); - memset(buffer.get(), 0x1, header_size - 1); - - const char* start = buffer.get(); - const char* end = start + header_size - 1; - - EXPECT_EQ(nullptr, Pickle::FindNext(header_size, start, end)); -} - -#if defined(COMPILER_MSVC) -#pragma warning(push) -#pragma warning(disable: 4146) -#endif -TEST(PickleTest, FindNextOverflow) { - size_t header_size = sizeof(Pickle::Header); - size_t header_size2 = 2 * header_size; - size_t payload_received = 100; - std::unique_ptr<char[]> buffer(new char[header_size2 + payload_received]); - const char* start = buffer.get(); - Pickle::Header* header = reinterpret_cast<Pickle::Header*>(buffer.get()); - const char* end = start + header_size2 + payload_received; - // It is impossible to construct an overflow test otherwise. - if (sizeof(size_t) > sizeof(header->payload_size) || - sizeof(uintptr_t) > sizeof(header->payload_size)) - return; - - header->payload_size = -(reinterpret_cast<uintptr_t>(start) + header_size2); - EXPECT_EQ(nullptr, Pickle::FindNext(header_size2, start, end)); - - header->payload_size = -header_size2; - EXPECT_EQ(nullptr, Pickle::FindNext(header_size2, start, end)); - - header->payload_size = 0; - end = start + header_size; - EXPECT_EQ(nullptr, Pickle::FindNext(header_size2, start, end)); -} -#if defined(COMPILER_MSVC) -#pragma warning(pop) -#endif - -TEST(PickleTest, GetReadPointerAndAdvance) { - Pickle pickle; - - PickleIterator iter(pickle); - EXPECT_FALSE(iter.GetReadPointerAndAdvance(1)); - - pickle.WriteInt(1); - pickle.WriteInt(2); - int bytes = sizeof(int) * 2; - - EXPECT_TRUE(PickleIterator(pickle).GetReadPointerAndAdvance(0)); - EXPECT_TRUE(PickleIterator(pickle).GetReadPointerAndAdvance(1)); - EXPECT_FALSE(PickleIterator(pickle).GetReadPointerAndAdvance(-1)); - EXPECT_TRUE(PickleIterator(pickle).GetReadPointerAndAdvance(bytes)); - EXPECT_FALSE(PickleIterator(pickle).GetReadPointerAndAdvance(bytes + 1)); - EXPECT_FALSE(PickleIterator(pickle).GetReadPointerAndAdvance(INT_MAX)); - EXPECT_FALSE(PickleIterator(pickle).GetReadPointerAndAdvance(INT_MIN)); -} - -TEST(PickleTest, Resize) { - size_t unit = Pickle::kPayloadUnit; - std::unique_ptr<char[]> data(new char[unit]); - char* data_ptr = data.get(); - for (size_t i = 0; i < unit; i++) - data_ptr[i] = 'G'; - - // construct a message that will be exactly the size of one payload unit, - // note that any data will have a 4-byte header indicating the size - const size_t payload_size_after_header = unit - sizeof(uint32_t); - Pickle pickle; - pickle.WriteData( - data_ptr, static_cast<int>(payload_size_after_header - sizeof(uint32_t))); - size_t cur_payload = payload_size_after_header; - - // note: we assume 'unit' is a power of 2 - EXPECT_EQ(unit, pickle.capacity_after_header()); - EXPECT_EQ(pickle.payload_size(), payload_size_after_header); - - // fill out a full page (noting data header) - pickle.WriteData(data_ptr, static_cast<int>(unit - sizeof(uint32_t))); - cur_payload += unit; - EXPECT_EQ(unit * 2, pickle.capacity_after_header()); - EXPECT_EQ(cur_payload, pickle.payload_size()); - - // one more byte should double the capacity - pickle.WriteData(data_ptr, 1); - cur_payload += 8; - EXPECT_EQ(unit * 4, pickle.capacity_after_header()); - EXPECT_EQ(cur_payload, pickle.payload_size()); -} - -namespace { - -struct CustomHeader : Pickle::Header { - int blah; -}; - -} // namespace - -TEST(PickleTest, HeaderPadding) { - const uint32_t kMagic = 0x12345678; - - Pickle pickle(sizeof(CustomHeader)); - pickle.WriteInt(kMagic); - - // this should not overwrite the 'int' payload - pickle.headerT<CustomHeader>()->blah = 10; - - PickleIterator iter(pickle); - int result; - ASSERT_TRUE(iter.ReadInt(&result)); - - EXPECT_EQ(static_cast<uint32_t>(result), kMagic); -} - -TEST(PickleTest, EqualsOperator) { - Pickle source; - source.WriteInt(1); - - Pickle copy_refs_source_buffer(static_cast<const char*>(source.data()), - source.size()); - Pickle copy; - copy = copy_refs_source_buffer; - ASSERT_EQ(source.size(), copy.size()); -} - -TEST(PickleTest, EvilLengths) { - Pickle source; - std::string str(100000, 'A'); - source.WriteData(str.c_str(), 100000); - // ReadString16 used to have its read buffer length calculation wrong leading - // to out-of-bounds reading. - PickleIterator iter(source); - string16 str16; - EXPECT_FALSE(iter.ReadString16(&str16)); - - // And check we didn't break ReadString16. - str16 = (wchar_t) 'A'; - Pickle str16_pickle; - str16_pickle.WriteString16(str16); - iter = PickleIterator(str16_pickle); - EXPECT_TRUE(iter.ReadString16(&str16)); - EXPECT_EQ(1U, str16.length()); - - // Check we don't fail in a length check with invalid String16 size. - // (1<<31) * sizeof(char16) == 0, so this is particularly evil. - Pickle bad_len; - bad_len.WriteInt(1 << 31); - iter = PickleIterator(bad_len); - EXPECT_FALSE(iter.ReadString16(&str16)); -} - -// Check we can write zero bytes of data and 'data' can be NULL. -TEST(PickleTest, ZeroLength) { - Pickle pickle; - pickle.WriteData(nullptr, 0); - - PickleIterator iter(pickle); - const char* outdata; - int outdatalen; - EXPECT_TRUE(iter.ReadData(&outdata, &outdatalen)); - EXPECT_EQ(0, outdatalen); - // We can't assert that outdata is NULL. -} - -// Check that ReadBytes works properly with an iterator initialized to NULL. -TEST(PickleTest, ReadBytes) { - Pickle pickle; - int data = 0x7abcd; - pickle.WriteBytes(&data, sizeof(data)); - - PickleIterator iter(pickle); - const char* outdata_char = nullptr; - EXPECT_TRUE(iter.ReadBytes(&outdata_char, sizeof(data))); - - int outdata; - memcpy(&outdata, outdata_char, sizeof(outdata)); - EXPECT_EQ(data, outdata); -} - -// Checks that when a pickle is deep-copied, the result is not larger than -// needed. -TEST(PickleTest, DeepCopyResize) { - Pickle pickle; - while (pickle.capacity_after_header() != pickle.payload_size()) - pickle.WriteBool(true); - - // Make a deep copy. - Pickle pickle2(pickle); - - // Check that there isn't any extraneous capacity. - EXPECT_EQ(pickle.capacity_after_header(), pickle2.capacity_after_header()); -} - -namespace { - -// Publicly exposes the ClaimBytes interface for testing. -class TestingPickle : public Pickle { - public: - TestingPickle() = default; - - void* ClaimBytes(size_t num_bytes) { return Pickle::ClaimBytes(num_bytes); } -}; - -} // namespace - -// Checks that claimed bytes are zero-initialized. -TEST(PickleTest, ClaimBytesInitialization) { - static const int kChunkSize = 64; - TestingPickle pickle; - const char* bytes = static_cast<const char*>(pickle.ClaimBytes(kChunkSize)); - for (size_t i = 0; i < kChunkSize; ++i) { - EXPECT_EQ(0, bytes[i]); - } -} - -// Checks that ClaimBytes properly advances the write offset. -TEST(PickleTest, ClaimBytes) { - std::string data("Hello, world!"); - - TestingPickle pickle; - pickle.WriteUInt32(data.size()); - void* bytes = pickle.ClaimBytes(data.size()); - pickle.WriteInt(42); - memcpy(bytes, data.data(), data.size()); - - PickleIterator iter(pickle); - uint32_t out_data_length; - EXPECT_TRUE(iter.ReadUInt32(&out_data_length)); - EXPECT_EQ(data.size(), out_data_length); - - const char* out_data = nullptr; - EXPECT_TRUE(iter.ReadBytes(&out_data, out_data_length)); - EXPECT_EQ(data, std::string(out_data, out_data_length)); - - int out_value; - EXPECT_TRUE(iter.ReadInt(&out_value)); - EXPECT_EQ(42, out_value); -} - -} // namespace base
diff --git a/base/posix/file_descriptor_shuffle_unittest.cc b/base/posix/file_descriptor_shuffle_unittest.cc deleted file mode 100644 index 3dfbf7e..0000000 --- a/base/posix/file_descriptor_shuffle_unittest.cc +++ /dev/null
@@ -1,281 +0,0 @@ -// 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/posix/file_descriptor_shuffle.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -// 'Duplicated' file descriptors start at this number -const int kDuplicateBase = 1000; - -} // namespace - -namespace base { - -struct Action { - enum Type { - CLOSE, - MOVE, - DUPLICATE, - }; - - Action(Type in_type, int in_fd1, int in_fd2 = -1) - : type(in_type), - fd1(in_fd1), - fd2(in_fd2) { - } - - bool operator==(const Action& other) const { - return other.type == type && - other.fd1 == fd1 && - other.fd2 == fd2; - } - - Type type; - int fd1; - int fd2; -}; - -class InjectionTracer : public InjectionDelegate { - public: - InjectionTracer() - : next_duplicate_(kDuplicateBase) { - } - - bool Duplicate(int* result, int fd) override { - *result = next_duplicate_++; - actions_.push_back(Action(Action::DUPLICATE, *result, fd)); - return true; - } - - bool Move(int src, int dest) override { - actions_.push_back(Action(Action::MOVE, src, dest)); - return true; - } - - void Close(int fd) override { actions_.push_back(Action(Action::CLOSE, fd)); } - - const std::vector<Action>& actions() const { return actions_; } - - private: - int next_duplicate_; - std::vector<Action> actions_; -}; - -TEST(FileDescriptorShuffleTest, Empty) { - InjectiveMultimap map; - InjectionTracer tracer; - - EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer)); - EXPECT_EQ(0u, tracer.actions().size()); -} - -TEST(FileDescriptorShuffleTest, Noop) { - InjectiveMultimap map; - InjectionTracer tracer; - map.push_back(InjectionArc(0, 0, false)); - - EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer)); - EXPECT_EQ(0u, tracer.actions().size()); -} - -TEST(FileDescriptorShuffleTest, NoopAndClose) { - InjectiveMultimap map; - InjectionTracer tracer; - map.push_back(InjectionArc(0, 0, true)); - - EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer)); - EXPECT_EQ(0u, tracer.actions().size()); -} - -TEST(FileDescriptorShuffleTest, Simple1) { - InjectiveMultimap map; - InjectionTracer tracer; - map.push_back(InjectionArc(0, 1, false)); - - EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer)); - ASSERT_EQ(1u, tracer.actions().size()); - EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1)); -} - -TEST(FileDescriptorShuffleTest, Simple2) { - InjectiveMultimap map; - InjectionTracer tracer; - map.push_back(InjectionArc(0, 1, false)); - map.push_back(InjectionArc(2, 3, false)); - - EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer)); - ASSERT_EQ(2u, tracer.actions().size()); - EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1)); - EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 2, 3)); -} - -TEST(FileDescriptorShuffleTest, Simple3) { - InjectiveMultimap map; - InjectionTracer tracer; - map.push_back(InjectionArc(0, 1, true)); - - EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer)); - ASSERT_EQ(2u, tracer.actions().size()); - EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1)); - EXPECT_TRUE(tracer.actions()[1] == Action(Action::CLOSE, 0)); -} - -TEST(FileDescriptorShuffleTest, Simple4) { - InjectiveMultimap map; - InjectionTracer tracer; - map.push_back(InjectionArc(10, 0, true)); - map.push_back(InjectionArc(1, 1, true)); - - EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer)); - ASSERT_EQ(2u, tracer.actions().size()); - EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 10, 0)); - EXPECT_TRUE(tracer.actions()[1] == Action(Action::CLOSE, 10)); -} - -TEST(FileDescriptorShuffleTest, Cycle) { - InjectiveMultimap map; - InjectionTracer tracer; - map.push_back(InjectionArc(0, 1, false)); - map.push_back(InjectionArc(1, 0, false)); - - EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer)); - ASSERT_EQ(4u, tracer.actions().size()); - EXPECT_TRUE(tracer.actions()[0] == - Action(Action::DUPLICATE, kDuplicateBase, 1)); - EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1)); - EXPECT_TRUE(tracer.actions()[2] == Action(Action::MOVE, kDuplicateBase, 0)); - EXPECT_TRUE(tracer.actions()[3] == Action(Action::CLOSE, kDuplicateBase)); -} - -TEST(FileDescriptorShuffleTest, CycleAndClose1) { - InjectiveMultimap map; - InjectionTracer tracer; - map.push_back(InjectionArc(0, 1, true)); - map.push_back(InjectionArc(1, 0, false)); - - EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer)); - ASSERT_EQ(4u, tracer.actions().size()); - EXPECT_TRUE(tracer.actions()[0] == - Action(Action::DUPLICATE, kDuplicateBase, 1)); - EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1)); - EXPECT_TRUE(tracer.actions()[2] == Action(Action::MOVE, kDuplicateBase, 0)); - EXPECT_TRUE(tracer.actions()[3] == Action(Action::CLOSE, kDuplicateBase)); -} - -TEST(FileDescriptorShuffleTest, CycleAndClose2) { - InjectiveMultimap map; - InjectionTracer tracer; - map.push_back(InjectionArc(0, 1, false)); - map.push_back(InjectionArc(1, 0, true)); - - EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer)); - ASSERT_EQ(4u, tracer.actions().size()); - EXPECT_TRUE(tracer.actions()[0] == - Action(Action::DUPLICATE, kDuplicateBase, 1)); - EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1)); - EXPECT_TRUE(tracer.actions()[2] == Action(Action::MOVE, kDuplicateBase, 0)); - EXPECT_TRUE(tracer.actions()[3] == Action(Action::CLOSE, kDuplicateBase)); -} - -TEST(FileDescriptorShuffleTest, CycleAndClose3) { - InjectiveMultimap map; - InjectionTracer tracer; - map.push_back(InjectionArc(0, 1, true)); - map.push_back(InjectionArc(1, 0, true)); - - EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer)); - ASSERT_EQ(4u, tracer.actions().size()); - EXPECT_TRUE(tracer.actions()[0] == - Action(Action::DUPLICATE, kDuplicateBase, 1)); - EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1)); - EXPECT_TRUE(tracer.actions()[2] == Action(Action::MOVE, kDuplicateBase, 0)); - EXPECT_TRUE(tracer.actions()[3] == Action(Action::CLOSE, kDuplicateBase)); -} - -TEST(FileDescriptorShuffleTest, Fanout) { - InjectiveMultimap map; - InjectionTracer tracer; - map.push_back(InjectionArc(0, 1, false)); - map.push_back(InjectionArc(0, 2, false)); - - EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer)); - ASSERT_EQ(2u, tracer.actions().size()); - EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1)); - EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2)); -} - -TEST(FileDescriptorShuffleTest, FanoutAndClose1) { - InjectiveMultimap map; - InjectionTracer tracer; - map.push_back(InjectionArc(0, 1, true)); - map.push_back(InjectionArc(0, 2, false)); - - EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer)); - ASSERT_EQ(3u, tracer.actions().size()); - EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1)); - EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2)); - EXPECT_TRUE(tracer.actions()[2] == Action(Action::CLOSE, 0)); -} - -TEST(FileDescriptorShuffleTest, FanoutAndClose2) { - InjectiveMultimap map; - InjectionTracer tracer; - map.push_back(InjectionArc(0, 1, false)); - map.push_back(InjectionArc(0, 2, true)); - - EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer)); - ASSERT_EQ(3u, tracer.actions().size()); - EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1)); - EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2)); - EXPECT_TRUE(tracer.actions()[2] == Action(Action::CLOSE, 0)); -} - -TEST(FileDescriptorShuffleTest, FanoutAndClose3) { - InjectiveMultimap map; - InjectionTracer tracer; - map.push_back(InjectionArc(0, 1, true)); - map.push_back(InjectionArc(0, 2, true)); - - EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer)); - ASSERT_EQ(3u, tracer.actions().size()); - EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1)); - EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2)); - EXPECT_TRUE(tracer.actions()[2] == Action(Action::CLOSE, 0)); -} - -class FailingDelegate : public InjectionDelegate { - public: - bool Duplicate(int* result, int fd) override { return false; } - - bool Move(int src, int dest) override { return false; } - - void Close(int fd) override {} -}; - -TEST(FileDescriptorShuffleTest, EmptyWithFailure) { - InjectiveMultimap map; - FailingDelegate failing; - - EXPECT_TRUE(PerformInjectiveMultimap(map, &failing)); -} - -TEST(FileDescriptorShuffleTest, NoopWithFailure) { - InjectiveMultimap map; - FailingDelegate failing; - map.push_back(InjectionArc(0, 0, false)); - - EXPECT_TRUE(PerformInjectiveMultimap(map, &failing)); -} - -TEST(FileDescriptorShuffleTest, Simple1WithFailure) { - InjectiveMultimap map; - FailingDelegate failing; - map.push_back(InjectionArc(0, 1, false)); - - EXPECT_FALSE(PerformInjectiveMultimap(map, &failing)); -} - -} // namespace base
diff --git a/base/posix/unix_domain_socket_unittest.cc b/base/posix/unix_domain_socket_unittest.cc deleted file mode 100644 index f626de5..0000000 --- a/base/posix/unix_domain_socket_unittest.cc +++ /dev/null
@@ -1,183 +0,0 @@ -// 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 "build_config.h" - -#include <stddef.h> -#include <stdint.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <unistd.h> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/files/file_util.h" -#include "base/files/scoped_file.h" -#include "base/location.h" -#include "base/pickle.h" -#include "base/posix/unix_domain_socket.h" -#include "base/single_thread_task_runner.h" -#include "base/synchronization/waitable_event.h" -#include "base/threading/thread.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -// Callers should use ASSERT_NO_FATAL_FAILURE with this function, to -// ensure that execution is aborted if the function has assertion failure. -void CreateSocketPair(int fds[2]) { -#if defined(OS_MACOSX) - // Mac OS does not support SOCK_SEQPACKET. - int flags = SOCK_STREAM; -#else - int flags = SOCK_SEQPACKET; -#endif - ASSERT_EQ(0, socketpair(AF_UNIX, flags, 0, fds)); -#if defined(OS_MACOSX) - // On OSX an attempt to read or write to a closed socket may generate a - // SIGPIPE rather than returning -1, corrected with SO_NOSIGPIPE option. - int nosigpipe = 1; - ASSERT_EQ(0, setsockopt(fds[0], SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe, - sizeof(nosigpipe))); - ASSERT_EQ(0, setsockopt(fds[1], SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe, - sizeof(nosigpipe))); -#endif -} - -TEST(UnixDomainSocketTest, SendRecvMsgAbortOnReplyFDClose) { - Thread message_thread("UnixDomainSocketTest"); - ASSERT_TRUE(message_thread.Start()); - int fds[2]; - ASSERT_NO_FATAL_FAILURE(CreateSocketPair(fds)); - ScopedFD scoped_fd0(fds[0]); - ScopedFD scoped_fd1(fds[1]); - - // Have the thread send a synchronous message via the socket. - Pickle request; - message_thread.task_runner()->PostTask( - FROM_HERE, BindOnce(IgnoreResult(&UnixDomainSocket::SendRecvMsg), fds[1], - nullptr, 0U, nullptr, request)); - - // Receive the message. - std::vector<ScopedFD> message_fds; - uint8_t buffer[16]; - ASSERT_EQ( - static_cast<int>(request.size()), - UnixDomainSocket::RecvMsg(fds[0], buffer, sizeof(buffer), &message_fds)); - ASSERT_EQ(1U, message_fds.size()); - - // Close the reply FD. - message_fds.clear(); - - // Check that the thread didn't get blocked. - WaitableEvent event(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - message_thread.task_runner()->PostTask( - FROM_HERE, BindOnce(&WaitableEvent::Signal, Unretained(&event))); - ASSERT_TRUE(event.TimedWait(TimeDelta::FromMilliseconds(5000))); -} - -TEST(UnixDomainSocketTest, SendRecvMsgAvoidsSIGPIPE) { - // Make sure SIGPIPE isn't being ignored. - struct sigaction act = {}, oldact; - act.sa_handler = SIG_DFL; - ASSERT_EQ(0, sigaction(SIGPIPE, &act, &oldact)); - int fds[2]; - ASSERT_NO_FATAL_FAILURE(CreateSocketPair(fds)); - ScopedFD scoped_fd1(fds[1]); - ASSERT_EQ(0, IGNORE_EINTR(close(fds[0]))); - - // Have the thread send a synchronous message via the socket. Unless the - // message is sent with MSG_NOSIGNAL, this shall result in SIGPIPE. - Pickle request; - ASSERT_EQ( - -1, UnixDomainSocket::SendRecvMsg(fds[1], nullptr, 0U, nullptr, request)); - ASSERT_EQ(EPIPE, errno); - // Restore the SIGPIPE handler. - ASSERT_EQ(0, sigaction(SIGPIPE, &oldact, nullptr)); -} - -// Simple sanity check within a single process that receiving PIDs works. -TEST(UnixDomainSocketTest, RecvPid) { - int fds[2]; - ASSERT_NO_FATAL_FAILURE(CreateSocketPair(fds)); - ScopedFD recv_sock(fds[0]); - ScopedFD send_sock(fds[1]); - - ASSERT_TRUE(UnixDomainSocket::EnableReceiveProcessId(recv_sock.get())); - - static const char kHello[] = "hello"; - ASSERT_TRUE(UnixDomainSocket::SendMsg(send_sock.get(), kHello, sizeof(kHello), - std::vector<int>())); - - // Extra receiving buffer space to make sure we really received only - // sizeof(kHello) bytes and it wasn't just truncated to fit the buffer. - char buf[sizeof(kHello) + 1]; - ProcessId sender_pid; - std::vector<ScopedFD> fd_vec; - const ssize_t nread = UnixDomainSocket::RecvMsgWithPid( - recv_sock.get(), buf, sizeof(buf), &fd_vec, &sender_pid); - ASSERT_EQ(sizeof(kHello), static_cast<size_t>(nread)); - ASSERT_EQ(0, memcmp(buf, kHello, sizeof(kHello))); - ASSERT_EQ(0U, fd_vec.size()); - - ASSERT_EQ(getpid(), sender_pid); -} - -// Same as above, but send the max number of file descriptors too. -TEST(UnixDomainSocketTest, RecvPidWithMaxDescriptors) { - int fds[2]; - ASSERT_NO_FATAL_FAILURE(CreateSocketPair(fds)); - ScopedFD recv_sock(fds[0]); - ScopedFD send_sock(fds[1]); - - ASSERT_TRUE(UnixDomainSocket::EnableReceiveProcessId(recv_sock.get())); - - static const char kHello[] = "hello"; - std::vector<int> send_fds(UnixDomainSocket::kMaxFileDescriptors, - send_sock.get()); - ASSERT_TRUE(UnixDomainSocket::SendMsg(send_sock.get(), kHello, sizeof(kHello), - send_fds)); - - // Extra receiving buffer space to make sure we really received only - // sizeof(kHello) bytes and it wasn't just truncated to fit the buffer. - char buf[sizeof(kHello) + 1]; - ProcessId sender_pid; - std::vector<ScopedFD> recv_fds; - const ssize_t nread = UnixDomainSocket::RecvMsgWithPid( - recv_sock.get(), buf, sizeof(buf), &recv_fds, &sender_pid); - ASSERT_EQ(sizeof(kHello), static_cast<size_t>(nread)); - ASSERT_EQ(0, memcmp(buf, kHello, sizeof(kHello))); - ASSERT_EQ(UnixDomainSocket::kMaxFileDescriptors, recv_fds.size()); - - ASSERT_EQ(getpid(), sender_pid); -} - -// Check that RecvMsgWithPid doesn't DCHECK fail when reading EOF from a -// disconnected socket. -TEST(UnixDomianSocketTest, RecvPidDisconnectedSocket) { - int fds[2]; - ASSERT_NO_FATAL_FAILURE(CreateSocketPair(fds)); - ScopedFD recv_sock(fds[0]); - ScopedFD send_sock(fds[1]); - - ASSERT_TRUE(UnixDomainSocket::EnableReceiveProcessId(recv_sock.get())); - - send_sock.reset(); - - char ch; - ProcessId sender_pid; - std::vector<ScopedFD> recv_fds; - const ssize_t nread = UnixDomainSocket::RecvMsgWithPid( - recv_sock.get(), &ch, sizeof(ch), &recv_fds, &sender_pid); - ASSERT_EQ(0, nread); - ASSERT_EQ(-1, sender_pid); - ASSERT_EQ(0U, recv_fds.size()); -} - -} // namespace - -} // namespace base
diff --git a/base/power_monitor/power_monitor_unittest.cc b/base/power_monitor/power_monitor_unittest.cc deleted file mode 100644 index 7f2a84b..0000000 --- a/base/power_monitor/power_monitor_unittest.cc +++ /dev/null
@@ -1,83 +0,0 @@ -// 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/macros.h" -#include "base/message_loop/message_loop.h" -#include "base/power_monitor/power_monitor.h" -#include "base/test/power_monitor_test_base.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -class PowerMonitorTest : public testing::Test { - protected: - PowerMonitorTest() { - power_monitor_source_ = new PowerMonitorTestSource(); - power_monitor_.reset(new PowerMonitor( - std::unique_ptr<PowerMonitorSource>(power_monitor_source_))); - } - ~PowerMonitorTest() override = default; - - PowerMonitorTestSource* source() { return power_monitor_source_; } - PowerMonitor* monitor() { return power_monitor_.get(); } - - private: - base::MessageLoop message_loop_; - PowerMonitorTestSource* power_monitor_source_; - std::unique_ptr<PowerMonitor> power_monitor_; - - DISALLOW_COPY_AND_ASSIGN(PowerMonitorTest); -}; - -// PowerMonitorSource is tightly coupled with the PowerMonitor, so this test -// Will cover both classes -TEST_F(PowerMonitorTest, PowerNotifications) { - const int kObservers = 5; - - PowerMonitorTestObserver observers[kObservers]; - for (int index = 0; index < kObservers; ++index) - monitor()->AddObserver(&observers[index]); - - // Sending resume when not suspended should have no effect. - source()->GenerateResumeEvent(); - EXPECT_EQ(observers[0].resumes(), 0); - - // Pretend we suspended. - source()->GenerateSuspendEvent(); - // Ensure all observers were notified of the event - for (int index = 0; index < kObservers; ++index) - EXPECT_EQ(observers[index].suspends(), 1); - - // Send a second suspend notification. This should be suppressed. - source()->GenerateSuspendEvent(); - EXPECT_EQ(observers[0].suspends(), 1); - - // Pretend we were awakened. - source()->GenerateResumeEvent(); - EXPECT_EQ(observers[0].resumes(), 1); - - // Send a duplicate resume notification. This should be suppressed. - source()->GenerateResumeEvent(); - EXPECT_EQ(observers[0].resumes(), 1); - - // Pretend the device has gone on battery power - source()->GeneratePowerStateEvent(true); - EXPECT_EQ(observers[0].power_state_changes(), 1); - EXPECT_EQ(observers[0].last_power_state(), true); - - // Repeated indications the device is on battery power should be suppressed. - source()->GeneratePowerStateEvent(true); - EXPECT_EQ(observers[0].power_state_changes(), 1); - - // Pretend the device has gone off battery power - source()->GeneratePowerStateEvent(false); - EXPECT_EQ(observers[0].power_state_changes(), 2); - EXPECT_EQ(observers[0].last_power_state(), false); - - // Repeated indications the device is off battery power should be suppressed. - source()->GeneratePowerStateEvent(false); - EXPECT_EQ(observers[0].power_state_changes(), 2); -} - -} // namespace base
diff --git a/base/process/memory_unittest.cc b/base/process/memory_unittest.cc deleted file mode 100644 index 3a565ee..0000000 --- a/base/process/memory_unittest.cc +++ /dev/null
@@ -1,91 +0,0 @@ -// 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. - -#define _CRT_SECURE_NO_WARNINGS - -#include "base/process/memory.h" - -#include <stddef.h> - -#include <limits> - -#include "base/allocator/allocator_check.h" -#include "base/compiler_specific.h" -#include "base/debug/alias.h" -#include "base/memory/aligned_memory.h" -#include "base/strings/stringprintf.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(OS_WIN) -#include <windows.h> -#endif -#if defined(OS_POSIX) -#include <errno.h> -#endif -#if defined(OS_MACOSX) -#include <malloc/malloc.h> -#include "base/allocator/allocator_interception_mac.h" -#include "base/allocator/allocator_shim.h" -#include "base/process/memory_unittest_mac.h" -#endif -#if defined(OS_LINUX) -#include <malloc.h> -#include "base/test/malloc_wrapper.h" -#endif - -#if defined(OS_WIN) - -#if defined(COMPILER_MSVC) -// ssize_t needed for OutOfMemoryTest. -#if defined(_WIN64) -typedef __int64 ssize_t; -#else -typedef long ssize_t; -#endif -#endif - -// HeapQueryInformation function pointer. -typedef BOOL (WINAPI* HeapQueryFn) \ - (HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T); - -#endif // defined(OS_WIN) - -#if defined(OS_MACOSX) - -// For the following Mac tests: -// Note that base::EnableTerminationOnHeapCorruption() is called as part of -// test suite setup and does not need to be done again, else mach_override -// will fail. - -TEST(ProcessMemoryTest, MacTerminateOnHeapCorruption) { - // Assert that freeing an unallocated pointer will crash the process. - char buf[9]; - asm("" : "=r" (buf)); // Prevent clang from being too smart. -#if ARCH_CPU_64_BITS - // On 64 bit Macs, the malloc system automatically abort()s on heap corruption - // but does not output anything. - ASSERT_DEATH(free(buf), ""); -#elif defined(ADDRESS_SANITIZER) - // AddressSanitizer replaces malloc() and prints a different error message on - // heap corruption. - ASSERT_DEATH(free(buf), "attempting free on address which " - "was not malloc\\(\\)-ed"); -#else - ADD_FAILURE() << "This test is not supported in this build configuration."; -#endif -} - -#endif // defined(OS_MACOSX) - -TEST(MemoryTest, AllocatorShimWorking) { -#if defined(OS_MACOSX) - base::allocator::InterceptAllocationsMac(); -#endif - ASSERT_TRUE(base::allocator::IsAllocatorInitialized()); - -#if defined(OS_MACOSX) - base::allocator::UninterceptMallocZonesForTesting(); -#endif -}
diff --git a/base/process/process_info_unittest.cc b/base/process/process_info_unittest.cc deleted file mode 100644 index 51b15b9..0000000 --- a/base/process/process_info_unittest.cc +++ /dev/null
@@ -1,22 +0,0 @@ -// 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/process/process_info.h" - -#include "base/time/time.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -// See https://crbug.com/726484 for Fuchsia. -// Cannot read boot time on Android O, crbug.com/788870. -#if !defined(OS_IOS) && !defined(OS_FUCHSIA) && !defined(OS_ANDROID) -TEST(ProcessInfoTest, CreationTime) { - Time creation_time = CurrentProcessInfo::CreationTime(); - ASSERT_FALSE(creation_time.is_null()); -} -#endif // !defined(OS_IOS) && !defined(OS_FUCHSIA) && !defined(OS_ANDROID) - -} // namespace base
diff --git a/base/process/process_metrics_unittest.cc b/base/process/process_metrics_unittest.cc deleted file mode 100644 index aec7be1..0000000 --- a/base/process/process_metrics_unittest.cc +++ /dev/null
@@ -1,633 +0,0 @@ -// 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/process/process_metrics.h" - -#include <stddef.h> -#include <stdint.h> - -#include <sstream> -#include <string> -#include <vector> - -#include "base/bind.h" -#include "base/command_line.h" -#include "base/files/file.h" -#include "base/files/file_util.h" -#include "base/files/scoped_temp_dir.h" -#include "base/macros.h" -#include "base/memory/shared_memory.h" -#include "base/strings/string_number_conversions.h" -#include "base/sys_info.h" -#include "base/test/multiprocess_test.h" -#include "base/threading/thread.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/multiprocess_func_list.h" - -#if defined(OS_MACOSX) -#include <sys/mman.h> -#endif - -namespace base { -namespace debug { - -#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_WIN) -namespace { - -void BusyWork(std::vector<std::string>* vec) { - int64_t test_value = 0; - for (int i = 0; i < 100000; ++i) { - ++test_value; - vec->push_back(Int64ToString(test_value)); - } -} - -} // namespace -#endif // defined(OS_LINUX) || defined(OS_CHROMEOS) - -// Tests for SystemMetrics. -// Exists as a class so it can be a friend of SystemMetrics. -class SystemMetricsTest : public testing::Test { - public: - SystemMetricsTest() = default; - - private: - DISALLOW_COPY_AND_ASSIGN(SystemMetricsTest); -}; - -#if defined(OS_LINUX) || defined(OS_ANDROID) -TEST_F(SystemMetricsTest, IsValidDiskName) { - const char invalid_input1[] = ""; - const char invalid_input2[] = "s"; - const char invalid_input3[] = "sdz+"; - const char invalid_input4[] = "hda0"; - const char invalid_input5[] = "mmcbl"; - const char invalid_input6[] = "mmcblka"; - const char invalid_input7[] = "mmcblkb"; - const char invalid_input8[] = "mmmblk0"; - - EXPECT_FALSE(IsValidDiskName(invalid_input1)); - EXPECT_FALSE(IsValidDiskName(invalid_input2)); - EXPECT_FALSE(IsValidDiskName(invalid_input3)); - EXPECT_FALSE(IsValidDiskName(invalid_input4)); - EXPECT_FALSE(IsValidDiskName(invalid_input5)); - EXPECT_FALSE(IsValidDiskName(invalid_input6)); - EXPECT_FALSE(IsValidDiskName(invalid_input7)); - EXPECT_FALSE(IsValidDiskName(invalid_input8)); - - const char valid_input1[] = "sda"; - const char valid_input2[] = "sdaaaa"; - const char valid_input3[] = "hdz"; - const char valid_input4[] = "mmcblk0"; - const char valid_input5[] = "mmcblk999"; - - EXPECT_TRUE(IsValidDiskName(valid_input1)); - EXPECT_TRUE(IsValidDiskName(valid_input2)); - EXPECT_TRUE(IsValidDiskName(valid_input3)); - EXPECT_TRUE(IsValidDiskName(valid_input4)); - EXPECT_TRUE(IsValidDiskName(valid_input5)); -} - -TEST_F(SystemMetricsTest, ParseMeminfo) { - SystemMemoryInfoKB meminfo; - const char invalid_input1[] = "abc"; - const char invalid_input2[] = "MemTotal:"; - // Partial file with no MemTotal - const char invalid_input3[] = - "MemFree: 3913968 kB\n" - "Buffers: 2348340 kB\n" - "Cached: 49071596 kB\n" - "SwapCached: 12 kB\n" - "Active: 36393900 kB\n" - "Inactive: 21221496 kB\n" - "Active(anon): 5674352 kB\n" - "Inactive(anon): 633992 kB\n"; - EXPECT_FALSE(ParseProcMeminfo(invalid_input1, &meminfo)); - EXPECT_FALSE(ParseProcMeminfo(invalid_input2, &meminfo)); - EXPECT_FALSE(ParseProcMeminfo(invalid_input3, &meminfo)); - - const char valid_input1[] = - "MemTotal: 3981504 kB\n" - "MemFree: 140764 kB\n" - "MemAvailable: 535413 kB\n" - "Buffers: 116480 kB\n" - "Cached: 406160 kB\n" - "SwapCached: 21304 kB\n" - "Active: 3152040 kB\n" - "Inactive: 472856 kB\n" - "Active(anon): 2972352 kB\n" - "Inactive(anon): 270108 kB\n" - "Active(file): 179688 kB\n" - "Inactive(file): 202748 kB\n" - "Unevictable: 0 kB\n" - "Mlocked: 0 kB\n" - "SwapTotal: 5832280 kB\n" - "SwapFree: 3672368 kB\n" - "Dirty: 184 kB\n" - "Writeback: 0 kB\n" - "AnonPages: 3101224 kB\n" - "Mapped: 142296 kB\n" - "Shmem: 140204 kB\n" - "Slab: 54212 kB\n" - "SReclaimable: 30936 kB\n" - "SUnreclaim: 23276 kB\n" - "KernelStack: 2464 kB\n" - "PageTables: 24812 kB\n" - "NFS_Unstable: 0 kB\n" - "Bounce: 0 kB\n" - "WritebackTmp: 0 kB\n" - "CommitLimit: 7823032 kB\n" - "Committed_AS: 7973536 kB\n" - "VmallocTotal: 34359738367 kB\n" - "VmallocUsed: 375940 kB\n" - "VmallocChunk: 34359361127 kB\n" - "DirectMap4k: 72448 kB\n" - "DirectMap2M: 4061184 kB\n"; - // output from a much older kernel where the Active and Inactive aren't - // broken down into anon and file and Huge Pages are enabled - const char valid_input2[] = - "MemTotal: 255908 kB\n" - "MemFree: 69936 kB\n" - "Buffers: 15812 kB\n" - "Cached: 115124 kB\n" - "SwapCached: 0 kB\n" - "Active: 92700 kB\n" - "Inactive: 63792 kB\n" - "HighTotal: 0 kB\n" - "HighFree: 0 kB\n" - "LowTotal: 255908 kB\n" - "LowFree: 69936 kB\n" - "SwapTotal: 524280 kB\n" - "SwapFree: 524200 kB\n" - "Dirty: 4 kB\n" - "Writeback: 0 kB\n" - "Mapped: 42236 kB\n" - "Slab: 25912 kB\n" - "Committed_AS: 118680 kB\n" - "PageTables: 1236 kB\n" - "VmallocTotal: 3874808 kB\n" - "VmallocUsed: 1416 kB\n" - "VmallocChunk: 3872908 kB\n" - "HugePages_Total: 0\n" - "HugePages_Free: 0\n" - "Hugepagesize: 4096 kB\n"; - - EXPECT_TRUE(ParseProcMeminfo(valid_input1, &meminfo)); - EXPECT_EQ(meminfo.total, 3981504); - EXPECT_EQ(meminfo.free, 140764); - EXPECT_EQ(meminfo.available, 535413); - EXPECT_EQ(meminfo.buffers, 116480); - EXPECT_EQ(meminfo.cached, 406160); - EXPECT_EQ(meminfo.active_anon, 2972352); - EXPECT_EQ(meminfo.active_file, 179688); - EXPECT_EQ(meminfo.inactive_anon, 270108); - EXPECT_EQ(meminfo.inactive_file, 202748); - EXPECT_EQ(meminfo.swap_total, 5832280); - EXPECT_EQ(meminfo.swap_free, 3672368); - EXPECT_EQ(meminfo.dirty, 184); - EXPECT_EQ(meminfo.reclaimable, 30936); -#if defined(OS_CHROMEOS) - EXPECT_EQ(meminfo.shmem, 140204); - EXPECT_EQ(meminfo.slab, 54212); -#endif - EXPECT_EQ(355725, - base::SysInfo::AmountOfAvailablePhysicalMemory(meminfo) / 1024); - // Simulate as if there is no MemAvailable. - meminfo.available = 0; - EXPECT_EQ(374448, - base::SysInfo::AmountOfAvailablePhysicalMemory(meminfo) / 1024); - meminfo = {}; - EXPECT_TRUE(ParseProcMeminfo(valid_input2, &meminfo)); - EXPECT_EQ(meminfo.total, 255908); - EXPECT_EQ(meminfo.free, 69936); - EXPECT_EQ(meminfo.available, 0); - EXPECT_EQ(meminfo.buffers, 15812); - EXPECT_EQ(meminfo.cached, 115124); - EXPECT_EQ(meminfo.swap_total, 524280); - EXPECT_EQ(meminfo.swap_free, 524200); - EXPECT_EQ(meminfo.dirty, 4); - EXPECT_EQ(69936, - base::SysInfo::AmountOfAvailablePhysicalMemory(meminfo) / 1024); -} - -TEST_F(SystemMetricsTest, ParseVmstat) { - VmStatInfo vmstat; - // part of vmstat from a 3.2 kernel with numa enabled - const char valid_input1[] = - "nr_free_pages 905104\n" - "nr_inactive_anon 142478" - "nr_active_anon 1520046\n" - "nr_inactive_file 4481001\n" - "nr_active_file 8313439\n" - "nr_unevictable 5044\n" - "nr_mlock 5044\n" - "nr_anon_pages 1633780\n" - "nr_mapped 104742\n" - "nr_file_pages 12828218\n" - "nr_dirty 245\n" - "nr_writeback 0\n" - "nr_slab_reclaimable 831609\n" - "nr_slab_unreclaimable 41164\n" - "nr_page_table_pages 31470\n" - "nr_kernel_stack 1735\n" - "nr_unstable 0\n" - "nr_bounce 0\n" - "nr_vmscan_write 406\n" - "nr_vmscan_immediate_reclaim 281\n" - "nr_writeback_temp 0\n" - "nr_isolated_anon 0\n" - "nr_isolated_file 0\n" - "nr_shmem 28820\n" - "nr_dirtied 84674644\n" - "nr_written 75307109\n" - "nr_anon_transparent_hugepages 0\n" - "nr_dirty_threshold 1536206\n" - "nr_dirty_background_threshold 768103\n" - "pgpgin 30777108\n" - "pgpgout 319023278\n" - "pswpin 179\n" - "pswpout 406\n" - "pgalloc_dma 0\n" - "pgalloc_dma32 20833399\n" - "pgalloc_normal 1622609290\n" - "pgalloc_movable 0\n" - "pgfree 1644355583\n" - "pgactivate 75391882\n" - "pgdeactivate 4121019\n" - "pgfault 2542879679\n" - "pgmajfault 487192\n"; - const char valid_input2[] = - "nr_free_pages 180125\n" - "nr_inactive_anon 51\n" - "nr_active_anon 38832\n" - "nr_inactive_file 50171\n" - "nr_active_file 47510\n" - "nr_unevictable 0\n" - "nr_mlock 0\n" - "nr_anon_pages 38825\n" - "nr_mapped 24043\n" - "nr_file_pages 97733\n" - "nr_dirty 0\n" - "nr_writeback 0\n" - "nr_slab_reclaimable 4032\n" - "nr_slab_unreclaimable 2848\n" - "nr_page_table_pages 1505\n" - "nr_kernel_stack 626\n" - "nr_unstable 0\n" - "nr_bounce 0\n" - "nr_vmscan_write 0\n" - "nr_vmscan_immediate_reclaim 0\n" - "nr_writeback_temp 0\n" - "nr_isolated_anon 0\n" - "nr_isolated_file 0\n" - "nr_shmem 58\n" - "nr_dirtied 435358\n" - "nr_written 401258\n" - "nr_anon_transparent_hugepages 0\n" - "nr_dirty_threshold 18566\n" - "nr_dirty_background_threshold 4641\n" - "pgpgin 299464\n" - "pgpgout 2437788\n" - "pswpin 12\n" - "pswpout 901\n" - "pgalloc_normal 144213030\n" - "pgalloc_high 164501274\n" - "pgalloc_movable 0\n" - "pgfree 308894908\n" - "pgactivate 239320\n" - "pgdeactivate 1\n" - "pgfault 716044601\n" - "pgmajfault 2023\n" - "pgrefill_normal 0\n" - "pgrefill_high 0\n" - "pgrefill_movable 0\n"; - EXPECT_TRUE(ParseProcVmstat(valid_input1, &vmstat)); - EXPECT_EQ(179LU, vmstat.pswpin); - EXPECT_EQ(406LU, vmstat.pswpout); - EXPECT_EQ(487192LU, vmstat.pgmajfault); - EXPECT_TRUE(ParseProcVmstat(valid_input2, &vmstat)); - EXPECT_EQ(12LU, vmstat.pswpin); - EXPECT_EQ(901LU, vmstat.pswpout); - EXPECT_EQ(2023LU, vmstat.pgmajfault); - - const char missing_pgmajfault_input[] = - "pswpin 12\n" - "pswpout 901\n"; - EXPECT_FALSE(ParseProcVmstat(missing_pgmajfault_input, &vmstat)); - const char empty_input[] = ""; - EXPECT_FALSE(ParseProcVmstat(empty_input, &vmstat)); -} -#endif // defined(OS_LINUX) || defined(OS_ANDROID) - -#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_WIN) - -// Test that ProcessMetrics::GetPlatformIndependentCPUUsage() doesn't return -// negative values when the number of threads running on the process decreases -// between two successive calls to it. -TEST_F(SystemMetricsTest, TestNoNegativeCpuUsage) { - ProcessHandle handle = GetCurrentProcessHandle(); - std::unique_ptr<ProcessMetrics> metrics( - ProcessMetrics::CreateProcessMetrics(handle)); - - EXPECT_GE(metrics->GetPlatformIndependentCPUUsage(), 0.0); - Thread thread1("thread1"); - Thread thread2("thread2"); - Thread thread3("thread3"); - - thread1.StartAndWaitForTesting(); - thread2.StartAndWaitForTesting(); - thread3.StartAndWaitForTesting(); - - ASSERT_TRUE(thread1.IsRunning()); - ASSERT_TRUE(thread2.IsRunning()); - ASSERT_TRUE(thread3.IsRunning()); - - std::vector<std::string> vec1; - std::vector<std::string> vec2; - std::vector<std::string> vec3; - - thread1.task_runner()->PostTask(FROM_HERE, BindOnce(&BusyWork, &vec1)); - thread2.task_runner()->PostTask(FROM_HERE, BindOnce(&BusyWork, &vec2)); - thread3.task_runner()->PostTask(FROM_HERE, BindOnce(&BusyWork, &vec3)); - - TimeDelta prev_cpu_usage = metrics->GetCumulativeCPUUsage(); - EXPECT_GE(prev_cpu_usage, TimeDelta()); - EXPECT_GE(metrics->GetPlatformIndependentCPUUsage(), 0.0); - - thread1.Stop(); - TimeDelta current_cpu_usage = metrics->GetCumulativeCPUUsage(); - EXPECT_GE(current_cpu_usage, prev_cpu_usage); - prev_cpu_usage = current_cpu_usage; - EXPECT_GE(metrics->GetPlatformIndependentCPUUsage(), 0.0); - - thread2.Stop(); - current_cpu_usage = metrics->GetCumulativeCPUUsage(); - EXPECT_GE(current_cpu_usage, prev_cpu_usage); - prev_cpu_usage = current_cpu_usage; - EXPECT_GE(metrics->GetPlatformIndependentCPUUsage(), 0.0); - - thread3.Stop(); - current_cpu_usage = metrics->GetCumulativeCPUUsage(); - EXPECT_GE(current_cpu_usage, prev_cpu_usage); - EXPECT_GE(metrics->GetPlatformIndependentCPUUsage(), 0.0); -} - -#endif // defined(OS_LINUX) || defined(OS_CHROMEOS) - -#if defined(OS_CHROMEOS) -TEST_F(SystemMetricsTest, ParseZramMmStat) { - SwapInfo swapinfo; - - const char invalid_input1[] = "aaa"; - const char invalid_input2[] = "1 2 3 4 5 6"; - const char invalid_input3[] = "a 2 3 4 5 6 7"; - EXPECT_FALSE(ParseZramMmStat(invalid_input1, &swapinfo)); - EXPECT_FALSE(ParseZramMmStat(invalid_input2, &swapinfo)); - EXPECT_FALSE(ParseZramMmStat(invalid_input3, &swapinfo)); - - const char valid_input1[] = - "17715200 5008166 566062 0 1225715712 127 183842"; - EXPECT_TRUE(ParseZramMmStat(valid_input1, &swapinfo)); - EXPECT_EQ(17715200ULL, swapinfo.orig_data_size); - EXPECT_EQ(5008166ULL, swapinfo.compr_data_size); - EXPECT_EQ(566062ULL, swapinfo.mem_used_total); -} - -TEST_F(SystemMetricsTest, ParseZramStat) { - SwapInfo swapinfo; - - const char invalid_input1[] = "aaa"; - const char invalid_input2[] = "1 2 3 4 5 6 7 8 9 10"; - const char invalid_input3[] = "a 2 3 4 5 6 7 8 9 10 11"; - EXPECT_FALSE(ParseZramStat(invalid_input1, &swapinfo)); - EXPECT_FALSE(ParseZramStat(invalid_input2, &swapinfo)); - EXPECT_FALSE(ParseZramStat(invalid_input3, &swapinfo)); - - const char valid_input1[] = - "299 0 2392 0 1 0 8 0 0 0 0"; - EXPECT_TRUE(ParseZramStat(valid_input1, &swapinfo)); - EXPECT_EQ(299ULL, swapinfo.num_reads); - EXPECT_EQ(1ULL, swapinfo.num_writes); -} -#endif // defined(OS_CHROMEOS) - -#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) || \ - defined(OS_ANDROID) -TEST(SystemMetrics2Test, GetSystemMemoryInfo) { - SystemMemoryInfoKB info; - EXPECT_TRUE(GetSystemMemoryInfo(&info)); - - // Ensure each field received a value. - EXPECT_GT(info.total, 0); -#if defined(OS_WIN) - EXPECT_GT(info.avail_phys, 0); -#else - EXPECT_GT(info.free, 0); -#endif -#if defined(OS_LINUX) || defined(OS_ANDROID) - EXPECT_GT(info.buffers, 0); - EXPECT_GT(info.cached, 0); - EXPECT_GT(info.active_anon, 0); - EXPECT_GT(info.inactive_anon, 0); - EXPECT_GT(info.active_file, 0); - EXPECT_GT(info.inactive_file, 0); -#endif // defined(OS_LINUX) || defined(OS_ANDROID) - - // All the values should be less than the total amount of memory. -#if !defined(OS_WIN) && !defined(OS_IOS) - // TODO(crbug.com/711450): re-enable the following assertion on iOS. - EXPECT_LT(info.free, info.total); -#endif -#if defined(OS_LINUX) || defined(OS_ANDROID) - EXPECT_LT(info.buffers, info.total); - EXPECT_LT(info.cached, info.total); - EXPECT_LT(info.active_anon, info.total); - EXPECT_LT(info.inactive_anon, info.total); - EXPECT_LT(info.active_file, info.total); - EXPECT_LT(info.inactive_file, info.total); -#endif // defined(OS_LINUX) || defined(OS_ANDROID) - -#if defined(OS_MACOSX) || defined(OS_IOS) - EXPECT_GT(info.file_backed, 0); -#endif - -#if defined(OS_CHROMEOS) - // Chrome OS exposes shmem. - EXPECT_GT(info.shmem, 0); - EXPECT_LT(info.shmem, info.total); - // Chrome unit tests are not run on actual Chrome OS hardware, so gem_objects - // and gem_size cannot be tested here. -#endif -} -#endif // defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) || - // defined(OS_ANDROID) - -#if defined(OS_LINUX) || defined(OS_ANDROID) -TEST(ProcessMetricsTest, ParseProcStatCPU) { - // /proc/self/stat for a process running "top". - const char kTopStat[] = "960 (top) S 16230 960 16230 34818 960 " - "4202496 471 0 0 0 " - "12 16 0 0 " // <- These are the goods. - "20 0 1 0 121946157 15077376 314 18446744073709551615 4194304 " - "4246868 140733983044336 18446744073709551615 140244213071219 " - "0 0 0 138047495 0 0 0 17 1 0 0 0 0 0"; - EXPECT_EQ(12 + 16, ParseProcStatCPU(kTopStat)); - - // cat /proc/self/stat on a random other machine I have. - const char kSelfStat[] = "5364 (cat) R 5354 5364 5354 34819 5364 " - "0 142 0 0 0 " - "0 0 0 0 " // <- No CPU, apparently. - "16 0 1 0 1676099790 2957312 114 4294967295 134512640 134528148 " - "3221224832 3221224344 3086339742 0 0 0 0 0 0 0 17 0 0 0"; - - EXPECT_EQ(0, ParseProcStatCPU(kSelfStat)); - - // Some weird long-running process with a weird name that I created for the - // purposes of this test. - const char kWeirdNameStat[] = "26115 (Hello) You ())) ) R 24614 26115 24614" - " 34839 26115 4218880 227 0 0 0 " - "5186 11 0 0 " - "20 0 1 0 36933953 4296704 90 18446744073709551615 4194304 4196116 " - "140735857761568 140735857761160 4195644 0 0 0 0 0 0 0 17 14 0 0 0 0 0 " - "6295056 6295616 16519168 140735857770710 140735857770737 " - "140735857770737 140735857774557 0"; - EXPECT_EQ(5186 + 11, ParseProcStatCPU(kWeirdNameStat)); -} -#endif // defined(OS_LINUX) || defined(OS_ANDROID) - -// Disable on Android because base_unittests runs inside a Dalvik VM that -// starts and stop threads (crbug.com/175563). -#if defined(OS_LINUX) -// http://crbug.com/396455 -TEST(ProcessMetricsTest, DISABLED_GetNumberOfThreads) { - const ProcessHandle current = GetCurrentProcessHandle(); - const int initial_threads = GetNumberOfThreads(current); - ASSERT_GT(initial_threads, 0); - const int kNumAdditionalThreads = 10; - { - std::unique_ptr<Thread> my_threads[kNumAdditionalThreads]; - for (int i = 0; i < kNumAdditionalThreads; ++i) { - my_threads[i].reset(new Thread("GetNumberOfThreadsTest")); - my_threads[i]->Start(); - ASSERT_EQ(GetNumberOfThreads(current), initial_threads + 1 + i); - } - } - // The Thread destructor will stop them. - ASSERT_EQ(initial_threads, GetNumberOfThreads(current)); -} -#endif // defined(OS_LINUX) - -#if defined(OS_LINUX) -namespace { - -// Keep these in sync so the GetChildOpenFdCount test can refer to correct test -// main. -#define ChildMain ChildFdCount -#define ChildMainString "ChildFdCount" - -// Command line flag name and file name used for synchronization. -const char kTempDirFlag[] = "temp-dir"; -const char kSignalClosed[] = "closed"; - -bool SignalEvent(const FilePath& signal_dir, const char* signal_file) { - File file(signal_dir.AppendASCII(signal_file), - File::FLAG_CREATE | File::FLAG_WRITE); - return file.IsValid(); -} - -// Check whether an event was signaled. -bool CheckEvent(const FilePath& signal_dir, const char* signal_file) { - File file(signal_dir.AppendASCII(signal_file), - File::FLAG_OPEN | File::FLAG_READ); - return file.IsValid(); -} - -// Busy-wait for an event to be signaled. -void WaitForEvent(const FilePath& signal_dir, const char* signal_file) { - while (!CheckEvent(signal_dir, signal_file)) - PlatformThread::Sleep(TimeDelta::FromMilliseconds(10)); -} - -// Subprocess to test the number of open file descriptors. -MULTIPROCESS_TEST_MAIN(ChildMain) { - CommandLine* command_line = CommandLine::ForCurrentProcess(); - const FilePath temp_path = command_line->GetSwitchValuePath(kTempDirFlag); - CHECK(DirectoryExists(temp_path)); - - // Try to close all the file descriptors, so the open count goes to 0. - for (size_t i = 0; i < 1000; ++i) - close(i); - CHECK(SignalEvent(temp_path, kSignalClosed)); - - // Wait to be terminated. - while (true) - PlatformThread::Sleep(TimeDelta::FromSeconds(1)); - return 0; -} - -} // namespace - -TEST(ProcessMetricsTest, GetChildOpenFdCount) { - ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - const FilePath temp_path = temp_dir.GetPath(); - CommandLine child_command_line(GetMultiProcessTestChildBaseCommandLine()); - child_command_line.AppendSwitchPath(kTempDirFlag, temp_path); - Process child = SpawnMultiProcessTestChild( - ChildMainString, child_command_line, LaunchOptions()); - ASSERT_TRUE(child.IsValid()); - WaitForEvent(temp_path, kSignalClosed); - - std::unique_ptr<ProcessMetrics> metrics( - ProcessMetrics::CreateProcessMetrics(child.Handle())); - EXPECT_EQ(0, metrics->GetOpenFdCount()); - ASSERT_TRUE(child.Terminate(0, true)); -} -#endif // defined(OS_LINUX) - -#if defined(OS_ANDROID) || defined(OS_LINUX) - -TEST(ProcessMetricsTest, GetOpenFdCount) { - std::unique_ptr<base::ProcessMetrics> metrics( - base::ProcessMetrics::CreateProcessMetrics( - base::GetCurrentProcessHandle())); - int fd_count = metrics->GetOpenFdCount(); - EXPECT_GT(fd_count, 0); - ScopedFILE file(fopen("/proc/self/statm", "r")); - EXPECT_TRUE(file); - int new_fd_count = metrics->GetOpenFdCount(); - EXPECT_GT(new_fd_count, 0); - EXPECT_EQ(new_fd_count, fd_count + 1); -} - -TEST(ProcessMetricsTestLinux, GetPageFaultCounts) { - std::unique_ptr<base::ProcessMetrics> process_metrics( - base::ProcessMetrics::CreateProcessMetrics( - base::GetCurrentProcessHandle())); - - PageFaultCounts counts; - ASSERT_TRUE(process_metrics->GetPageFaultCounts(&counts)); - ASSERT_GT(counts.minor, 0); - ASSERT_GE(counts.major, 0); - - { - // Allocate and touch memory. Touching it is required to make sure that the - // page fault count goes up, as memory is typically mapped lazily. - const size_t kMappedSize = 4 * (1 << 20); - SharedMemory memory; - ASSERT_TRUE(memory.CreateAndMapAnonymous(kMappedSize)); - memset(memory.memory(), 42, kMappedSize); - memory.Unmap(); - } - - PageFaultCounts counts_after; - ASSERT_TRUE(process_metrics->GetPageFaultCounts(&counts_after)); - ASSERT_GT(counts_after.minor, counts.minor); - ASSERT_GE(counts_after.major, counts.major); -} -#endif // defined(OS_ANDROID) || defined(OS_LINUX) - -} // namespace debug -} // namespace base
diff --git a/base/process/process_unittest.cc b/base/process/process_unittest.cc deleted file mode 100644 index 0f05d24..0000000 --- a/base/process/process_unittest.cc +++ /dev/null
@@ -1,330 +0,0 @@ -// 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/process/process.h" - -#include <utility> - -#include "base/at_exit.h" -#include "base/process/kill.h" -#include "base/test/multiprocess_test.h" -#include "base/test/test_timeouts.h" -#include "base/threading/platform_thread.h" -#include "base/threading/thread_local.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/multiprocess_func_list.h" - -namespace { - -#if defined(OS_WIN) -const int kExpectedStillRunningExitCode = 0x102; -#else -const int kExpectedStillRunningExitCode = 0; -#endif - -#if defined(OS_MACOSX) -// Fake port provider that returns the calling process's -// task port, ignoring its argument. -class FakePortProvider : public base::PortProvider { - mach_port_t TaskForPid(base::ProcessHandle process) const override { - return mach_task_self(); - } -}; -#endif - -} // namespace - -namespace base { - -class ProcessTest : public MultiProcessTest { -}; - -TEST_F(ProcessTest, Create) { - Process process(SpawnChild("SimpleChildProcess")); - ASSERT_TRUE(process.IsValid()); - ASSERT_FALSE(process.is_current()); - EXPECT_NE(process.Pid(), kNullProcessId); - process.Close(); - ASSERT_FALSE(process.IsValid()); -} - -TEST_F(ProcessTest, CreateCurrent) { - Process process = Process::Current(); - ASSERT_TRUE(process.IsValid()); - ASSERT_TRUE(process.is_current()); - EXPECT_NE(process.Pid(), kNullProcessId); - process.Close(); - ASSERT_FALSE(process.IsValid()); -} - -TEST_F(ProcessTest, Move) { - Process process1(SpawnChild("SimpleChildProcess")); - EXPECT_TRUE(process1.IsValid()); - - Process process2; - EXPECT_FALSE(process2.IsValid()); - - process2 = std::move(process1); - EXPECT_TRUE(process2.IsValid()); - EXPECT_FALSE(process1.IsValid()); - EXPECT_FALSE(process2.is_current()); - - Process process3 = Process::Current(); - process2 = std::move(process3); - EXPECT_TRUE(process2.is_current()); - EXPECT_TRUE(process2.IsValid()); - EXPECT_FALSE(process3.IsValid()); -} - -TEST_F(ProcessTest, Duplicate) { - Process process1(SpawnChild("SimpleChildProcess")); - ASSERT_TRUE(process1.IsValid()); - - Process process2 = process1.Duplicate(); - ASSERT_TRUE(process1.IsValid()); - ASSERT_TRUE(process2.IsValid()); - EXPECT_EQ(process1.Pid(), process2.Pid()); - EXPECT_FALSE(process1.is_current()); - EXPECT_FALSE(process2.is_current()); - - process1.Close(); - ASSERT_TRUE(process2.IsValid()); -} - -TEST_F(ProcessTest, DuplicateCurrent) { - Process process1 = Process::Current(); - ASSERT_TRUE(process1.IsValid()); - - Process process2 = process1.Duplicate(); - ASSERT_TRUE(process1.IsValid()); - ASSERT_TRUE(process2.IsValid()); - EXPECT_EQ(process1.Pid(), process2.Pid()); - EXPECT_TRUE(process1.is_current()); - EXPECT_TRUE(process2.is_current()); - - process1.Close(); - ASSERT_TRUE(process2.IsValid()); -} - -TEST_F(ProcessTest, DeprecatedGetProcessFromHandle) { - Process process1(SpawnChild("SimpleChildProcess")); - ASSERT_TRUE(process1.IsValid()); - - Process process2 = Process::DeprecatedGetProcessFromHandle(process1.Handle()); - ASSERT_TRUE(process1.IsValid()); - ASSERT_TRUE(process2.IsValid()); - EXPECT_EQ(process1.Pid(), process2.Pid()); - EXPECT_FALSE(process1.is_current()); - EXPECT_FALSE(process2.is_current()); - - process1.Close(); - ASSERT_TRUE(process2.IsValid()); -} - -MULTIPROCESS_TEST_MAIN(SleepyChildProcess) { - PlatformThread::Sleep(TestTimeouts::action_max_timeout()); - return 0; -} - -TEST_F(ProcessTest, Terminate) { - Process process(SpawnChild("SleepyChildProcess")); - ASSERT_TRUE(process.IsValid()); - - const int kDummyExitCode = 42; - int exit_code = kDummyExitCode; - EXPECT_EQ(TERMINATION_STATUS_STILL_RUNNING, - GetTerminationStatus(process.Handle(), &exit_code)); - EXPECT_EQ(kExpectedStillRunningExitCode, exit_code); - - exit_code = kDummyExitCode; - int kExpectedExitCode = 250; - process.Terminate(kExpectedExitCode, false); - process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(), - &exit_code); - - EXPECT_NE(TERMINATION_STATUS_STILL_RUNNING, - GetTerminationStatus(process.Handle(), &exit_code)); -#if !defined(OS_POSIX) && !defined(OS_FUCHSIA) - // The POSIX implementation actually ignores the exit_code. - EXPECT_EQ(kExpectedExitCode, exit_code); -#endif -} - -void AtExitHandler(void*) { - // At-exit handler should not be called at - // Process::TerminateCurrentProcessImmediately. - DCHECK(false); -} - -class ThreadLocalObject { - ~ThreadLocalObject() { - // Thread-local storage should not be destructed at - // Process::TerminateCurrentProcessImmediately. - DCHECK(false); - } -}; - -MULTIPROCESS_TEST_MAIN(TerminateCurrentProcessImmediatelyWithCode0) { - base::ThreadLocalPointer<ThreadLocalObject> object; - base::AtExitManager::RegisterCallback(&AtExitHandler, nullptr); - Process::TerminateCurrentProcessImmediately(0); -} - -TEST_F(ProcessTest, TerminateCurrentProcessImmediatelyWithZeroExitCode) { - Process process(SpawnChild("TerminateCurrentProcessImmediatelyWithCode0")); - ASSERT_TRUE(process.IsValid()); - int exit_code = 42; - ASSERT_TRUE(process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(), - &exit_code)); - EXPECT_EQ(0, exit_code); -} - -MULTIPROCESS_TEST_MAIN(TerminateCurrentProcessImmediatelyWithCode250) { - Process::TerminateCurrentProcessImmediately(250); -} - -TEST_F(ProcessTest, TerminateCurrentProcessImmediatelyWithNonZeroExitCode) { - Process process(SpawnChild("TerminateCurrentProcessImmediatelyWithCode250")); - ASSERT_TRUE(process.IsValid()); - int exit_code = 42; - ASSERT_TRUE(process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(), - &exit_code)); - EXPECT_EQ(250, exit_code); -} - -MULTIPROCESS_TEST_MAIN(FastSleepyChildProcess) { - PlatformThread::Sleep(TestTimeouts::tiny_timeout() * 10); - return 0; -} - -TEST_F(ProcessTest, WaitForExit) { - Process process(SpawnChild("FastSleepyChildProcess")); - ASSERT_TRUE(process.IsValid()); - - const int kDummyExitCode = 42; - int exit_code = kDummyExitCode; - EXPECT_TRUE(process.WaitForExit(&exit_code)); - EXPECT_EQ(0, exit_code); -} - -TEST_F(ProcessTest, WaitForExitWithTimeout) { - Process process(SpawnChild("SleepyChildProcess")); - ASSERT_TRUE(process.IsValid()); - - const int kDummyExitCode = 42; - int exit_code = kDummyExitCode; - TimeDelta timeout = TestTimeouts::tiny_timeout(); - EXPECT_FALSE(process.WaitForExitWithTimeout(timeout, &exit_code)); - EXPECT_EQ(kDummyExitCode, exit_code); - - process.Terminate(kDummyExitCode, false); -} - -// Ensure that the priority of a process is restored correctly after -// backgrounding and restoring. -// Note: a platform may not be willing or able to lower the priority of -// a process. The calls to SetProcessBackground should be noops then. -TEST_F(ProcessTest, SetProcessBackgrounded) { - if (!Process::CanBackgroundProcesses()) - return; - Process process(SpawnChild("SimpleChildProcess")); - int old_priority = process.GetPriority(); -#if defined(OS_WIN) - EXPECT_TRUE(process.SetProcessBackgrounded(true)); - EXPECT_TRUE(process.IsProcessBackgrounded()); - EXPECT_TRUE(process.SetProcessBackgrounded(false)); - EXPECT_FALSE(process.IsProcessBackgrounded()); -#elif defined(OS_MACOSX) - // On the Mac, backgrounding a process requires a port to that process. - // In the browser it's available through the MachBroker class, which is not - // part of base. Additionally, there is an indefinite amount of time between - // spawning a process and receiving its port. Because this test just checks - // the ability to background/foreground a process, we can use the current - // process's port instead. - FakePortProvider provider; - EXPECT_TRUE(process.SetProcessBackgrounded(&provider, true)); - EXPECT_TRUE(process.IsProcessBackgrounded(&provider)); - EXPECT_TRUE(process.SetProcessBackgrounded(&provider, false)); - EXPECT_FALSE(process.IsProcessBackgrounded(&provider)); - -#else - process.SetProcessBackgrounded(true); - process.SetProcessBackgrounded(false); -#endif - int new_priority = process.GetPriority(); - EXPECT_EQ(old_priority, new_priority); -} - -// Same as SetProcessBackgrounded but to this very process. It uses -// a different code path at least for Windows. -TEST_F(ProcessTest, SetProcessBackgroundedSelf) { - if (!Process::CanBackgroundProcesses()) - return; - Process process = Process::Current(); - int old_priority = process.GetPriority(); -#if defined(OS_WIN) - EXPECT_TRUE(process.SetProcessBackgrounded(true)); - EXPECT_TRUE(process.IsProcessBackgrounded()); - EXPECT_TRUE(process.SetProcessBackgrounded(false)); - EXPECT_FALSE(process.IsProcessBackgrounded()); -#elif defined(OS_MACOSX) - FakePortProvider provider; - EXPECT_TRUE(process.SetProcessBackgrounded(&provider, true)); - EXPECT_TRUE(process.IsProcessBackgrounded(&provider)); - EXPECT_TRUE(process.SetProcessBackgrounded(&provider, false)); - EXPECT_FALSE(process.IsProcessBackgrounded(&provider)); -#else - process.SetProcessBackgrounded(true); - process.SetProcessBackgrounded(false); -#endif - int new_priority = process.GetPriority(); - EXPECT_EQ(old_priority, new_priority); -} - -// Consumers can use WaitForExitWithTimeout(base::TimeDelta(), nullptr) to check -// whether the process is still running. This may not be safe because of the -// potential reusing of the process id. So we won't export Process::IsRunning() -// on all platforms. But for the controllable scenario in the test cases, the -// behavior should be guaranteed. -TEST_F(ProcessTest, CurrentProcessIsRunning) { - EXPECT_FALSE(Process::Current().WaitForExitWithTimeout( - base::TimeDelta(), nullptr)); -} - -#if defined(OS_MACOSX) -// On Mac OSX, we can detect whether a non-child process is running. -TEST_F(ProcessTest, PredefinedProcessIsRunning) { - // Process 1 is the /sbin/launchd, it should be always running. - EXPECT_FALSE(Process::Open(1).WaitForExitWithTimeout( - base::TimeDelta(), nullptr)); -} -#endif - -TEST_F(ProcessTest, ChildProcessIsRunning) { - Process process(SpawnChild("SleepyChildProcess")); - EXPECT_FALSE(process.WaitForExitWithTimeout( - base::TimeDelta(), nullptr)); - process.Terminate(0, true); - EXPECT_TRUE(process.WaitForExitWithTimeout( - base::TimeDelta(), nullptr)); -} - -#if defined(OS_CHROMEOS) - -// Tests that the function IsProcessBackgroundedCGroup() can parse the contents -// of the /proc/<pid>/cgroup file successfully. -TEST_F(ProcessTest, TestIsProcessBackgroundedCGroup) { - const char kNotBackgrounded[] = "5:cpuacct,cpu,cpuset:/daemons\n"; - const char kBackgrounded[] = - "2:freezer:/chrome_renderers/to_be_frozen\n" - "1:cpu:/chrome_renderers/background\n"; - - EXPECT_FALSE(IsProcessBackgroundedCGroup(kNotBackgrounded)); - EXPECT_TRUE(IsProcessBackgroundedCGroup(kBackgrounded)); -} - -#endif // defined(OS_CHROMEOS) - -} // namespace base
diff --git a/base/process/process_util_unittest.cc b/base/process/process_util_unittest.cc deleted file mode 100644 index 81c31b2..0000000 --- a/base/process/process_util_unittest.cc +++ /dev/null
@@ -1,1140 +0,0 @@ -// 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. - -#define _CRT_SECURE_NO_WARNINGS - -#include <stddef.h> -#include <stdint.h> - -#include <limits> - -#include "base/command_line.h" -#include "base/debug/alias.h" -#include "base/debug/stack_trace.h" -#include "base/files/file_enumerator.h" -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/files/scoped_file.h" -#include "base/logging.h" -#include "base/macros.h" -#include "base/path_service.h" -#include "base/posix/eintr_wrapper.h" -#include "base/process/kill.h" -#include "base/process/launch.h" -#include "base/process/memory.h" -#include "base/process/process.h" -#include "base/process/process_metrics.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/utf_string_conversions.h" -#include "base/synchronization/waitable_event.h" -#include "base/test/multiprocess_test.h" -#include "base/test/scoped_task_environment.h" -#include "base/test/test_timeouts.h" -#include "base/threading/platform_thread.h" -#include "base/threading/thread.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/multiprocess_func_list.h" - -#if defined(OS_LINUX) -#include <malloc.h> -#include <sched.h> -#include <sys/syscall.h> -#endif -#if defined(OS_POSIX) -#include <sys/resource.h> -#endif -#if defined(OS_POSIX) || defined(OS_FUCHSIA) -#include <dlfcn.h> -#include <errno.h> -#include <fcntl.h> -#include <sched.h> -#include <signal.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <unistd.h> -#endif -#if defined(OS_WIN) -#include <windows.h> -#endif -#if defined(OS_MACOSX) -#include <mach/vm_param.h> -#include <malloc/malloc.h> -#endif -#if defined(OS_ANDROID) -#include "third_party/lss/linux_syscall_support.h" -#endif -#if defined(OS_FUCHSIA) -#include <fdio/limits.h> -#include <zircon/process.h> -#include <zircon/processargs.h> -#include <zircon/syscalls.h> -#include "base/base_paths_fuchsia.h" -#endif - -namespace base { - -namespace { - -const char kSignalFileSlow[] = "SlowChildProcess.die"; -const char kSignalFileKill[] = "KilledChildProcess.die"; -const char kTestHelper[] = "test_child_process"; - -#if defined(OS_POSIX) || defined(OS_FUCHSIA) -const char kSignalFileTerm[] = "TerminatedChildProcess.die"; -#endif - -#if defined(OS_FUCHSIA) -const char kSignalFileClone[] = "ClonedTmpDir.die"; -#endif - -#if defined(OS_WIN) -const int kExpectedStillRunningExitCode = 0x102; -const int kExpectedKilledExitCode = 1; -#elif defined(OS_POSIX) || defined(OS_FUCHSIA) -const int kExpectedStillRunningExitCode = 0; -#endif - -// Sleeps until file filename is created. -void WaitToDie(const char* filename) { - FILE* fp; - do { - PlatformThread::Sleep(TimeDelta::FromMilliseconds(10)); - fp = fopen(filename, "r"); - } while (!fp); - fclose(fp); -} - -// Signals children they should die now. -void SignalChildren(const char* filename) { - FILE* fp = fopen(filename, "w"); - fclose(fp); -} - -// Using a pipe to the child to wait for an event was considered, but -// there were cases in the past where pipes caused problems (other -// libraries closing the fds, child deadlocking). This is a simple -// case, so it's not worth the risk. Using wait loops is discouraged -// in most instances. -TerminationStatus WaitForChildTermination(ProcessHandle handle, - int* exit_code) { - // Now we wait until the result is something other than STILL_RUNNING. - TerminationStatus status = TERMINATION_STATUS_STILL_RUNNING; - const TimeDelta kInterval = TimeDelta::FromMilliseconds(20); - TimeDelta waited; - do { - status = GetTerminationStatus(handle, exit_code); - PlatformThread::Sleep(kInterval); - waited += kInterval; - } while (status == TERMINATION_STATUS_STILL_RUNNING && - waited < TestTimeouts::action_max_timeout()); - - return status; -} - -} // namespace - -const int kSuccess = 0; - -class ProcessUtilTest : public MultiProcessTest { - public: - void SetUp() override { - ASSERT_TRUE(PathService::Get(DIR_ASSETS, &test_helper_path_)); - test_helper_path_ = test_helper_path_.AppendASCII(kTestHelper); - } - -#if defined(OS_POSIX) || defined(OS_FUCHSIA) - // Spawn a child process that counts how many file descriptors are open. - int CountOpenFDsInChild(); -#endif - // Converts the filename to a platform specific filepath. - // On Android files can not be created in arbitrary directories. - static std::string GetSignalFilePath(const char* filename); - - protected: - base::FilePath test_helper_path_; -}; - -std::string ProcessUtilTest::GetSignalFilePath(const char* filename) { -#if defined(OS_ANDROID) || defined(OS_FUCHSIA) - FilePath tmp_dir; - PathService::Get(DIR_TEMP, &tmp_dir); - tmp_dir = tmp_dir.Append(filename); - return tmp_dir.value(); -#else - return filename; -#endif -} - -MULTIPROCESS_TEST_MAIN(SimpleChildProcess) { - return kSuccess; -} - -// TODO(viettrungluu): This should be in a "MultiProcessTestTest". -TEST_F(ProcessUtilTest, SpawnChild) { - Process process = SpawnChild("SimpleChildProcess"); - ASSERT_TRUE(process.IsValid()); - int exit_code; - EXPECT_TRUE(process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(), - &exit_code)); -} - -MULTIPROCESS_TEST_MAIN(SlowChildProcess) { - WaitToDie(ProcessUtilTest::GetSignalFilePath(kSignalFileSlow).c_str()); - return kSuccess; -} - -TEST_F(ProcessUtilTest, KillSlowChild) { - const std::string signal_file = - ProcessUtilTest::GetSignalFilePath(kSignalFileSlow); - remove(signal_file.c_str()); - Process process = SpawnChild("SlowChildProcess"); - ASSERT_TRUE(process.IsValid()); - SignalChildren(signal_file.c_str()); - int exit_code; - EXPECT_TRUE(process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(), - &exit_code)); - remove(signal_file.c_str()); -} - -// Times out on Linux and Win, flakes on other platforms, http://crbug.com/95058 -TEST_F(ProcessUtilTest, DISABLED_GetTerminationStatusExit) { - const std::string signal_file = - ProcessUtilTest::GetSignalFilePath(kSignalFileSlow); - remove(signal_file.c_str()); - Process process = SpawnChild("SlowChildProcess"); - ASSERT_TRUE(process.IsValid()); - - int exit_code = 42; - EXPECT_EQ(TERMINATION_STATUS_STILL_RUNNING, - GetTerminationStatus(process.Handle(), &exit_code)); - EXPECT_EQ(kExpectedStillRunningExitCode, exit_code); - - SignalChildren(signal_file.c_str()); - exit_code = 42; - TerminationStatus status = - WaitForChildTermination(process.Handle(), &exit_code); - EXPECT_EQ(TERMINATION_STATUS_NORMAL_TERMINATION, status); - EXPECT_EQ(kSuccess, exit_code); - remove(signal_file.c_str()); -} - -#if defined(OS_FUCHSIA) - -MULTIPROCESS_TEST_MAIN(CheckTmpFileExists) { - // Look through the filesystem to ensure that no other directories - // besides "tmp" are in the namespace. - base::FileEnumerator enumerator( - base::FilePath("/"), false, - base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES); - base::FilePath next_path; - while (!(next_path = enumerator.Next()).empty()) { - if (next_path != base::FilePath("/tmp")) { - LOG(ERROR) << "Clone policy violation: found non-tmp directory " - << next_path.MaybeAsASCII(); - return 1; - } - } - WaitToDie(ProcessUtilTest::GetSignalFilePath(kSignalFileClone).c_str()); - return kSuccess; -} - -TEST_F(ProcessUtilTest, SelectivelyClonedDir) { - const std::string signal_file = - ProcessUtilTest::GetSignalFilePath(kSignalFileClone); - remove(signal_file.c_str()); - - LaunchOptions options; - options.paths_to_map.push_back(base::FilePath("/tmp")); - options.clone_flags = LP_CLONE_FDIO_STDIO; - - Process process(SpawnChildWithOptions("CheckTmpFileExists", options)); - ASSERT_TRUE(process.IsValid()); - - SignalChildren(signal_file.c_str()); - - int exit_code = 42; - EXPECT_TRUE(process.WaitForExit(&exit_code)); - EXPECT_EQ(kSuccess, exit_code); -} - -// Test that we can clone other directories. CheckTmpFileExists will return an -// error code if it detects a directory other than "/tmp", so we can use that as -// a signal that it successfully detected another entry in the root namespace. -TEST_F(ProcessUtilTest, CloneAlternateDir) { - const std::string signal_file = - ProcessUtilTest::GetSignalFilePath(kSignalFileClone); - remove(signal_file.c_str()); - - LaunchOptions options; - options.paths_to_map.push_back(base::FilePath("/tmp")); - options.paths_to_map.push_back(base::FilePath("/data")); - options.clone_flags = LP_CLONE_FDIO_STDIO; - - Process process(SpawnChildWithOptions("CheckTmpFileExists", options)); - ASSERT_TRUE(process.IsValid()); - - SignalChildren(signal_file.c_str()); - - int exit_code = 42; - EXPECT_TRUE(process.WaitForExit(&exit_code)); - EXPECT_EQ(1, exit_code); -} - -#endif // defined(OS_FUCHSIA) - -// On Android SpawnProcess() doesn't use LaunchProcess() and doesn't support -// LaunchOptions::current_directory. -#if !defined(OS_ANDROID) -MULTIPROCESS_TEST_MAIN(CheckCwdProcess) { - FilePath expected; - CHECK(GetTempDir(&expected)); - expected = MakeAbsoluteFilePath(expected); - CHECK(!expected.empty()); - - FilePath actual; - CHECK(GetCurrentDirectory(&actual)); - actual = MakeAbsoluteFilePath(actual); - CHECK(!actual.empty()); - - CHECK(expected == actual) << "Expected: " << expected.value() - << " Actual: " << actual.value(); - return kSuccess; -} - -TEST_F(ProcessUtilTest, CurrentDirectory) { - // TODO(rickyz): Add support for passing arguments to multiprocess children, - // then create a special directory for this test. - FilePath tmp_dir; - ASSERT_TRUE(GetTempDir(&tmp_dir)); - - LaunchOptions options; - options.current_directory = tmp_dir; - - Process process(SpawnChildWithOptions("CheckCwdProcess", options)); - ASSERT_TRUE(process.IsValid()); - - int exit_code = 42; - EXPECT_TRUE(process.WaitForExit(&exit_code)); - EXPECT_EQ(kSuccess, exit_code); -} -#endif // !defined(OS_ANDROID) - -#if defined(OS_WIN) -// TODO(cpu): figure out how to test this in other platforms. -TEST_F(ProcessUtilTest, GetProcId) { - ProcessId id1 = GetProcId(GetCurrentProcess()); - EXPECT_NE(0ul, id1); - Process process = SpawnChild("SimpleChildProcess"); - ASSERT_TRUE(process.IsValid()); - ProcessId id2 = process.Pid(); - EXPECT_NE(0ul, id2); - EXPECT_NE(id1, id2); -} -#endif // defined(OS_WIN) - -#if !defined(OS_MACOSX) && !defined(OS_ANDROID) -// This test is disabled on Mac, since it's flaky due to ReportCrash -// taking a variable amount of time to parse and load the debug and -// symbol data for this unit test's executable before firing the -// signal handler. -// -// TODO(gspencer): turn this test process into a very small program -// with no symbols (instead of using the multiprocess testing -// framework) to reduce the ReportCrash overhead. -// -// It is disabled on Android as MultiprocessTests are started as services that -// the framework restarts on crashes. -const char kSignalFileCrash[] = "CrashingChildProcess.die"; - -MULTIPROCESS_TEST_MAIN(CrashingChildProcess) { - WaitToDie(ProcessUtilTest::GetSignalFilePath(kSignalFileCrash).c_str()); -#if defined(OS_POSIX) || defined(OS_FUCHSIA) - // Have to disable to signal handler for segv so we can get a crash - // instead of an abnormal termination through the crash dump handler. - ::signal(SIGSEGV, SIG_DFL); -#endif - // Make this process have a segmentation fault. - volatile int* oops = nullptr; - *oops = 0xDEAD; - return 1; -} - -// This test intentionally crashes, so we don't need to run it under -// AddressSanitizer. -#if defined(ADDRESS_SANITIZER) -#define MAYBE_GetTerminationStatusCrash DISABLED_GetTerminationStatusCrash -#else -#define MAYBE_GetTerminationStatusCrash GetTerminationStatusCrash -#endif -TEST_F(ProcessUtilTest, MAYBE_GetTerminationStatusCrash) { - const std::string signal_file = - ProcessUtilTest::GetSignalFilePath(kSignalFileCrash); - remove(signal_file.c_str()); - Process process = SpawnChild("CrashingChildProcess"); - ASSERT_TRUE(process.IsValid()); - - int exit_code = 42; - EXPECT_EQ(TERMINATION_STATUS_STILL_RUNNING, - GetTerminationStatus(process.Handle(), &exit_code)); - EXPECT_EQ(kExpectedStillRunningExitCode, exit_code); - - SignalChildren(signal_file.c_str()); - exit_code = 42; - TerminationStatus status = - WaitForChildTermination(process.Handle(), &exit_code); - EXPECT_EQ(TERMINATION_STATUS_PROCESS_CRASHED, status); - -#if defined(OS_WIN) - EXPECT_EQ(static_cast<int>(0xc0000005), exit_code); -#elif defined(OS_POSIX) || defined(OS_FUCHSIA) - int signaled = WIFSIGNALED(exit_code); - EXPECT_NE(0, signaled); - int signal = WTERMSIG(exit_code); - EXPECT_EQ(SIGSEGV, signal); -#endif - - // Reset signal handlers back to "normal". - debug::EnableInProcessStackDumping(); - remove(signal_file.c_str()); -} -#endif // !defined(OS_MACOSX) && !defined(OS_ANDROID) - -MULTIPROCESS_TEST_MAIN(KilledChildProcess) { - WaitToDie(ProcessUtilTest::GetSignalFilePath(kSignalFileKill).c_str()); -#if defined(OS_WIN) - // Kill ourselves. - HANDLE handle = ::OpenProcess(PROCESS_ALL_ACCESS, 0, ::GetCurrentProcessId()); - ::TerminateProcess(handle, kExpectedKilledExitCode); -#elif defined(OS_POSIX) || defined(OS_FUCHSIA) - // Send a SIGKILL to this process, just like the OOM killer would. - ::kill(getpid(), SIGKILL); -#endif - return 1; -} - -#if defined(OS_POSIX) || defined(OS_FUCHSIA) -MULTIPROCESS_TEST_MAIN(TerminatedChildProcess) { - WaitToDie(ProcessUtilTest::GetSignalFilePath(kSignalFileTerm).c_str()); - // Send a SIGTERM to this process. - ::kill(getpid(), SIGTERM); - return 1; -} -#endif // defined(OS_POSIX) || defined(OS_FUCHSIA) - -TEST_F(ProcessUtilTest, GetTerminationStatusSigKill) { - const std::string signal_file = - ProcessUtilTest::GetSignalFilePath(kSignalFileKill); - remove(signal_file.c_str()); - Process process = SpawnChild("KilledChildProcess"); - ASSERT_TRUE(process.IsValid()); - - int exit_code = 42; - EXPECT_EQ(TERMINATION_STATUS_STILL_RUNNING, - GetTerminationStatus(process.Handle(), &exit_code)); - EXPECT_EQ(kExpectedStillRunningExitCode, exit_code); - - SignalChildren(signal_file.c_str()); - exit_code = 42; - TerminationStatus status = - WaitForChildTermination(process.Handle(), &exit_code); -#if defined(OS_CHROMEOS) - EXPECT_EQ(TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM, status); -#else - EXPECT_EQ(TERMINATION_STATUS_PROCESS_WAS_KILLED, status); -#endif - -#if defined(OS_WIN) - EXPECT_EQ(kExpectedKilledExitCode, exit_code); -#elif defined(OS_POSIX) || defined(OS_FUCHSIA) - int signaled = WIFSIGNALED(exit_code); - EXPECT_NE(0, signaled); - int signal = WTERMSIG(exit_code); - EXPECT_EQ(SIGKILL, signal); -#endif - remove(signal_file.c_str()); -} - -#if defined(OS_POSIX) || defined(OS_FUCHSIA) -TEST_F(ProcessUtilTest, GetTerminationStatusSigTerm) { - const std::string signal_file = - ProcessUtilTest::GetSignalFilePath(kSignalFileTerm); - remove(signal_file.c_str()); - Process process = SpawnChild("TerminatedChildProcess"); - ASSERT_TRUE(process.IsValid()); - - int exit_code = 42; - EXPECT_EQ(TERMINATION_STATUS_STILL_RUNNING, - GetTerminationStatus(process.Handle(), &exit_code)); - EXPECT_EQ(kExpectedStillRunningExitCode, exit_code); - - SignalChildren(signal_file.c_str()); - exit_code = 42; - TerminationStatus status = - WaitForChildTermination(process.Handle(), &exit_code); - EXPECT_EQ(TERMINATION_STATUS_PROCESS_WAS_KILLED, status); - - int signaled = WIFSIGNALED(exit_code); - EXPECT_NE(0, signaled); - int signal = WTERMSIG(exit_code); - EXPECT_EQ(SIGTERM, signal); - remove(signal_file.c_str()); -} -#endif // defined(OS_POSIX) || defined(OS_FUCHSIA) - -TEST_F(ProcessUtilTest, EnsureTerminationUndying) { - test::ScopedTaskEnvironment task_environment; - - Process child_process = SpawnChild("process_util_test_never_die"); - ASSERT_TRUE(child_process.IsValid()); - - EnsureProcessTerminated(child_process.Duplicate()); - - // Allow a generous timeout, to cope with slow/loaded test bots. - EXPECT_TRUE(child_process.WaitForExitWithTimeout( - TestTimeouts::action_max_timeout(), nullptr)); -} - -MULTIPROCESS_TEST_MAIN(process_util_test_never_die) { - while (1) { - PlatformThread::Sleep(TimeDelta::FromSeconds(500)); - } - return kSuccess; -} - -TEST_F(ProcessUtilTest, EnsureTerminationGracefulExit) { - test::ScopedTaskEnvironment task_environment; - - Process child_process = SpawnChild("process_util_test_die_immediately"); - ASSERT_TRUE(child_process.IsValid()); - - // Wait for the child process to actually exit. - child_process.Duplicate().WaitForExitWithTimeout( - TestTimeouts::action_max_timeout(), nullptr); - - EnsureProcessTerminated(child_process.Duplicate()); - - // Verify that the process is really, truly gone. - EXPECT_TRUE(child_process.WaitForExitWithTimeout( - TestTimeouts::action_max_timeout(), nullptr)); -} - -MULTIPROCESS_TEST_MAIN(process_util_test_die_immediately) { - return kSuccess; -} - -#if defined(OS_WIN) -// TODO(estade): if possible, port this test. -TEST_F(ProcessUtilTest, LaunchAsUser) { - UserTokenHandle token; - ASSERT_TRUE(OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token)); - LaunchOptions options; - options.as_user = token; - EXPECT_TRUE( - LaunchProcess(MakeCmdLine("SimpleChildProcess"), options).IsValid()); -} - -static const char kEventToTriggerHandleSwitch[] = "event-to-trigger-handle"; - -MULTIPROCESS_TEST_MAIN(TriggerEventChildProcess) { - std::string handle_value_string = - CommandLine::ForCurrentProcess()->GetSwitchValueASCII( - kEventToTriggerHandleSwitch); - CHECK(!handle_value_string.empty()); - - uint64_t handle_value_uint64; - CHECK(StringToUint64(handle_value_string, &handle_value_uint64)); - // Give ownership of the handle to |event|. - WaitableEvent event( - win::ScopedHandle(reinterpret_cast<HANDLE>(handle_value_uint64))); - - event.Signal(); - - return 0; -} - -TEST_F(ProcessUtilTest, InheritSpecifiedHandles) { - // Manually create the event, so that it can be inheritable. - SECURITY_ATTRIBUTES security_attributes = {}; - security_attributes.nLength = static_cast<DWORD>(sizeof(security_attributes)); - security_attributes.lpSecurityDescriptor = NULL; - security_attributes.bInheritHandle = true; - - // Takes ownership of the event handle. - WaitableEvent event( - win::ScopedHandle(CreateEvent(&security_attributes, true, false, NULL))); - LaunchOptions options; - options.handles_to_inherit.emplace_back(event.handle()); - - CommandLine cmd_line = MakeCmdLine("TriggerEventChildProcess"); - cmd_line.AppendSwitchASCII( - kEventToTriggerHandleSwitch, - NumberToString(reinterpret_cast<uint64_t>(event.handle()))); - - // Launch the process and wait for it to trigger the event. - ASSERT_TRUE(LaunchProcess(cmd_line, options).IsValid()); - EXPECT_TRUE(event.TimedWait(TestTimeouts::action_max_timeout())); -} -#endif // defined(OS_WIN) - -TEST_F(ProcessUtilTest, GetAppOutput) { - base::CommandLine command(test_helper_path_); - command.AppendArg("hello"); - command.AppendArg("there"); - command.AppendArg("good"); - command.AppendArg("people"); - std::string output; - EXPECT_TRUE(GetAppOutput(command, &output)); - EXPECT_EQ("hello there good people", output); - output.clear(); - - const char* kEchoMessage = "blah"; - command = base::CommandLine(test_helper_path_); - command.AppendArg("-x"); - command.AppendArg("28"); - command.AppendArg(kEchoMessage); - EXPECT_FALSE(GetAppOutput(command, &output)); - EXPECT_EQ(kEchoMessage, output); -} - -TEST_F(ProcessUtilTest, GetAppOutputWithExitCode) { - const char* kEchoMessage1 = "doge"; - int exit_code = -1; - base::CommandLine command(test_helper_path_); - command.AppendArg(kEchoMessage1); - std::string output; - EXPECT_TRUE(GetAppOutputWithExitCode(command, &output, &exit_code)); - EXPECT_EQ(kEchoMessage1, output); - EXPECT_EQ(0, exit_code); - output.clear(); - - const char* kEchoMessage2 = "pupper"; - const int kExpectedExitCode = 42; - command = base::CommandLine(test_helper_path_); - command.AppendArg("-x"); - command.AppendArg(base::IntToString(kExpectedExitCode)); - command.AppendArg(kEchoMessage2); -#if defined(OS_WIN) - // On Windows, anything that quits with a nonzero status code is handled as a - // "crash", so just ignore GetAppOutputWithExitCode's return value. - GetAppOutputWithExitCode(command, &output, &exit_code); -#elif defined(OS_POSIX) || defined(OS_FUCHSIA) - EXPECT_TRUE(GetAppOutputWithExitCode(command, &output, &exit_code)); -#endif - EXPECT_EQ(kEchoMessage2, output); - EXPECT_EQ(kExpectedExitCode, exit_code); -} - -#if defined(OS_POSIX) || defined(OS_FUCHSIA) - -namespace { - -// Returns the maximum number of files that a process can have open. -// Returns 0 on error. -int GetMaxFilesOpenInProcess() { -#if defined(OS_FUCHSIA) - return FDIO_MAX_FD; -#else - struct rlimit rlim; - if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) { - return 0; - } - - // rlim_t is a uint64_t - clip to maxint. We do this since FD #s are ints - // which are all 32 bits on the supported platforms. - rlim_t max_int = static_cast<rlim_t>(std::numeric_limits<int32_t>::max()); - if (rlim.rlim_cur > max_int) { - return max_int; - } - - return rlim.rlim_cur; -#endif // defined(OS_FUCHSIA) -} - -const int kChildPipe = 20; // FD # for write end of pipe in child process. - -#if defined(OS_MACOSX) - -// <http://opensource.apple.com/source/xnu/xnu-2422.1.72/bsd/sys/guarded.h> -#if !defined(_GUARDID_T) -#define _GUARDID_T -typedef __uint64_t guardid_t; -#endif // _GUARDID_T - -// From .../MacOSX10.9.sdk/usr/include/sys/syscall.h -#if !defined(SYS_change_fdguard_np) -#define SYS_change_fdguard_np 444 -#endif - -// <http://opensource.apple.com/source/xnu/xnu-2422.1.72/bsd/sys/guarded.h> -#if !defined(GUARD_DUP) -#define GUARD_DUP (1u << 1) -#endif - -// <http://opensource.apple.com/source/xnu/xnu-2422.1.72/bsd/kern/kern_guarded.c?txt> -// -// Atomically replaces |guard|/|guardflags| with |nguard|/|nguardflags| on |fd|. -int change_fdguard_np(int fd, - const guardid_t *guard, u_int guardflags, - const guardid_t *nguard, u_int nguardflags, - int *fdflagsp) { - return syscall(SYS_change_fdguard_np, fd, guard, guardflags, - nguard, nguardflags, fdflagsp); -} - -// Attempt to set a file-descriptor guard on |fd|. In case of success, remove -// it and return |true| to indicate that it can be guarded. Returning |false| -// means either that |fd| is guarded by some other code, or more likely EBADF. -// -// Starting with 10.9, libdispatch began setting GUARD_DUP on a file descriptor. -// Unfortunately, it is spun up as part of +[NSApplication initialize], which is -// not really something that Chromium can avoid using on OSX. See -// <http://crbug.com/338157>. This function allows querying whether the file -// descriptor is guarded before attempting to close it. -bool CanGuardFd(int fd) { - // Saves the original flags to reset later. - int original_fdflags = 0; - - // This can be any value at all, it just has to match up between the two - // calls. - const guardid_t kGuard = 15; - - // Attempt to change the guard. This can fail with EBADF if the file - // descriptor is bad, or EINVAL if the fd already has a guard set. - int ret = - change_fdguard_np(fd, NULL, 0, &kGuard, GUARD_DUP, &original_fdflags); - if (ret == -1) - return false; - - // Remove the guard. It should not be possible to fail in removing the guard - // just added. - ret = change_fdguard_np(fd, &kGuard, GUARD_DUP, NULL, 0, &original_fdflags); - DPCHECK(ret == 0); - - return true; -} -#endif // defined(OS_MACOSX) - -} // namespace - -MULTIPROCESS_TEST_MAIN(ProcessUtilsLeakFDChildProcess) { - // This child process counts the number of open FDs, it then writes that - // number out to a pipe connected to the parent. - int num_open_files = 0; - int write_pipe = kChildPipe; - int max_files = GetMaxFilesOpenInProcess(); - for (int i = STDERR_FILENO + 1; i < max_files; i++) { -#if defined(OS_MACOSX) - // Ignore guarded or invalid file descriptors. - if (!CanGuardFd(i)) - continue; -#endif - - if (i != kChildPipe) { - int fd; - if ((fd = HANDLE_EINTR(dup(i))) != -1) { - close(fd); - num_open_files += 1; - } - } - } - - int written = HANDLE_EINTR(write(write_pipe, &num_open_files, - sizeof(num_open_files))); - DCHECK_EQ(static_cast<size_t>(written), sizeof(num_open_files)); - int ret = IGNORE_EINTR(close(write_pipe)); - DPCHECK(ret == 0); - - return 0; -} - -int ProcessUtilTest::CountOpenFDsInChild() { - int fds[2]; - if (pipe(fds) < 0) - NOTREACHED(); - - LaunchOptions options; - options.fds_to_remap.emplace_back(fds[1], kChildPipe); - Process process = - SpawnChildWithOptions("ProcessUtilsLeakFDChildProcess", options); - CHECK(process.IsValid()); - int ret = IGNORE_EINTR(close(fds[1])); - DPCHECK(ret == 0); - - // Read number of open files in client process from pipe; - int num_open_files = -1; - ssize_t bytes_read = - HANDLE_EINTR(read(fds[0], &num_open_files, sizeof(num_open_files))); - CHECK_EQ(bytes_read, static_cast<ssize_t>(sizeof(num_open_files))); - -#if defined(THREAD_SANITIZER) - // Compiler-based ThreadSanitizer makes this test slow. - TimeDelta timeout = TimeDelta::FromSeconds(3); -#else - TimeDelta timeout = TimeDelta::FromSeconds(1); -#endif - int exit_code; - CHECK(process.WaitForExitWithTimeout(timeout, &exit_code)); - ret = IGNORE_EINTR(close(fds[0])); - DPCHECK(ret == 0); - - return num_open_files; -} - -#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) -// ProcessUtilTest.FDRemapping is flaky when ran under xvfb-run on Precise. -// The problem is 100% reproducible with both ASan and TSan. -// See http://crbug.com/136720. -#define MAYBE_FDRemapping DISABLED_FDRemapping -#else -#define MAYBE_FDRemapping FDRemapping -#endif // defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) -TEST_F(ProcessUtilTest, MAYBE_FDRemapping) { - int fds_before = CountOpenFDsInChild(); - - // open some dummy fds to make sure they don't propagate over to the - // child process. - int dev_null = open("/dev/null", O_RDONLY); - DPCHECK(dev_null != -1); - int sockets[2]; - int ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sockets); - DPCHECK(ret == 0); - - int fds_after = CountOpenFDsInChild(); - - ASSERT_EQ(fds_after, fds_before); - - ret = IGNORE_EINTR(close(sockets[0])); - DPCHECK(ret == 0); - ret = IGNORE_EINTR(close(sockets[1])); - DPCHECK(ret == 0); - ret = IGNORE_EINTR(close(dev_null)); - DPCHECK(ret == 0); -} - -const char kPipeValue = '\xcc'; -MULTIPROCESS_TEST_MAIN(ProcessUtilsVerifyStdio) { - // Write to stdio so the parent process can observe output. - CHECK_EQ(1, HANDLE_EINTR(write(STDOUT_FILENO, &kPipeValue, 1))); - - // Close all of the handles, to verify they are valid. - CHECK_EQ(0, IGNORE_EINTR(close(STDIN_FILENO))); - CHECK_EQ(0, IGNORE_EINTR(close(STDOUT_FILENO))); - CHECK_EQ(0, IGNORE_EINTR(close(STDERR_FILENO))); - return 0; -} - -TEST_F(ProcessUtilTest, FDRemappingIncludesStdio) { - int dev_null = open("/dev/null", O_RDONLY); - ASSERT_LT(2, dev_null); - - // Backup stdio and replace it with the write end of a pipe, for our - // child process to inherit. - int pipe_fds[2]; - int result = pipe(pipe_fds); - ASSERT_EQ(0, result); - int backup_stdio = HANDLE_EINTR(dup(STDOUT_FILENO)); - ASSERT_LE(0, backup_stdio); - result = dup2(pipe_fds[1], STDOUT_FILENO); - ASSERT_EQ(STDOUT_FILENO, result); - - // Launch the test process, which should inherit our pipe stdio. - LaunchOptions options; - options.fds_to_remap.emplace_back(dev_null, dev_null); - Process process = SpawnChildWithOptions("ProcessUtilsVerifyStdio", options); - ASSERT_TRUE(process.IsValid()); - - // Restore stdio, so we can output stuff. - result = dup2(backup_stdio, STDOUT_FILENO); - ASSERT_EQ(STDOUT_FILENO, result); - - // Close our copy of the write end of the pipe, so that the read() - // from the other end will see EOF if it wasn't copied to the child. - result = IGNORE_EINTR(close(pipe_fds[1])); - ASSERT_EQ(0, result); - - result = IGNORE_EINTR(close(backup_stdio)); - ASSERT_EQ(0, result); - result = IGNORE_EINTR(close(dev_null)); - ASSERT_EQ(0, result); - - // Read from the pipe to verify that it is connected to the child - // process' stdio. - char buf[16] = {}; - EXPECT_EQ(1, HANDLE_EINTR(read(pipe_fds[0], buf, sizeof(buf)))); - EXPECT_EQ(kPipeValue, buf[0]); - - result = IGNORE_EINTR(close(pipe_fds[0])); - ASSERT_EQ(0, result); - - int exit_code; - ASSERT_TRUE( - process.WaitForExitWithTimeout(TimeDelta::FromSeconds(5), &exit_code)); - EXPECT_EQ(0, exit_code); -} - -#if defined(OS_FUCHSIA) - -const uint16_t kStartupHandleId = 43; -MULTIPROCESS_TEST_MAIN(ProcessUtilsVerifyHandle) { - zx_handle_t handle = - zx_get_startup_handle(PA_HND(PA_USER0, kStartupHandleId)); - CHECK_NE(ZX_HANDLE_INVALID, handle); - - // Write to the pipe so the parent process can observe output. - size_t bytes_written = 0; - zx_status_t result = zx_socket_write(handle, 0, &kPipeValue, - sizeof(kPipeValue), &bytes_written); - CHECK_EQ(ZX_OK, result); - CHECK_EQ(1u, bytes_written); - - CHECK_EQ(ZX_OK, zx_handle_close(handle)); - return 0; -} - -TEST_F(ProcessUtilTest, LaunchWithHandleTransfer) { - // Create a pipe to pass to the child process. - zx_handle_t handles[2]; - zx_status_t result = - zx_socket_create(ZX_SOCKET_STREAM, &handles[0], &handles[1]); - ASSERT_EQ(ZX_OK, result); - - // Launch the test process, and pass it one end of the pipe. - LaunchOptions options; - options.handles_to_transfer.push_back( - {PA_HND(PA_USER0, kStartupHandleId), handles[0]}); - Process process = SpawnChildWithOptions("ProcessUtilsVerifyHandle", options); - ASSERT_TRUE(process.IsValid()); - - // Read from the pipe to verify that the child received it. - zx_signals_t signals = 0; - result = zx_object_wait_one( - handles[1], ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED, - (base::TimeTicks::Now() + TestTimeouts::action_timeout()).ToZxTime(), - &signals); - ASSERT_EQ(ZX_OK, result); - ASSERT_TRUE(signals & ZX_SOCKET_READABLE); - - size_t bytes_read = 0; - char buf[16] = {0}; - result = zx_socket_read(handles[1], 0, buf, sizeof(buf), &bytes_read); - EXPECT_EQ(ZX_OK, result); - EXPECT_EQ(1u, bytes_read); - EXPECT_EQ(kPipeValue, buf[0]); - - CHECK_EQ(ZX_OK, zx_handle_close(handles[1])); - - int exit_code; - ASSERT_TRUE(process.WaitForExitWithTimeout(TestTimeouts::action_timeout(), - &exit_code)); - EXPECT_EQ(0, exit_code); -} - -#endif // defined(OS_FUCHSIA) - -namespace { - -std::string TestLaunchProcess(const std::vector<std::string>& args, - const EnvironmentMap& env_changes, - const bool clear_environ, - const int clone_flags) { - int fds[2]; - PCHECK(pipe(fds) == 0); - - LaunchOptions options; - options.wait = true; - options.environ = env_changes; - options.clear_environ = clear_environ; - options.fds_to_remap.emplace_back(fds[1], 1); -#if defined(OS_LINUX) - options.clone_flags = clone_flags; -#else - CHECK_EQ(0, clone_flags); -#endif // defined(OS_LINUX) - EXPECT_TRUE(LaunchProcess(args, options).IsValid()); - PCHECK(IGNORE_EINTR(close(fds[1])) == 0); - - char buf[512]; - const ssize_t n = HANDLE_EINTR(read(fds[0], buf, sizeof(buf))); - - PCHECK(IGNORE_EINTR(close(fds[0])) == 0); - - return std::string(buf, n); -} - -const char kLargeString[] = - "0123456789012345678901234567890123456789012345678901234567890123456789" - "0123456789012345678901234567890123456789012345678901234567890123456789" - "0123456789012345678901234567890123456789012345678901234567890123456789" - "0123456789012345678901234567890123456789012345678901234567890123456789" - "0123456789012345678901234567890123456789012345678901234567890123456789" - "0123456789012345678901234567890123456789012345678901234567890123456789" - "0123456789012345678901234567890123456789012345678901234567890123456789"; - -} // namespace - -TEST_F(ProcessUtilTest, LaunchProcess) { - const int no_clone_flags = 0; - const bool no_clear_environ = false; - const char kBaseTest[] = "BASE_TEST"; - const std::vector<std::string> kPrintEnvCommand = {test_helper_path_.value(), - "-e", kBaseTest}; - - EnvironmentMap env_changes; - env_changes[kBaseTest] = "bar"; - EXPECT_EQ("bar", TestLaunchProcess(kPrintEnvCommand, env_changes, - no_clear_environ, no_clone_flags)); - env_changes.clear(); - - EXPECT_EQ(0, setenv(kBaseTest, "testing", 1 /* override */)); - EXPECT_EQ("testing", TestLaunchProcess(kPrintEnvCommand, env_changes, - no_clear_environ, no_clone_flags)); - - env_changes[kBaseTest] = std::string(); - EXPECT_EQ("", TestLaunchProcess(kPrintEnvCommand, env_changes, - no_clear_environ, no_clone_flags)); - - env_changes[kBaseTest] = "foo"; - EXPECT_EQ("foo", TestLaunchProcess(kPrintEnvCommand, env_changes, - no_clear_environ, no_clone_flags)); - - env_changes.clear(); - EXPECT_EQ(0, setenv(kBaseTest, kLargeString, 1 /* override */)); - EXPECT_EQ(std::string(kLargeString), - TestLaunchProcess(kPrintEnvCommand, env_changes, no_clear_environ, - no_clone_flags)); - - env_changes[kBaseTest] = "wibble"; - EXPECT_EQ("wibble", TestLaunchProcess(kPrintEnvCommand, env_changes, - no_clear_environ, no_clone_flags)); - -#if defined(OS_LINUX) - // Test a non-trival value for clone_flags. - EXPECT_EQ("wibble", TestLaunchProcess(kPrintEnvCommand, env_changes, - no_clear_environ, CLONE_FS)); - - EXPECT_EQ("wibble", - TestLaunchProcess(kPrintEnvCommand, env_changes, - true /* clear_environ */, no_clone_flags)); - env_changes.clear(); - EXPECT_EQ("", TestLaunchProcess(kPrintEnvCommand, env_changes, - true /* clear_environ */, no_clone_flags)); -#endif // defined(OS_LINUX) -} - -// There's no such thing as a parent process id on Fuchsia. -#if !defined(OS_FUCHSIA) -TEST_F(ProcessUtilTest, GetParentProcessId) { - ProcessId ppid = GetParentProcessId(GetCurrentProcessHandle()); - EXPECT_EQ(ppid, static_cast<ProcessId>(getppid())); -} -#endif // !defined(OS_FUCHSIA) - -#if !defined(OS_ANDROID) && !defined(OS_FUCHSIA) -class WriteToPipeDelegate : public LaunchOptions::PreExecDelegate { - public: - explicit WriteToPipeDelegate(int fd) : fd_(fd) {} - ~WriteToPipeDelegate() override = default; - void RunAsyncSafe() override { - RAW_CHECK(HANDLE_EINTR(write(fd_, &kPipeValue, 1)) == 1); - RAW_CHECK(IGNORE_EINTR(close(fd_)) == 0); - } - - private: - int fd_; - DISALLOW_COPY_AND_ASSIGN(WriteToPipeDelegate); -}; - -TEST_F(ProcessUtilTest, PreExecHook) { - int pipe_fds[2]; - ASSERT_EQ(0, pipe(pipe_fds)); - - ScopedFD read_fd(pipe_fds[0]); - ScopedFD write_fd(pipe_fds[1]); - - WriteToPipeDelegate write_to_pipe_delegate(write_fd.get()); - LaunchOptions options; - options.fds_to_remap.emplace_back(write_fd.get(), write_fd.get()); - options.pre_exec_delegate = &write_to_pipe_delegate; - Process process(SpawnChildWithOptions("SimpleChildProcess", options)); - ASSERT_TRUE(process.IsValid()); - - write_fd.reset(); - char c; - ASSERT_EQ(1, HANDLE_EINTR(read(read_fd.get(), &c, 1))); - EXPECT_EQ(c, kPipeValue); - - int exit_code = 42; - EXPECT_TRUE(process.WaitForExit(&exit_code)); - EXPECT_EQ(0, exit_code); -} -#endif // !defined(OS_ANDROID) && !defined(OS_FUCHSIA) - -#endif // !defined(OS_MACOSX) && !defined(OS_ANDROID) - -#if defined(OS_LINUX) -MULTIPROCESS_TEST_MAIN(CheckPidProcess) { - const pid_t kInitPid = 1; - const pid_t pid = syscall(__NR_getpid); - CHECK(pid == kInitPid); - CHECK(getpid() == pid); - return kSuccess; -} - -#if defined(CLONE_NEWUSER) && defined(CLONE_NEWPID) -TEST_F(ProcessUtilTest, CloneFlags) { - if (!PathExists(FilePath("/proc/self/ns/user")) || - !PathExists(FilePath("/proc/self/ns/pid"))) { - // User or PID namespaces are not supported. - return; - } - - LaunchOptions options; - options.clone_flags = CLONE_NEWUSER | CLONE_NEWPID; - - Process process(SpawnChildWithOptions("CheckPidProcess", options)); - ASSERT_TRUE(process.IsValid()); - - int exit_code = 42; - EXPECT_TRUE(process.WaitForExit(&exit_code)); - EXPECT_EQ(kSuccess, exit_code); -} -#endif // defined(CLONE_NEWUSER) && defined(CLONE_NEWPID) - -TEST(ForkWithFlagsTest, UpdatesPidCache) { - // Warm up the libc pid cache, if there is one. - ASSERT_EQ(syscall(__NR_getpid), getpid()); - - pid_t ctid = 0; - const pid_t pid = ForkWithFlags(SIGCHLD | CLONE_CHILD_SETTID, nullptr, &ctid); - if (pid == 0) { - // In child. Check both the raw getpid syscall and the libc getpid wrapper - // (which may rely on a pid cache). - RAW_CHECK(syscall(__NR_getpid) == ctid); - RAW_CHECK(getpid() == ctid); - _exit(kSuccess); - } - - ASSERT_NE(-1, pid); - int status = 42; - ASSERT_EQ(pid, HANDLE_EINTR(waitpid(pid, &status, 0))); - ASSERT_TRUE(WIFEXITED(status)); - EXPECT_EQ(kSuccess, WEXITSTATUS(status)); -} - -TEST_F(ProcessUtilTest, InvalidCurrentDirectory) { - LaunchOptions options; - options.current_directory = FilePath("/dev/null"); - - Process process(SpawnChildWithOptions("SimpleChildProcess", options)); - ASSERT_TRUE(process.IsValid()); - - int exit_code = kSuccess; - EXPECT_TRUE(process.WaitForExit(&exit_code)); - EXPECT_NE(kSuccess, exit_code); -} -#endif // defined(OS_LINUX) - -} // namespace base
diff --git a/base/profiler/stack_sampling_profiler_unittest.cc b/base/profiler/stack_sampling_profiler_unittest.cc deleted file mode 100644 index b25943f..0000000 --- a/base/profiler/stack_sampling_profiler_unittest.cc +++ /dev/null
@@ -1,1506 +0,0 @@ -// 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 <stddef.h> -#include <stdint.h> - -#include <algorithm> -#include <cstdlib> -#include <memory> -#include <utility> -#include <vector> - -#include "base/bind.h" -#include "base/compiler_specific.h" -#include "base/files/file_util.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/native_library.h" -#include "base/path_service.h" -#include "base/profiler/native_stack_sampler.h" -#include "base/profiler/stack_sampling_profiler.h" -#include "base/run_loop.h" -#include "base/scoped_native_library.h" -#include "base/strings/stringprintf.h" -#include "base/strings/utf_string_conversions.h" -#include "base/synchronization/lock.h" -#include "base/synchronization/waitable_event.h" -#include "base/threading/platform_thread.h" -#include "base/threading/simple_thread.h" -#include "base/time/time.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(OS_WIN) -#include <intrin.h> -#include <malloc.h> -#include <windows.h> -#else -#include <alloca.h> -#endif - -// STACK_SAMPLING_PROFILER_SUPPORTED is used to conditionally enable the tests -// below for supported platforms (currently Win x64 and Mac x64). -#if defined(_WIN64) || (defined(OS_MACOSX) && !defined(OS_IOS)) -#define STACK_SAMPLING_PROFILER_SUPPORTED 1 -#endif - -#if defined(OS_WIN) -#pragma intrinsic(_ReturnAddress) -#endif - -namespace base { - -#if defined(STACK_SAMPLING_PROFILER_SUPPORTED) -#define PROFILER_TEST_F(TestClass, TestName) TEST_F(TestClass, TestName) -#else -#define PROFILER_TEST_F(TestClass, TestName) \ - TEST_F(TestClass, DISABLED_##TestName) -#endif - -using SamplingParams = StackSamplingProfiler::SamplingParams; -using Frame = StackSamplingProfiler::Frame; -using Frames = std::vector<StackSamplingProfiler::Frame>; -using Module = StackSamplingProfiler::Module; -using Sample = StackSamplingProfiler::Sample; -using CallStackProfile = StackSamplingProfiler::CallStackProfile; -using CallStackProfiles = StackSamplingProfiler::CallStackProfiles; - -namespace { - -// Configuration for the frames that appear on the stack. -struct StackConfiguration { - enum Config { NORMAL, WITH_ALLOCA, WITH_OTHER_LIBRARY }; - - explicit StackConfiguration(Config config) - : StackConfiguration(config, nullptr) { - EXPECT_NE(config, WITH_OTHER_LIBRARY); - } - - StackConfiguration(Config config, NativeLibrary library) - : config(config), library(library) { - EXPECT_TRUE(config != WITH_OTHER_LIBRARY || library); - } - - Config config; - - // Only used if config == WITH_OTHER_LIBRARY. - NativeLibrary library; -}; - -// Signature for a target function that is expected to appear in the stack. See -// SignalAndWaitUntilSignaled() below. The return value should be a program -// counter pointer near the end of the function. -using TargetFunction = const void*(*)(WaitableEvent*, WaitableEvent*, - const StackConfiguration*); - -// A thread to target for profiling, whose stack is guaranteed to contain -// SignalAndWaitUntilSignaled() when coordinated with the main thread. -class TargetThread : public PlatformThread::Delegate { - public: - explicit TargetThread(const StackConfiguration& stack_config); - - // PlatformThread::Delegate: - void ThreadMain() override; - - // Waits for the thread to have started and be executing in - // SignalAndWaitUntilSignaled(). - void WaitForThreadStart(); - - // Allows the thread to return from SignalAndWaitUntilSignaled() and finish - // execution. - void SignalThreadToFinish(); - - // This function is guaranteed to be executing between calls to - // WaitForThreadStart() and SignalThreadToFinish() when invoked with - // |thread_started_event_| and |finish_event_|. Returns a program counter - // value near the end of the function. May be invoked with null WaitableEvents - // to just return the program counter. - // - // This function is static so that we can get a straightforward address - // for it in one of the tests below, rather than dealing with the complexity - // of a member function pointer representation. - static const void* SignalAndWaitUntilSignaled( - WaitableEvent* thread_started_event, - WaitableEvent* finish_event, - const StackConfiguration* stack_config); - - // Calls into SignalAndWaitUntilSignaled() after allocating memory on the - // stack with alloca. - static const void* CallWithAlloca(WaitableEvent* thread_started_event, - WaitableEvent* finish_event, - const StackConfiguration* stack_config); - - // Calls into SignalAndWaitUntilSignaled() via a function in - // base_profiler_test_support_library. - static const void* CallThroughOtherLibrary( - WaitableEvent* thread_started_event, - WaitableEvent* finish_event, - const StackConfiguration* stack_config); - - PlatformThreadId id() const { return id_; } - - private: - struct TargetFunctionArgs { - WaitableEvent* thread_started_event; - WaitableEvent* finish_event; - const StackConfiguration* stack_config; - }; - - // Callback function to be provided when calling through the other library. - static void OtherLibraryCallback(void *arg); - - // Returns the current program counter, or a value very close to it. - static const void* GetProgramCounter(); - - WaitableEvent thread_started_event_; - WaitableEvent finish_event_; - PlatformThreadId id_; - const StackConfiguration stack_config_; - - DISALLOW_COPY_AND_ASSIGN(TargetThread); -}; - -TargetThread::TargetThread(const StackConfiguration& stack_config) - : thread_started_event_(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED), - finish_event_(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED), - id_(0), - stack_config_(stack_config) {} - -void TargetThread::ThreadMain() { - id_ = PlatformThread::CurrentId(); - switch (stack_config_.config) { - case StackConfiguration::NORMAL: - SignalAndWaitUntilSignaled(&thread_started_event_, &finish_event_, - &stack_config_); - break; - - case StackConfiguration::WITH_ALLOCA: - CallWithAlloca(&thread_started_event_, &finish_event_, &stack_config_); - break; - - case StackConfiguration::WITH_OTHER_LIBRARY: - CallThroughOtherLibrary(&thread_started_event_, &finish_event_, - &stack_config_); - break; - } -} - -void TargetThread::WaitForThreadStart() { - thread_started_event_.Wait(); -} - -void TargetThread::SignalThreadToFinish() { - finish_event_.Signal(); -} - -// static -// Disable inlining for this function so that it gets its own stack frame. -NOINLINE const void* TargetThread::SignalAndWaitUntilSignaled( - WaitableEvent* thread_started_event, - WaitableEvent* finish_event, - const StackConfiguration* stack_config) { - if (thread_started_event && finish_event) { - thread_started_event->Signal(); - finish_event->Wait(); - } - - // Volatile to prevent a tail call to GetProgramCounter(). - const void* volatile program_counter = GetProgramCounter(); - return program_counter; -} - -// static -// Disable inlining for this function so that it gets its own stack frame. -NOINLINE const void* TargetThread::CallWithAlloca( - WaitableEvent* thread_started_event, - WaitableEvent* finish_event, - const StackConfiguration* stack_config) { - const size_t alloca_size = 100; - // Memset to 0 to generate a clean failure. - std::memset(alloca(alloca_size), 0, alloca_size); - - SignalAndWaitUntilSignaled(thread_started_event, finish_event, stack_config); - - // Volatile to prevent a tail call to GetProgramCounter(). - const void* volatile program_counter = GetProgramCounter(); - return program_counter; -} - -// static -NOINLINE const void* TargetThread::CallThroughOtherLibrary( - WaitableEvent* thread_started_event, - WaitableEvent* finish_event, - const StackConfiguration* stack_config) { - if (stack_config) { - // A function whose arguments are a function accepting void*, and a void*. - using InvokeCallbackFunction = void(*)(void (*)(void*), void*); - EXPECT_TRUE(stack_config->library); - InvokeCallbackFunction function = reinterpret_cast<InvokeCallbackFunction>( - GetFunctionPointerFromNativeLibrary(stack_config->library, - "InvokeCallbackFunction")); - EXPECT_TRUE(function); - - TargetFunctionArgs args = { - thread_started_event, - finish_event, - stack_config - }; - (*function)(&OtherLibraryCallback, &args); - } - - // Volatile to prevent a tail call to GetProgramCounter(). - const void* volatile program_counter = GetProgramCounter(); - return program_counter; -} - -// static -void TargetThread::OtherLibraryCallback(void *arg) { - const TargetFunctionArgs* args = static_cast<TargetFunctionArgs*>(arg); - SignalAndWaitUntilSignaled(args->thread_started_event, args->finish_event, - args->stack_config); - // Prevent tail call. - volatile int i = 0; - ALLOW_UNUSED_LOCAL(i); -} - -// static -// Disable inlining for this function so that it gets its own stack frame. -NOINLINE const void* TargetThread::GetProgramCounter() { -#if defined(OS_WIN) - return _ReturnAddress(); -#else - return __builtin_return_address(0); -#endif -} - -// Loads the other library, which defines a function to be called in the -// WITH_OTHER_LIBRARY configuration. -NativeLibrary LoadOtherLibrary() { - // The lambda gymnastics works around the fact that we can't use ASSERT_* - // macros in a function returning non-null. - const auto load = [](NativeLibrary* library) { - FilePath other_library_path; - ASSERT_TRUE(PathService::Get(DIR_EXE, &other_library_path)); - other_library_path = other_library_path.AppendASCII( - GetNativeLibraryName("base_profiler_test_support_library")); - NativeLibraryLoadError load_error; - *library = LoadNativeLibrary(other_library_path, &load_error); - ASSERT_TRUE(*library) << "error loading " << other_library_path.value() - << ": " << load_error.ToString(); - }; - - NativeLibrary library = nullptr; - load(&library); - return library; -} - -// Unloads |library| and returns when it has completed unloading. Unloading a -// library is asynchronous on Windows, so simply calling UnloadNativeLibrary() -// is insufficient to ensure it's been unloaded. -void SynchronousUnloadNativeLibrary(NativeLibrary library) { - UnloadNativeLibrary(library); -#if defined(OS_WIN) - // NativeLibrary is a typedef for HMODULE, which is actually the base address - // of the module. - uintptr_t module_base_address = reinterpret_cast<uintptr_t>(library); - HMODULE module_handle; - // Keep trying to get the module handle until the call fails. - while (::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | - GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, - reinterpret_cast<LPCTSTR>(module_base_address), - &module_handle) || - ::GetLastError() != ERROR_MOD_NOT_FOUND) { - PlatformThread::Sleep(TimeDelta::FromMilliseconds(1)); - } -#elif defined(OS_MACOSX) -// Unloading a library on the Mac is synchronous. -#else - NOTIMPLEMENTED(); -#endif -} - -// Called on the profiler thread when complete, to collect profiles. -void SaveProfiles(CallStackProfiles* profiles, - CallStackProfiles pending_profiles) { - *profiles = std::move(pending_profiles); -} - -// Called on the profiler thread when complete. Collects profiles produced by -// the profiler, and signals an event to allow the main thread to know that that -// the profiler is done. -void SaveProfilesAndSignalEvent(CallStackProfiles* profiles, - WaitableEvent* event, - CallStackProfiles pending_profiles) { - *profiles = std::move(pending_profiles); - event->Signal(); -} - -// Executes the function with the target thread running and executing within -// SignalAndWaitUntilSignaled(). Performs all necessary target thread startup -// and shutdown work before and afterward. -template <class Function> -void WithTargetThread(Function function, - const StackConfiguration& stack_config) { - TargetThread target_thread(stack_config); - PlatformThreadHandle target_thread_handle; - EXPECT_TRUE(PlatformThread::Create(0, &target_thread, &target_thread_handle)); - - target_thread.WaitForThreadStart(); - - function(target_thread.id()); - - target_thread.SignalThreadToFinish(); - - PlatformThread::Join(target_thread_handle); -} - -template <class Function> -void WithTargetThread(Function function) { - WithTargetThread(function, StackConfiguration(StackConfiguration::NORMAL)); -} - -struct TestProfilerInfo { - TestProfilerInfo(PlatformThreadId thread_id, - const SamplingParams& params, - NativeStackSamplerTestDelegate* delegate = nullptr) - : completed(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED), - profiler(thread_id, - params, - Bind(&SaveProfilesAndSignalEvent, - Unretained(&profiles), - Unretained(&completed)), - delegate) {} - - // The order here is important to ensure objects being referenced don't get - // destructed until after the objects referencing them. - CallStackProfiles profiles; - WaitableEvent completed; - StackSamplingProfiler profiler; - - private: - DISALLOW_COPY_AND_ASSIGN(TestProfilerInfo); -}; - -// Creates multiple profilers based on a vector of parameters. -std::vector<std::unique_ptr<TestProfilerInfo>> CreateProfilers( - PlatformThreadId target_thread_id, - const std::vector<SamplingParams>& params) { - DCHECK(!params.empty()); - - std::vector<std::unique_ptr<TestProfilerInfo>> profilers; - for (size_t i = 0; i < params.size(); ++i) { - profilers.push_back( - std::make_unique<TestProfilerInfo>(target_thread_id, params[i])); - } - - return profilers; -} - -// Captures profiles as specified by |params| on the TargetThread, and returns -// them in |profiles|. Waits up to |profiler_wait_time| for the profiler to -// complete. -void CaptureProfiles(const SamplingParams& params, TimeDelta profiler_wait_time, - CallStackProfiles* profiles) { - WithTargetThread([¶ms, profiles, - profiler_wait_time](PlatformThreadId target_thread_id) { - TestProfilerInfo info(target_thread_id, params); - info.profiler.Start(); - info.completed.TimedWait(profiler_wait_time); - info.profiler.Stop(); - info.completed.Wait(); - - *profiles = std::move(info.profiles); - }); -} - -// Waits for one of multiple samplings to complete. -size_t WaitForSamplingComplete( - const std::vector<std::unique_ptr<TestProfilerInfo>>& infos) { - // Map unique_ptrs to something that WaitMany can accept. - std::vector<WaitableEvent*> sampling_completed_rawptrs(infos.size()); - std::transform(infos.begin(), infos.end(), sampling_completed_rawptrs.begin(), - [](const std::unique_ptr<TestProfilerInfo>& info) { - return &info.get()->completed; - }); - // Wait for one profiler to finish. - return WaitableEvent::WaitMany(sampling_completed_rawptrs.data(), - sampling_completed_rawptrs.size()); -} - -// If this executable was linked with /INCREMENTAL (the default for non-official -// debug and release builds on Windows), function addresses do not correspond to -// function code itself, but instead to instructions in the Incremental Link -// Table that jump to the functions. Checks for a jump instruction and if -// present does a little decompilation to find the function's actual starting -// address. -const void* MaybeFixupFunctionAddressForILT(const void* function_address) { -#if defined(_WIN64) - const unsigned char* opcode = - reinterpret_cast<const unsigned char*>(function_address); - if (*opcode == 0xe9) { - // This is a relative jump instruction. Assume we're in the ILT and compute - // the function start address from the instruction offset. - const int32_t* offset = reinterpret_cast<const int32_t*>(opcode + 1); - const unsigned char* next_instruction = - reinterpret_cast<const unsigned char*>(offset + 1); - return next_instruction + *offset; - } -#endif - return function_address; -} - -// Searches through the frames in |sample|, returning an iterator to the first -// frame that has an instruction pointer within |target_function|. Returns -// sample.end() if no such frames are found. -Frames::const_iterator FindFirstFrameWithinFunction( - const Sample& sample, - TargetFunction target_function) { - uintptr_t function_start = reinterpret_cast<uintptr_t>( - MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>( - target_function))); - uintptr_t function_end = - reinterpret_cast<uintptr_t>(target_function(nullptr, nullptr, nullptr)); - for (auto it = sample.frames.begin(); it != sample.frames.end(); ++it) { - if ((it->instruction_pointer >= function_start) && - (it->instruction_pointer <= function_end)) - return it; - } - return sample.frames.end(); -} - -// Formats a sample into a string that can be output for test diagnostics. -std::string FormatSampleForDiagnosticOutput( - const Sample& sample, - const std::vector<Module>& modules) { - std::string output; - for (const Frame& frame : sample.frames) { - output += StringPrintf( - "0x%p %s\n", reinterpret_cast<const void*>(frame.instruction_pointer), - modules[frame.module_index].filename.AsUTF8Unsafe().c_str()); - } - return output; -} - -// Returns a duration that is longer than the test timeout. We would use -// TimeDelta::Max() but https://crbug.com/465948. -TimeDelta AVeryLongTimeDelta() { return TimeDelta::FromDays(1); } - -// Tests the scenario where the library is unloaded after copying the stack, but -// before walking it. If |wait_until_unloaded| is true, ensures that the -// asynchronous library loading has completed before walking the stack. If -// false, the unloading may still be occurring during the stack walk. -void TestLibraryUnload(bool wait_until_unloaded) { - // Test delegate that supports intervening between the copying of the stack - // and the walking of the stack. - class StackCopiedSignaler : public NativeStackSamplerTestDelegate { - public: - StackCopiedSignaler(WaitableEvent* stack_copied, - WaitableEvent* start_stack_walk, - bool wait_to_walk_stack) - : stack_copied_(stack_copied), - start_stack_walk_(start_stack_walk), - wait_to_walk_stack_(wait_to_walk_stack) {} - - void OnPreStackWalk() override { - stack_copied_->Signal(); - if (wait_to_walk_stack_) - start_stack_walk_->Wait(); - } - - private: - WaitableEvent* const stack_copied_; - WaitableEvent* const start_stack_walk_; - const bool wait_to_walk_stack_; - }; - - SamplingParams params; - params.sampling_interval = TimeDelta::FromMilliseconds(0); - params.samples_per_burst = 1; - - NativeLibrary other_library = LoadOtherLibrary(); - TargetThread target_thread(StackConfiguration( - StackConfiguration::WITH_OTHER_LIBRARY, - other_library)); - - PlatformThreadHandle target_thread_handle; - EXPECT_TRUE(PlatformThread::Create(0, &target_thread, &target_thread_handle)); - - target_thread.WaitForThreadStart(); - - WaitableEvent sampling_thread_completed( - WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - std::vector<CallStackProfile> profiles; - const StackSamplingProfiler::CompletedCallback callback = - Bind(&SaveProfilesAndSignalEvent, Unretained(&profiles), - Unretained(&sampling_thread_completed)); - WaitableEvent stack_copied(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - WaitableEvent start_stack_walk(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - StackCopiedSignaler test_delegate(&stack_copied, &start_stack_walk, - wait_until_unloaded); - StackSamplingProfiler profiler(target_thread.id(), params, callback, - &test_delegate); - - profiler.Start(); - - // Wait for the stack to be copied and the target thread to be resumed. - stack_copied.Wait(); - - // Cause the target thread to finish, so that it's no longer executing code in - // the library we're about to unload. - target_thread.SignalThreadToFinish(); - PlatformThread::Join(target_thread_handle); - - // Unload the library now that it's not being used. - if (wait_until_unloaded) - SynchronousUnloadNativeLibrary(other_library); - else - UnloadNativeLibrary(other_library); - - // Let the stack walk commence after unloading the library, if we're waiting - // on that event. - start_stack_walk.Signal(); - - // Wait for the sampling thread to complete and fill out |profiles|. - sampling_thread_completed.Wait(); - - // Look up the sample. - ASSERT_EQ(1u, profiles.size()); - const CallStackProfile& profile = profiles[0]; - ASSERT_EQ(1u, profile.samples.size()); - const Sample& sample = profile.samples[0]; - - // Check that the stack contains a frame for - // TargetThread::SignalAndWaitUntilSignaled(). - Frames::const_iterator end_frame = FindFirstFrameWithinFunction( - sample, &TargetThread::SignalAndWaitUntilSignaled); - ASSERT_TRUE(end_frame != sample.frames.end()) - << "Function at " - << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>( - &TargetThread::SignalAndWaitUntilSignaled)) - << " was not found in stack:\n" - << FormatSampleForDiagnosticOutput(sample, profile.modules); - - if (wait_until_unloaded) { - // The stack should look like this, resulting one frame after - // SignalAndWaitUntilSignaled. The frame in the now-unloaded library is not - // recorded since we can't get module information. - // - // ... WaitableEvent and system frames ... - // TargetThread::SignalAndWaitUntilSignaled - // TargetThread::OtherLibraryCallback - EXPECT_EQ(2, sample.frames.end() - end_frame) - << "Stack:\n" - << FormatSampleForDiagnosticOutput(sample, profile.modules); - } else { - // We didn't wait for the asynchronous unloading to complete, so the results - // are non-deterministic: if the library finished unloading we should have - // the same stack as |wait_until_unloaded|, if not we should have the full - // stack. The important thing is that we should not crash. - - if (sample.frames.end() - end_frame == 2) { - // This is the same case as |wait_until_unloaded|. - return; - } - - // Check that the stack contains a frame for - // TargetThread::CallThroughOtherLibrary(). - Frames::const_iterator other_library_frame = FindFirstFrameWithinFunction( - sample, &TargetThread::CallThroughOtherLibrary); - ASSERT_TRUE(other_library_frame != sample.frames.end()) - << "Function at " - << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>( - &TargetThread::CallThroughOtherLibrary)) - << " was not found in stack:\n" - << FormatSampleForDiagnosticOutput(sample, profile.modules); - - // The stack should look like this, resulting in three frames between - // SignalAndWaitUntilSignaled and CallThroughOtherLibrary: - // - // ... WaitableEvent and system frames ... - // TargetThread::SignalAndWaitUntilSignaled - // TargetThread::OtherLibraryCallback - // InvokeCallbackFunction (in other library) - // TargetThread::CallThroughOtherLibrary - EXPECT_EQ(3, other_library_frame - end_frame) - << "Stack:\n" - << FormatSampleForDiagnosticOutput(sample, profile.modules); - } -} - -// Provide a suitable (and clean) environment for the tests below. All tests -// must use this class to ensure that proper clean-up is done and thus be -// usable in a later test. -class StackSamplingProfilerTest : public testing::Test { - public: - void SetUp() override { - // The idle-shutdown time is too long for convenient (and accurate) testing. - // That behavior is checked instead by artificially triggering it through - // the TestAPI. - StackSamplingProfiler::TestAPI::DisableIdleShutdown(); - } - - void TearDown() override { - // Be a good citizen and clean up after ourselves. This also re-enables the - // idle-shutdown behavior. - StackSamplingProfiler::TestAPI::Reset(); - } -}; - -} // namespace - -// Checks that the basic expected information is present in a sampled call stack -// profile. -// macOS ASAN is not yet supported - crbug.com/718628. -#if !(defined(ADDRESS_SANITIZER) && defined(OS_MACOSX)) -#define MAYBE_Basic Basic -#else -#define MAYBE_Basic DISABLED_Basic -#endif -PROFILER_TEST_F(StackSamplingProfilerTest, MAYBE_Basic) { - SamplingParams params; - params.sampling_interval = TimeDelta::FromMilliseconds(0); - params.samples_per_burst = 1; - - std::vector<CallStackProfile> profiles; - CaptureProfiles(params, AVeryLongTimeDelta(), &profiles); - - // Check that the profile and samples sizes are correct, and the module - // indices are in range. - ASSERT_EQ(1u, profiles.size()); - const CallStackProfile& profile = profiles[0]; - ASSERT_EQ(1u, profile.samples.size()); - EXPECT_EQ(params.sampling_interval, profile.sampling_period); - const Sample& sample = profile.samples[0]; - EXPECT_EQ(0u, sample.process_milestones); - for (const auto& frame : sample.frames) { - ASSERT_GE(frame.module_index, 0u); - ASSERT_LT(frame.module_index, profile.modules.size()); - } - - // Check that the stack contains a frame for - // TargetThread::SignalAndWaitUntilSignaled() and that the frame has this - // executable's module. - Frames::const_iterator loc = FindFirstFrameWithinFunction( - sample, &TargetThread::SignalAndWaitUntilSignaled); - ASSERT_TRUE(loc != sample.frames.end()) - << "Function at " - << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>( - &TargetThread::SignalAndWaitUntilSignaled)) - << " was not found in stack:\n" - << FormatSampleForDiagnosticOutput(sample, profile.modules); - FilePath executable_path; - EXPECT_TRUE(PathService::Get(FILE_EXE, &executable_path)); - EXPECT_EQ(executable_path, - MakeAbsoluteFilePath(profile.modules[loc->module_index].filename)); -} - -// Checks that annotations are recorded in samples. -PROFILER_TEST_F(StackSamplingProfilerTest, Annotations) { - SamplingParams params; - params.sampling_interval = TimeDelta::FromMilliseconds(0); - params.samples_per_burst = 1; - - // Check that a run picks up annotations. - StackSamplingProfiler::SetProcessMilestone(1); - std::vector<CallStackProfile> profiles1; - CaptureProfiles(params, AVeryLongTimeDelta(), &profiles1); - ASSERT_EQ(1u, profiles1.size()); - const CallStackProfile& profile1 = profiles1[0]; - ASSERT_EQ(1u, profile1.samples.size()); - const Sample& sample1 = profile1.samples[0]; - EXPECT_EQ(1u << 1, sample1.process_milestones); - - // Run it a second time but with changed annotations. These annotations - // should appear in the first acquired sample. - StackSamplingProfiler::SetProcessMilestone(2); - std::vector<CallStackProfile> profiles2; - CaptureProfiles(params, AVeryLongTimeDelta(), &profiles2); - ASSERT_EQ(1u, profiles2.size()); - const CallStackProfile& profile2 = profiles2[0]; - ASSERT_EQ(1u, profile2.samples.size()); - const Sample& sample2 = profile2.samples[0]; - EXPECT_EQ(sample1.process_milestones | (1u << 2), sample2.process_milestones); -} - -// Checks that the profiler handles stacks containing dynamically-allocated -// stack memory. -// macOS ASAN is not yet supported - crbug.com/718628. -#if !(defined(ADDRESS_SANITIZER) && defined(OS_MACOSX)) -#define MAYBE_Alloca Alloca -#else -#define MAYBE_Alloca DISABLED_Alloca -#endif -PROFILER_TEST_F(StackSamplingProfilerTest, MAYBE_Alloca) { - SamplingParams params; - params.sampling_interval = TimeDelta::FromMilliseconds(0); - params.samples_per_burst = 1; - - std::vector<CallStackProfile> profiles; - WithTargetThread( - [¶ms, &profiles](PlatformThreadId target_thread_id) { - WaitableEvent sampling_thread_completed( - WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - const StackSamplingProfiler::CompletedCallback callback = - Bind(&SaveProfilesAndSignalEvent, Unretained(&profiles), - Unretained(&sampling_thread_completed)); - StackSamplingProfiler profiler(target_thread_id, params, callback); - profiler.Start(); - sampling_thread_completed.Wait(); - }, - StackConfiguration(StackConfiguration::WITH_ALLOCA)); - - // Look up the sample. - ASSERT_EQ(1u, profiles.size()); - const CallStackProfile& profile = profiles[0]; - ASSERT_EQ(1u, profile.samples.size()); - const Sample& sample = profile.samples[0]; - - // Check that the stack contains a frame for - // TargetThread::SignalAndWaitUntilSignaled(). - Frames::const_iterator end_frame = FindFirstFrameWithinFunction( - sample, &TargetThread::SignalAndWaitUntilSignaled); - ASSERT_TRUE(end_frame != sample.frames.end()) - << "Function at " - << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>( - &TargetThread::SignalAndWaitUntilSignaled)) - << " was not found in stack:\n" - << FormatSampleForDiagnosticOutput(sample, profile.modules); - - // Check that the stack contains a frame for TargetThread::CallWithAlloca(). - Frames::const_iterator alloca_frame = - FindFirstFrameWithinFunction(sample, &TargetThread::CallWithAlloca); - ASSERT_TRUE(alloca_frame != sample.frames.end()) - << "Function at " - << MaybeFixupFunctionAddressForILT( - reinterpret_cast<const void*>(&TargetThread::CallWithAlloca)) - << " was not found in stack:\n" - << FormatSampleForDiagnosticOutput(sample, profile.modules); - - // These frames should be adjacent on the stack. - EXPECT_EQ(1, alloca_frame - end_frame) - << "Stack:\n" - << FormatSampleForDiagnosticOutput(sample, profile.modules); -} - -// Checks that the expected number of profiles and samples are present in the -// call stack profiles produced. -PROFILER_TEST_F(StackSamplingProfilerTest, MultipleProfilesAndSamples) { - SamplingParams params; - params.burst_interval = params.sampling_interval = - TimeDelta::FromMilliseconds(0); - params.bursts = 2; - params.samples_per_burst = 3; - - std::vector<CallStackProfile> profiles; - CaptureProfiles(params, AVeryLongTimeDelta(), &profiles); - - ASSERT_EQ(2u, profiles.size()); - EXPECT_EQ(3u, profiles[0].samples.size()); - EXPECT_EQ(3u, profiles[1].samples.size()); -} - -// Checks that a profiler can stop/destruct without ever having started. -PROFILER_TEST_F(StackSamplingProfilerTest, StopWithoutStarting) { - WithTargetThread([](PlatformThreadId target_thread_id) { - SamplingParams params; - params.sampling_interval = TimeDelta::FromMilliseconds(0); - params.samples_per_burst = 1; - - CallStackProfiles profiles; - WaitableEvent sampling_completed(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - const StackSamplingProfiler::CompletedCallback callback = - Bind(&SaveProfilesAndSignalEvent, Unretained(&profiles), - Unretained(&sampling_completed)); - StackSamplingProfiler profiler(target_thread_id, params, callback); - - profiler.Stop(); // Constructed but never started. - EXPECT_FALSE(sampling_completed.IsSignaled()); - }); -} - -// Checks that its okay to stop a profiler before it finishes even when the -// sampling thread continues to run. -PROFILER_TEST_F(StackSamplingProfilerTest, StopSafely) { - // Test delegate that counts samples. - class SampleRecordedCounter : public NativeStackSamplerTestDelegate { - public: - SampleRecordedCounter() = default; - - void OnPreStackWalk() override { - AutoLock lock(lock_); - ++count_; - } - - size_t Get() { - AutoLock lock(lock_); - return count_; - } - - private: - Lock lock_; - size_t count_ = 0; - }; - - WithTargetThread([](PlatformThreadId target_thread_id) { - SamplingParams params[2]; - - // Providing an initial delay makes it more likely that both will be - // scheduled before either starts to run. Once started, samples will - // run ordered by their scheduled, interleaved times regardless of - // whatever interval the thread wakes up. - params[0].initial_delay = TimeDelta::FromMilliseconds(10); - params[0].sampling_interval = TimeDelta::FromMilliseconds(1); - params[0].samples_per_burst = 100000; - - params[1].initial_delay = TimeDelta::FromMilliseconds(10); - params[1].sampling_interval = TimeDelta::FromMilliseconds(1); - params[1].samples_per_burst = 100000; - - SampleRecordedCounter samples_recorded[arraysize(params)]; - - TestProfilerInfo profiler_info0(target_thread_id, params[0], - &samples_recorded[0]); - TestProfilerInfo profiler_info1(target_thread_id, params[1], - &samples_recorded[1]); - - profiler_info0.profiler.Start(); - profiler_info1.profiler.Start(); - - // Wait for both to start accumulating samples. Using a WaitableEvent is - // possible but gets complicated later on because there's no way of knowing - // if 0 or 1 additional sample will be taken after Stop() and thus no way - // of knowing how many Wait() calls to make on it. - while (samples_recorded[0].Get() == 0 || samples_recorded[1].Get() == 0) - PlatformThread::Sleep(TimeDelta::FromMilliseconds(1)); - - // Ensure that the first sampler can be safely stopped while the second - // continues to run. The stopped first profiler will still have a - // PerformCollectionTask pending that will do nothing when executed because - // the collection will have been removed by Stop(). - profiler_info0.profiler.Stop(); - profiler_info0.completed.Wait(); - size_t count0 = samples_recorded[0].Get(); - size_t count1 = samples_recorded[1].Get(); - - // Waiting for the second sampler to collect a couple samples ensures that - // the pending PerformCollectionTask for the first has executed because - // tasks are always ordered by their next scheduled time. - while (samples_recorded[1].Get() < count1 + 2) - PlatformThread::Sleep(TimeDelta::FromMilliseconds(1)); - - // Ensure that the first profiler didn't do anything since it was stopped. - EXPECT_EQ(count0, samples_recorded[0].Get()); - }); -} - -// Checks that no call stack profiles are captured if the profiling is stopped -// during the initial delay. -PROFILER_TEST_F(StackSamplingProfilerTest, StopDuringInitialDelay) { - SamplingParams params; - params.initial_delay = TimeDelta::FromSeconds(60); - - std::vector<CallStackProfile> profiles; - CaptureProfiles(params, TimeDelta::FromMilliseconds(0), &profiles); - - EXPECT_TRUE(profiles.empty()); -} - -// Checks that the single completed call stack profile is captured if the -// profiling is stopped between bursts. -PROFILER_TEST_F(StackSamplingProfilerTest, StopDuringInterBurstInterval) { - SamplingParams params; - params.sampling_interval = TimeDelta::FromMilliseconds(0); - params.burst_interval = TimeDelta::FromSeconds(60); - params.bursts = 2; - params.samples_per_burst = 1; - - std::vector<CallStackProfile> profiles; - CaptureProfiles(params, TimeDelta::FromMilliseconds(50), &profiles); - - ASSERT_EQ(1u, profiles.size()); - EXPECT_EQ(1u, profiles[0].samples.size()); -} - -// Checks that tasks can be stopped before completion and incomplete call stack -// profiles are captured. -PROFILER_TEST_F(StackSamplingProfilerTest, StopDuringInterSampleInterval) { - // Test delegate that counts samples. - class SampleRecordedEvent : public NativeStackSamplerTestDelegate { - public: - SampleRecordedEvent() - : sample_recorded_(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED) {} - - void OnPreStackWalk() override { sample_recorded_.Signal(); } - - void WaitForSample() { sample_recorded_.Wait(); } - - private: - WaitableEvent sample_recorded_; - }; - - WithTargetThread([](PlatformThreadId target_thread_id) { - SamplingParams params; - - params.sampling_interval = AVeryLongTimeDelta(); - params.samples_per_burst = 2; - - SampleRecordedEvent samples_recorded; - TestProfilerInfo profiler_info(target_thread_id, params, &samples_recorded); - - profiler_info.profiler.Start(); - - // Wait for profiler to start accumulating samples. - samples_recorded.WaitForSample(); - - // Ensure that it can stop safely. - profiler_info.profiler.Stop(); - profiler_info.completed.Wait(); - - ASSERT_EQ(1u, profiler_info.profiles.size()); - EXPECT_EQ(1u, profiler_info.profiles[0].samples.size()); - }); -} - -// Checks that we can destroy the profiler while profiling. -PROFILER_TEST_F(StackSamplingProfilerTest, DestroyProfilerWhileProfiling) { - SamplingParams params; - params.sampling_interval = TimeDelta::FromMilliseconds(10); - - CallStackProfiles profiles; - WithTargetThread([¶ms, &profiles](PlatformThreadId target_thread_id) { - std::unique_ptr<StackSamplingProfiler> profiler; - profiler.reset(new StackSamplingProfiler( - target_thread_id, params, Bind(&SaveProfiles, Unretained(&profiles)))); - profiler->Start(); - profiler.reset(); - - // Wait longer than a sample interval to catch any use-after-free actions by - // the profiler thread. - PlatformThread::Sleep(TimeDelta::FromMilliseconds(50)); - }); -} - -// Checks that the same profiler may be run multiple times. -PROFILER_TEST_F(StackSamplingProfilerTest, CanRunMultipleTimes) { - WithTargetThread([](PlatformThreadId target_thread_id) { - SamplingParams params; - params.sampling_interval = TimeDelta::FromMilliseconds(0); - params.samples_per_burst = 1; - - CallStackProfiles profiles; - WaitableEvent sampling_completed(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - const StackSamplingProfiler::CompletedCallback callback = - Bind(&SaveProfilesAndSignalEvent, Unretained(&profiles), - Unretained(&sampling_completed)); - StackSamplingProfiler profiler(target_thread_id, params, callback); - - // Just start and stop to execute code paths. - profiler.Start(); - profiler.Stop(); - sampling_completed.Wait(); - - // Ensure a second request will run and not block. - sampling_completed.Reset(); - profiles.clear(); - profiler.Start(); - sampling_completed.Wait(); - profiler.Stop(); - ASSERT_EQ(1u, profiles.size()); - }); -} - -// Checks that the different profilers may be run. -PROFILER_TEST_F(StackSamplingProfilerTest, CanRunMultipleProfilers) { - SamplingParams params; - params.sampling_interval = TimeDelta::FromMilliseconds(0); - params.samples_per_burst = 1; - - std::vector<CallStackProfile> profiles; - CaptureProfiles(params, AVeryLongTimeDelta(), &profiles); - ASSERT_EQ(1u, profiles.size()); - - profiles.clear(); - CaptureProfiles(params, AVeryLongTimeDelta(), &profiles); - ASSERT_EQ(1u, profiles.size()); -} - -// Checks that a sampler can be started while another is running. -PROFILER_TEST_F(StackSamplingProfilerTest, MultipleStart) { - WithTargetThread([](PlatformThreadId target_thread_id) { - std::vector<SamplingParams> params(2); - - params[0].initial_delay = AVeryLongTimeDelta(); - params[0].samples_per_burst = 1; - - params[1].sampling_interval = TimeDelta::FromMilliseconds(1); - params[1].samples_per_burst = 1; - - std::vector<std::unique_ptr<TestProfilerInfo>> profiler_infos = - CreateProfilers(target_thread_id, params); - - profiler_infos[0]->profiler.Start(); - profiler_infos[1]->profiler.Start(); - profiler_infos[1]->completed.Wait(); - EXPECT_EQ(1u, profiler_infos[1]->profiles.size()); - }); -} - -// Checks that the sampling thread can shut down. -PROFILER_TEST_F(StackSamplingProfilerTest, SamplerIdleShutdown) { - SamplingParams params; - params.sampling_interval = TimeDelta::FromMilliseconds(0); - params.samples_per_burst = 1; - - std::vector<CallStackProfile> profiles; - CaptureProfiles(params, AVeryLongTimeDelta(), &profiles); - ASSERT_EQ(1u, profiles.size()); - - // Capture thread should still be running at this point. - ASSERT_TRUE(StackSamplingProfiler::TestAPI::IsSamplingThreadRunning()); - - // Initiate an "idle" shutdown and ensure it happens. Idle-shutdown was - // disabled by the test fixture so the test will fail due to a timeout if - // it does not exit. - StackSamplingProfiler::TestAPI::PerformSamplingThreadIdleShutdown(false); - - // While the shutdown has been initiated, the actual exit of the thread still - // happens asynchronously. Watch until the thread actually exits. This test - // will time-out in the case of failure. - while (StackSamplingProfiler::TestAPI::IsSamplingThreadRunning()) - PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1)); -} - -// Checks that additional requests will restart a stopped profiler. -PROFILER_TEST_F(StackSamplingProfilerTest, - WillRestartSamplerAfterIdleShutdown) { - SamplingParams params; - params.sampling_interval = TimeDelta::FromMilliseconds(0); - params.samples_per_burst = 1; - - std::vector<CallStackProfile> profiles; - CaptureProfiles(params, AVeryLongTimeDelta(), &profiles); - ASSERT_EQ(1u, profiles.size()); - - // Capture thread should still be running at this point. - ASSERT_TRUE(StackSamplingProfiler::TestAPI::IsSamplingThreadRunning()); - - // Post a ShutdownTask on the sampling thread which, when executed, will - // mark the thread as EXITING and begin shut down of the thread. - StackSamplingProfiler::TestAPI::PerformSamplingThreadIdleShutdown(false); - - // Ensure another capture will start the sampling thread and run. - profiles.clear(); - CaptureProfiles(params, AVeryLongTimeDelta(), &profiles); - ASSERT_EQ(1u, profiles.size()); - EXPECT_TRUE(StackSamplingProfiler::TestAPI::IsSamplingThreadRunning()); -} - -// Checks that it's safe to stop a task after it's completed and the sampling -// thread has shut-down for being idle. -PROFILER_TEST_F(StackSamplingProfilerTest, StopAfterIdleShutdown) { - WithTargetThread([](PlatformThreadId target_thread_id) { - SamplingParams params; - - params.sampling_interval = TimeDelta::FromMilliseconds(1); - params.samples_per_burst = 1; - - TestProfilerInfo profiler_info(target_thread_id, params); - - profiler_info.profiler.Start(); - profiler_info.completed.Wait(); - - // Capture thread should still be running at this point. - ASSERT_TRUE(StackSamplingProfiler::TestAPI::IsSamplingThreadRunning()); - - // Perform an idle shutdown. - StackSamplingProfiler::TestAPI::PerformSamplingThreadIdleShutdown(false); - - // Stop should be safe though its impossible to know at this moment if the - // sampling thread has completely exited or will just "stop soon". - profiler_info.profiler.Stop(); - }); -} - -// Checks that profilers can run both before and after the sampling thread has -// started. -PROFILER_TEST_F(StackSamplingProfilerTest, - ProfileBeforeAndAfterSamplingThreadRunning) { - WithTargetThread([](PlatformThreadId target_thread_id) { - std::vector<SamplingParams> params(2); - - params[0].initial_delay = AVeryLongTimeDelta(); - params[0].sampling_interval = TimeDelta::FromMilliseconds(1); - params[0].samples_per_burst = 1; - - params[1].initial_delay = TimeDelta::FromMilliseconds(0); - params[1].sampling_interval = TimeDelta::FromMilliseconds(1); - params[1].samples_per_burst = 1; - - std::vector<std::unique_ptr<TestProfilerInfo>> profiler_infos = - CreateProfilers(target_thread_id, params); - - // First profiler is started when there has never been a sampling thread. - EXPECT_FALSE(StackSamplingProfiler::TestAPI::IsSamplingThreadRunning()); - profiler_infos[0]->profiler.Start(); - // Second profiler is started when sampling thread is already running. - EXPECT_TRUE(StackSamplingProfiler::TestAPI::IsSamplingThreadRunning()); - profiler_infos[1]->profiler.Start(); - - // Only the second profiler should finish before test times out. - size_t completed_profiler = WaitForSamplingComplete(profiler_infos); - EXPECT_EQ(1U, completed_profiler); - }); -} - -// Checks that an idle-shutdown task will abort if a new profiler starts -// between when it was posted and when it runs. -PROFILER_TEST_F(StackSamplingProfilerTest, IdleShutdownAbort) { - WithTargetThread([](PlatformThreadId target_thread_id) { - SamplingParams params; - - params.sampling_interval = TimeDelta::FromMilliseconds(1); - params.samples_per_burst = 1; - - TestProfilerInfo profiler_info(target_thread_id, params); - - profiler_info.profiler.Start(); - profiler_info.completed.Wait(); - EXPECT_EQ(1u, profiler_info.profiles.size()); - - // Perform an idle shutdown but simulate that a new capture is started - // before it can actually run. - StackSamplingProfiler::TestAPI::PerformSamplingThreadIdleShutdown(true); - - // Though the shutdown-task has been executed, any actual exit of the - // thread is asynchronous so there is no way to detect that *didn't* exit - // except to wait a reasonable amount of time and then check. Since the - // thread was just running ("perform" blocked until it was), it should - // finish almost immediately and without any waiting for tasks or events. - PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(200)); - EXPECT_TRUE(StackSamplingProfiler::TestAPI::IsSamplingThreadRunning()); - - // Ensure that it's still possible to run another sampler. - TestProfilerInfo another_info(target_thread_id, params); - another_info.profiler.Start(); - another_info.completed.Wait(); - EXPECT_EQ(1u, another_info.profiles.size()); - }); -} - -// Checks that synchronized multiple sampling requests execute in parallel. -PROFILER_TEST_F(StackSamplingProfilerTest, ConcurrentProfiling_InSync) { - WithTargetThread([](PlatformThreadId target_thread_id) { - std::vector<SamplingParams> params(2); - - // Providing an initial delay makes it more likely that both will be - // scheduled before either starts to run. Once started, samples will - // run ordered by their scheduled, interleaved times regardless of - // whatever interval the thread wakes up. Thus, total execution time - // will be 10ms (delay) + 10x1ms (sampling) + 1/2 timer minimum interval. - params[0].initial_delay = TimeDelta::FromMilliseconds(10); - params[0].sampling_interval = TimeDelta::FromMilliseconds(1); - params[0].samples_per_burst = 9; - - params[1].initial_delay = TimeDelta::FromMilliseconds(11); - params[1].sampling_interval = TimeDelta::FromMilliseconds(1); - params[1].samples_per_burst = 8; - - std::vector<std::unique_ptr<TestProfilerInfo>> profiler_infos = - CreateProfilers(target_thread_id, params); - - profiler_infos[0]->profiler.Start(); - profiler_infos[1]->profiler.Start(); - - // Wait for one profiler to finish. - size_t completed_profiler = WaitForSamplingComplete(profiler_infos); - ASSERT_EQ(1u, profiler_infos[completed_profiler]->profiles.size()); - - size_t other_profiler = 1 - completed_profiler; - // Wait for the other profiler to finish. - profiler_infos[other_profiler]->completed.Wait(); - ASSERT_EQ(1u, profiler_infos[other_profiler]->profiles.size()); - - // Ensure each got the correct number of samples. - EXPECT_EQ(9u, profiler_infos[0]->profiles[0].samples.size()); - EXPECT_EQ(8u, profiler_infos[1]->profiles[0].samples.size()); - }); -} - -// Checks that several mixed sampling requests execute in parallel. -PROFILER_TEST_F(StackSamplingProfilerTest, ConcurrentProfiling_Mixed) { - WithTargetThread([](PlatformThreadId target_thread_id) { - std::vector<SamplingParams> params(3); - - params[0].initial_delay = TimeDelta::FromMilliseconds(8); - params[0].sampling_interval = TimeDelta::FromMilliseconds(4); - params[0].samples_per_burst = 10; - - params[1].initial_delay = TimeDelta::FromMilliseconds(9); - params[1].sampling_interval = TimeDelta::FromMilliseconds(3); - params[1].samples_per_burst = 10; - - params[2].initial_delay = TimeDelta::FromMilliseconds(10); - params[2].sampling_interval = TimeDelta::FromMilliseconds(2); - params[2].samples_per_burst = 10; - - std::vector<std::unique_ptr<TestProfilerInfo>> profiler_infos = - CreateProfilers(target_thread_id, params); - - for (size_t i = 0; i < profiler_infos.size(); ++i) - profiler_infos[i]->profiler.Start(); - - // Wait for one profiler to finish. - size_t completed_profiler = WaitForSamplingComplete(profiler_infos); - EXPECT_EQ(1u, profiler_infos[completed_profiler]->profiles.size()); - // Stop and destroy all profilers, always in the same order. Don't crash. - for (size_t i = 0; i < profiler_infos.size(); ++i) - profiler_infos[i]->profiler.Stop(); - for (size_t i = 0; i < profiler_infos.size(); ++i) - profiler_infos[i].reset(); - }); -} - -// Checks that a stack that runs through another library produces a stack with -// the expected functions. -// macOS ASAN is not yet supported - crbug.com/718628. -#if !(defined(ADDRESS_SANITIZER) && defined(OS_MACOSX)) -#define MAYBE_OtherLibrary OtherLibrary -#else -#define MAYBE_OtherLibrary DISABLED_OtherLibrary -#endif -PROFILER_TEST_F(StackSamplingProfilerTest, MAYBE_OtherLibrary) { - SamplingParams params; - params.sampling_interval = TimeDelta::FromMilliseconds(0); - params.samples_per_burst = 1; - - std::vector<CallStackProfile> profiles; - { - ScopedNativeLibrary other_library(LoadOtherLibrary()); - WithTargetThread( - [¶ms, &profiles](PlatformThreadId target_thread_id) { - WaitableEvent sampling_thread_completed( - WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - const StackSamplingProfiler::CompletedCallback callback = - Bind(&SaveProfilesAndSignalEvent, Unretained(&profiles), - Unretained(&sampling_thread_completed)); - StackSamplingProfiler profiler(target_thread_id, params, callback); - profiler.Start(); - sampling_thread_completed.Wait(); - }, - StackConfiguration(StackConfiguration::WITH_OTHER_LIBRARY, - other_library.get())); - } - - // Look up the sample. - ASSERT_EQ(1u, profiles.size()); - const CallStackProfile& profile = profiles[0]; - ASSERT_EQ(1u, profile.samples.size()); - const Sample& sample = profile.samples[0]; - - // Check that the stack contains a frame for - // TargetThread::CallThroughOtherLibrary(). - Frames::const_iterator other_library_frame = FindFirstFrameWithinFunction( - sample, &TargetThread::CallThroughOtherLibrary); - ASSERT_TRUE(other_library_frame != sample.frames.end()) - << "Function at " - << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>( - &TargetThread::CallThroughOtherLibrary)) - << " was not found in stack:\n" - << FormatSampleForDiagnosticOutput(sample, profile.modules); - - // Check that the stack contains a frame for - // TargetThread::SignalAndWaitUntilSignaled(). - Frames::const_iterator end_frame = FindFirstFrameWithinFunction( - sample, &TargetThread::SignalAndWaitUntilSignaled); - ASSERT_TRUE(end_frame != sample.frames.end()) - << "Function at " - << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>( - &TargetThread::SignalAndWaitUntilSignaled)) - << " was not found in stack:\n" - << FormatSampleForDiagnosticOutput(sample, profile.modules); - - // The stack should look like this, resulting in three frames between - // SignalAndWaitUntilSignaled and CallThroughOtherLibrary: - // - // ... WaitableEvent and system frames ... - // TargetThread::SignalAndWaitUntilSignaled - // TargetThread::OtherLibraryCallback - // InvokeCallbackFunction (in other library) - // TargetThread::CallThroughOtherLibrary - EXPECT_EQ(3, other_library_frame - end_frame) - << "Stack:\n" << FormatSampleForDiagnosticOutput(sample, profile.modules); -} - -// Checks that a stack that runs through a library that is unloading produces a -// stack, and doesn't crash. -// Unloading is synchronous on the Mac, so this test is inapplicable. -#if !defined(OS_MACOSX) -#define MAYBE_UnloadingLibrary UnloadingLibrary -#else -#define MAYBE_UnloadingLibrary DISABLED_UnloadingLibrary -#endif -PROFILER_TEST_F(StackSamplingProfilerTest, MAYBE_UnloadingLibrary) { - TestLibraryUnload(false); -} - -// Checks that a stack that runs through a library that has been unloaded -// produces a stack, and doesn't crash. -// macOS ASAN is not yet supported - crbug.com/718628. -#if !(defined(ADDRESS_SANITIZER) && defined(OS_MACOSX)) -#define MAYBE_UnloadedLibrary UnloadedLibrary -#else -#define MAYBE_UnloadedLibrary DISABLED_UnloadedLibrary -#endif -PROFILER_TEST_F(StackSamplingProfilerTest, MAYBE_UnloadedLibrary) { - TestLibraryUnload(true); -} - -// Checks that different threads can be sampled in parallel. -PROFILER_TEST_F(StackSamplingProfilerTest, MultipleSampledThreads) { - // Create target threads. The extra parethesis around the StackConfiguration - // call are to avoid the most-vexing-parse problem. - TargetThread target_thread1((StackConfiguration(StackConfiguration::NORMAL))); - TargetThread target_thread2((StackConfiguration(StackConfiguration::NORMAL))); - PlatformThreadHandle target_thread_handle1, target_thread_handle2; - EXPECT_TRUE( - PlatformThread::Create(0, &target_thread1, &target_thread_handle1)); - EXPECT_TRUE( - PlatformThread::Create(0, &target_thread2, &target_thread_handle2)); - target_thread1.WaitForThreadStart(); - target_thread2.WaitForThreadStart(); - - // Providing an initial delay makes it more likely that both will be - // scheduled before either starts to run. Once started, samples will - // run ordered by their scheduled, interleaved times regardless of - // whatever interval the thread wakes up. - SamplingParams params1, params2; - params1.initial_delay = TimeDelta::FromMilliseconds(10); - params1.sampling_interval = TimeDelta::FromMilliseconds(1); - params1.samples_per_burst = 9; - params2.initial_delay = TimeDelta::FromMilliseconds(10); - params2.sampling_interval = TimeDelta::FromMilliseconds(1); - params2.samples_per_burst = 8; - - std::vector<CallStackProfile> profiles1, profiles2; - - WaitableEvent sampling_thread_completed1( - WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - const StackSamplingProfiler::CompletedCallback callback1 = - Bind(&SaveProfilesAndSignalEvent, Unretained(&profiles1), - Unretained(&sampling_thread_completed1)); - StackSamplingProfiler profiler1(target_thread1.id(), params1, callback1); - - WaitableEvent sampling_thread_completed2( - WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - const StackSamplingProfiler::CompletedCallback callback2 = - Bind(&SaveProfilesAndSignalEvent, Unretained(&profiles2), - Unretained(&sampling_thread_completed2)); - StackSamplingProfiler profiler2(target_thread2.id(), params2, callback2); - - // Finally the real work. - profiler1.Start(); - profiler2.Start(); - sampling_thread_completed1.Wait(); - sampling_thread_completed2.Wait(); - ASSERT_EQ(1u, profiles1.size()); - EXPECT_EQ(9u, profiles1[0].samples.size()); - ASSERT_EQ(1u, profiles2.size()); - EXPECT_EQ(8u, profiles2[0].samples.size()); - - target_thread1.SignalThreadToFinish(); - target_thread2.SignalThreadToFinish(); - PlatformThread::Join(target_thread_handle1); - PlatformThread::Join(target_thread_handle2); -} - -// A simple thread that runs a profiler on another thread. -class ProfilerThread : public SimpleThread { - public: - ProfilerThread(const std::string& name, - PlatformThreadId thread_id, - const SamplingParams& params) - : SimpleThread(name, Options()), - run_(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED), - completed_(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED), - profiler_(thread_id, - params, - Bind(&SaveProfilesAndSignalEvent, - Unretained(&profiles_), - Unretained(&completed_))) {} - - void Run() override { - run_.Wait(); - profiler_.Start(); - } - - void Go() { run_.Signal(); } - - void Wait() { completed_.Wait(); } - - CallStackProfiles& profiles() { return profiles_; } - - private: - WaitableEvent run_; - - CallStackProfiles profiles_; - WaitableEvent completed_; - StackSamplingProfiler profiler_; -}; - -// Checks that different threads can run samplers in parallel. -PROFILER_TEST_F(StackSamplingProfilerTest, MultipleProfilerThreads) { - WithTargetThread([](PlatformThreadId target_thread_id) { - // Providing an initial delay makes it more likely that both will be - // scheduled before either starts to run. Once started, samples will - // run ordered by their scheduled, interleaved times regardless of - // whatever interval the thread wakes up. - SamplingParams params1, params2; - params1.initial_delay = TimeDelta::FromMilliseconds(10); - params1.sampling_interval = TimeDelta::FromMilliseconds(1); - params1.samples_per_burst = 9; - params2.initial_delay = TimeDelta::FromMilliseconds(10); - params2.sampling_interval = TimeDelta::FromMilliseconds(1); - params2.samples_per_burst = 8; - - // Start the profiler threads and give them a moment to get going. - ProfilerThread profiler_thread1("profiler1", target_thread_id, params1); - ProfilerThread profiler_thread2("profiler2", target_thread_id, params2); - profiler_thread1.Start(); - profiler_thread2.Start(); - PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10)); - - // This will (approximately) synchronize the two threads. - profiler_thread1.Go(); - profiler_thread2.Go(); - - // Wait for them both to finish and validate collection. - profiler_thread1.Wait(); - profiler_thread2.Wait(); - ASSERT_EQ(1u, profiler_thread1.profiles().size()); - EXPECT_EQ(9u, profiler_thread1.profiles()[0].samples.size()); - ASSERT_EQ(1u, profiler_thread2.profiles().size()); - EXPECT_EQ(8u, profiler_thread2.profiles()[0].samples.size()); - - profiler_thread1.Join(); - profiler_thread2.Join(); - }); -} - -} // namespace base
diff --git a/base/profiler/win32_stack_frame_unwinder_unittest.cc b/base/profiler/win32_stack_frame_unwinder_unittest.cc deleted file mode 100644 index cecfe22..0000000 --- a/base/profiler/win32_stack_frame_unwinder_unittest.cc +++ /dev/null
@@ -1,223 +0,0 @@ -// 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/profiler/win32_stack_frame_unwinder.h" - -#include <memory> -#include <utility> -#include <vector> - -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -class TestUnwindFunctions : public Win32StackFrameUnwinder::UnwindFunctions { - public: - TestUnwindFunctions(); - - PRUNTIME_FUNCTION LookupFunctionEntry(DWORD64 program_counter, - PDWORD64 image_base) override; - void VirtualUnwind(DWORD64 image_base, - DWORD64 program_counter, - PRUNTIME_FUNCTION runtime_function, - CONTEXT* context) override; - ScopedModuleHandle GetModuleForProgramCounter( - DWORD64 program_counter) override; - - // Instructs GetModuleForProgramCounter to return null on the next call. - void SetUnloadedModule(); - - // These functions set whether the next frame will have a RUNTIME_FUNCTION. - void SetHasRuntimeFunction(CONTEXT* context); - void SetNoRuntimeFunction(CONTEXT* context); - - private: - enum { kImageBaseIncrement = 1 << 20 }; - - static RUNTIME_FUNCTION* const kInvalidRuntimeFunction; - - bool module_is_loaded_; - DWORD64 expected_program_counter_; - DWORD64 next_image_base_; - DWORD64 expected_image_base_; - RUNTIME_FUNCTION* next_runtime_function_; - std::vector<RUNTIME_FUNCTION> runtime_functions_; - - DISALLOW_COPY_AND_ASSIGN(TestUnwindFunctions); -}; - -RUNTIME_FUNCTION* const TestUnwindFunctions::kInvalidRuntimeFunction = - reinterpret_cast<RUNTIME_FUNCTION*>(static_cast<uintptr_t>(-1)); - -TestUnwindFunctions::TestUnwindFunctions() - : module_is_loaded_(true), - expected_program_counter_(0), - next_image_base_(kImageBaseIncrement), - expected_image_base_(0), - next_runtime_function_(kInvalidRuntimeFunction) { -} - -PRUNTIME_FUNCTION TestUnwindFunctions::LookupFunctionEntry( - DWORD64 program_counter, - PDWORD64 image_base) { - EXPECT_EQ(expected_program_counter_, program_counter); - *image_base = expected_image_base_ = next_image_base_; - next_image_base_ += kImageBaseIncrement; - RUNTIME_FUNCTION* return_value = next_runtime_function_; - next_runtime_function_ = kInvalidRuntimeFunction; - return return_value; -} - -void TestUnwindFunctions::VirtualUnwind(DWORD64 image_base, - DWORD64 program_counter, - PRUNTIME_FUNCTION runtime_function, - CONTEXT* context) { - ASSERT_NE(kInvalidRuntimeFunction, runtime_function) - << "expected call to SetHasRuntimeFunction() or SetNoRuntimeFunction() " - << "before invoking TryUnwind()"; - EXPECT_EQ(expected_image_base_, image_base); - expected_image_base_ = 0; - EXPECT_EQ(expected_program_counter_, program_counter); - expected_program_counter_ = 0; - // This function should only be called when LookupFunctionEntry returns - // a RUNTIME_FUNCTION. - EXPECT_EQ(&runtime_functions_.back(), runtime_function); -} - -ScopedModuleHandle TestUnwindFunctions::GetModuleForProgramCounter( - DWORD64 program_counter) { - bool return_non_null_value = module_is_loaded_; - module_is_loaded_ = true; - return ScopedModuleHandle(return_non_null_value ? - ModuleHandleTraits::kNonNullModuleForTesting : - nullptr); -} - -void TestUnwindFunctions::SetUnloadedModule() { - module_is_loaded_ = false; -} - -void TestUnwindFunctions::SetHasRuntimeFunction(CONTEXT* context) { - RUNTIME_FUNCTION runtime_function = {}; - runtime_function.BeginAddress = 16; - runtime_function.EndAddress = runtime_function.BeginAddress + 256; - runtime_functions_.push_back(runtime_function); - next_runtime_function_ = &runtime_functions_.back(); - - expected_program_counter_ = context->Rip = - next_image_base_ + runtime_function.BeginAddress + 8; -} - -void TestUnwindFunctions::SetNoRuntimeFunction(CONTEXT* context) { - expected_program_counter_ = context->Rip = 100; - next_runtime_function_ = nullptr; -} - -} // namespace - -class Win32StackFrameUnwinderTest : public testing::Test { - protected: - Win32StackFrameUnwinderTest() {} - - // This exists so that Win32StackFrameUnwinder's constructor can be private - // with a single friend declaration of this test fixture. - std::unique_ptr<Win32StackFrameUnwinder> CreateUnwinder(); - - // Weak pointer to the unwind functions used by last created unwinder. - TestUnwindFunctions* unwind_functions_; - - private: - DISALLOW_COPY_AND_ASSIGN(Win32StackFrameUnwinderTest); -}; - -std::unique_ptr<Win32StackFrameUnwinder> -Win32StackFrameUnwinderTest::CreateUnwinder() { - std::unique_ptr<TestUnwindFunctions> unwind_functions( - new TestUnwindFunctions); - unwind_functions_ = unwind_functions.get(); - return WrapUnique( - new Win32StackFrameUnwinder(std::move(unwind_functions))); -} - -// Checks the case where all frames have unwind information. -TEST_F(Win32StackFrameUnwinderTest, FramesWithUnwindInfo) { - std::unique_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); - CONTEXT context = {0}; - ScopedModuleHandle module; - - unwind_functions_->SetHasRuntimeFunction(&context); - EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); - EXPECT_TRUE(module.IsValid()); - - unwind_functions_->SetHasRuntimeFunction(&context); - module.Set(nullptr); - EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); - EXPECT_TRUE(module.IsValid()); - - unwind_functions_->SetHasRuntimeFunction(&context); - module.Set(nullptr); - EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); - EXPECT_TRUE(module.IsValid()); -} - -// Checks that an instruction pointer in an unloaded module fails to unwind. -TEST_F(Win32StackFrameUnwinderTest, UnloadedModule) { - std::unique_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); - CONTEXT context = {0}; - ScopedModuleHandle module; - - unwind_functions_->SetUnloadedModule(); - EXPECT_FALSE(unwinder->TryUnwind(&context, &module)); -} - -// Checks that the CONTEXT's stack pointer gets popped when the top frame has no -// unwind information. -TEST_F(Win32StackFrameUnwinderTest, FrameAtTopWithoutUnwindInfo) { - std::unique_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); - CONTEXT context = {0}; - ScopedModuleHandle module; - DWORD64 next_ip = 0x0123456789abcdef; - DWORD64 original_rsp = reinterpret_cast<DWORD64>(&next_ip); - context.Rsp = original_rsp; - - unwind_functions_->SetNoRuntimeFunction(&context); - EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); - EXPECT_EQ(next_ip, context.Rip); - EXPECT_EQ(original_rsp + 8, context.Rsp); - EXPECT_TRUE(module.IsValid()); - - unwind_functions_->SetHasRuntimeFunction(&context); - module.Set(nullptr); - EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); - EXPECT_TRUE(module.IsValid()); - - unwind_functions_->SetHasRuntimeFunction(&context); - module.Set(nullptr); - EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); - EXPECT_TRUE(module.IsValid()); -} - -// Checks that a frame below the top of the stack with missing unwind info -// terminates the unwinding. -TEST_F(Win32StackFrameUnwinderTest, FrameBelowTopWithoutUnwindInfo) { - { - // First stack, with a bad function below the top of the stack. - std::unique_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); - CONTEXT context = {0}; - ScopedModuleHandle module; - unwind_functions_->SetHasRuntimeFunction(&context); - EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); - EXPECT_TRUE(module.IsValid()); - - unwind_functions_->SetNoRuntimeFunction(&context); - EXPECT_FALSE(unwinder->TryUnwind(&context, &module)); - } -} - -} // namespace base
diff --git a/base/rand_util_unittest.cc b/base/rand_util_unittest.cc deleted file mode 100644 index 11a118a..0000000 --- a/base/rand_util_unittest.cc +++ /dev/null
@@ -1,170 +0,0 @@ -// 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/rand_util.h" - -#include <stddef.h> -#include <stdint.h> - -#include <algorithm> -#include <limits> -#include <memory> - -#include "base/logging.h" -#include "base/time/time.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -const int kIntMin = std::numeric_limits<int>::min(); -const int kIntMax = std::numeric_limits<int>::max(); - -} // namespace - -TEST(RandUtilTest, RandInt) { - EXPECT_EQ(base::RandInt(0, 0), 0); - EXPECT_EQ(base::RandInt(kIntMin, kIntMin), kIntMin); - EXPECT_EQ(base::RandInt(kIntMax, kIntMax), kIntMax); - - // Check that the DCHECKS in RandInt() don't fire due to internal overflow. - // There was a 50% chance of that happening, so calling it 40 times means - // the chances of this passing by accident are tiny (9e-13). - for (int i = 0; i < 40; ++i) - base::RandInt(kIntMin, kIntMax); -} - -TEST(RandUtilTest, RandDouble) { - // Force 64-bit precision, making sure we're not in a 80-bit FPU register. - volatile double number = base::RandDouble(); - EXPECT_GT(1.0, number); - EXPECT_LE(0.0, number); -} - -TEST(RandUtilTest, RandBytes) { - const size_t buffer_size = 50; - char buffer[buffer_size]; - memset(buffer, 0, buffer_size); - base::RandBytes(buffer, buffer_size); - std::sort(buffer, buffer + buffer_size); - // Probability of occurrence of less than 25 unique bytes in 50 random bytes - // is below 10^-25. - EXPECT_GT(std::unique(buffer, buffer + buffer_size) - buffer, 25); -} - -// Verify that calling base::RandBytes with an empty buffer doesn't fail. -TEST(RandUtilTest, RandBytes0) { - base::RandBytes(nullptr, 0); -} - -TEST(RandUtilTest, RandBytesAsString) { - std::string random_string = base::RandBytesAsString(1); - EXPECT_EQ(1U, random_string.size()); - random_string = base::RandBytesAsString(145); - EXPECT_EQ(145U, random_string.size()); - char accumulator = 0; - for (size_t i = 0; i < random_string.size(); ++i) - accumulator |= random_string[i]; - // In theory this test can fail, but it won't before the universe dies of - // heat death. - EXPECT_NE(0, accumulator); -} - -// Make sure that it is still appropriate to use RandGenerator in conjunction -// with std::random_shuffle(). -TEST(RandUtilTest, RandGeneratorForRandomShuffle) { - EXPECT_EQ(base::RandGenerator(1), 0U); - EXPECT_LE(std::numeric_limits<ptrdiff_t>::max(), - std::numeric_limits<int64_t>::max()); -} - -TEST(RandUtilTest, RandGeneratorIsUniform) { - // Verify that RandGenerator has a uniform distribution. This is a - // regression test that consistently failed when RandGenerator was - // implemented this way: - // - // return base::RandUint64() % max; - // - // A degenerate case for such an implementation is e.g. a top of - // range that is 2/3rds of the way to MAX_UINT64, in which case the - // bottom half of the range would be twice as likely to occur as the - // top half. A bit of calculus care of jar@ shows that the largest - // measurable delta is when the top of the range is 3/4ths of the - // way, so that's what we use in the test. - const uint64_t kTopOfRange = - (std::numeric_limits<uint64_t>::max() / 4ULL) * 3ULL; - const uint64_t kExpectedAverage = kTopOfRange / 2ULL; - const uint64_t kAllowedVariance = kExpectedAverage / 50ULL; // +/- 2% - const int kMinAttempts = 1000; - const int kMaxAttempts = 1000000; - - double cumulative_average = 0.0; - int count = 0; - while (count < kMaxAttempts) { - uint64_t value = base::RandGenerator(kTopOfRange); - cumulative_average = (count * cumulative_average + value) / (count + 1); - - // Don't quit too quickly for things to start converging, or we may have - // a false positive. - if (count > kMinAttempts && - kExpectedAverage - kAllowedVariance < cumulative_average && - cumulative_average < kExpectedAverage + kAllowedVariance) { - break; - } - - ++count; - } - - ASSERT_LT(count, kMaxAttempts) << "Expected average was " << - kExpectedAverage << ", average ended at " << cumulative_average; -} - -TEST(RandUtilTest, RandUint64ProducesBothValuesOfAllBits) { - // This tests to see that our underlying random generator is good - // enough, for some value of good enough. - uint64_t kAllZeros = 0ULL; - uint64_t kAllOnes = ~kAllZeros; - uint64_t found_ones = kAllZeros; - uint64_t found_zeros = kAllOnes; - - for (size_t i = 0; i < 1000; ++i) { - uint64_t value = base::RandUint64(); - found_ones |= value; - found_zeros &= value; - - if (found_zeros == kAllZeros && found_ones == kAllOnes) - return; - } - - FAIL() << "Didn't achieve all bit values in maximum number of tries."; -} - -TEST(RandUtilTest, RandBytesLonger) { - // Fuchsia can only retrieve 256 bytes of entropy at a time, so make sure we - // handle longer requests than that. - std::string random_string0 = base::RandBytesAsString(255); - EXPECT_EQ(255u, random_string0.size()); - std::string random_string1 = base::RandBytesAsString(1023); - EXPECT_EQ(1023u, random_string1.size()); - std::string random_string2 = base::RandBytesAsString(4097); - EXPECT_EQ(4097u, random_string2.size()); -} - -// Benchmark test for RandBytes(). Disabled since it's intentionally slow and -// does not test anything that isn't already tested by the existing RandBytes() -// tests. -TEST(RandUtilTest, DISABLED_RandBytesPerf) { - // Benchmark the performance of |kTestIterations| of RandBytes() using a - // buffer size of |kTestBufferSize|. - const int kTestIterations = 10; - const size_t kTestBufferSize = 1 * 1024 * 1024; - - std::unique_ptr<uint8_t[]> buffer(new uint8_t[kTestBufferSize]); - const base::TimeTicks now = base::TimeTicks::Now(); - for (int i = 0; i < kTestIterations; ++i) - base::RandBytes(buffer.get(), kTestBufferSize); - const base::TimeTicks end = base::TimeTicks::Now(); - - LOG(INFO) << "RandBytes(" << kTestBufferSize << ") took: " - << (end - now).InMicroseconds() << "µs"; -}
diff --git a/base/run_loop_unittest.cc b/base/run_loop_unittest.cc deleted file mode 100644 index 3564a2e..0000000 --- a/base/run_loop_unittest.cc +++ /dev/null
@@ -1,636 +0,0 @@ -// 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/run_loop.h" - -#include <utility> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/containers/queue.h" -#include "base/location.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/memory/ref_counted.h" -#include "base/single_thread_task_runner.h" -#include "base/synchronization/lock.h" -#include "base/synchronization/waitable_event.h" -#include "base/test/gtest_util.h" -#include "base/test/scoped_task_environment.h" -#include "base/test/test_timeouts.h" -#include "base/threading/platform_thread.h" -#include "base/threading/thread.h" -#include "base/threading/thread_checker_impl.h" -#include "base/threading/thread_task_runner_handle.h" -#include "build_config.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -void QuitWhenIdleTask(RunLoop* run_loop, int* counter) { - run_loop->QuitWhenIdle(); - ++(*counter); -} - -void ShouldRunTask(int* counter) { - ++(*counter); -} - -void ShouldNotRunTask() { - ADD_FAILURE() << "Ran a task that shouldn't run."; -} - -void RunNestedLoopTask(int* counter) { - RunLoop nested_run_loop(RunLoop::Type::kNestableTasksAllowed); - - // This task should quit |nested_run_loop| but not the main RunLoop. - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce(&QuitWhenIdleTask, Unretained(&nested_run_loop), - Unretained(counter))); - - ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, BindOnce(&ShouldNotRunTask), TimeDelta::FromDays(1)); - - nested_run_loop.Run(); - - ++(*counter); -} - -// A simple SingleThreadTaskRunner that just queues undelayed tasks (and ignores -// delayed tasks). Tasks can then be processed one by one by ProcessTask() which -// will return true if it processed a task and false otherwise. -class SimpleSingleThreadTaskRunner : public SingleThreadTaskRunner { - public: - SimpleSingleThreadTaskRunner() = default; - - bool PostDelayedTask(const Location& from_here, - OnceClosure task, - base::TimeDelta delay) override { - if (delay > base::TimeDelta()) - return false; - AutoLock auto_lock(tasks_lock_); - pending_tasks_.push(std::move(task)); - return true; - } - - bool PostNonNestableDelayedTask(const Location& from_here, - OnceClosure task, - base::TimeDelta delay) override { - return PostDelayedTask(from_here, std::move(task), delay); - } - - bool RunsTasksInCurrentSequence() const override { - return origin_thread_checker_.CalledOnValidThread(); - } - - bool ProcessSingleTask() { - OnceClosure task; - { - AutoLock auto_lock(tasks_lock_); - if (pending_tasks_.empty()) - return false; - task = std::move(pending_tasks_.front()); - pending_tasks_.pop(); - } - // It's important to Run() after pop() and outside the lock as |task| may - // run a nested loop which will re-enter ProcessSingleTask(). - std::move(task).Run(); - return true; - } - - private: - ~SimpleSingleThreadTaskRunner() override = default; - - Lock tasks_lock_; - base::queue<OnceClosure> pending_tasks_; - - // RunLoop relies on RunsTasksInCurrentSequence() signal. Use a - // ThreadCheckerImpl to be able to reliably provide that signal even in - // non-dcheck builds. - ThreadCheckerImpl origin_thread_checker_; - - DISALLOW_COPY_AND_ASSIGN(SimpleSingleThreadTaskRunner); -}; - -// The basis of all TestDelegates, allows safely injecting a OnceClosure to be -// run in the next idle phase of this delegate's Run() implementation. This can -// be used to have code run on a thread that is otherwise livelocked in an idle -// phase (sometimes a simple PostTask() won't do it -- e.g. when processing -// application tasks is disallowed). -class InjectableTestDelegate : public RunLoop::Delegate { - public: - void InjectClosureOnDelegate(OnceClosure closure) { - AutoLock auto_lock(closure_lock_); - closure_ = std::move(closure); - } - - bool RunInjectedClosure() { - AutoLock auto_lock(closure_lock_); - if (closure_.is_null()) - return false; - std::move(closure_).Run(); - return true; - } - - private: - Lock closure_lock_; - OnceClosure closure_; -}; - -// A simple test RunLoop::Delegate to exercise Runloop logic independent of any -// other base constructs. BindToCurrentThread() must be called before this -// TestBoundDelegate is operational. -class TestBoundDelegate final : public InjectableTestDelegate { - public: - TestBoundDelegate() = default; - - // Makes this TestBoundDelegate become the RunLoop::Delegate and - // ThreadTaskRunnerHandle for this thread. - void BindToCurrentThread() { - thread_task_runner_handle_ = - std::make_unique<ThreadTaskRunnerHandle>(simple_task_runner_); - RunLoop::RegisterDelegateForCurrentThread(this); - } - - private: - void Run(bool application_tasks_allowed) override { - if (nested_run_allowing_tasks_incoming_) { - EXPECT_TRUE(RunLoop::IsNestedOnCurrentThread()); - EXPECT_TRUE(application_tasks_allowed); - } else if (RunLoop::IsNestedOnCurrentThread()) { - EXPECT_FALSE(application_tasks_allowed); - } - nested_run_allowing_tasks_incoming_ = false; - - while (!should_quit_) { - if (application_tasks_allowed && simple_task_runner_->ProcessSingleTask()) - continue; - - if (ShouldQuitWhenIdle()) - break; - - if (RunInjectedClosure()) - continue; - - PlatformThread::YieldCurrentThread(); - } - should_quit_ = false; - } - - void Quit() override { should_quit_ = true; } - - void EnsureWorkScheduled() override { - nested_run_allowing_tasks_incoming_ = true; - } - - // True if the next invocation of Run() is expected to be from a - // kNestableTasksAllowed RunLoop. - bool nested_run_allowing_tasks_incoming_ = false; - - scoped_refptr<SimpleSingleThreadTaskRunner> simple_task_runner_ = - MakeRefCounted<SimpleSingleThreadTaskRunner>(); - - std::unique_ptr<ThreadTaskRunnerHandle> thread_task_runner_handle_; - - bool should_quit_ = false; -}; - -enum class RunLoopTestType { - // Runs all RunLoopTests under a ScopedTaskEnvironment to make sure real world - // scenarios work. - kRealEnvironment, - - // Runs all RunLoopTests under a test RunLoop::Delegate to make sure the - // delegate interface fully works standalone. - kTestDelegate, -}; - -// The task environment for the RunLoopTest of a given type. A separate class -// so it can be instantiated on the stack in the RunLoopTest fixture. -class RunLoopTestEnvironment { - public: - RunLoopTestEnvironment(RunLoopTestType type) { - switch (type) { - case RunLoopTestType::kRealEnvironment: { - task_environment_ = std::make_unique<test::ScopedTaskEnvironment>(); - break; - } - case RunLoopTestType::kTestDelegate: { - auto test_delegate = std::make_unique<TestBoundDelegate>(); - test_delegate->BindToCurrentThread(); - test_delegate_ = std::move(test_delegate); - break; - } - } - } - - private: - // Instantiates one or the other based on the RunLoopTestType. - std::unique_ptr<test::ScopedTaskEnvironment> task_environment_; - std::unique_ptr<InjectableTestDelegate> test_delegate_; -}; - -class RunLoopTest : public testing::TestWithParam<RunLoopTestType> { - protected: - RunLoopTest() : test_environment_(GetParam()) {} - - RunLoopTestEnvironment test_environment_; - RunLoop run_loop_; - int counter_ = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(RunLoopTest); -}; - -} // namespace - -TEST_P(RunLoopTest, QuitWhenIdle) { - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce(&QuitWhenIdleTask, Unretained(&run_loop_), - Unretained(&counter_))); - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce(&ShouldRunTask, Unretained(&counter_))); - ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, BindOnce(&ShouldNotRunTask), TimeDelta::FromDays(1)); - - run_loop_.Run(); - EXPECT_EQ(2, counter_); -} - -TEST_P(RunLoopTest, QuitWhenIdleNestedLoop) { - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce(&RunNestedLoopTask, Unretained(&counter_))); - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce(&QuitWhenIdleTask, Unretained(&run_loop_), - Unretained(&counter_))); - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce(&ShouldRunTask, Unretained(&counter_))); - ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, BindOnce(&ShouldNotRunTask), TimeDelta::FromDays(1)); - - run_loop_.Run(); - EXPECT_EQ(4, counter_); -} - -TEST_P(RunLoopTest, QuitWhenIdleClosure) { - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - run_loop_.QuitWhenIdleClosure()); - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce(&ShouldRunTask, Unretained(&counter_))); - ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, BindOnce(&ShouldNotRunTask), TimeDelta::FromDays(1)); - - run_loop_.Run(); - EXPECT_EQ(1, counter_); -} - -// Verify that the QuitWhenIdleClosure() can run after the RunLoop has been -// deleted. It should have no effect. -TEST_P(RunLoopTest, QuitWhenIdleClosureAfterRunLoopScope) { - Closure quit_when_idle_closure; - { - RunLoop run_loop; - quit_when_idle_closure = run_loop.QuitWhenIdleClosure(); - run_loop.RunUntilIdle(); - } - quit_when_idle_closure.Run(); -} - -// Verify that Quit can be executed from another sequence. -TEST_P(RunLoopTest, QuitFromOtherSequence) { - Thread other_thread("test"); - other_thread.Start(); - scoped_refptr<SequencedTaskRunner> other_sequence = - other_thread.task_runner(); - - // Always expected to run before asynchronous Quit() kicks in. - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_))); - - WaitableEvent loop_was_quit(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - other_sequence->PostTask( - FROM_HERE, base::BindOnce([](RunLoop* run_loop) { run_loop->Quit(); }, - Unretained(&run_loop_))); - other_sequence->PostTask( - FROM_HERE, - base::BindOnce(&WaitableEvent::Signal, base::Unretained(&loop_was_quit))); - - // Anything that's posted after the Quit closure was posted back to this - // sequence shouldn't get a chance to run. - loop_was_quit.Wait(); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - base::BindOnce(&ShouldNotRunTask)); - - run_loop_.Run(); - - EXPECT_EQ(1, counter_); -} - -// Verify that QuitClosure can be executed from another sequence. -TEST_P(RunLoopTest, QuitFromOtherSequenceWithClosure) { - Thread other_thread("test"); - other_thread.Start(); - scoped_refptr<SequencedTaskRunner> other_sequence = - other_thread.task_runner(); - - // Always expected to run before asynchronous Quit() kicks in. - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_))); - - WaitableEvent loop_was_quit(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - other_sequence->PostTask(FROM_HERE, run_loop_.QuitClosure()); - other_sequence->PostTask( - FROM_HERE, - base::BindOnce(&WaitableEvent::Signal, base::Unretained(&loop_was_quit))); - - // Anything that's posted after the Quit closure was posted back to this - // sequence shouldn't get a chance to run. - loop_was_quit.Wait(); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - base::BindOnce(&ShouldNotRunTask)); - - run_loop_.Run(); - - EXPECT_EQ(1, counter_); -} - -// Verify that Quit can be executed from another sequence even when the -// Quit is racing with Run() -- i.e. forgo the WaitableEvent used above. -TEST_P(RunLoopTest, QuitFromOtherSequenceRacy) { - Thread other_thread("test"); - other_thread.Start(); - scoped_refptr<SequencedTaskRunner> other_sequence = - other_thread.task_runner(); - - // Always expected to run before asynchronous Quit() kicks in. - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_))); - - other_sequence->PostTask( - FROM_HERE, base::BindOnce([](RunLoop* run_loop) { run_loop->Quit(); }, - Unretained(&run_loop_))); - - run_loop_.Run(); - - EXPECT_EQ(1, counter_); -} - -// Verify that QuitClosure can be executed from another sequence even when the -// Quit is racing with Run() -- i.e. forgo the WaitableEvent used above. -TEST_P(RunLoopTest, QuitFromOtherSequenceRacyWithClosure) { - Thread other_thread("test"); - other_thread.Start(); - scoped_refptr<SequencedTaskRunner> other_sequence = - other_thread.task_runner(); - - // Always expected to run before asynchronous Quit() kicks in. - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_))); - - other_sequence->PostTask(FROM_HERE, run_loop_.QuitClosure()); - - run_loop_.Run(); - - EXPECT_EQ(1, counter_); -} - -// Verify that QuitWhenIdle can be executed from another sequence. -TEST_P(RunLoopTest, QuitWhenIdleFromOtherSequence) { - Thread other_thread("test"); - other_thread.Start(); - scoped_refptr<SequencedTaskRunner> other_sequence = - other_thread.task_runner(); - - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_))); - - other_sequence->PostTask( - FROM_HERE, - base::BindOnce([](RunLoop* run_loop) { run_loop->QuitWhenIdle(); }, - Unretained(&run_loop_))); - - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_))); - - run_loop_.Run(); - - // Regardless of the outcome of the race this thread shouldn't have been idle - // until the counter was ticked twice. - EXPECT_EQ(2, counter_); -} - -// Verify that QuitWhenIdleClosure can be executed from another sequence. -TEST_P(RunLoopTest, QuitWhenIdleFromOtherSequenceWithClosure) { - Thread other_thread("test"); - other_thread.Start(); - scoped_refptr<SequencedTaskRunner> other_sequence = - other_thread.task_runner(); - - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_))); - - other_sequence->PostTask(FROM_HERE, run_loop_.QuitWhenIdleClosure()); - - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_))); - - run_loop_.Run(); - - // Regardless of the outcome of the race this thread shouldn't have been idle - // until the counter was ticked twice. - EXPECT_EQ(2, counter_); -} - -TEST_P(RunLoopTest, IsRunningOnCurrentThread) { - EXPECT_FALSE(RunLoop::IsRunningOnCurrentThread()); - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - BindOnce([]() { EXPECT_TRUE(RunLoop::IsRunningOnCurrentThread()); })); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, run_loop_.QuitClosure()); - run_loop_.Run(); -} - -TEST_P(RunLoopTest, IsNestedOnCurrentThread) { - EXPECT_FALSE(RunLoop::IsNestedOnCurrentThread()); - - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce([]() { - EXPECT_FALSE(RunLoop::IsNestedOnCurrentThread()); - - RunLoop nested_run_loop(RunLoop::Type::kNestableTasksAllowed); - - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce([]() { - EXPECT_TRUE(RunLoop::IsNestedOnCurrentThread()); - })); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - nested_run_loop.QuitClosure()); - - EXPECT_FALSE(RunLoop::IsNestedOnCurrentThread()); - nested_run_loop.Run(); - EXPECT_FALSE(RunLoop::IsNestedOnCurrentThread()); - })); - - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, run_loop_.QuitClosure()); - run_loop_.Run(); -} - -namespace { - -class MockNestingObserver : public RunLoop::NestingObserver { - public: - MockNestingObserver() = default; - - // RunLoop::NestingObserver: - MOCK_METHOD0(OnBeginNestedRunLoop, void()); - MOCK_METHOD0(OnExitNestedRunLoop, void()); - - private: - DISALLOW_COPY_AND_ASSIGN(MockNestingObserver); -}; - -class MockTask { - public: - MockTask() = default; - MOCK_METHOD0(Task, void()); - - private: - DISALLOW_COPY_AND_ASSIGN(MockTask); -}; - -} // namespace - -TEST_P(RunLoopTest, NestingObservers) { - testing::StrictMock<MockNestingObserver> nesting_observer; - testing::StrictMock<MockTask> mock_task_a; - testing::StrictMock<MockTask> mock_task_b; - - RunLoop::AddNestingObserverOnCurrentThread(&nesting_observer); - - const RepeatingClosure run_nested_loop = Bind([]() { - RunLoop nested_run_loop(RunLoop::Type::kNestableTasksAllowed); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - nested_run_loop.QuitClosure()); - nested_run_loop.Run(); - }); - - // Generate a stack of nested RunLoops. OnBeginNestedRunLoop() is expected - // when beginning each nesting depth and OnExitNestedRunLoop() is expected - // when exiting each nesting depth. Each one of these tasks is ahead of the - // QuitClosures as those are only posted at the end of the queue when - // |run_nested_loop| is executed. - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, run_nested_loop); - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::BindOnce(&MockTask::Task, base::Unretained(&mock_task_a))); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, run_nested_loop); - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::BindOnce(&MockTask::Task, base::Unretained(&mock_task_b))); - - { - testing::InSequence in_sequence; - EXPECT_CALL(nesting_observer, OnBeginNestedRunLoop()); - EXPECT_CALL(mock_task_a, Task()); - EXPECT_CALL(nesting_observer, OnBeginNestedRunLoop()); - EXPECT_CALL(mock_task_b, Task()); - EXPECT_CALL(nesting_observer, OnExitNestedRunLoop()).Times(2); - } - run_loop_.RunUntilIdle(); - - RunLoop::RemoveNestingObserverOnCurrentThread(&nesting_observer); -} - -TEST_P(RunLoopTest, DisallowRunningForTesting) { - RunLoop::ScopedDisallowRunningForTesting disallow_running; - EXPECT_DCHECK_DEATH({ run_loop_.RunUntilIdle(); }); -} - -TEST_P(RunLoopTest, ExpiredDisallowRunningForTesting) { - { RunLoop::ScopedDisallowRunningForTesting disallow_running; } - // Running should be fine after |disallow_running| goes out of scope. - run_loop_.RunUntilIdle(); -} - -INSTANTIATE_TEST_CASE_P(Real, - RunLoopTest, - testing::Values(RunLoopTestType::kRealEnvironment)); -INSTANTIATE_TEST_CASE_P(Mock, - RunLoopTest, - testing::Values(RunLoopTestType::kTestDelegate)); - -TEST(RunLoopDeathTest, MustRegisterBeforeInstantiating) { - TestBoundDelegate unbound_test_delegate_; - // RunLoop::RunLoop() should CHECK fetching the ThreadTaskRunnerHandle. - EXPECT_DEATH_IF_SUPPORTED({ RunLoop(); }, ""); -} - -TEST(RunLoopDelegateTest, NestableTasksDontRunInDefaultNestedLoops) { - TestBoundDelegate test_delegate; - test_delegate.BindToCurrentThread(); - - base::Thread other_thread("test"); - other_thread.Start(); - - RunLoop main_loop; - // A nested run loop which isn't kNestableTasksAllowed. - RunLoop nested_run_loop(RunLoop::Type::kDefault); - - bool nested_run_loop_ended = false; - - // The first task on the main loop will result in a nested run loop. Since - // it's not kNestableTasksAllowed, no further task should be processed until - // it's quit. - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - BindOnce([](RunLoop* nested_run_loop) { nested_run_loop->Run(); }, - Unretained(&nested_run_loop))); - - // Post a task that will fail if it runs inside the nested run loop. - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, BindOnce( - [](const bool& nested_run_loop_ended, - OnceClosure continuation_callback) { - EXPECT_TRUE(nested_run_loop_ended); - EXPECT_FALSE(RunLoop::IsNestedOnCurrentThread()); - std::move(continuation_callback).Run(); - }, - ConstRef(nested_run_loop_ended), main_loop.QuitClosure())); - - // Post a task flipping the boolean bit for extra verification right before - // quitting |nested_run_loop|. - other_thread.task_runner()->PostDelayedTask( - FROM_HERE, - BindOnce( - [](bool* nested_run_loop_ended) { - EXPECT_FALSE(*nested_run_loop_ended); - *nested_run_loop_ended = true; - }, - Unretained(&nested_run_loop_ended)), - TestTimeouts::tiny_timeout()); - // Post an async delayed task to exit the run loop when idle. This confirms - // that (1) the test task only ran in the main loop after the nested loop - // exited and (2) the nested run loop actually considers itself idle while - // spinning. Note: The quit closure needs to be injected directly on the - // delegate as invoking QuitWhenIdle() off-thread results in a thread bounce - // which will not processed because of the very logic under test (nestable - // tasks don't run in |nested_run_loop|). - other_thread.task_runner()->PostDelayedTask( - FROM_HERE, - BindOnce( - [](TestBoundDelegate* test_delegate, OnceClosure injected_closure) { - test_delegate->InjectClosureOnDelegate(std::move(injected_closure)); - }, - Unretained(&test_delegate), nested_run_loop.QuitWhenIdleClosure()), - TestTimeouts::tiny_timeout()); - - main_loop.Run(); -} - -} // namespace base
diff --git a/base/safe_numerics_unittest.cc b/base/safe_numerics_unittest.cc deleted file mode 100644 index 7fcc5d1..0000000 --- a/base/safe_numerics_unittest.cc +++ /dev/null
@@ -1,1640 +0,0 @@ -// 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 <stddef.h> -#include <stdint.h> - -#include <limits> -#include <type_traits> - -#include "base/compiler_specific.h" - -// WARNING: This block must come before the base/numerics headers are included. -// These tests deliberately cause arithmetic boundary errors. If the compiler is -// aggressive enough, it can const detect these errors, so we disable warnings. -#if defined(OS_WIN) -#pragma warning(disable : 4756) // Arithmetic overflow. -#pragma warning(disable : 4293) // Invalid shift. -#endif - -// This may not need to come before the base/numerics headers, but let's keep -// it close to the MSVC equivalent. -#if defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Winteger-overflow" -#endif - -#include "base/logging.h" -#include "base/numerics/safe_conversions.h" -#include "base/numerics/safe_math.h" -#include "base/test/gtest_util.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(COMPILER_MSVC) && defined(ARCH_CPU_32_BITS) -#include <mmintrin.h> -#endif - -namespace base { -namespace internal { - -using std::numeric_limits; - -// This is a helper function for finding the maximum value in Src that can be -// wholy represented as the destination floating-point type. -template <typename Dst, typename Src> -Dst GetMaxConvertibleToFloat() { - using DstLimits = numeric_limits<Dst>; - using SrcLimits = numeric_limits<Src>; - static_assert(SrcLimits::is_specialized, "Source must be numeric."); - static_assert(DstLimits::is_specialized, "Destination must be numeric."); - CHECK(DstLimits::is_iec559); - - if (SrcLimits::digits <= DstLimits::digits && - MaxExponent<Src>::value <= MaxExponent<Dst>::value) - return SrcLimits::max(); - Src max = SrcLimits::max() / 2 + (SrcLimits::is_integer ? 1 : 0); - while (max != static_cast<Src>(static_cast<Dst>(max))) { - max /= 2; - } - return static_cast<Dst>(max); -} - -// Test corner case promotions used -static_assert(IsIntegerArithmeticSafe<int32_t, int8_t, int8_t>::value, ""); -static_assert(IsIntegerArithmeticSafe<int32_t, int16_t, int8_t>::value, ""); -static_assert(IsIntegerArithmeticSafe<int32_t, int8_t, int16_t>::value, ""); -static_assert(!IsIntegerArithmeticSafe<int32_t, int32_t, int8_t>::value, ""); -static_assert(BigEnoughPromotion<int16_t, int8_t>::is_contained, ""); -static_assert(BigEnoughPromotion<int32_t, uint32_t>::is_contained, ""); -static_assert(BigEnoughPromotion<intmax_t, int8_t>::is_contained, ""); -static_assert(!BigEnoughPromotion<uintmax_t, int8_t>::is_contained, ""); -static_assert( - std::is_same<BigEnoughPromotion<int16_t, int8_t>::type, int16_t>::value, - ""); -static_assert( - std::is_same<BigEnoughPromotion<int32_t, uint32_t>::type, int64_t>::value, - ""); -static_assert( - std::is_same<BigEnoughPromotion<intmax_t, int8_t>::type, intmax_t>::value, - ""); -static_assert( - std::is_same<BigEnoughPromotion<uintmax_t, int8_t>::type, uintmax_t>::value, - ""); -static_assert(BigEnoughPromotion<int16_t, int8_t>::is_contained, ""); -static_assert(BigEnoughPromotion<int32_t, uint32_t>::is_contained, ""); -static_assert(BigEnoughPromotion<intmax_t, int8_t>::is_contained, ""); -static_assert(!BigEnoughPromotion<uintmax_t, int8_t>::is_contained, ""); -static_assert( - std::is_same<FastIntegerArithmeticPromotion<int16_t, int8_t>::type, - int32_t>::value, - ""); -static_assert( - std::is_same<FastIntegerArithmeticPromotion<int32_t, uint32_t>::type, - int64_t>::value, - ""); -static_assert( - std::is_same<FastIntegerArithmeticPromotion<intmax_t, int8_t>::type, - intmax_t>::value, - ""); -static_assert( - std::is_same<FastIntegerArithmeticPromotion<uintmax_t, int8_t>::type, - uintmax_t>::value, - ""); -static_assert(FastIntegerArithmeticPromotion<int16_t, int8_t>::is_contained, - ""); -static_assert(FastIntegerArithmeticPromotion<int32_t, uint32_t>::is_contained, - ""); -static_assert(!FastIntegerArithmeticPromotion<intmax_t, int8_t>::is_contained, - ""); -static_assert(!FastIntegerArithmeticPromotion<uintmax_t, int8_t>::is_contained, - ""); - -template <typename U> -U GetNumericValueForTest(const CheckedNumeric<U>& src) { - return src.state_.value(); -} - -template <typename U> -U GetNumericValueForTest(const ClampedNumeric<U>& src) { - return static_cast<U>(src); -} - -template <typename U> -U GetNumericValueForTest(const U& src) { - return src; -} - -// Logs the ValueOrDie() failure instead of crashing. -struct LogOnFailure { - template <typename T> - static T HandleFailure() { - LOG(WARNING) << "ValueOrDie() failed unexpectedly."; - return T(); - } -}; - -template <typename T> -constexpr T GetValue(const T& src) { - return src; -} - -template <typename T, typename U> -constexpr T GetValueAsDest(const U& src) { - return static_cast<T>(src); -} - -template <typename T> -constexpr T GetValue(const CheckedNumeric<T>& src) { - return src.template ValueOrDie<T, LogOnFailure>(); -} - -template <typename T, typename U> -constexpr T GetValueAsDest(const CheckedNumeric<U>& src) { - return src.template ValueOrDie<T, LogOnFailure>(); -} - -template <typename T> -constexpr T GetValue(const ClampedNumeric<T>& src) { - return static_cast<T>(src); -} - -template <typename T, typename U> -constexpr T GetValueAsDest(const ClampedNumeric<U>& src) { - return static_cast<T>(src); -} - -// Helper macros to wrap displaying the conversion types and line numbers. -#define TEST_EXPECTED_VALIDITY(expected, actual) \ - EXPECT_EQ(expected, (actual).template Cast<Dst>().IsValid()) \ - << "Result test: Value " << GetNumericValueForTest(actual) << " as " \ - << dst << " on line " << line - -#define TEST_EXPECTED_SUCCESS(actual) TEST_EXPECTED_VALIDITY(true, actual) -#define TEST_EXPECTED_FAILURE(actual) TEST_EXPECTED_VALIDITY(false, actual) - -// We have to handle promotions, so infer the underlying type below from actual. -#define TEST_EXPECTED_VALUE(expected, actual) \ - EXPECT_EQ(GetValue(expected), GetValueAsDest<decltype(expected)>(actual)) \ - << "Result test: Value " << GetNumericValueForTest(actual) << " as " \ - << dst << " on line " << line - -// Test the simple pointer arithmetic overrides. -template <typename Dst> -void TestStrictPointerMath() { - Dst dummy_value = 0; - Dst* dummy_ptr = &dummy_value; - static const Dst kDummyOffset = 2; // Don't want to go too far. - EXPECT_EQ(dummy_ptr + kDummyOffset, - dummy_ptr + StrictNumeric<Dst>(kDummyOffset)); - EXPECT_EQ(dummy_ptr - kDummyOffset, - dummy_ptr - StrictNumeric<Dst>(kDummyOffset)); - EXPECT_NE(dummy_ptr, dummy_ptr + StrictNumeric<Dst>(kDummyOffset)); - EXPECT_NE(dummy_ptr, dummy_ptr - StrictNumeric<Dst>(kDummyOffset)); - EXPECT_DEATH_IF_SUPPORTED( - dummy_ptr + StrictNumeric<size_t>(std::numeric_limits<size_t>::max()), - ""); -} - -// Signed integer arithmetic. -template <typename Dst> -static void TestSpecializedArithmetic( - const char* dst, - int line, - typename std::enable_if<numeric_limits<Dst>::is_integer && - numeric_limits<Dst>::is_signed, - int>::type = 0) { - using DstLimits = SaturationDefaultLimits<Dst>; - TEST_EXPECTED_FAILURE(-CheckedNumeric<Dst>(DstLimits::lowest())); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()).Abs()); - TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(-1).Abs()); - TEST_EXPECTED_VALUE(DstLimits::max(), - MakeCheckedNum(-DstLimits::max()).Abs()); - - TEST_EXPECTED_VALUE(DstLimits::Overflow(), - -ClampedNumeric<Dst>(DstLimits::lowest())); - TEST_EXPECTED_VALUE(DstLimits::Overflow(), - ClampedNumeric<Dst>(DstLimits::lowest()).Abs()); - TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(-1).Abs()); - TEST_EXPECTED_VALUE(DstLimits::max(), - MakeClampedNum(-DstLimits::max()).Abs()); - - TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::max()) + -1); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) + -1); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) + - DstLimits::lowest()); - - TEST_EXPECTED_VALUE(DstLimits::max() - 1, - ClampedNumeric<Dst>(DstLimits::max()) + -1); - TEST_EXPECTED_VALUE(DstLimits::Underflow(), - ClampedNumeric<Dst>(DstLimits::lowest()) + -1); - TEST_EXPECTED_VALUE( - DstLimits::Underflow(), - ClampedNumeric<Dst>(DstLimits::lowest()) + DstLimits::lowest()); - - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) - 1); - TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::lowest()) - -1); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::max()) - - DstLimits::lowest()); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) - - DstLimits::max()); - - TEST_EXPECTED_VALUE(DstLimits::Underflow(), - ClampedNumeric<Dst>(DstLimits::lowest()) - 1); - TEST_EXPECTED_VALUE(DstLimits::lowest() + 1, - ClampedNumeric<Dst>(DstLimits::lowest()) - -1); - TEST_EXPECTED_VALUE( - DstLimits::Overflow(), - ClampedNumeric<Dst>(DstLimits::max()) - DstLimits::lowest()); - TEST_EXPECTED_VALUE( - DstLimits::Underflow(), - ClampedNumeric<Dst>(DstLimits::lowest()) - DstLimits::max()); - - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) * 2); - TEST_EXPECTED_VALUE(DstLimits::Underflow(), - ClampedNumeric<Dst>(DstLimits::lowest()) * 2); - - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) / -1); - TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(-1) / 2); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) * -1); - TEST_EXPECTED_VALUE(DstLimits::max(), - CheckedNumeric<Dst>(DstLimits::lowest() + 1) * Dst(-1)); - TEST_EXPECTED_VALUE(DstLimits::max(), - CheckedNumeric<Dst>(-1) * Dst(DstLimits::lowest() + 1)); - TEST_EXPECTED_VALUE(DstLimits::lowest(), - CheckedNumeric<Dst>(DstLimits::lowest()) * Dst(1)); - TEST_EXPECTED_VALUE(DstLimits::lowest(), - CheckedNumeric<Dst>(1) * Dst(DstLimits::lowest())); - TEST_EXPECTED_VALUE( - typename std::make_unsigned<Dst>::type(0) - DstLimits::lowest(), - MakeCheckedNum(DstLimits::lowest()).UnsignedAbs()); - TEST_EXPECTED_VALUE(DstLimits::max(), - MakeCheckedNum(DstLimits::max()).UnsignedAbs()); - TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(0).UnsignedAbs()); - TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1).UnsignedAbs()); - TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(-1).UnsignedAbs()); - - TEST_EXPECTED_VALUE(DstLimits::Overflow(), - ClampedNumeric<Dst>(DstLimits::lowest()) / -1); - TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(-1) / 2); - TEST_EXPECTED_VALUE(DstLimits::Overflow(), - ClampedNumeric<Dst>(DstLimits::lowest()) * -1); - TEST_EXPECTED_VALUE(DstLimits::max(), - ClampedNumeric<Dst>(DstLimits::lowest() + 1) * Dst(-1)); - TEST_EXPECTED_VALUE(DstLimits::max(), - ClampedNumeric<Dst>(-1) * Dst(DstLimits::lowest() + 1)); - TEST_EXPECTED_VALUE(DstLimits::lowest(), - ClampedNumeric<Dst>(DstLimits::lowest()) * Dst(1)); - TEST_EXPECTED_VALUE(DstLimits::lowest(), - ClampedNumeric<Dst>(1) * Dst(DstLimits::lowest())); - TEST_EXPECTED_VALUE( - typename std::make_unsigned<Dst>::type(0) - DstLimits::lowest(), - MakeClampedNum(DstLimits::lowest()).UnsignedAbs()); - TEST_EXPECTED_VALUE(DstLimits::max(), - MakeClampedNum(DstLimits::max()).UnsignedAbs()); - TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(0).UnsignedAbs()); - TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(1).UnsignedAbs()); - TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(-1).UnsignedAbs()); - - // Modulus is legal only for integers. - TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>() % 1); - TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % 1); - TEST_EXPECTED_VALUE(-1, CheckedNumeric<Dst>(-1) % 2); - TEST_EXPECTED_VALUE(-1, CheckedNumeric<Dst>(-1) % -2); - TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(DstLimits::lowest()) % 2); - TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(DstLimits::max()) % 2); - // Test all the different modulus combinations. - TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % CheckedNumeric<Dst>(1)); - TEST_EXPECTED_VALUE(0, 1 % CheckedNumeric<Dst>(1)); - TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % 1); - CheckedNumeric<Dst> checked_dst = 1; - TEST_EXPECTED_VALUE(0, checked_dst %= 1); - // Test that div by 0 is avoided but returns invalid result. - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) % 0); - // Test bit shifts. - volatile Dst negative_one = -1; - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) << negative_one); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) - << (IntegerBitsPlusSign<Dst>::value - 1)); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(0) - << IntegerBitsPlusSign<Dst>::value); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::max()) << 1); - TEST_EXPECTED_VALUE( - static_cast<Dst>(1) << (IntegerBitsPlusSign<Dst>::value - 2), - CheckedNumeric<Dst>(1) << (IntegerBitsPlusSign<Dst>::value - 2)); - TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(0) - << (IntegerBitsPlusSign<Dst>::value - 1)); - TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) << 0); - TEST_EXPECTED_VALUE(2, CheckedNumeric<Dst>(1) << 1); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) >> - IntegerBitsPlusSign<Dst>::value); - TEST_EXPECTED_VALUE( - 0, CheckedNumeric<Dst>(1) >> (IntegerBitsPlusSign<Dst>::value - 1)); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) >> negative_one); - - // Modulus is legal only for integers. - TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>() % 1); - TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(1) % 1); - TEST_EXPECTED_VALUE(-1, ClampedNumeric<Dst>(-1) % 2); - TEST_EXPECTED_VALUE(-1, ClampedNumeric<Dst>(-1) % -2); - TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(DstLimits::lowest()) % 2); - TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(DstLimits::max()) % 2); - // Test all the different modulus combinations. - TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(1) % ClampedNumeric<Dst>(1)); - TEST_EXPECTED_VALUE(0, 1 % ClampedNumeric<Dst>(1)); - TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(1) % 1); - ClampedNumeric<Dst> clamped_dst = 1; - TEST_EXPECTED_VALUE(0, clamped_dst %= 1); - TEST_EXPECTED_VALUE(Dst(1), ClampedNumeric<Dst>(1) % 0); - // Test bit shifts. - TEST_EXPECTED_VALUE(DstLimits::Overflow(), - ClampedNumeric<Dst>(1) - << (IntegerBitsPlusSign<Dst>::value - 1U)); - TEST_EXPECTED_VALUE(Dst(0), ClampedNumeric<Dst>(0) - << (IntegerBitsPlusSign<Dst>::value + 0U)); - TEST_EXPECTED_VALUE(DstLimits::Overflow(), - ClampedNumeric<Dst>(DstLimits::max()) << 1U); - TEST_EXPECTED_VALUE( - static_cast<Dst>(1) << (IntegerBitsPlusSign<Dst>::value - 2U), - ClampedNumeric<Dst>(1) << (IntegerBitsPlusSign<Dst>::value - 2U)); - TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(0) - << (IntegerBitsPlusSign<Dst>::value - 1U)); - TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(1) << 0U); - TEST_EXPECTED_VALUE(2, ClampedNumeric<Dst>(1) << 1U); - TEST_EXPECTED_VALUE( - 0, ClampedNumeric<Dst>(1) >> (IntegerBitsPlusSign<Dst>::value + 0U)); - TEST_EXPECTED_VALUE( - 0, ClampedNumeric<Dst>(1) >> (IntegerBitsPlusSign<Dst>::value - 1U)); - TEST_EXPECTED_VALUE( - -1, ClampedNumeric<Dst>(-1) >> (IntegerBitsPlusSign<Dst>::value - 1U)); - TEST_EXPECTED_VALUE(-1, ClampedNumeric<Dst>(DstLimits::lowest()) >> - (IntegerBitsPlusSign<Dst>::value - 0U)); - - TestStrictPointerMath<Dst>(); -} - -// Unsigned integer arithmetic. -template <typename Dst> -static void TestSpecializedArithmetic( - const char* dst, - int line, - typename std::enable_if<numeric_limits<Dst>::is_integer && - !numeric_limits<Dst>::is_signed, - int>::type = 0) { - using DstLimits = SaturationDefaultLimits<Dst>; - TEST_EXPECTED_SUCCESS(-CheckedNumeric<Dst>(DstLimits::lowest())); - TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::lowest()).Abs()); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) + -1); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) - 1); - TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(DstLimits::lowest()) * 2); - TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) / 2); - TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::lowest()).UnsignedAbs()); - TEST_EXPECTED_SUCCESS( - CheckedNumeric<typename std::make_signed<Dst>::type>( - std::numeric_limits<typename std::make_signed<Dst>::type>::lowest()) - .UnsignedAbs()); - TEST_EXPECTED_VALUE(DstLimits::lowest(), - MakeCheckedNum(DstLimits::lowest()).UnsignedAbs()); - TEST_EXPECTED_VALUE(DstLimits::max(), - MakeCheckedNum(DstLimits::max()).UnsignedAbs()); - TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(0).UnsignedAbs()); - TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1).UnsignedAbs()); - - TEST_EXPECTED_VALUE(0, -ClampedNumeric<Dst>(DstLimits::lowest())); - TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(DstLimits::lowest()).Abs()); - TEST_EXPECTED_VALUE(DstLimits::Underflow(), - ClampedNumeric<Dst>(DstLimits::lowest()) + -1); - TEST_EXPECTED_VALUE(DstLimits::Underflow(), - ClampedNumeric<Dst>(DstLimits::lowest()) - 1); - TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(DstLimits::lowest()) * 2); - TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(1) / 2); - TEST_EXPECTED_VALUE(0, - ClampedNumeric<Dst>(DstLimits::lowest()).UnsignedAbs()); - TEST_EXPECTED_VALUE( - as_unsigned( - std::numeric_limits<typename std::make_signed<Dst>::type>::lowest()), - ClampedNumeric<typename std::make_signed<Dst>::type>( - std::numeric_limits<typename std::make_signed<Dst>::type>::lowest()) - .UnsignedAbs()); - TEST_EXPECTED_VALUE(DstLimits::lowest(), - MakeClampedNum(DstLimits::lowest()).UnsignedAbs()); - TEST_EXPECTED_VALUE(DstLimits::max(), - MakeClampedNum(DstLimits::max()).UnsignedAbs()); - TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(0).UnsignedAbs()); - TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(1).UnsignedAbs()); - - // Modulus is legal only for integers. - TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>() % 1); - TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % 1); - TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) % 2); - TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(DstLimits::lowest()) % 2); - TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(DstLimits::max()) % 2); - // Test all the different modulus combinations. - TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % CheckedNumeric<Dst>(1)); - TEST_EXPECTED_VALUE(0, 1 % CheckedNumeric<Dst>(1)); - TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % 1); - CheckedNumeric<Dst> checked_dst = 1; - TEST_EXPECTED_VALUE(0, checked_dst %= 1); - // Test that div by 0 is avoided but returns invalid result. - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) % 0); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) - << IntegerBitsPlusSign<Dst>::value); - // Test bit shifts. - volatile int negative_one = -1; - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) << negative_one); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) - << IntegerBitsPlusSign<Dst>::value); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(0) - << IntegerBitsPlusSign<Dst>::value); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::max()) << 1); - TEST_EXPECTED_VALUE( - static_cast<Dst>(1) << (IntegerBitsPlusSign<Dst>::value - 1), - CheckedNumeric<Dst>(1) << (IntegerBitsPlusSign<Dst>::value - 1)); - TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) << 0); - TEST_EXPECTED_VALUE(2, CheckedNumeric<Dst>(1) << 1); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) >> - IntegerBitsPlusSign<Dst>::value); - TEST_EXPECTED_VALUE( - 0, CheckedNumeric<Dst>(1) >> (IntegerBitsPlusSign<Dst>::value - 1)); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) >> negative_one); - TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) & 1); - TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) & 0); - TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(0) & 1); - TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) & 0); - TEST_EXPECTED_VALUE(std::numeric_limits<Dst>::max(), - MakeCheckedNum(DstLimits::max()) & -1); - TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) | 1); - TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) | 0); - TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(0) | 1); - TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(0) | 0); - TEST_EXPECTED_VALUE(std::numeric_limits<Dst>::max(), - CheckedNumeric<Dst>(0) | static_cast<Dst>(-1)); - TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) ^ 1); - TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) ^ 0); - TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(0) ^ 1); - TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(0) ^ 0); - TEST_EXPECTED_VALUE(std::numeric_limits<Dst>::max(), - CheckedNumeric<Dst>(0) ^ static_cast<Dst>(-1)); - TEST_EXPECTED_VALUE(DstLimits::max(), ~CheckedNumeric<Dst>(0)); - - // Modulus is legal only for integers. - TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>() % 1); - TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(1) % 1); - TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(1) % 2); - TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(DstLimits::lowest()) % 2); - TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(DstLimits::max()) % 2); - // Test all the different modulus combinations. - TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(1) % ClampedNumeric<Dst>(1)); - TEST_EXPECTED_VALUE(0, 1 % ClampedNumeric<Dst>(1)); - TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(1) % 1); - ClampedNumeric<Dst> clamped_dst = 1; - TEST_EXPECTED_VALUE(0, clamped_dst %= 1); - // Test that div by 0 is avoided but returns invalid result. - TEST_EXPECTED_VALUE(Dst(1), ClampedNumeric<Dst>(1) % 0); - // Test bit shifts. - TEST_EXPECTED_VALUE(DstLimits::Overflow(), - ClampedNumeric<Dst>(1) - << as_unsigned(IntegerBitsPlusSign<Dst>::value)); - TEST_EXPECTED_VALUE(Dst(0), ClampedNumeric<Dst>(0) << as_unsigned( - IntegerBitsPlusSign<Dst>::value)); - TEST_EXPECTED_VALUE(DstLimits::Overflow(), - ClampedNumeric<Dst>(DstLimits::max()) << 1U); - TEST_EXPECTED_VALUE( - static_cast<Dst>(1) << (IntegerBitsPlusSign<Dst>::value - 1U), - ClampedNumeric<Dst>(1) << (IntegerBitsPlusSign<Dst>::value - 1U)); - TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(1) << 0U); - TEST_EXPECTED_VALUE(2, ClampedNumeric<Dst>(1) << 1U); - TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(1) >> - as_unsigned(IntegerBitsPlusSign<Dst>::value)); - TEST_EXPECTED_VALUE( - 0, ClampedNumeric<Dst>(1) >> (IntegerBitsPlusSign<Dst>::value - 1U)); - TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(1) & 1); - TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(1) & 0); - TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(0) & 1); - TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(1) & 0); - TEST_EXPECTED_VALUE(std::numeric_limits<Dst>::max(), - MakeClampedNum(DstLimits::max()) & -1); - TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(1) | 1); - TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(1) | 0); - TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(0) | 1); - TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(0) | 0); - TEST_EXPECTED_VALUE(std::numeric_limits<Dst>::max(), - ClampedNumeric<Dst>(0) | static_cast<Dst>(-1)); - TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(1) ^ 1); - TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(1) ^ 0); - TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(0) ^ 1); - TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(0) ^ 0); - TEST_EXPECTED_VALUE(std::numeric_limits<Dst>::max(), - ClampedNumeric<Dst>(0) ^ static_cast<Dst>(-1)); - TEST_EXPECTED_VALUE(DstLimits::max(), ~ClampedNumeric<Dst>(0)); - - TestStrictPointerMath<Dst>(); -} - -// Floating point arithmetic. -template <typename Dst> -void TestSpecializedArithmetic( - const char* dst, - int line, - typename std::enable_if<numeric_limits<Dst>::is_iec559, int>::type = 0) { - using DstLimits = SaturationDefaultLimits<Dst>; - TEST_EXPECTED_SUCCESS(-CheckedNumeric<Dst>(DstLimits::lowest())); - - TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::lowest()).Abs()); - TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(-1).Abs()); - - TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::lowest()) + -1); - TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::max()) + 1); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) + - DstLimits::lowest()); - - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::max()) - - DstLimits::lowest()); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) - - DstLimits::max()); - - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) * 2); - - TEST_EXPECTED_VALUE(-0.5, CheckedNumeric<Dst>(-1.0) / 2); - - TEST_EXPECTED_VALUE(DstLimits::max(), - -ClampedNumeric<Dst>(DstLimits::lowest())); - - TEST_EXPECTED_VALUE(DstLimits::max(), - ClampedNumeric<Dst>(DstLimits::lowest()).Abs()); - TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(-1).Abs()); - - TEST_EXPECTED_VALUE(DstLimits::lowest() - 1, - ClampedNumeric<Dst>(DstLimits::lowest()) + -1); - TEST_EXPECTED_VALUE(DstLimits::max() + 1, - ClampedNumeric<Dst>(DstLimits::max()) + 1); - TEST_EXPECTED_VALUE( - DstLimits::Underflow(), - ClampedNumeric<Dst>(DstLimits::lowest()) + DstLimits::lowest()); - - TEST_EXPECTED_VALUE( - DstLimits::Overflow(), - ClampedNumeric<Dst>(DstLimits::max()) - DstLimits::lowest()); - TEST_EXPECTED_VALUE( - DstLimits::Underflow(), - ClampedNumeric<Dst>(DstLimits::lowest()) - DstLimits::max()); - - TEST_EXPECTED_VALUE(DstLimits::Underflow(), - ClampedNumeric<Dst>(DstLimits::lowest()) * 2); - - TEST_EXPECTED_VALUE(-0.5, ClampedNumeric<Dst>(-1.0) / 2); -} - -// Generic arithmetic tests. -template <typename Dst> -static void TestArithmetic(const char* dst, int line) { - using DstLimits = SaturationDefaultLimits<Dst>; - - EXPECT_EQ(true, CheckedNumeric<Dst>().IsValid()); - EXPECT_EQ(false, CheckedNumeric<Dst>(CheckedNumeric<Dst>(DstLimits::max()) * - DstLimits::max()) - .IsValid()); - EXPECT_EQ(static_cast<Dst>(0), CheckedNumeric<Dst>().ValueOrDie()); - EXPECT_EQ(static_cast<Dst>(0), CheckedNumeric<Dst>().ValueOrDefault(1)); - EXPECT_EQ(static_cast<Dst>(1), - CheckedNumeric<Dst>(CheckedNumeric<Dst>(DstLimits::max()) * - DstLimits::max()) - .ValueOrDefault(1)); - - // Test the operator combinations. - TEST_EXPECTED_VALUE(2, CheckedNumeric<Dst>(1) + CheckedNumeric<Dst>(1)); - TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) - CheckedNumeric<Dst>(1)); - TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) * CheckedNumeric<Dst>(1)); - TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) / CheckedNumeric<Dst>(1)); - TEST_EXPECTED_VALUE(2, 1 + CheckedNumeric<Dst>(1)); - TEST_EXPECTED_VALUE(0, 1 - CheckedNumeric<Dst>(1)); - TEST_EXPECTED_VALUE(1, 1 * CheckedNumeric<Dst>(1)); - TEST_EXPECTED_VALUE(1, 1 / CheckedNumeric<Dst>(1)); - TEST_EXPECTED_VALUE(2, CheckedNumeric<Dst>(1) + 1); - TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) - 1); - TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) * 1); - TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) / 1); - CheckedNumeric<Dst> checked_dst = 1; - TEST_EXPECTED_VALUE(2, checked_dst += 1); - checked_dst = 1; - TEST_EXPECTED_VALUE(0, checked_dst -= 1); - checked_dst = 1; - TEST_EXPECTED_VALUE(1, checked_dst *= 1); - checked_dst = 1; - TEST_EXPECTED_VALUE(1, checked_dst /= 1); - - TEST_EXPECTED_VALUE(2, ClampedNumeric<Dst>(1) + ClampedNumeric<Dst>(1)); - TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(1) - ClampedNumeric<Dst>(1)); - TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(1) * ClampedNumeric<Dst>(1)); - TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(1) / ClampedNumeric<Dst>(1)); - TEST_EXPECTED_VALUE(2, 1 + ClampedNumeric<Dst>(1)); - TEST_EXPECTED_VALUE(0, 1 - ClampedNumeric<Dst>(1)); - TEST_EXPECTED_VALUE(1, 1 * ClampedNumeric<Dst>(1)); - TEST_EXPECTED_VALUE(1, 1 / ClampedNumeric<Dst>(1)); - TEST_EXPECTED_VALUE(2, ClampedNumeric<Dst>(1) + 1); - TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(1) - 1); - TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(1) * 1); - TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(1) / 1); - ClampedNumeric<Dst> clamped_dst = 1; - TEST_EXPECTED_VALUE(2, clamped_dst += 1); - clamped_dst = 1; - TEST_EXPECTED_VALUE(0, clamped_dst -= 1); - clamped_dst = 1; - TEST_EXPECTED_VALUE(1, clamped_dst *= 1); - clamped_dst = 1; - TEST_EXPECTED_VALUE(1, clamped_dst /= 1); - - // Generic negation. - if (DstLimits::is_signed) { - TEST_EXPECTED_VALUE(0, -CheckedNumeric<Dst>()); - TEST_EXPECTED_VALUE(-1, -CheckedNumeric<Dst>(1)); - TEST_EXPECTED_VALUE(1, -CheckedNumeric<Dst>(-1)); - TEST_EXPECTED_VALUE(static_cast<Dst>(DstLimits::max() * -1), - -CheckedNumeric<Dst>(DstLimits::max())); - - TEST_EXPECTED_VALUE(0, -ClampedNumeric<Dst>()); - TEST_EXPECTED_VALUE(-1, -ClampedNumeric<Dst>(1)); - TEST_EXPECTED_VALUE(1, -ClampedNumeric<Dst>(-1)); - TEST_EXPECTED_VALUE(static_cast<Dst>(DstLimits::max() * -1), - -ClampedNumeric<Dst>(DstLimits::max())); - - // The runtime paths for saturated negation differ significantly from what - // gets evaluated at compile-time. Making this test volatile forces the - // compiler to generate code rather than fold constant expressions. - volatile Dst value = Dst(0); - TEST_EXPECTED_VALUE(0, -MakeClampedNum(value)); - value = Dst(1); - TEST_EXPECTED_VALUE(-1, -MakeClampedNum(value)); - value = Dst(2); - TEST_EXPECTED_VALUE(-2, -MakeClampedNum(value)); - value = Dst(-1); - TEST_EXPECTED_VALUE(1, -MakeClampedNum(value)); - value = Dst(-2); - TEST_EXPECTED_VALUE(2, -MakeClampedNum(value)); - value = DstLimits::max(); - TEST_EXPECTED_VALUE(Dst(DstLimits::max() * -1), -MakeClampedNum(value)); - value = Dst(-1 * DstLimits::max()); - TEST_EXPECTED_VALUE(DstLimits::max(), -MakeClampedNum(value)); - value = DstLimits::lowest(); - TEST_EXPECTED_VALUE(DstLimits::max(), -MakeClampedNum(value)); - } - - // Generic absolute value. - TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>().Abs()); - TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1).Abs()); - TEST_EXPECTED_VALUE(DstLimits::max(), - CheckedNumeric<Dst>(DstLimits::max()).Abs()); - - TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>().Abs()); - TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(1).Abs()); - TEST_EXPECTED_VALUE(DstLimits::max(), - ClampedNumeric<Dst>(DstLimits::max()).Abs()); - - // Generic addition. - TEST_EXPECTED_VALUE(1, (CheckedNumeric<Dst>() + 1)); - TEST_EXPECTED_VALUE(2, (CheckedNumeric<Dst>(1) + 1)); - if (numeric_limits<Dst>::is_signed) - TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>(-1) + 1)); - TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::lowest()) + 1); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::max()) + - DstLimits::max()); - - TEST_EXPECTED_VALUE(1, (ClampedNumeric<Dst>() + 1)); - TEST_EXPECTED_VALUE(2, (ClampedNumeric<Dst>(1) + 1)); - if (numeric_limits<Dst>::is_signed) - TEST_EXPECTED_VALUE(0, (ClampedNumeric<Dst>(-1) + 1)); - TEST_EXPECTED_VALUE(DstLimits::lowest() + 1, - ClampedNumeric<Dst>(DstLimits::lowest()) + 1); - TEST_EXPECTED_VALUE(DstLimits::Overflow(), - ClampedNumeric<Dst>(DstLimits::max()) + DstLimits::max()); - - // Generic subtraction. - TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>(1) - 1)); - TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::max()) - 1); - if (numeric_limits<Dst>::is_signed) { - TEST_EXPECTED_VALUE(-1, (CheckedNumeric<Dst>() - 1)); - TEST_EXPECTED_VALUE(-2, (CheckedNumeric<Dst>(-1) - 1)); - } else { - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::max()) - -1); - } - - TEST_EXPECTED_VALUE(0, (ClampedNumeric<Dst>(1) - 1)); - TEST_EXPECTED_VALUE(DstLimits::max() - 1, - ClampedNumeric<Dst>(DstLimits::max()) - 1); - if (numeric_limits<Dst>::is_signed) { - TEST_EXPECTED_VALUE(-1, (ClampedNumeric<Dst>() - 1)); - TEST_EXPECTED_VALUE(-2, (ClampedNumeric<Dst>(-1) - 1)); - } else { - TEST_EXPECTED_VALUE(DstLimits::max(), - ClampedNumeric<Dst>(DstLimits::max()) - -1); - } - - // Generic multiplication. - TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>() * 1)); - TEST_EXPECTED_VALUE(1, (CheckedNumeric<Dst>(1) * 1)); - TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>(0) * 0)); - if (numeric_limits<Dst>::is_signed) { - TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>(-1) * 0)); - TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>(0) * -1)); - TEST_EXPECTED_VALUE(-2, (CheckedNumeric<Dst>(-1) * 2)); - } else { - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::max()) * -2); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::max()) * - CheckedNumeric<uintmax_t>(-2)); - } - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::max()) * - DstLimits::max()); - - TEST_EXPECTED_VALUE(0, (ClampedNumeric<Dst>() * 1)); - TEST_EXPECTED_VALUE(1, (ClampedNumeric<Dst>(1) * 1)); - TEST_EXPECTED_VALUE(0, (ClampedNumeric<Dst>(0) * 0)); - if (numeric_limits<Dst>::is_signed) { - TEST_EXPECTED_VALUE(0, (ClampedNumeric<Dst>(-1) * 0)); - TEST_EXPECTED_VALUE(0, (ClampedNumeric<Dst>(0) * -1)); - TEST_EXPECTED_VALUE(-2, (ClampedNumeric<Dst>(-1) * 2)); - } else { - TEST_EXPECTED_VALUE(DstLimits::Underflow(), - ClampedNumeric<Dst>(DstLimits::max()) * -2); - TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(DstLimits::max()) * - ClampedNumeric<uintmax_t>(-2)); - } - TEST_EXPECTED_VALUE(DstLimits::Overflow(), - ClampedNumeric<Dst>(DstLimits::max()) * DstLimits::max()); - - // Generic division. - TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>() / 1); - TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) / 1); - TEST_EXPECTED_VALUE(DstLimits::lowest() / 2, - CheckedNumeric<Dst>(DstLimits::lowest()) / 2); - TEST_EXPECTED_VALUE(DstLimits::max() / 2, - CheckedNumeric<Dst>(DstLimits::max()) / 2); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) / 0); - - TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>() / 1); - TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(1) / 1); - TEST_EXPECTED_VALUE(DstLimits::lowest() / 2, - ClampedNumeric<Dst>(DstLimits::lowest()) / 2); - TEST_EXPECTED_VALUE(DstLimits::max() / 2, - ClampedNumeric<Dst>(DstLimits::max()) / 2); - TEST_EXPECTED_VALUE(DstLimits::Overflow(), ClampedNumeric<Dst>(1) / 0); - TEST_EXPECTED_VALUE(DstLimits::Underflow(), ClampedNumeric<Dst>(-1) / 0); - TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(0) / 0); - - TestSpecializedArithmetic<Dst>(dst, line); -} - -// Helper macro to wrap displaying the conversion types and line numbers. -#define TEST_ARITHMETIC(Dst) TestArithmetic<Dst>(#Dst, __LINE__) - -TEST(SafeNumerics, SignedIntegerMath) { - TEST_ARITHMETIC(int8_t); - TEST_ARITHMETIC(int16_t); - TEST_ARITHMETIC(int); - TEST_ARITHMETIC(intptr_t); - TEST_ARITHMETIC(intmax_t); -} - -TEST(SafeNumerics, UnsignedIntegerMath) { - TEST_ARITHMETIC(uint8_t); - TEST_ARITHMETIC(uint16_t); - TEST_ARITHMETIC(unsigned int); - TEST_ARITHMETIC(uintptr_t); - TEST_ARITHMETIC(uintmax_t); -} - -TEST(SafeNumerics, FloatingPointMath) { - TEST_ARITHMETIC(float); - TEST_ARITHMETIC(double); -} - -// Enumerates the five different conversions types we need to test. -enum NumericConversionType { - SIGN_PRESERVING_VALUE_PRESERVING, - SIGN_PRESERVING_NARROW, - SIGN_TO_UNSIGN_WIDEN_OR_EQUAL, - SIGN_TO_UNSIGN_NARROW, - UNSIGN_TO_SIGN_NARROW_OR_EQUAL, -}; - -// Template covering the different conversion tests. -template <typename Dst, typename Src, NumericConversionType conversion> -struct TestNumericConversion {}; - -enum RangeConstraint { - RANGE_VALID = 0x0, // Value can be represented by the destination type. - RANGE_UNDERFLOW = 0x1, // Value would underflow. - RANGE_OVERFLOW = 0x2, // Value would overflow. - RANGE_INVALID = RANGE_UNDERFLOW | RANGE_OVERFLOW // Invalid (i.e. NaN). -}; - -// These are some wrappers to make the tests a bit cleaner. -constexpr RangeConstraint RangeCheckToEnum(const RangeCheck constraint) { - return static_cast<RangeConstraint>( - static_cast<int>(constraint.IsOverflowFlagSet()) << 1 | - static_cast<int>(constraint.IsUnderflowFlagSet())); -} - -// EXPECT_EQ wrappers providing specific detail on test failures. -#define TEST_EXPECTED_RANGE(expected, actual) \ - EXPECT_EQ(expected, \ - RangeCheckToEnum(DstRangeRelationToSrcRange<Dst>(actual))) \ - << "Conversion test: " << src << " value " << actual << " to " << dst \ - << " on line " << line - -template <typename Dst, typename Src> -void TestStrictComparison(const char* dst, const char* src, int line) { - using DstLimits = numeric_limits<Dst>; - using SrcLimits = numeric_limits<Src>; - static_assert(StrictNumeric<Src>(SrcLimits::lowest()) < DstLimits::max(), ""); - static_assert(StrictNumeric<Src>(SrcLimits::lowest()) < SrcLimits::max(), ""); - static_assert(!(StrictNumeric<Src>(SrcLimits::lowest()) >= DstLimits::max()), - ""); - static_assert(!(StrictNumeric<Src>(SrcLimits::lowest()) >= SrcLimits::max()), - ""); - static_assert(StrictNumeric<Src>(SrcLimits::lowest()) <= DstLimits::max(), - ""); - static_assert(StrictNumeric<Src>(SrcLimits::lowest()) <= SrcLimits::max(), - ""); - static_assert(!(StrictNumeric<Src>(SrcLimits::lowest()) > DstLimits::max()), - ""); - static_assert(!(StrictNumeric<Src>(SrcLimits::lowest()) > SrcLimits::max()), - ""); - static_assert(StrictNumeric<Src>(SrcLimits::max()) > DstLimits::lowest(), ""); - static_assert(StrictNumeric<Src>(SrcLimits::max()) > SrcLimits::lowest(), ""); - static_assert(!(StrictNumeric<Src>(SrcLimits::max()) <= DstLimits::lowest()), - ""); - static_assert(!(StrictNumeric<Src>(SrcLimits::max()) <= SrcLimits::lowest()), - ""); - static_assert(StrictNumeric<Src>(SrcLimits::max()) >= DstLimits::lowest(), - ""); - static_assert(StrictNumeric<Src>(SrcLimits::max()) >= SrcLimits::lowest(), - ""); - static_assert(!(StrictNumeric<Src>(SrcLimits::max()) < DstLimits::lowest()), - ""); - static_assert(!(StrictNumeric<Src>(SrcLimits::max()) < SrcLimits::lowest()), - ""); - static_assert(StrictNumeric<Src>(static_cast<Src>(1)) == static_cast<Dst>(1), - ""); - static_assert(StrictNumeric<Src>(static_cast<Src>(1)) != static_cast<Dst>(0), - ""); - static_assert(StrictNumeric<Src>(SrcLimits::max()) != static_cast<Dst>(0), - ""); - static_assert(StrictNumeric<Src>(SrcLimits::max()) != DstLimits::lowest(), - ""); - static_assert( - !(StrictNumeric<Src>(static_cast<Src>(1)) != static_cast<Dst>(1)), ""); - static_assert( - !(StrictNumeric<Src>(static_cast<Src>(1)) == static_cast<Dst>(0)), ""); - - // Due to differences in float handling between compilers, these aren't - // compile-time constants everywhere. So, we use run-time tests. - EXPECT_EQ( - SrcLimits::max(), - MakeCheckedNum(SrcLimits::max()).Max(DstLimits::lowest()).ValueOrDie()); - EXPECT_EQ( - DstLimits::max(), - MakeCheckedNum(SrcLimits::lowest()).Max(DstLimits::max()).ValueOrDie()); - EXPECT_EQ( - DstLimits::lowest(), - MakeCheckedNum(SrcLimits::max()).Min(DstLimits::lowest()).ValueOrDie()); - EXPECT_EQ( - SrcLimits::lowest(), - MakeCheckedNum(SrcLimits::lowest()).Min(DstLimits::max()).ValueOrDie()); - EXPECT_EQ(SrcLimits::lowest(), CheckMin(MakeStrictNum(1), MakeCheckedNum(0), - DstLimits::max(), SrcLimits::lowest()) - .ValueOrDie()); - EXPECT_EQ(DstLimits::max(), CheckMax(MakeStrictNum(1), MakeCheckedNum(0), - DstLimits::max(), SrcLimits::lowest()) - .ValueOrDie()); - - EXPECT_EQ(SrcLimits::max(), - MakeClampedNum(SrcLimits::max()).Max(DstLimits::lowest())); - EXPECT_EQ(DstLimits::max(), - MakeClampedNum(SrcLimits::lowest()).Max(DstLimits::max())); - EXPECT_EQ(DstLimits::lowest(), - MakeClampedNum(SrcLimits::max()).Min(DstLimits::lowest())); - EXPECT_EQ(SrcLimits::lowest(), - MakeClampedNum(SrcLimits::lowest()).Min(DstLimits::max())); - EXPECT_EQ(SrcLimits::lowest(), - ClampMin(MakeStrictNum(1), MakeClampedNum(0), DstLimits::max(), - SrcLimits::lowest())); - EXPECT_EQ(DstLimits::max(), ClampMax(MakeStrictNum(1), MakeClampedNum(0), - DstLimits::max(), SrcLimits::lowest())); - - if (IsValueInRangeForNumericType<Dst>(SrcLimits::max())) { - TEST_EXPECTED_VALUE(Dst(SrcLimits::max()), (CommonMax<Dst, Src>())); - TEST_EXPECTED_VALUE(Dst(SrcLimits::max()), - (CommonMaxOrMin<Dst, Src>(false))); - } else { - TEST_EXPECTED_VALUE(DstLimits::max(), (CommonMax<Dst, Src>())); - TEST_EXPECTED_VALUE(DstLimits::max(), (CommonMaxOrMin<Dst, Src>(false))); - } - - if (IsValueInRangeForNumericType<Dst>(SrcLimits::lowest())) { - TEST_EXPECTED_VALUE(Dst(SrcLimits::lowest()), (CommonMin<Dst, Src>())); - TEST_EXPECTED_VALUE(Dst(SrcLimits::lowest()), - (CommonMaxOrMin<Dst, Src>(true))); - } else { - TEST_EXPECTED_VALUE(DstLimits::lowest(), (CommonMin<Dst, Src>())); - TEST_EXPECTED_VALUE(DstLimits::lowest(), (CommonMaxOrMin<Dst, Src>(true))); - } -} - -template <typename Dst, typename Src> -struct TestNumericConversion<Dst, Src, SIGN_PRESERVING_VALUE_PRESERVING> { - static void Test(const char* dst, const char* src, int line) { - using SrcLimits = SaturationDefaultLimits<Src>; - using DstLimits = SaturationDefaultLimits<Dst>; - // Integral to floating. - static_assert((DstLimits::is_iec559 && SrcLimits::is_integer) || - // Not floating to integral and... - (!(DstLimits::is_integer && SrcLimits::is_iec559) && - // Same sign, same numeric, source is narrower or same. - ((SrcLimits::is_signed == DstLimits::is_signed && - MaxExponent<Dst>::value >= MaxExponent<Src>::value) || - // Or signed destination and source is smaller - (DstLimits::is_signed && - MaxExponent<Dst>::value >= MaxExponent<Src>::value))), - "Comparison must be sign preserving and value preserving"); - - TestStrictComparison<Dst, Src>(dst, src, line); - - const CheckedNumeric<Dst> checked_dst = SrcLimits::max(); - const ClampedNumeric<Dst> clamped_dst = SrcLimits::max(); - TEST_EXPECTED_SUCCESS(checked_dst); - TEST_EXPECTED_VALUE(Dst(SrcLimits::max()), clamped_dst); - if (MaxExponent<Dst>::value > MaxExponent<Src>::value) { - if (MaxExponent<Dst>::value >= MaxExponent<Src>::value * 2 - 1) { - // At least twice larger type. - TEST_EXPECTED_SUCCESS(SrcLimits::max() * checked_dst); - TEST_EXPECTED_VALUE(SrcLimits::max() * clamped_dst, - Dst(SrcLimits::max()) * SrcLimits::max()); - } else { // Larger, but not at least twice as large. - TEST_EXPECTED_FAILURE(SrcLimits::max() * checked_dst); - TEST_EXPECTED_SUCCESS(checked_dst + 1); - TEST_EXPECTED_VALUE(DstLimits::Overflow(), - SrcLimits::max() * clamped_dst); - TEST_EXPECTED_VALUE(Dst(SrcLimits::max()) + Dst(1), - clamped_dst + Dst(1)); - } - } else { // Same width type. - TEST_EXPECTED_FAILURE(checked_dst + 1); - TEST_EXPECTED_VALUE(DstLimits::Overflow(), clamped_dst + Dst(1)); - } - - TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::max()); - TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(1)); - if (SrcLimits::is_iec559) { - TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::max() * static_cast<Src>(-1)); - TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity()); - TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1); - TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN()); - } else if (numeric_limits<Src>::is_signed) { - // This block reverses the Src to Dst relationship so we don't have to - // complicate the test macros. - if (!std::is_same<Src, Dst>::value) { - TEST_EXPECTED_SUCCESS(CheckDiv(SrcLimits::lowest(), Dst(-1))); - } - TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(-1)); - TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::lowest()); - } - } -}; - -template <typename Dst, typename Src> -struct TestNumericConversion<Dst, Src, SIGN_PRESERVING_NARROW> { - static void Test(const char* dst, const char* src, int line) { - using SrcLimits = SaturationDefaultLimits<Src>; - using DstLimits = SaturationDefaultLimits<Dst>; - static_assert(SrcLimits::is_signed == DstLimits::is_signed, - "Destination and source sign must be the same"); - static_assert(MaxExponent<Dst>::value <= MaxExponent<Src>::value, - "Destination must be narrower than source"); - - TestStrictComparison<Dst, Src>(dst, src, line); - - const CheckedNumeric<Dst> checked_dst; - TEST_EXPECTED_FAILURE(checked_dst + SrcLimits::max()); - TEST_EXPECTED_VALUE(1, checked_dst + Src(1)); - TEST_EXPECTED_FAILURE(checked_dst - SrcLimits::max()); - - ClampedNumeric<Dst> clamped_dst; - TEST_EXPECTED_VALUE(DstLimits::Overflow(), clamped_dst + SrcLimits::max()); - TEST_EXPECTED_VALUE(1, clamped_dst + Src(1)); - TEST_EXPECTED_VALUE(DstLimits::Underflow(), clamped_dst - SrcLimits::max()); - clamped_dst += SrcLimits::max(); - TEST_EXPECTED_VALUE(DstLimits::Overflow(), clamped_dst); - clamped_dst = DstLimits::max(); - clamped_dst += SrcLimits::max(); - TEST_EXPECTED_VALUE(DstLimits::Overflow(), clamped_dst); - clamped_dst = DstLimits::max(); - clamped_dst -= SrcLimits::max(); - TEST_EXPECTED_VALUE(DstLimits::Underflow(), clamped_dst); - clamped_dst = 0; - - TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::max()); - TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(1)); - if (SrcLimits::is_iec559) { - TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::max() * -1); - TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(-1)); - TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity()); - TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1); - TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN()); - if (DstLimits::is_integer) { - if (SrcLimits::digits < DstLimits::digits) { - TEST_EXPECTED_RANGE(RANGE_OVERFLOW, - static_cast<Src>(DstLimits::max())); - } else { - TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(DstLimits::max())); - } - TEST_EXPECTED_RANGE( - RANGE_VALID, - static_cast<Src>(GetMaxConvertibleToFloat<Src, Dst>())); - TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(DstLimits::lowest())); - } - } else if (SrcLimits::is_signed) { - TEST_EXPECTED_VALUE(-1, checked_dst - static_cast<Src>(1)); - TEST_EXPECTED_VALUE(-1, clamped_dst - static_cast<Src>(1)); - TEST_EXPECTED_VALUE(Src(Src(0) - DstLimits::lowest()), - ClampDiv(DstLimits::lowest(), Src(-1))); - TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::lowest()); - TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(-1)); - } else { - TEST_EXPECTED_FAILURE(checked_dst - static_cast<Src>(1)); - TEST_EXPECTED_VALUE(Dst(0), clamped_dst - static_cast<Src>(1)); - TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::lowest()); - } - } -}; - -template <typename Dst, typename Src> -struct TestNumericConversion<Dst, Src, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL> { - static void Test(const char* dst, const char* src, int line) { - using SrcLimits = SaturationDefaultLimits<Src>; - using DstLimits = SaturationDefaultLimits<Dst>; - static_assert(MaxExponent<Dst>::value >= MaxExponent<Src>::value, - "Destination must be equal or wider than source."); - static_assert(SrcLimits::is_signed, "Source must be signed"); - static_assert(!DstLimits::is_signed, "Destination must be unsigned"); - - TestStrictComparison<Dst, Src>(dst, src, line); - - const CheckedNumeric<Dst> checked_dst; - TEST_EXPECTED_VALUE(SrcLimits::max(), checked_dst + SrcLimits::max()); - TEST_EXPECTED_FAILURE(checked_dst + static_cast<Src>(-1)); - TEST_EXPECTED_SUCCESS(checked_dst * static_cast<Src>(-1)); - TEST_EXPECTED_FAILURE(checked_dst + SrcLimits::lowest()); - TEST_EXPECTED_VALUE(Dst(0), CheckDiv(Dst(0), Src(-1))); - - const ClampedNumeric<Dst> clamped_dst; - TEST_EXPECTED_VALUE(SrcLimits::max(), clamped_dst + SrcLimits::max()); - TEST_EXPECTED_VALUE(DstLimits::Underflow(), - clamped_dst + static_cast<Src>(-1)); - TEST_EXPECTED_VALUE(0, clamped_dst * static_cast<Src>(-1)); - TEST_EXPECTED_VALUE(DstLimits::Underflow(), - clamped_dst + SrcLimits::lowest()); - - TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::lowest()); - TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::max()); - TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(1)); - TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, static_cast<Src>(-1)); - } -}; - -template <typename Dst, typename Src> -struct TestNumericConversion<Dst, Src, SIGN_TO_UNSIGN_NARROW> { - static void Test(const char* dst, const char* src, int line) { - using SrcLimits = SaturationDefaultLimits<Src>; - using DstLimits = SaturationDefaultLimits<Dst>; - static_assert(MaxExponent<Dst>::value < MaxExponent<Src>::value, - "Destination must be narrower than source."); - static_assert(SrcLimits::is_signed, "Source must be signed."); - static_assert(!DstLimits::is_signed, "Destination must be unsigned."); - - TestStrictComparison<Dst, Src>(dst, src, line); - - const CheckedNumeric<Dst> checked_dst; - TEST_EXPECTED_VALUE(1, checked_dst + static_cast<Src>(1)); - TEST_EXPECTED_FAILURE(checked_dst + SrcLimits::max()); - TEST_EXPECTED_FAILURE(checked_dst + static_cast<Src>(-1)); - TEST_EXPECTED_FAILURE(checked_dst + SrcLimits::lowest()); - - ClampedNumeric<Dst> clamped_dst; - TEST_EXPECTED_VALUE(1, clamped_dst + static_cast<Src>(1)); - TEST_EXPECTED_VALUE(DstLimits::Overflow(), clamped_dst + SrcLimits::max()); - TEST_EXPECTED_VALUE(DstLimits::Underflow(), - clamped_dst + static_cast<Src>(-1)); - TEST_EXPECTED_VALUE(DstLimits::Underflow(), - clamped_dst + SrcLimits::lowest()); - clamped_dst += SrcLimits::max(); - TEST_EXPECTED_VALUE(DstLimits::Overflow(), clamped_dst); - clamped_dst = DstLimits::max(); - clamped_dst += SrcLimits::max(); - TEST_EXPECTED_VALUE(DstLimits::Overflow(), clamped_dst); - clamped_dst = DstLimits::max(); - clamped_dst -= SrcLimits::max(); - TEST_EXPECTED_VALUE(DstLimits::Underflow(), clamped_dst); - clamped_dst = 0; - - TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::max()); - TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(1)); - TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, static_cast<Src>(-1)); - - // Additional saturation tests. - EXPECT_EQ(DstLimits::max(), saturated_cast<Dst>(SrcLimits::max())); - EXPECT_EQ(DstLimits::lowest(), saturated_cast<Dst>(SrcLimits::lowest())); - - if (SrcLimits::is_iec559) { - EXPECT_EQ(Dst(0), saturated_cast<Dst>(SrcLimits::quiet_NaN())); - - TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::max() * -1); - TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity()); - TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1); - TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN()); - if (DstLimits::is_integer) { - if (SrcLimits::digits < DstLimits::digits) { - TEST_EXPECTED_RANGE(RANGE_OVERFLOW, - static_cast<Src>(DstLimits::max())); - } else { - TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(DstLimits::max())); - } - TEST_EXPECTED_RANGE( - RANGE_VALID, - static_cast<Src>(GetMaxConvertibleToFloat<Src, Dst>())); - TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(DstLimits::lowest())); - } - } else { - TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::lowest()); - } - } -}; - -template <typename Dst, typename Src> -struct TestNumericConversion<Dst, Src, UNSIGN_TO_SIGN_NARROW_OR_EQUAL> { - static void Test(const char* dst, const char* src, int line) { - using SrcLimits = SaturationDefaultLimits<Src>; - using DstLimits = SaturationDefaultLimits<Dst>; - static_assert(MaxExponent<Dst>::value <= MaxExponent<Src>::value, - "Destination must be narrower or equal to source."); - static_assert(!SrcLimits::is_signed, "Source must be unsigned."); - static_assert(DstLimits::is_signed, "Destination must be signed."); - - TestStrictComparison<Dst, Src>(dst, src, line); - - const CheckedNumeric<Dst> checked_dst; - TEST_EXPECTED_VALUE(1, checked_dst + static_cast<Src>(1)); - TEST_EXPECTED_FAILURE(checked_dst + SrcLimits::max()); - TEST_EXPECTED_VALUE(SrcLimits::lowest(), checked_dst + SrcLimits::lowest()); - - const ClampedNumeric<Dst> clamped_dst; - TEST_EXPECTED_VALUE(1, clamped_dst + static_cast<Src>(1)); - TEST_EXPECTED_VALUE(DstLimits::Overflow(), clamped_dst + SrcLimits::max()); - TEST_EXPECTED_VALUE(SrcLimits::lowest(), clamped_dst + SrcLimits::lowest()); - - TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::lowest()); - TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::max()); - TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(1)); - - // Additional saturation tests. - EXPECT_EQ(DstLimits::max(), saturated_cast<Dst>(SrcLimits::max())); - EXPECT_EQ(Dst(0), saturated_cast<Dst>(SrcLimits::lowest())); - } -}; - -// Helper macro to wrap displaying the conversion types and line numbers -#define TEST_NUMERIC_CONVERSION(d, s, t) \ - TestNumericConversion<d, s, t>::Test(#d, #s, __LINE__) - -TEST(SafeNumerics, IntMinOperations) { - TEST_NUMERIC_CONVERSION(int8_t, int8_t, SIGN_PRESERVING_VALUE_PRESERVING); - TEST_NUMERIC_CONVERSION(uint8_t, uint8_t, SIGN_PRESERVING_VALUE_PRESERVING); - - TEST_NUMERIC_CONVERSION(int8_t, int16_t, SIGN_PRESERVING_NARROW); - TEST_NUMERIC_CONVERSION(int8_t, int, SIGN_PRESERVING_NARROW); - TEST_NUMERIC_CONVERSION(uint8_t, uint16_t, SIGN_PRESERVING_NARROW); - TEST_NUMERIC_CONVERSION(uint8_t, unsigned int, SIGN_PRESERVING_NARROW); - TEST_NUMERIC_CONVERSION(int8_t, float, SIGN_PRESERVING_NARROW); - - TEST_NUMERIC_CONVERSION(uint8_t, int8_t, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); - - TEST_NUMERIC_CONVERSION(uint8_t, int16_t, SIGN_TO_UNSIGN_NARROW); - TEST_NUMERIC_CONVERSION(uint8_t, int, SIGN_TO_UNSIGN_NARROW); - TEST_NUMERIC_CONVERSION(uint8_t, intmax_t, SIGN_TO_UNSIGN_NARROW); - TEST_NUMERIC_CONVERSION(uint8_t, float, SIGN_TO_UNSIGN_NARROW); - - TEST_NUMERIC_CONVERSION(int8_t, uint16_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); - TEST_NUMERIC_CONVERSION(int8_t, unsigned int, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); - TEST_NUMERIC_CONVERSION(int8_t, uintmax_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); -} - -TEST(SafeNumerics, Int16Operations) { - TEST_NUMERIC_CONVERSION(int16_t, int16_t, SIGN_PRESERVING_VALUE_PRESERVING); - TEST_NUMERIC_CONVERSION(uint16_t, uint16_t, SIGN_PRESERVING_VALUE_PRESERVING); - - TEST_NUMERIC_CONVERSION(int16_t, int, SIGN_PRESERVING_NARROW); - TEST_NUMERIC_CONVERSION(uint16_t, unsigned int, SIGN_PRESERVING_NARROW); - TEST_NUMERIC_CONVERSION(int16_t, float, SIGN_PRESERVING_NARROW); - - TEST_NUMERIC_CONVERSION(uint16_t, int16_t, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); - - TEST_NUMERIC_CONVERSION(uint16_t, int, SIGN_TO_UNSIGN_NARROW); - TEST_NUMERIC_CONVERSION(uint16_t, intmax_t, SIGN_TO_UNSIGN_NARROW); - TEST_NUMERIC_CONVERSION(uint16_t, float, SIGN_TO_UNSIGN_NARROW); - - TEST_NUMERIC_CONVERSION(int16_t, unsigned int, - UNSIGN_TO_SIGN_NARROW_OR_EQUAL); - TEST_NUMERIC_CONVERSION(int16_t, uintmax_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); -} - -TEST(SafeNumerics, IntOperations) { - TEST_NUMERIC_CONVERSION(int, int, SIGN_PRESERVING_VALUE_PRESERVING); - TEST_NUMERIC_CONVERSION(unsigned int, unsigned int, - SIGN_PRESERVING_VALUE_PRESERVING); - TEST_NUMERIC_CONVERSION(int, int8_t, SIGN_PRESERVING_VALUE_PRESERVING); - TEST_NUMERIC_CONVERSION(unsigned int, uint8_t, - SIGN_PRESERVING_VALUE_PRESERVING); - TEST_NUMERIC_CONVERSION(int, uint8_t, SIGN_PRESERVING_VALUE_PRESERVING); - - TEST_NUMERIC_CONVERSION(int, intmax_t, SIGN_PRESERVING_NARROW); - TEST_NUMERIC_CONVERSION(unsigned int, uintmax_t, SIGN_PRESERVING_NARROW); - TEST_NUMERIC_CONVERSION(int, float, SIGN_PRESERVING_NARROW); - TEST_NUMERIC_CONVERSION(int, double, SIGN_PRESERVING_NARROW); - - TEST_NUMERIC_CONVERSION(unsigned int, int, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); - TEST_NUMERIC_CONVERSION(unsigned int, int8_t, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); - - TEST_NUMERIC_CONVERSION(unsigned int, intmax_t, SIGN_TO_UNSIGN_NARROW); - TEST_NUMERIC_CONVERSION(unsigned int, float, SIGN_TO_UNSIGN_NARROW); - TEST_NUMERIC_CONVERSION(unsigned int, double, SIGN_TO_UNSIGN_NARROW); - - TEST_NUMERIC_CONVERSION(int, unsigned int, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); - TEST_NUMERIC_CONVERSION(int, uintmax_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); -} - -TEST(SafeNumerics, IntMaxOperations) { - TEST_NUMERIC_CONVERSION(intmax_t, intmax_t, SIGN_PRESERVING_VALUE_PRESERVING); - TEST_NUMERIC_CONVERSION(uintmax_t, uintmax_t, - SIGN_PRESERVING_VALUE_PRESERVING); - TEST_NUMERIC_CONVERSION(intmax_t, int, SIGN_PRESERVING_VALUE_PRESERVING); - TEST_NUMERIC_CONVERSION(uintmax_t, unsigned int, - SIGN_PRESERVING_VALUE_PRESERVING); - TEST_NUMERIC_CONVERSION(intmax_t, unsigned int, - SIGN_PRESERVING_VALUE_PRESERVING); - TEST_NUMERIC_CONVERSION(intmax_t, uint8_t, SIGN_PRESERVING_VALUE_PRESERVING); - - TEST_NUMERIC_CONVERSION(intmax_t, float, SIGN_PRESERVING_NARROW); - TEST_NUMERIC_CONVERSION(intmax_t, double, SIGN_PRESERVING_NARROW); - - TEST_NUMERIC_CONVERSION(uintmax_t, int, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); - TEST_NUMERIC_CONVERSION(uintmax_t, int8_t, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); - - TEST_NUMERIC_CONVERSION(uintmax_t, float, SIGN_TO_UNSIGN_NARROW); - TEST_NUMERIC_CONVERSION(uintmax_t, double, SIGN_TO_UNSIGN_NARROW); - - TEST_NUMERIC_CONVERSION(intmax_t, uintmax_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); -} - -TEST(SafeNumerics, FloatOperations) { - TEST_NUMERIC_CONVERSION(float, intmax_t, SIGN_PRESERVING_VALUE_PRESERVING); - TEST_NUMERIC_CONVERSION(float, uintmax_t, SIGN_PRESERVING_VALUE_PRESERVING); - TEST_NUMERIC_CONVERSION(float, int, SIGN_PRESERVING_VALUE_PRESERVING); - TEST_NUMERIC_CONVERSION(float, unsigned int, - SIGN_PRESERVING_VALUE_PRESERVING); - - TEST_NUMERIC_CONVERSION(float, double, SIGN_PRESERVING_NARROW); -} - -TEST(SafeNumerics, DoubleOperations) { - TEST_NUMERIC_CONVERSION(double, intmax_t, SIGN_PRESERVING_VALUE_PRESERVING); - TEST_NUMERIC_CONVERSION(double, uintmax_t, SIGN_PRESERVING_VALUE_PRESERVING); - TEST_NUMERIC_CONVERSION(double, int, SIGN_PRESERVING_VALUE_PRESERVING); - TEST_NUMERIC_CONVERSION(double, unsigned int, - SIGN_PRESERVING_VALUE_PRESERVING); -} - -TEST(SafeNumerics, SizeTOperations) { - TEST_NUMERIC_CONVERSION(size_t, int, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); - TEST_NUMERIC_CONVERSION(int, size_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); -} - -// A one-off test to ensure StrictNumeric won't resolve to an incorrect type. -// If this fails we'll just get a compiler error on an ambiguous overload. -int TestOverload(int) { // Overload fails. - return 0; -} -uint8_t TestOverload(uint8_t) { // Overload fails. - return 0; -} -size_t TestOverload(size_t) { // Overload succeeds. - return 0; -} - -static_assert( - std::is_same<decltype(TestOverload(StrictNumeric<int>())), int>::value, - ""); -static_assert(std::is_same<decltype(TestOverload(StrictNumeric<size_t>())), - size_t>::value, - ""); - -template <typename T> -struct CastTest1 { - static constexpr T NaN() { return -1; } - static constexpr T max() { return numeric_limits<T>::max() - 1; } - static constexpr T Overflow() { return max(); } - static constexpr T lowest() { return numeric_limits<T>::lowest() + 1; } - static constexpr T Underflow() { return lowest(); } -}; - -template <typename T> -struct CastTest2 { - static constexpr T NaN() { return 11; } - static constexpr T max() { return 10; } - static constexpr T Overflow() { return max(); } - static constexpr T lowest() { return 1; } - static constexpr T Underflow() { return lowest(); } -}; - -TEST(SafeNumerics, CastTests) { -// MSVC catches and warns that we're forcing saturation in these tests. -// Since that's intentional, we need to shut this warning off. -#if defined(COMPILER_MSVC) -#pragma warning(disable : 4756) -#endif - - int small_positive = 1; - int small_negative = -1; - double double_small = 1.0; - double double_large = numeric_limits<double>::max(); - double double_infinity = numeric_limits<float>::infinity(); - double double_large_int = numeric_limits<int>::max(); - double double_small_int = numeric_limits<int>::lowest(); - - // Just test that the casts compile, since the other tests cover logic. - EXPECT_EQ(0, checked_cast<int>(static_cast<size_t>(0))); - EXPECT_EQ(0, strict_cast<int>(static_cast<char>(0))); - EXPECT_EQ(0, strict_cast<int>(static_cast<unsigned char>(0))); - EXPECT_EQ(0U, strict_cast<unsigned>(static_cast<unsigned char>(0))); - EXPECT_EQ(1ULL, static_cast<uint64_t>(StrictNumeric<size_t>(1U))); - EXPECT_EQ(1ULL, static_cast<uint64_t>(SizeT(1U))); - EXPECT_EQ(1U, static_cast<size_t>(StrictNumeric<unsigned>(1U))); - - EXPECT_TRUE(CheckedNumeric<uint64_t>(StrictNumeric<unsigned>(1U)).IsValid()); - EXPECT_TRUE(CheckedNumeric<int>(StrictNumeric<unsigned>(1U)).IsValid()); - EXPECT_FALSE(CheckedNumeric<unsigned>(StrictNumeric<int>(-1)).IsValid()); - - EXPECT_TRUE(IsValueNegative(-1)); - EXPECT_TRUE(IsValueNegative(numeric_limits<int>::lowest())); - EXPECT_FALSE(IsValueNegative(numeric_limits<unsigned>::lowest())); - EXPECT_TRUE(IsValueNegative(numeric_limits<double>::lowest())); - EXPECT_FALSE(IsValueNegative(0)); - EXPECT_FALSE(IsValueNegative(1)); - EXPECT_FALSE(IsValueNegative(0u)); - EXPECT_FALSE(IsValueNegative(1u)); - EXPECT_FALSE(IsValueNegative(numeric_limits<int>::max())); - EXPECT_FALSE(IsValueNegative(numeric_limits<unsigned>::max())); - EXPECT_FALSE(IsValueNegative(numeric_limits<double>::max())); - - // These casts and coercions will fail to compile: - // EXPECT_EQ(0, strict_cast<int>(static_cast<size_t>(0))); - // EXPECT_EQ(0, strict_cast<size_t>(static_cast<int>(0))); - // EXPECT_EQ(1ULL, StrictNumeric<size_t>(1)); - // EXPECT_EQ(1, StrictNumeric<size_t>(1U)); - - // Test various saturation corner cases. - EXPECT_EQ(saturated_cast<int>(small_negative), - static_cast<int>(small_negative)); - EXPECT_EQ(saturated_cast<int>(small_positive), - static_cast<int>(small_positive)); - EXPECT_EQ(saturated_cast<unsigned>(small_negative), static_cast<unsigned>(0)); - EXPECT_EQ(saturated_cast<int>(double_small), static_cast<int>(double_small)); - EXPECT_EQ(saturated_cast<int>(double_large), numeric_limits<int>::max()); - EXPECT_EQ(saturated_cast<float>(double_large), double_infinity); - EXPECT_EQ(saturated_cast<float>(-double_large), -double_infinity); - EXPECT_EQ(numeric_limits<int>::lowest(), - saturated_cast<int>(double_small_int)); - EXPECT_EQ(numeric_limits<int>::max(), saturated_cast<int>(double_large_int)); - - // Test the saturated cast overrides. - using FloatLimits = numeric_limits<float>; - using IntLimits = numeric_limits<int>; - EXPECT_EQ(-1, (saturated_cast<int, CastTest1>(FloatLimits::quiet_NaN()))); - EXPECT_EQ(CastTest1<int>::max(), - (saturated_cast<int, CastTest1>(FloatLimits::infinity()))); - EXPECT_EQ(CastTest1<int>::max(), - (saturated_cast<int, CastTest1>(FloatLimits::max()))); - EXPECT_EQ(CastTest1<int>::max(), - (saturated_cast<int, CastTest1>(float(IntLimits::max())))); - EXPECT_EQ(CastTest1<int>::lowest(), - (saturated_cast<int, CastTest1>(-FloatLimits::infinity()))); - EXPECT_EQ(CastTest1<int>::lowest(), - (saturated_cast<int, CastTest1>(FloatLimits::lowest()))); - EXPECT_EQ(0, (saturated_cast<int, CastTest1>(0.0))); - EXPECT_EQ(1, (saturated_cast<int, CastTest1>(1.0))); - EXPECT_EQ(-1, (saturated_cast<int, CastTest1>(-1.0))); - EXPECT_EQ(0, (saturated_cast<int, CastTest1>(0))); - EXPECT_EQ(1, (saturated_cast<int, CastTest1>(1))); - EXPECT_EQ(-1, (saturated_cast<int, CastTest1>(-1))); - EXPECT_EQ(CastTest1<int>::lowest(), - (saturated_cast<int, CastTest1>(float(IntLimits::lowest())))); - EXPECT_EQ(11, (saturated_cast<int, CastTest2>(FloatLimits::quiet_NaN()))); - EXPECT_EQ(10, (saturated_cast<int, CastTest2>(FloatLimits::infinity()))); - EXPECT_EQ(10, (saturated_cast<int, CastTest2>(FloatLimits::max()))); - EXPECT_EQ(1, (saturated_cast<int, CastTest2>(-FloatLimits::infinity()))); - EXPECT_EQ(1, (saturated_cast<int, CastTest2>(FloatLimits::lowest()))); - EXPECT_EQ(1, (saturated_cast<int, CastTest2>(0U))); - - float not_a_number = std::numeric_limits<float>::infinity() - - std::numeric_limits<float>::infinity(); - EXPECT_TRUE(std::isnan(not_a_number)); - EXPECT_EQ(0, saturated_cast<int>(not_a_number)); - - // Test the CheckedNumeric value extractions functions. - auto int8_min = MakeCheckedNum(numeric_limits<int8_t>::lowest()); - auto int8_max = MakeCheckedNum(numeric_limits<int8_t>::max()); - auto double_max = MakeCheckedNum(numeric_limits<double>::max()); - static_assert( - std::is_same<int16_t, - decltype(int8_min.ValueOrDie<int16_t>())::type>::value, - "ValueOrDie returning incorrect type."); - static_assert( - std::is_same<int16_t, - decltype(int8_min.ValueOrDefault<int16_t>(0))::type>::value, - "ValueOrDefault returning incorrect type."); - EXPECT_FALSE(IsValidForType<uint8_t>(int8_min)); - EXPECT_TRUE(IsValidForType<uint8_t>(int8_max)); - EXPECT_EQ(static_cast<int>(numeric_limits<int8_t>::lowest()), - ValueOrDieForType<int>(int8_min)); - EXPECT_TRUE(IsValidForType<uint32_t>(int8_max)); - EXPECT_EQ(static_cast<int>(numeric_limits<int8_t>::max()), - ValueOrDieForType<int>(int8_max)); - EXPECT_EQ(0, ValueOrDefaultForType<int>(double_max, 0)); - uint8_t uint8_dest = 0; - int16_t int16_dest = 0; - double double_dest = 0; - EXPECT_TRUE(int8_max.AssignIfValid(&uint8_dest)); - EXPECT_EQ(static_cast<uint8_t>(numeric_limits<int8_t>::max()), uint8_dest); - EXPECT_FALSE(int8_min.AssignIfValid(&uint8_dest)); - EXPECT_TRUE(int8_max.AssignIfValid(&int16_dest)); - EXPECT_EQ(static_cast<int16_t>(numeric_limits<int8_t>::max()), int16_dest); - EXPECT_TRUE(int8_min.AssignIfValid(&int16_dest)); - EXPECT_EQ(static_cast<int16_t>(numeric_limits<int8_t>::lowest()), int16_dest); - EXPECT_FALSE(double_max.AssignIfValid(&uint8_dest)); - EXPECT_FALSE(double_max.AssignIfValid(&int16_dest)); - EXPECT_TRUE(double_max.AssignIfValid(&double_dest)); - EXPECT_EQ(numeric_limits<double>::max(), double_dest); - EXPECT_EQ(1, checked_cast<int>(StrictNumeric<int>(1))); - EXPECT_EQ(1, saturated_cast<int>(StrictNumeric<int>(1))); - EXPECT_EQ(1, strict_cast<int>(StrictNumeric<int>(1))); - - enum class EnumTest { kOne = 1 }; - EXPECT_EQ(1, checked_cast<int>(EnumTest::kOne)); - EXPECT_EQ(1, saturated_cast<int>(EnumTest::kOne)); - EXPECT_EQ(1, strict_cast<int>(EnumTest::kOne)); -} - -TEST(SafeNumerics, IsValueInRangeForNumericType) { - EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(0)); - EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(1)); - EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(2)); - EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(-1)); - EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(0xffffffffu)); - EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(UINT64_C(0xffffffff))); - EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(UINT64_C(0x100000000))); - EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(UINT64_C(0x100000001))); - EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>( - std::numeric_limits<int32_t>::lowest())); - EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>( - std::numeric_limits<int64_t>::lowest())); - - EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(0)); - EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(1)); - EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(2)); - EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(-1)); - EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(0x7fffffff)); - EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(0x7fffffffu)); - EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(0x80000000u)); - EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(0xffffffffu)); - EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(INT64_C(0x80000000))); - EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(INT64_C(0xffffffff))); - EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(INT64_C(0x100000000))); - EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>( - std::numeric_limits<int32_t>::lowest())); - EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>( - static_cast<int64_t>(std::numeric_limits<int32_t>::lowest()))); - EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>( - static_cast<int64_t>(std::numeric_limits<int32_t>::lowest()) - 1)); - EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>( - std::numeric_limits<int64_t>::lowest())); - - EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(0)); - EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(1)); - EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(2)); - EXPECT_FALSE(IsValueInRangeForNumericType<uint64_t>(-1)); - EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(0xffffffffu)); - EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(UINT64_C(0xffffffff))); - EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(UINT64_C(0x100000000))); - EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(UINT64_C(0x100000001))); - EXPECT_FALSE(IsValueInRangeForNumericType<uint64_t>( - std::numeric_limits<int32_t>::lowest())); - EXPECT_FALSE(IsValueInRangeForNumericType<uint64_t>(INT64_C(-1))); - EXPECT_FALSE(IsValueInRangeForNumericType<uint64_t>( - std::numeric_limits<int64_t>::lowest())); - - EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0)); - EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(1)); - EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(2)); - EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(-1)); - EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0x7fffffff)); - EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0x7fffffffu)); - EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0x80000000u)); - EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0xffffffffu)); - EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(INT64_C(0x80000000))); - EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(INT64_C(0xffffffff))); - EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(INT64_C(0x100000000))); - EXPECT_TRUE( - IsValueInRangeForNumericType<int64_t>(INT64_C(0x7fffffffffffffff))); - EXPECT_TRUE( - IsValueInRangeForNumericType<int64_t>(UINT64_C(0x7fffffffffffffff))); - EXPECT_FALSE( - IsValueInRangeForNumericType<int64_t>(UINT64_C(0x8000000000000000))); - EXPECT_FALSE( - IsValueInRangeForNumericType<int64_t>(UINT64_C(0xffffffffffffffff))); - EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>( - std::numeric_limits<int32_t>::lowest())); - EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>( - static_cast<int64_t>(std::numeric_limits<int32_t>::lowest()))); - EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>( - std::numeric_limits<int64_t>::lowest())); -} - -TEST(SafeNumerics, CompoundNumericOperations) { - CheckedNumeric<int> a = 1; - CheckedNumeric<int> b = 2; - CheckedNumeric<int> c = 3; - CheckedNumeric<int> d = 4; - a += b; - EXPECT_EQ(3, a.ValueOrDie()); - a -= c; - EXPECT_EQ(0, a.ValueOrDie()); - d /= b; - EXPECT_EQ(2, d.ValueOrDie()); - d *= d; - EXPECT_EQ(4, d.ValueOrDie()); - - CheckedNumeric<int> too_large = std::numeric_limits<int>::max(); - EXPECT_TRUE(too_large.IsValid()); - too_large += d; - EXPECT_FALSE(too_large.IsValid()); - too_large -= d; - EXPECT_FALSE(too_large.IsValid()); - too_large /= d; - EXPECT_FALSE(too_large.IsValid()); -} - -TEST(SafeNumerics, VariadicNumericOperations) { - { // Synthetic scope to avoid variable naming collisions. - auto a = CheckAdd(1, 2UL, MakeCheckedNum(3LL), 4).ValueOrDie(); - EXPECT_EQ(static_cast<decltype(a)::type>(10), a); - auto b = CheckSub(MakeCheckedNum(20.0), 2UL, 4).ValueOrDie(); - EXPECT_EQ(static_cast<decltype(b)::type>(14.0), b); - auto c = CheckMul(20.0, MakeCheckedNum(1), 5, 3UL).ValueOrDie(); - EXPECT_EQ(static_cast<decltype(c)::type>(300.0), c); - auto d = CheckDiv(20.0, 2.0, MakeCheckedNum(5LL), -4).ValueOrDie(); - EXPECT_EQ(static_cast<decltype(d)::type>(-.5), d); - auto e = CheckMod(MakeCheckedNum(20), 3).ValueOrDie(); - EXPECT_EQ(static_cast<decltype(e)::type>(2), e); - auto f = CheckLsh(1, MakeCheckedNum(2)).ValueOrDie(); - EXPECT_EQ(static_cast<decltype(f)::type>(4), f); - auto g = CheckRsh(4, MakeCheckedNum(2)).ValueOrDie(); - EXPECT_EQ(static_cast<decltype(g)::type>(1), g); - auto h = CheckRsh(CheckAdd(1, 1, 1, 1), CheckSub(4, 2)).ValueOrDie(); - EXPECT_EQ(static_cast<decltype(h)::type>(1), h); - } - - { - auto a = ClampAdd(1, 2UL, MakeClampedNum(3LL), 4); - EXPECT_EQ(static_cast<decltype(a)::type>(10), a); - auto b = ClampSub(MakeClampedNum(20.0), 2UL, 4); - EXPECT_EQ(static_cast<decltype(b)::type>(14.0), b); - auto c = ClampMul(20.0, MakeClampedNum(1), 5, 3UL); - EXPECT_EQ(static_cast<decltype(c)::type>(300.0), c); - auto d = ClampDiv(20.0, 2.0, MakeClampedNum(5LL), -4); - EXPECT_EQ(static_cast<decltype(d)::type>(-.5), d); - auto e = ClampMod(MakeClampedNum(20), 3); - EXPECT_EQ(static_cast<decltype(e)::type>(2), e); - auto f = ClampLsh(1, MakeClampedNum(2U)); - EXPECT_EQ(static_cast<decltype(f)::type>(4), f); - auto g = ClampRsh(4, MakeClampedNum(2U)); - EXPECT_EQ(static_cast<decltype(g)::type>(1), g); - auto h = ClampRsh(ClampAdd(1, 1, 1, 1), ClampSub(4U, 2)); - EXPECT_EQ(static_cast<decltype(h)::type>(1), h); - } -} - -#if defined(__clang__) -#pragma clang diagnostic pop // -Winteger-overflow -#endif - -} // namespace internal -} // namespace base
diff --git a/base/sampling_heap_profiler/sampling_heap_profiler_unittest.cc b/base/sampling_heap_profiler/sampling_heap_profiler_unittest.cc deleted file mode 100644 index d3bef90..0000000 --- a/base/sampling_heap_profiler/sampling_heap_profiler_unittest.cc +++ /dev/null
@@ -1,165 +0,0 @@ -// 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/sampling_heap_profiler/sampling_heap_profiler.h" - -#include <stdlib.h> -#include <cinttypes> - -#include "base/allocator/allocator_shim.h" -#include "base/debug/alias.h" -#include "base/threading/simple_thread.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -class SamplingHeapProfilerTest : public ::testing::Test { -#if defined(OS_MACOSX) - void SetUp() override { allocator::InitializeAllocatorShim(); } -#endif -}; - -class SamplesCollector : public SamplingHeapProfiler::SamplesObserver { - public: - explicit SamplesCollector(size_t watch_size) : watch_size_(watch_size) {} - - void SampleAdded(uint32_t id, size_t size, size_t) override { - if (sample_added || size != watch_size_) - return; - sample_id_ = id; - sample_added = true; - } - - void SampleRemoved(uint32_t id) override { - if (id == sample_id_) - sample_removed = true; - } - - bool sample_added = false; - bool sample_removed = false; - - private: - size_t watch_size_; - uint32_t sample_id_ = 0; -}; - -TEST_F(SamplingHeapProfilerTest, CollectSamples) { - SamplingHeapProfiler::InitTLSSlot(); - SamplesCollector collector(10000); - SamplingHeapProfiler* profiler = SamplingHeapProfiler::GetInstance(); - profiler->SuppressRandomnessForTest(true); - profiler->SetSamplingInterval(1024); - profiler->Start(); - profiler->AddSamplesObserver(&collector); - void* volatile p = malloc(10000); - free(p); - profiler->Stop(); - profiler->RemoveSamplesObserver(&collector); - CHECK(collector.sample_added); - CHECK(collector.sample_removed); -} - -const int kNumberOfAllocations = 10000; - -NOINLINE void Allocate1() { - void* p = malloc(400); - base::debug::Alias(&p); -} - -NOINLINE void Allocate2() { - void* p = malloc(700); - base::debug::Alias(&p); -} - -NOINLINE void Allocate3() { - void* p = malloc(20480); - base::debug::Alias(&p); -} - -class MyThread1 : public SimpleThread { - public: - MyThread1() : SimpleThread("MyThread1") {} - void Run() override { - for (int i = 0; i < kNumberOfAllocations; ++i) - Allocate1(); - } -}; - -class MyThread2 : public SimpleThread { - public: - MyThread2() : SimpleThread("MyThread2") {} - void Run() override { - for (int i = 0; i < kNumberOfAllocations; ++i) - Allocate2(); - } -}; - -void CheckAllocationPattern(void (*allocate_callback)()) { - SamplingHeapProfiler::InitTLSSlot(); - SamplingHeapProfiler* profiler = SamplingHeapProfiler::GetInstance(); - profiler->SuppressRandomnessForTest(false); - profiler->SetSamplingInterval(10240); - base::TimeTicks t0 = base::TimeTicks::Now(); - std::map<size_t, size_t> sums; - const int iterations = 40; - for (int i = 0; i < iterations; ++i) { - uint32_t id = profiler->Start(); - allocate_callback(); - std::vector<SamplingHeapProfiler::Sample> samples = - profiler->GetSamples(id); - profiler->Stop(); - std::map<size_t, size_t> buckets; - for (auto& sample : samples) { - buckets[sample.size] += sample.total; - } - for (auto& it : buckets) { - if (it.first != 400 && it.first != 700 && it.first != 20480) - continue; - sums[it.first] += it.second; - printf("%zu,", it.second); - } - printf("\n"); - } - - printf("Time taken %" PRIu64 "ms\n", - (base::TimeTicks::Now() - t0).InMilliseconds()); - - for (auto sum : sums) { - intptr_t expected = sum.first * kNumberOfAllocations; - intptr_t actual = sum.second / iterations; - printf("%zu:\tmean: %zu\trelative error: %.2f%%\n", sum.first, actual, - 100. * (actual - expected) / expected); - } -} - -// Manual tests to check precision of the sampling profiler. -// Yes, they do leak lots of memory. - -TEST_F(SamplingHeapProfilerTest, DISABLED_ParallelLargeSmallStats) { - CheckAllocationPattern([]() { - SimpleThread* t1 = new MyThread1(); - SimpleThread* t2 = new MyThread2(); - t1->Start(); - t2->Start(); - for (int i = 0; i < kNumberOfAllocations; ++i) - Allocate3(); - t1->Join(); - t2->Join(); - }); -} - -TEST_F(SamplingHeapProfilerTest, DISABLED_SequentialLargeSmallStats) { - CheckAllocationPattern([]() { - for (int i = 0; i < kNumberOfAllocations; ++i) { - Allocate1(); - Allocate2(); - Allocate3(); - } - }); -} - -} // namespace -} // namespace base
diff --git a/base/scoped_clear_errno_unittest.cc b/base/scoped_clear_errno_unittest.cc deleted file mode 100644 index 8afb33e..0000000 --- a/base/scoped_clear_errno_unittest.cc +++ /dev/null
@@ -1,30 +0,0 @@ -// 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 <errno.h> - -#include "base/scoped_clear_errno.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(ScopedClearErrno, TestNoError) { - errno = 1; - { - ScopedClearErrno clear_error; - EXPECT_EQ(0, errno); - } - EXPECT_EQ(1, errno); -} - -TEST(ScopedClearErrno, TestError) { - errno = 1; - { - ScopedClearErrno clear_error; - errno = 2; - } - EXPECT_EQ(2, errno); -} - -} // namespace base
diff --git a/base/scoped_generic_unittest.cc b/base/scoped_generic_unittest.cc deleted file mode 100644 index 5a6abfb..0000000 --- a/base/scoped_generic_unittest.cc +++ /dev/null
@@ -1,172 +0,0 @@ -// 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/scoped_generic.h" - -#include <utility> -#include <vector> - -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -struct IntTraits { - IntTraits(std::vector<int>* freed) : freed_ints(freed) {} - - static int InvalidValue() { - return -1; - } - void Free(int value) { - freed_ints->push_back(value); - } - - std::vector<int>* freed_ints; -}; - -typedef ScopedGeneric<int, IntTraits> ScopedInt; - -} // namespace - -TEST(ScopedGenericTest, ScopedGeneric) { - std::vector<int> values_freed; - IntTraits traits(&values_freed); - - // Invalid case, delete should not be called. - { - ScopedInt a(IntTraits::InvalidValue(), traits); - } - EXPECT_TRUE(values_freed.empty()); - - // Simple deleting case. - static const int kFirst = 0; - { - ScopedInt a(kFirst, traits); - } - ASSERT_EQ(1u, values_freed.size()); - ASSERT_EQ(kFirst, values_freed[0]); - values_freed.clear(); - - // Release should return the right value and leave the object empty. - { - ScopedInt a(kFirst, traits); - EXPECT_EQ(kFirst, a.release()); - - ScopedInt b(IntTraits::InvalidValue(), traits); - EXPECT_EQ(IntTraits::InvalidValue(), b.release()); - } - ASSERT_TRUE(values_freed.empty()); - - // Reset should free the old value, then the new one should go away when - // it goes out of scope. - static const int kSecond = 1; - { - ScopedInt b(kFirst, traits); - b.reset(kSecond); - ASSERT_EQ(1u, values_freed.size()); - ASSERT_EQ(kFirst, values_freed[0]); - } - ASSERT_EQ(2u, values_freed.size()); - ASSERT_EQ(kSecond, values_freed[1]); - values_freed.clear(); - - // Swap. - { - ScopedInt a(kFirst, traits); - ScopedInt b(kSecond, traits); - a.swap(b); - EXPECT_TRUE(values_freed.empty()); // Nothing should be freed. - EXPECT_EQ(kSecond, a.get()); - EXPECT_EQ(kFirst, b.get()); - } - // Values should be deleted in the opposite order. - ASSERT_EQ(2u, values_freed.size()); - EXPECT_EQ(kFirst, values_freed[0]); - EXPECT_EQ(kSecond, values_freed[1]); - values_freed.clear(); - - // Move constructor. - { - ScopedInt a(kFirst, traits); - ScopedInt b(std::move(a)); - EXPECT_TRUE(values_freed.empty()); // Nothing should be freed. - ASSERT_EQ(IntTraits::InvalidValue(), a.get()); - ASSERT_EQ(kFirst, b.get()); - } - - ASSERT_EQ(1u, values_freed.size()); - ASSERT_EQ(kFirst, values_freed[0]); - values_freed.clear(); - - // Move assign. - { - ScopedInt a(kFirst, traits); - ScopedInt b(kSecond, traits); - b = std::move(a); - ASSERT_EQ(1u, values_freed.size()); - EXPECT_EQ(kSecond, values_freed[0]); - ASSERT_EQ(IntTraits::InvalidValue(), a.get()); - ASSERT_EQ(kFirst, b.get()); - } - - ASSERT_EQ(2u, values_freed.size()); - EXPECT_EQ(kFirst, values_freed[1]); - values_freed.clear(); -} - -TEST(ScopedGenericTest, Operators) { - std::vector<int> values_freed; - IntTraits traits(&values_freed); - - static const int kFirst = 0; - static const int kSecond = 1; - { - ScopedInt a(kFirst, traits); - EXPECT_TRUE(a == kFirst); - EXPECT_FALSE(a != kFirst); - EXPECT_FALSE(a == kSecond); - EXPECT_TRUE(a != kSecond); - - EXPECT_TRUE(kFirst == a); - EXPECT_FALSE(kFirst != a); - EXPECT_FALSE(kSecond == a); - EXPECT_TRUE(kSecond != a); - } - - // is_valid(). - { - ScopedInt a(kFirst, traits); - EXPECT_TRUE(a.is_valid()); - a.reset(); - EXPECT_FALSE(a.is_valid()); - } -} - -// Cheesy manual "no compile" test for manually validating changes. -#if 0 -TEST(ScopedGenericTest, NoCompile) { - // Assignment shouldn't work. - /*{ - ScopedInt a(kFirst, traits); - ScopedInt b(a); - }*/ - - // Comparison shouldn't work. - /*{ - ScopedInt a(kFirst, traits); - ScopedInt b(kFirst, traits); - if (a == b) { - } - }*/ - - // Implicit conversion to bool shouldn't work. - /*{ - ScopedInt a(kFirst, traits); - bool result = a; - }*/ -} -#endif - -} // namespace base
diff --git a/base/scoped_native_library_unittest.cc b/base/scoped_native_library_unittest.cc deleted file mode 100644 index 261e9d1..0000000 --- a/base/scoped_native_library_unittest.cc +++ /dev/null
@@ -1,48 +0,0 @@ -// 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/scoped_native_library.h" - -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(OS_WIN) -#include "base/files/file_path.h" -#include "base/strings/utf_string_conversions.h" -#endif - -namespace base { - -// Tests whether or not a function pointer retrieved via ScopedNativeLibrary -// is available only in a scope. -TEST(ScopedNativeLibrary, Basic) { -#if defined(OS_WIN) - // Get the pointer to DirectDrawCreate() from "ddraw.dll" and verify it - // is valid only in this scope. - // FreeLibrary() doesn't actually unload a DLL until its reference count - // becomes zero, i.e. function pointer is still valid if the DLL used - // in this test is also used by another part of this executable. - // So, this test uses "ddraw.dll", which is not used by Chrome at all but - // installed on all versions of Windows. - const char kFunctionName[] = "DirectDrawCreate"; - NativeLibrary native_library; - { - FilePath path(FilePath::FromUTF8Unsafe(GetNativeLibraryName("ddraw"))); - native_library = LoadNativeLibrary(path, nullptr); - ScopedNativeLibrary library(native_library); - EXPECT_TRUE(library.is_valid()); - EXPECT_EQ(native_library, library.get()); - FARPROC test_function = - reinterpret_cast<FARPROC>(library.GetFunctionPointer(kFunctionName)); - EXPECT_EQ(0, IsBadCodePtr(test_function)); - EXPECT_EQ( - GetFunctionPointerFromNativeLibrary(native_library, kFunctionName), - test_function); - } - EXPECT_FALSE( - GetFunctionPointerFromNativeLibrary(native_library, kFunctionName)); -#endif -} - -} // namespace base
diff --git a/base/security_unittest.cc b/base/security_unittest.cc deleted file mode 100644 index 9a3bc27..0000000 --- a/base/security_unittest.cc +++ /dev/null
@@ -1,172 +0,0 @@ -// 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 <fcntl.h> -#include <stddef.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/stat.h> -#include <sys/types.h> - -#include <algorithm> -#include <limits> -#include <memory> - -#include "base/files/file_util.h" -#include "base/logging.h" -#include "base/memory/free_deleter.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(OS_POSIX) -#include <sys/mman.h> -#include <unistd.h> -#endif - -using std::nothrow; -using std::numeric_limits; - -namespace { - -// This function acts as a compiler optimization barrier. We use it to -// prevent the compiler from making an expression a compile-time constant. -// We also use it so that the compiler doesn't discard certain return values -// as something we don't need (see the comment with calloc below). -template <typename Type> -NOINLINE Type HideValueFromCompiler(volatile Type value) { -#if defined(__GNUC__) - // In a GCC compatible compiler (GCC or Clang), make this compiler barrier - // more robust than merely using "volatile". - __asm__ volatile ("" : "+r" (value)); -#endif // __GNUC__ - return value; -} - -// TCmalloc, currently supported only by Linux/CrOS, supports malloc limits. -// - NO_TCMALLOC (should be defined if compiled with use_allocator!="tcmalloc") -// - ADDRESS_SANITIZER it has its own memory allocator -#if defined(OS_LINUX) && !defined(NO_TCMALLOC) && !defined(ADDRESS_SANITIZER) -#define MALLOC_OVERFLOW_TEST(function) function -#else -#define MALLOC_OVERFLOW_TEST(function) DISABLED_##function -#endif - -// There are platforms where these tests are known to fail. We would like to -// be able to easily check the status on the bots, but marking tests as -// FAILS_ is too clunky. -void OverflowTestsSoftExpectTrue(bool overflow_detected) { - if (!overflow_detected) { -#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_MACOSX) - // Sadly, on Linux, Android, and OSX we don't have a good story yet. Don't - // fail the test, but report. - printf("Platform has overflow: %s\n", - !overflow_detected ? "yes." : "no."); -#else - // Otherwise, fail the test. (Note: EXPECT are ok in subfunctions, ASSERT - // aren't). - EXPECT_TRUE(overflow_detected); -#endif - } -} - -#if defined(OS_IOS) || defined(OS_FUCHSIA) || defined(ADDRESS_SANITIZER) || \ - defined(THREAD_SANITIZER) || defined(MEMORY_SANITIZER) -#define MAYBE_NewOverflow DISABLED_NewOverflow -#else -#define MAYBE_NewOverflow NewOverflow -#endif -// Test array[TooBig][X] and array[X][TooBig] allocations for int overflows. -// IOS doesn't honor nothrow, so disable the test there. -// TODO(https://crbug.com/828229): Fuchsia SDK exports an incorrect new[] that -// gets picked up in Debug/component builds, breaking this test. -// Disabled under XSan because asan aborts when new returns nullptr, -// https://bugs.chromium.org/p/chromium/issues/detail?id=690271#c15 -TEST(SecurityTest, MAYBE_NewOverflow) { - const size_t kArraySize = 4096; - // We want something "dynamic" here, so that the compiler doesn't - // immediately reject crazy arrays. - const size_t kDynamicArraySize = HideValueFromCompiler(kArraySize); - const size_t kMaxSizeT = std::numeric_limits<size_t>::max(); - const size_t kArraySize2 = kMaxSizeT / kArraySize + 10; - const size_t kDynamicArraySize2 = HideValueFromCompiler(kArraySize2); - { - std::unique_ptr<char[][kArraySize]> array_pointer( - new (nothrow) char[kDynamicArraySize2][kArraySize]); - // Prevent clang from optimizing away the whole test. - char* volatile p = reinterpret_cast<char*>(array_pointer.get()); - OverflowTestsSoftExpectTrue(!p); - } - // On windows, the compiler prevents static array sizes of more than - // 0x7fffffff (error C2148). -#if defined(OS_WIN) && defined(ARCH_CPU_64_BITS) - ALLOW_UNUSED_LOCAL(kDynamicArraySize); -#else - { - std::unique_ptr<char[][kArraySize2]> array_pointer( - new (nothrow) char[kDynamicArraySize][kArraySize2]); - // Prevent clang from optimizing away the whole test. - char* volatile p = reinterpret_cast<char*>(array_pointer.get()); - OverflowTestsSoftExpectTrue(!p); - } -#endif // !defined(OS_WIN) || !defined(ARCH_CPU_64_BITS) -} - -#if defined(OS_LINUX) && defined(__x86_64__) -// Check if ptr1 and ptr2 are separated by less than size chars. -bool ArePointersToSameArea(void* ptr1, void* ptr2, size_t size) { - ptrdiff_t ptr_diff = reinterpret_cast<char*>(std::max(ptr1, ptr2)) - - reinterpret_cast<char*>(std::min(ptr1, ptr2)); - return static_cast<size_t>(ptr_diff) <= size; -} - -// Check if TCMalloc uses an underlying random memory allocator. -TEST(SecurityTest, MALLOC_OVERFLOW_TEST(RandomMemoryAllocations)) { - size_t kPageSize = 4096; // We support x86_64 only. - // Check that malloc() returns an address that is neither the kernel's - // un-hinted mmap area, nor the current brk() area. The first malloc() may - // not be at a random address because TCMalloc will first exhaust any memory - // that it has allocated early on, before starting the sophisticated - // allocators. - void* default_mmap_heap_address = - mmap(nullptr, kPageSize, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - ASSERT_NE(default_mmap_heap_address, - static_cast<void*>(MAP_FAILED)); - ASSERT_EQ(munmap(default_mmap_heap_address, kPageSize), 0); - void* brk_heap_address = sbrk(0); - ASSERT_NE(brk_heap_address, reinterpret_cast<void*>(-1)); - ASSERT_TRUE(brk_heap_address != nullptr); - // 1 MB should get us past what TCMalloc pre-allocated before initializing - // the sophisticated allocators. - size_t kAllocSize = 1<<20; - std::unique_ptr<char, base::FreeDeleter> ptr( - static_cast<char*>(malloc(kAllocSize))); - ASSERT_TRUE(ptr != nullptr); - // If two pointers are separated by less than 512MB, they are considered - // to be in the same area. - // Our random pointer could be anywhere within 0x3fffffffffff (46bits), - // and we are checking that it's not withing 1GB (30 bits) from two - // addresses (brk and mmap heap). We have roughly one chance out of - // 2^15 to flake. - const size_t kAreaRadius = 1<<29; - bool in_default_mmap_heap = ArePointersToSameArea( - ptr.get(), default_mmap_heap_address, kAreaRadius); - EXPECT_FALSE(in_default_mmap_heap); - - bool in_default_brk_heap = ArePointersToSameArea( - ptr.get(), brk_heap_address, kAreaRadius); - EXPECT_FALSE(in_default_brk_heap); - - // In the implementation, we always mask our random addresses with - // kRandomMask, so we use it as an additional detection mechanism. - const uintptr_t kRandomMask = 0x3fffffffffffULL; - bool impossible_random_address = - reinterpret_cast<uintptr_t>(ptr.get()) & ~kRandomMask; - EXPECT_FALSE(impossible_random_address); -} - -#endif // defined(OS_LINUX) && defined(__x86_64__) - -} // namespace
diff --git a/base/sequence_checker_unittest.cc b/base/sequence_checker_unittest.cc deleted file mode 100644 index 8d44f3e..0000000 --- a/base/sequence_checker_unittest.cc +++ /dev/null
@@ -1,181 +0,0 @@ -// 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/sequence_checker.h" - -#include <stddef.h> - -#include <memory> -#include <string> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/callback_forward.h" -#include "base/macros.h" -#include "base/sequence_token.h" -#include "base/single_thread_task_runner.h" -#include "base/test/gtest_util.h" -#include "base/threading/simple_thread.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -// Runs a callback on another thread. -class RunCallbackThread : public SimpleThread { - public: - explicit RunCallbackThread(const Closure& callback) - : SimpleThread("RunCallbackThread"), callback_(callback) { - Start(); - Join(); - } - - private: - // SimpleThread: - void Run() override { callback_.Run(); } - - const Closure callback_; - - DISALLOW_COPY_AND_ASSIGN(RunCallbackThread); -}; - -void ExpectCalledOnValidSequence(SequenceCheckerImpl* sequence_checker) { - ASSERT_TRUE(sequence_checker); - - // This should bind |sequence_checker| to the current sequence if it wasn't - // already bound to a sequence. - EXPECT_TRUE(sequence_checker->CalledOnValidSequence()); - - // Since |sequence_checker| is now bound to the current sequence, another call - // to CalledOnValidSequence() should return true. - EXPECT_TRUE(sequence_checker->CalledOnValidSequence()); -} - -void ExpectCalledOnValidSequenceWithSequenceToken( - SequenceCheckerImpl* sequence_checker, - SequenceToken sequence_token) { - ScopedSetSequenceTokenForCurrentThread - scoped_set_sequence_token_for_current_thread(sequence_token); - ExpectCalledOnValidSequence(sequence_checker); -} - -void ExpectNotCalledOnValidSequence(SequenceCheckerImpl* sequence_checker) { - ASSERT_TRUE(sequence_checker); - EXPECT_FALSE(sequence_checker->CalledOnValidSequence()); -} - -} // namespace - -TEST(SequenceCheckerTest, CallsAllowedOnSameThreadNoSequenceToken) { - SequenceCheckerImpl sequence_checker; - EXPECT_TRUE(sequence_checker.CalledOnValidSequence()); -} - -TEST(SequenceCheckerTest, CallsAllowedOnSameThreadSameSequenceToken) { - ScopedSetSequenceTokenForCurrentThread - scoped_set_sequence_token_for_current_thread(SequenceToken::Create()); - SequenceCheckerImpl sequence_checker; - EXPECT_TRUE(sequence_checker.CalledOnValidSequence()); -} - -TEST(SequenceCheckerTest, CallsDisallowedOnDifferentThreadsNoSequenceToken) { - SequenceCheckerImpl sequence_checker; - RunCallbackThread thread( - Bind(&ExpectNotCalledOnValidSequence, Unretained(&sequence_checker))); -} - -TEST(SequenceCheckerTest, CallsAllowedOnDifferentThreadsSameSequenceToken) { - const SequenceToken sequence_token(SequenceToken::Create()); - - ScopedSetSequenceTokenForCurrentThread - scoped_set_sequence_token_for_current_thread(sequence_token); - SequenceCheckerImpl sequence_checker; - EXPECT_TRUE(sequence_checker.CalledOnValidSequence()); - - RunCallbackThread thread(Bind(&ExpectCalledOnValidSequenceWithSequenceToken, - Unretained(&sequence_checker), sequence_token)); -} - -TEST(SequenceCheckerTest, CallsDisallowedOnSameThreadDifferentSequenceToken) { - std::unique_ptr<SequenceCheckerImpl> sequence_checker; - - { - ScopedSetSequenceTokenForCurrentThread - scoped_set_sequence_token_for_current_thread(SequenceToken::Create()); - sequence_checker.reset(new SequenceCheckerImpl); - } - - { - // Different SequenceToken. - ScopedSetSequenceTokenForCurrentThread - scoped_set_sequence_token_for_current_thread(SequenceToken::Create()); - EXPECT_FALSE(sequence_checker->CalledOnValidSequence()); - } - - // No SequenceToken. - EXPECT_FALSE(sequence_checker->CalledOnValidSequence()); -} - -TEST(SequenceCheckerTest, DetachFromSequence) { - std::unique_ptr<SequenceCheckerImpl> sequence_checker; - - { - ScopedSetSequenceTokenForCurrentThread - scoped_set_sequence_token_for_current_thread(SequenceToken::Create()); - sequence_checker.reset(new SequenceCheckerImpl); - } - - sequence_checker->DetachFromSequence(); - - { - // Verify that CalledOnValidSequence() returns true when called with - // a different sequence token after a call to DetachFromSequence(). - ScopedSetSequenceTokenForCurrentThread - scoped_set_sequence_token_for_current_thread(SequenceToken::Create()); - EXPECT_TRUE(sequence_checker->CalledOnValidSequence()); - } -} - -TEST(SequenceCheckerTest, DetachFromSequenceNoSequenceToken) { - SequenceCheckerImpl sequence_checker; - sequence_checker.DetachFromSequence(); - - // Verify that CalledOnValidSequence() returns true when called on a - // different thread after a call to DetachFromSequence(). - RunCallbackThread thread( - Bind(&ExpectCalledOnValidSequence, Unretained(&sequence_checker))); - - EXPECT_FALSE(sequence_checker.CalledOnValidSequence()); -} - -TEST(SequenceCheckerMacroTest, Macros) { - auto scope = std::make_unique<ScopedSetSequenceTokenForCurrentThread>( - SequenceToken::Create()); - SEQUENCE_CHECKER(my_sequence_checker); - - // Don't expect a DCHECK death when a SequenceChecker is used on the right - // sequence. - DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker) << "Error message."; - - scope.reset(); - -#if DCHECK_IS_ON() - // Expect DCHECK death when used on a different sequence. - EXPECT_DCHECK_DEATH({ - DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker) << "Error message."; - }); -#else - // Happily no-ops on non-dcheck builds. - DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker) << "Error message."; -#endif - - DETACH_FROM_SEQUENCE(my_sequence_checker); - - // Don't expect a DCHECK death when a SequenceChecker is used for the first - // time after having been detached. - DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker) << "Error message."; -} - -} // namespace base
diff --git a/base/sequence_token_unittest.cc b/base/sequence_token_unittest.cc deleted file mode 100644 index 2ed6878..0000000 --- a/base/sequence_token_unittest.cc +++ /dev/null
@@ -1,133 +0,0 @@ -// 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/sequence_token.h" - -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(SequenceTokenTest, IsValid) { - EXPECT_FALSE(SequenceToken().IsValid()); - EXPECT_TRUE(SequenceToken::Create().IsValid()); -} - -TEST(SequenceTokenTest, OperatorEquals) { - const SequenceToken invalid_a; - const SequenceToken invalid_b; - const SequenceToken valid_a = SequenceToken::Create(); - const SequenceToken valid_b = SequenceToken::Create(); - - EXPECT_FALSE(invalid_a == invalid_a); - EXPECT_FALSE(invalid_a == invalid_b); - EXPECT_FALSE(invalid_a == valid_a); - EXPECT_FALSE(invalid_a == valid_b); - - EXPECT_FALSE(valid_a == invalid_a); - EXPECT_FALSE(valid_a == invalid_b); - EXPECT_EQ(valid_a, valid_a); - EXPECT_FALSE(valid_a == valid_b); -} - -TEST(SequenceTokenTest, OperatorNotEquals) { - const SequenceToken invalid_a; - const SequenceToken invalid_b; - const SequenceToken valid_a = SequenceToken::Create(); - const SequenceToken valid_b = SequenceToken::Create(); - - EXPECT_NE(invalid_a, invalid_a); - EXPECT_NE(invalid_a, invalid_b); - EXPECT_NE(invalid_a, valid_a); - EXPECT_NE(invalid_a, valid_b); - - EXPECT_NE(valid_a, invalid_a); - EXPECT_NE(valid_a, invalid_b); - EXPECT_FALSE(valid_a != valid_a); - EXPECT_NE(valid_a, valid_b); -} - -TEST(SequenceTokenTest, GetForCurrentThread) { - const SequenceToken token = SequenceToken::Create(); - - EXPECT_FALSE(SequenceToken::GetForCurrentThread().IsValid()); - - { - ScopedSetSequenceTokenForCurrentThread - scoped_set_sequence_token_for_current_thread(token); - EXPECT_TRUE(SequenceToken::GetForCurrentThread().IsValid()); - EXPECT_EQ(token, SequenceToken::GetForCurrentThread()); - } - - EXPECT_FALSE(SequenceToken::GetForCurrentThread().IsValid()); -} - -TEST(SequenceTokenTest, ToInternalValue) { - const SequenceToken token1 = SequenceToken::Create(); - const SequenceToken token2 = SequenceToken::Create(); - - // Confirm that internal values are unique. - EXPECT_NE(token1.ToInternalValue(), token2.ToInternalValue()); -} - -// Expect a default-constructed TaskToken to be invalid and not equal to -// another invalid TaskToken. -TEST(TaskTokenTest, InvalidDefaultConstructed) { - EXPECT_FALSE(TaskToken().IsValid()); - EXPECT_NE(TaskToken(), TaskToken()); -} - -// Expect a TaskToken returned by TaskToken::GetForCurrentThread() outside the -// scope of a ScopedSetSequenceTokenForCurrentThread to be invalid. -TEST(TaskTokenTest, InvalidOutsideScope) { - EXPECT_FALSE(TaskToken::GetForCurrentThread().IsValid()); -} - -// Expect an invalid TaskToken not to be equal with a valid TaskToken. -TEST(TaskTokenTest, ValidNotEqualsInvalid) { - ScopedSetSequenceTokenForCurrentThread - scoped_set_sequence_token_for_current_thread(SequenceToken::Create()); - TaskToken valid = TaskToken::GetForCurrentThread(); - TaskToken invalid; - EXPECT_NE(valid, invalid); -} - -// Expect TaskTokens returned by TaskToken::GetForCurrentThread() in the scope -// of the same ScopedSetSequenceTokenForCurrentThread instance to be -// valid and equal with each other. -TEST(TaskTokenTest, EqualInSameScope) { - ScopedSetSequenceTokenForCurrentThread - scoped_set_sequence_token_for_current_thread(SequenceToken::Create()); - - const TaskToken token_a = TaskToken::GetForCurrentThread(); - const TaskToken token_b = TaskToken::GetForCurrentThread(); - - EXPECT_TRUE(token_a.IsValid()); - EXPECT_TRUE(token_b.IsValid()); - EXPECT_EQ(token_a, token_b); -} - -// Expect TaskTokens returned by TaskToken::GetForCurrentThread() in the scope -// of different ScopedSetSequenceTokenForCurrentThread instances to be -// valid but not equal to each other. -TEST(TaskTokenTest, NotEqualInDifferentScopes) { - TaskToken token_a; - TaskToken token_b; - - { - ScopedSetSequenceTokenForCurrentThread - scoped_set_sequence_token_for_current_thread(SequenceToken::Create()); - token_a = TaskToken::GetForCurrentThread(); - } - { - ScopedSetSequenceTokenForCurrentThread - scoped_set_sequence_token_for_current_thread(SequenceToken::Create()); - token_b = TaskToken::GetForCurrentThread(); - } - - EXPECT_TRUE(token_a.IsValid()); - EXPECT_TRUE(token_b.IsValid()); - EXPECT_NE(token_a, token_b); -} - -} // namespace base
diff --git a/base/sequenced_task_runner_unittest.cc b/base/sequenced_task_runner_unittest.cc deleted file mode 100644 index 4dcc7e5..0000000 --- a/base/sequenced_task_runner_unittest.cc +++ /dev/null
@@ -1,104 +0,0 @@ -// 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/sequenced_task_runner.h" - -#include <utility> - -#include "base/bind.h" -#include "base/gtest_prod_util.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "base/threading/thread.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -class FlagOnDelete { - public: - FlagOnDelete(bool* deleted, - scoped_refptr<SequencedTaskRunner> expected_deletion_sequence) - : deleted_(deleted), - expected_deletion_sequence_(std::move(expected_deletion_sequence)) {} - - private: - friend class DeleteHelper<FlagOnDelete>; - FRIEND_TEST_ALL_PREFIXES(SequencedTaskRunnerTest, - OnTaskRunnerDeleterTargetStoppedEarly); - - ~FlagOnDelete() { - EXPECT_FALSE(*deleted_); - *deleted_ = true; - if (expected_deletion_sequence_) - EXPECT_TRUE(expected_deletion_sequence_->RunsTasksInCurrentSequence()); - } - - bool* deleted_; - const scoped_refptr<SequencedTaskRunner> expected_deletion_sequence_; - - DISALLOW_COPY_AND_ASSIGN(FlagOnDelete); -}; - -class SequencedTaskRunnerTest : public testing::Test { - protected: - SequencedTaskRunnerTest() : foreign_thread_("foreign") {} - - void SetUp() override { - main_runner_ = message_loop_.task_runner(); - - foreign_thread_.Start(); - foreign_runner_ = foreign_thread_.task_runner(); - } - - scoped_refptr<SequencedTaskRunner> main_runner_; - scoped_refptr<SequencedTaskRunner> foreign_runner_; - - Thread foreign_thread_; - - private: - MessageLoop message_loop_; - - DISALLOW_COPY_AND_ASSIGN(SequencedTaskRunnerTest); -}; - -using SequenceBoundUniquePtr = - std::unique_ptr<FlagOnDelete, OnTaskRunnerDeleter>; - -TEST_F(SequencedTaskRunnerTest, OnTaskRunnerDeleterOnMainThread) { - bool deleted_on_main_thread = false; - SequenceBoundUniquePtr ptr( - new FlagOnDelete(&deleted_on_main_thread, main_runner_), - OnTaskRunnerDeleter(main_runner_)); - EXPECT_FALSE(deleted_on_main_thread); - foreign_runner_->PostTask( - FROM_HERE, BindOnce([](SequenceBoundUniquePtr) {}, std::move(ptr))); - - { - RunLoop run_loop; - foreign_runner_->PostTaskAndReply(FROM_HERE, BindOnce([] {}), - run_loop.QuitClosure()); - run_loop.Run(); - } - EXPECT_TRUE(deleted_on_main_thread); -} - -TEST_F(SequencedTaskRunnerTest, OnTaskRunnerDeleterTargetStoppedEarly) { - bool deleted_on_main_thread = false; - FlagOnDelete* raw = new FlagOnDelete(&deleted_on_main_thread, main_runner_); - SequenceBoundUniquePtr ptr(raw, OnTaskRunnerDeleter(foreign_runner_)); - EXPECT_FALSE(deleted_on_main_thread); - - // Stopping the target ahead of deleting |ptr| should make its - // OnTaskRunnerDeleter no-op. - foreign_thread_.Stop(); - ptr = nullptr; - EXPECT_FALSE(deleted_on_main_thread); - - delete raw; - EXPECT_TRUE(deleted_on_main_thread); -} - -} // namespace -} // namespace base
diff --git a/base/sha1_unittest.cc b/base/sha1_unittest.cc deleted file mode 100644 index ea9cf63..0000000 --- a/base/sha1_unittest.cc +++ /dev/null
@@ -1,109 +0,0 @@ -// 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/sha1.h" - -#include <stddef.h> - -#include <string> - -#include "testing/gtest/include/gtest/gtest.h" - -TEST(SHA1Test, Test1) { - // Example A.1 from FIPS 180-2: one-block message. - std::string input = "abc"; - - int expected[] = { 0xa9, 0x99, 0x3e, 0x36, - 0x47, 0x06, 0x81, 0x6a, - 0xba, 0x3e, 0x25, 0x71, - 0x78, 0x50, 0xc2, 0x6c, - 0x9c, 0xd0, 0xd8, 0x9d }; - - std::string output = base::SHA1HashString(input); - for (size_t i = 0; i < base::kSHA1Length; i++) - EXPECT_EQ(expected[i], output[i] & 0xFF); -} - -TEST(SHA1Test, Test2) { - // Example A.2 from FIPS 180-2: multi-block message. - std::string input = - "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; - - int expected[] = { 0x84, 0x98, 0x3e, 0x44, - 0x1c, 0x3b, 0xd2, 0x6e, - 0xba, 0xae, 0x4a, 0xa1, - 0xf9, 0x51, 0x29, 0xe5, - 0xe5, 0x46, 0x70, 0xf1 }; - - std::string output = base::SHA1HashString(input); - for (size_t i = 0; i < base::kSHA1Length; i++) - EXPECT_EQ(expected[i], output[i] & 0xFF); -} - -TEST(SHA1Test, Test3) { - // Example A.3 from FIPS 180-2: long message. - std::string input(1000000, 'a'); - - int expected[] = { 0x34, 0xaa, 0x97, 0x3c, - 0xd4, 0xc4, 0xda, 0xa4, - 0xf6, 0x1e, 0xeb, 0x2b, - 0xdb, 0xad, 0x27, 0x31, - 0x65, 0x34, 0x01, 0x6f }; - - std::string output = base::SHA1HashString(input); - for (size_t i = 0; i < base::kSHA1Length; i++) - EXPECT_EQ(expected[i], output[i] & 0xFF); -} - -TEST(SHA1Test, Test1Bytes) { - // Example A.1 from FIPS 180-2: one-block message. - std::string input = "abc"; - unsigned char output[base::kSHA1Length]; - - unsigned char expected[] = { 0xa9, 0x99, 0x3e, 0x36, - 0x47, 0x06, 0x81, 0x6a, - 0xba, 0x3e, 0x25, 0x71, - 0x78, 0x50, 0xc2, 0x6c, - 0x9c, 0xd0, 0xd8, 0x9d }; - - base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(input.c_str()), - input.length(), output); - for (size_t i = 0; i < base::kSHA1Length; i++) - EXPECT_EQ(expected[i], output[i]); -} - -TEST(SHA1Test, Test2Bytes) { - // Example A.2 from FIPS 180-2: multi-block message. - std::string input = - "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; - unsigned char output[base::kSHA1Length]; - - unsigned char expected[] = { 0x84, 0x98, 0x3e, 0x44, - 0x1c, 0x3b, 0xd2, 0x6e, - 0xba, 0xae, 0x4a, 0xa1, - 0xf9, 0x51, 0x29, 0xe5, - 0xe5, 0x46, 0x70, 0xf1 }; - - base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(input.c_str()), - input.length(), output); - for (size_t i = 0; i < base::kSHA1Length; i++) - EXPECT_EQ(expected[i], output[i]); -} - -TEST(SHA1Test, Test3Bytes) { - // Example A.3 from FIPS 180-2: long message. - std::string input(1000000, 'a'); - unsigned char output[base::kSHA1Length]; - - unsigned char expected[] = { 0x34, 0xaa, 0x97, 0x3c, - 0xd4, 0xc4, 0xda, 0xa4, - 0xf6, 0x1e, 0xeb, 0x2b, - 0xdb, 0xad, 0x27, 0x31, - 0x65, 0x34, 0x01, 0x6f }; - - base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(input.c_str()), - input.length(), output); - for (size_t i = 0; i < base::kSHA1Length; i++) - EXPECT_EQ(expected[i], output[i]); -}
diff --git a/base/stl_util_unittest.cc b/base/stl_util_unittest.cc deleted file mode 100644 index f13f881..0000000 --- a/base/stl_util_unittest.cc +++ /dev/null
@@ -1,612 +0,0 @@ -// Copyright 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/stl_util.h" - -#include <array> -#include <deque> -#include <forward_list> -#include <functional> -#include <initializer_list> -#include <iterator> -#include <list> -#include <map> -#include <queue> -#include <set> -#include <stack> -#include <string> -#include <type_traits> -#include <unordered_map> -#include <unordered_set> -#include <vector> - -#include "base/containers/queue.h" -#include "base/strings/string16.h" -#include "base/strings/utf_string_conversions.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -// Used as test case to ensure the various base::STLXxx functions don't require -// more than operators "<" and "==" on values stored in containers. -class ComparableValue { - public: - explicit ComparableValue(int value) : value_(value) {} - - bool operator==(const ComparableValue& rhs) const { - return value_ == rhs.value_; - } - - bool operator<(const ComparableValue& rhs) const { - return value_ < rhs.value_; - } - - private: - int value_; -}; - -template <typename Container> -void RunEraseTest() { - const std::pair<Container, Container> test_data[] = { - {Container(), Container()}, {{1, 2, 3}, {1, 3}}, {{1, 2, 3, 2}, {1, 3}}}; - - for (auto test_case : test_data) { - base::Erase(test_case.first, 2); - EXPECT_EQ(test_case.second, test_case.first); - } -} - -// This test is written for containers of std::pair<int, int> to support maps. -template <typename Container> -void RunEraseIfTest() { - struct { - Container input; - Container erase_even; - Container erase_odd; - } test_data[] = { - {Container(), Container(), Container()}, - {{{1, 1}, {2, 2}, {3, 3}}, {{1, 1}, {3, 3}}, {{2, 2}}}, - {{{1, 1}, {2, 2}, {3, 3}, {4, 4}}, {{1, 1}, {3, 3}}, {{2, 2}, {4, 4}}}, - }; - - for (auto test_case : test_data) { - base::EraseIf(test_case.input, [](const std::pair<int, int>& elem) { - return !(elem.first & 1); - }); - EXPECT_EQ(test_case.erase_even, test_case.input); - } - - for (auto test_case : test_data) { - base::EraseIf(test_case.input, [](const std::pair<int, int>& elem) { - return elem.first & 1; - }); - EXPECT_EQ(test_case.erase_odd, test_case.input); - } -} - -struct CustomIntHash { - size_t operator()(int elem) const { return std::hash<int>()(elem) + 1; } -}; - -struct HashByFirst { - size_t operator()(const std::pair<int, int>& elem) const { - return std::hash<int>()(elem.first); - } -}; - -} // namespace - -namespace base { -namespace { - -TEST(STLUtilTest, Size) { - { - std::vector<int> vector = {1, 2, 3, 4, 5}; - static_assert( - std::is_same<decltype(base::size(vector)), - decltype(vector.size())>::value, - "base::size(vector) should have the same type as vector.size()"); - EXPECT_EQ(vector.size(), base::size(vector)); - } - - { - std::string empty_str; - static_assert( - std::is_same<decltype(base::size(empty_str)), - decltype(empty_str.size())>::value, - "base::size(empty_str) should have the same type as empty_str.size()"); - EXPECT_EQ(0u, base::size(empty_str)); - } - - { - std::array<int, 4> array = {{1, 2, 3, 4}}; - static_assert( - std::is_same<decltype(base::size(array)), - decltype(array.size())>::value, - "base::size(array) should have the same type as array.size()"); - static_assert(base::size(array) == array.size(), - "base::size(array) should be equal to array.size()"); - } - - { - int array[] = {1, 2, 3}; - static_assert(std::is_same<size_t, decltype(base::size(array))>::value, - "base::size(array) should be of type size_t"); - static_assert(3u == base::size(array), "base::size(array) should be 3"); - } -} - -TEST(STLUtilTest, Empty) { - { - std::vector<int> vector; - static_assert( - std::is_same<decltype(base::empty(vector)), - decltype(vector.empty())>::value, - "base::empty(vector) should have the same type as vector.empty()"); - EXPECT_EQ(vector.empty(), base::empty(vector)); - } - - { - std::array<int, 4> array = {{1, 2, 3, 4}}; - static_assert( - std::is_same<decltype(base::empty(array)), - decltype(array.empty())>::value, - "base::empty(array) should have the same type as array.empty()"); - static_assert(base::empty(array) == array.empty(), - "base::empty(array) should be equal to array.empty()"); - } - - { - int array[] = {1, 2, 3}; - static_assert(std::is_same<bool, decltype(base::empty(array))>::value, - "base::empty(array) should be of type bool"); - static_assert(!base::empty(array), "base::empty(array) should be false"); - } - - { - constexpr std::initializer_list<int> il; - static_assert(std::is_same<bool, decltype(base::empty(il))>::value, - "base::empty(il) should be of type bool"); - static_assert(base::empty(il), "base::empty(il) should be true"); - } -} - -TEST(STLUtilTest, Data) { - { - std::vector<int> vector = {1, 2, 3, 4, 5}; - static_assert( - std::is_same<decltype(base::data(vector)), - decltype(vector.data())>::value, - "base::data(vector) should have the same type as vector.data()"); - EXPECT_EQ(vector.data(), base::data(vector)); - } - - { - const std::string cstr = "const string"; - static_assert( - std::is_same<decltype(base::data(cstr)), decltype(cstr.data())>::value, - "base::data(cstr) should have the same type as cstr.data()"); - - EXPECT_EQ(cstr.data(), base::data(cstr)); - } - - { - std::string str = "mutable string"; - static_assert(std::is_same<decltype(base::data(str)), char*>::value, - "base::data(str) should be of type char*"); - EXPECT_EQ(str.data(), base::data(str)); - } - - { - std::string empty_str; - static_assert(std::is_same<decltype(base::data(empty_str)), char*>::value, - "base::data(empty_str) should be of type char*"); - EXPECT_EQ(empty_str.data(), base::data(empty_str)); - } - - { - std::array<int, 4> array = {{1, 2, 3, 4}}; - static_assert( - std::is_same<decltype(base::data(array)), - decltype(array.data())>::value, - "base::data(array) should have the same type as array.data()"); - // std::array::data() is not constexpr prior to C++17, hence the runtime - // check. - EXPECT_EQ(array.data(), base::data(array)); - } - - { - constexpr int array[] = {1, 2, 3}; - static_assert(std::is_same<const int*, decltype(base::data(array))>::value, - "base::data(array) should be of type const int*"); - static_assert(array == base::data(array), - "base::data(array) should be array"); - } - - { - constexpr std::initializer_list<int> il; - static_assert( - std::is_same<decltype(il.begin()), decltype(base::data(il))>::value, - "base::data(il) should have the same type as il.begin()"); - static_assert(il.begin() == base::data(il), - "base::data(il) should be equal to il.begin()"); - } -} - -TEST(STLUtilTest, GetUnderlyingContainer) { - { - std::queue<int> queue({1, 2, 3, 4, 5}); - static_assert(std::is_same<decltype(GetUnderlyingContainer(queue)), - const std::deque<int>&>::value, - "GetUnderlyingContainer(queue) should be of type deque"); - EXPECT_THAT(GetUnderlyingContainer(queue), - testing::ElementsAre(1, 2, 3, 4, 5)); - } - - { - std::queue<int> queue; - EXPECT_THAT(GetUnderlyingContainer(queue), testing::ElementsAre()); - } - - { - base::queue<int> queue({1, 2, 3, 4, 5}); - static_assert( - std::is_same<decltype(GetUnderlyingContainer(queue)), - const base::circular_deque<int>&>::value, - "GetUnderlyingContainer(queue) should be of type circular_deque"); - EXPECT_THAT(GetUnderlyingContainer(queue), - testing::ElementsAre(1, 2, 3, 4, 5)); - } - - { - std::vector<int> values = {1, 2, 3, 4, 5}; - std::priority_queue<int> queue(values.begin(), values.end()); - static_assert(std::is_same<decltype(GetUnderlyingContainer(queue)), - const std::vector<int>&>::value, - "GetUnderlyingContainer(queue) should be of type vector"); - EXPECT_THAT(GetUnderlyingContainer(queue), - testing::UnorderedElementsAre(1, 2, 3, 4, 5)); - } - - { - std::stack<int> stack({1, 2, 3, 4, 5}); - static_assert(std::is_same<decltype(GetUnderlyingContainer(stack)), - const std::deque<int>&>::value, - "GetUnderlyingContainer(stack) should be of type deque"); - EXPECT_THAT(GetUnderlyingContainer(stack), - testing::ElementsAre(1, 2, 3, 4, 5)); - } -} - -TEST(STLUtilTest, STLIsSorted) { - { - std::set<int> set; - set.insert(24); - set.insert(1); - set.insert(12); - EXPECT_TRUE(STLIsSorted(set)); - } - - { - std::set<ComparableValue> set; - set.insert(ComparableValue(24)); - set.insert(ComparableValue(1)); - set.insert(ComparableValue(12)); - EXPECT_TRUE(STLIsSorted(set)); - } - - { - std::vector<int> vector; - vector.push_back(1); - vector.push_back(1); - vector.push_back(4); - vector.push_back(64); - vector.push_back(12432); - EXPECT_TRUE(STLIsSorted(vector)); - vector.back() = 1; - EXPECT_FALSE(STLIsSorted(vector)); - } -} - -TEST(STLUtilTest, STLSetDifference) { - std::set<int> a1; - a1.insert(1); - a1.insert(2); - a1.insert(3); - a1.insert(4); - - std::set<int> a2; - a2.insert(3); - a2.insert(4); - a2.insert(5); - a2.insert(6); - a2.insert(7); - - { - std::set<int> difference; - difference.insert(1); - difference.insert(2); - EXPECT_EQ(difference, STLSetDifference<std::set<int> >(a1, a2)); - } - - { - std::set<int> difference; - difference.insert(5); - difference.insert(6); - difference.insert(7); - EXPECT_EQ(difference, STLSetDifference<std::set<int> >(a2, a1)); - } - - { - std::vector<int> difference; - difference.push_back(1); - difference.push_back(2); - EXPECT_EQ(difference, STLSetDifference<std::vector<int> >(a1, a2)); - } - - { - std::vector<int> difference; - difference.push_back(5); - difference.push_back(6); - difference.push_back(7); - EXPECT_EQ(difference, STLSetDifference<std::vector<int> >(a2, a1)); - } -} - -TEST(STLUtilTest, STLSetUnion) { - std::set<int> a1; - a1.insert(1); - a1.insert(2); - a1.insert(3); - a1.insert(4); - - std::set<int> a2; - a2.insert(3); - a2.insert(4); - a2.insert(5); - a2.insert(6); - a2.insert(7); - - { - std::set<int> result; - result.insert(1); - result.insert(2); - result.insert(3); - result.insert(4); - result.insert(5); - result.insert(6); - result.insert(7); - EXPECT_EQ(result, STLSetUnion<std::set<int> >(a1, a2)); - } - - { - std::set<int> result; - result.insert(1); - result.insert(2); - result.insert(3); - result.insert(4); - result.insert(5); - result.insert(6); - result.insert(7); - EXPECT_EQ(result, STLSetUnion<std::set<int> >(a2, a1)); - } - - { - std::vector<int> result; - result.push_back(1); - result.push_back(2); - result.push_back(3); - result.push_back(4); - result.push_back(5); - result.push_back(6); - result.push_back(7); - EXPECT_EQ(result, STLSetUnion<std::vector<int> >(a1, a2)); - } - - { - std::vector<int> result; - result.push_back(1); - result.push_back(2); - result.push_back(3); - result.push_back(4); - result.push_back(5); - result.push_back(6); - result.push_back(7); - EXPECT_EQ(result, STLSetUnion<std::vector<int> >(a2, a1)); - } -} - -TEST(STLUtilTest, STLSetIntersection) { - std::set<int> a1; - a1.insert(1); - a1.insert(2); - a1.insert(3); - a1.insert(4); - - std::set<int> a2; - a2.insert(3); - a2.insert(4); - a2.insert(5); - a2.insert(6); - a2.insert(7); - - { - std::set<int> result; - result.insert(3); - result.insert(4); - EXPECT_EQ(result, STLSetIntersection<std::set<int> >(a1, a2)); - } - - { - std::set<int> result; - result.insert(3); - result.insert(4); - EXPECT_EQ(result, STLSetIntersection<std::set<int> >(a2, a1)); - } - - { - std::vector<int> result; - result.push_back(3); - result.push_back(4); - EXPECT_EQ(result, STLSetIntersection<std::vector<int> >(a1, a2)); - } - - { - std::vector<int> result; - result.push_back(3); - result.push_back(4); - EXPECT_EQ(result, STLSetIntersection<std::vector<int> >(a2, a1)); - } -} - -TEST(STLUtilTest, STLIncludes) { - std::set<int> a1; - a1.insert(1); - a1.insert(2); - a1.insert(3); - a1.insert(4); - - std::set<int> a2; - a2.insert(3); - a2.insert(4); - - std::set<int> a3; - a3.insert(3); - a3.insert(4); - a3.insert(5); - - EXPECT_TRUE(STLIncludes<std::set<int> >(a1, a2)); - EXPECT_FALSE(STLIncludes<std::set<int> >(a1, a3)); - EXPECT_FALSE(STLIncludes<std::set<int> >(a2, a1)); - EXPECT_FALSE(STLIncludes<std::set<int> >(a2, a3)); - EXPECT_FALSE(STLIncludes<std::set<int> >(a3, a1)); - EXPECT_TRUE(STLIncludes<std::set<int> >(a3, a2)); -} - -TEST(Erase, String) { - const std::pair<std::string, std::string> test_data[] = { - {"", ""}, {"abc", "bc"}, {"abca", "bc"}, - }; - - for (auto test_case : test_data) { - Erase(test_case.first, 'a'); - EXPECT_EQ(test_case.second, test_case.first); - } - - for (auto test_case : test_data) { - EraseIf(test_case.first, [](char elem) { return elem < 'b'; }); - EXPECT_EQ(test_case.second, test_case.first); - } -} - -TEST(Erase, String16) { - std::pair<base::string16, base::string16> test_data[] = { - {base::string16(), base::string16()}, - {UTF8ToUTF16("abc"), UTF8ToUTF16("bc")}, - {UTF8ToUTF16("abca"), UTF8ToUTF16("bc")}, - }; - - const base::string16 letters = UTF8ToUTF16("ab"); - for (auto test_case : test_data) { - Erase(test_case.first, letters[0]); - EXPECT_EQ(test_case.second, test_case.first); - } - - for (auto test_case : test_data) { - EraseIf(test_case.first, [&](short elem) { return elem < letters[1]; }); - EXPECT_EQ(test_case.second, test_case.first); - } -} - -TEST(Erase, Deque) { - RunEraseTest<std::deque<int>>(); - RunEraseIfTest<std::deque<std::pair<int, int>>>(); -} - -TEST(Erase, Vector) { - RunEraseTest<std::vector<int>>(); - RunEraseIfTest<std::vector<std::pair<int, int>>>(); -} - -TEST(Erase, ForwardList) { - RunEraseTest<std::forward_list<int>>(); - RunEraseIfTest<std::forward_list<std::pair<int, int>>>(); -} - -TEST(Erase, List) { - RunEraseTest<std::list<int>>(); - RunEraseIfTest<std::list<std::pair<int, int>>>(); -} - -TEST(Erase, Map) { - RunEraseIfTest<std::map<int, int>>(); - RunEraseIfTest<std::map<int, int, std::greater<int>>>(); -} - -TEST(Erase, Multimap) { - RunEraseIfTest<std::multimap<int, int>>(); - RunEraseIfTest<std::multimap<int, int, std::greater<int>>>(); -} - -TEST(Erase, Set) { - RunEraseIfTest<std::set<std::pair<int, int>>>(); - RunEraseIfTest< - std::set<std::pair<int, int>, std::greater<std::pair<int, int>>>>(); -} - -TEST(Erase, Multiset) { - RunEraseIfTest<std::multiset<std::pair<int, int>>>(); - RunEraseIfTest< - std::multiset<std::pair<int, int>, std::greater<std::pair<int, int>>>>(); -} - -TEST(Erase, UnorderedMap) { - RunEraseIfTest<std::unordered_map<int, int>>(); - RunEraseIfTest<std::unordered_map<int, int, CustomIntHash>>(); -} - -TEST(Erase, UnorderedMultimap) { - RunEraseIfTest<std::unordered_multimap<int, int>>(); - RunEraseIfTest<std::unordered_multimap<int, int, CustomIntHash>>(); -} - -TEST(Erase, UnorderedSet) { - RunEraseIfTest<std::unordered_set<std::pair<int, int>, HashByFirst>>(); -} - -TEST(Erase, UnorderedMultiset) { - RunEraseIfTest<std::unordered_multiset<std::pair<int, int>, HashByFirst>>(); -} - -TEST(Erase, IsNotIn) { - // Should keep both '2' but only one '4', like std::set_intersection. - std::vector<int> lhs = {0, 2, 2, 4, 4, 4, 6, 8, 10}; - std::vector<int> rhs = {1, 2, 2, 4, 5, 6, 7}; - std::vector<int> expected = {2, 2, 4, 6}; - EraseIf(lhs, IsNotIn<std::vector<int>>(rhs)); - EXPECT_EQ(expected, lhs); -} - -TEST(ContainsValue, OrdinaryArrays) { - const char allowed_chars[] = {'a', 'b', 'c', 'd'}; - EXPECT_TRUE(ContainsValue(allowed_chars, 'a')); - EXPECT_FALSE(ContainsValue(allowed_chars, 'z')); - EXPECT_FALSE(ContainsValue(allowed_chars, 0)); - - const char allowed_chars_including_nul[] = "abcd"; - EXPECT_TRUE(ContainsValue(allowed_chars_including_nul, 0)); -} - -TEST(STLUtilTest, OptionalOrNullptr) { - Optional<float> optional; - EXPECT_EQ(nullptr, base::OptionalOrNullptr(optional)); - - optional = 0.1f; - EXPECT_EQ(&optional.value(), base::OptionalOrNullptr(optional)); - EXPECT_NE(nullptr, base::OptionalOrNullptr(optional)); -} - -} // namespace -} // namespace base
diff --git a/base/strings/char_traits_unittest.cc b/base/strings/char_traits_unittest.cc deleted file mode 100644 index 31c421b..0000000 --- a/base/strings/char_traits_unittest.cc +++ /dev/null
@@ -1,32 +0,0 @@ -// 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/strings/char_traits.h" -#include "base/strings/string16.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(CharTraitsTest, CharCompare) { - static_assert(CharTraits<char>::compare("abc", "def", 3) == -1, ""); - static_assert(CharTraits<char>::compare("def", "def", 3) == 0, ""); - static_assert(CharTraits<char>::compare("ghi", "def", 3) == 1, ""); -} - -TEST(CharTraitsTest, CharLength) { - static_assert(CharTraits<char>::length("") == 0, ""); - static_assert(CharTraits<char>::length("abc") == 3, ""); -} - -TEST(CharTraitsTest, Char16TCompare) { - static_assert(CharTraits<char16_t>::compare(u"abc", u"def", 3) == -1, ""); - static_assert(CharTraits<char16_t>::compare(u"def", u"def", 3) == 0, ""); - static_assert(CharTraits<char16_t>::compare(u"ghi", u"def", 3) == 1, ""); -} - -TEST(CharTraitsTest, Char16TLength) { - static_assert(CharTraits<char16_t>::length(u"abc") == 3, ""); -} - -} // namespace base
diff --git a/base/strings/nullable_string16_unittest.cc b/base/strings/nullable_string16_unittest.cc deleted file mode 100644 index f02fdce..0000000 --- a/base/strings/nullable_string16_unittest.cc +++ /dev/null
@@ -1,35 +0,0 @@ -// 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/strings/nullable_string16.h" -#include "base/strings/utf_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(NullableString16Test, DefaultConstructor) { - NullableString16 s; - EXPECT_TRUE(s.is_null()); - EXPECT_EQ(string16(), s.string()); -} - -TEST(NullableString16Test, Equals) { - NullableString16 a(ASCIIToUTF16("hello"), false); - NullableString16 b(ASCIIToUTF16("hello"), false); - EXPECT_EQ(a, b); -} - -TEST(NullableString16Test, NotEquals) { - NullableString16 a(ASCIIToUTF16("hello"), false); - NullableString16 b(ASCIIToUTF16("world"), false); - EXPECT_NE(a, b); -} - -TEST(NullableString16Test, NotEqualsNull) { - NullableString16 a(ASCIIToUTF16("hello"), false); - NullableString16 b; - EXPECT_NE(a, b); -} - -} // namespace base
diff --git a/base/strings/pattern_unittest.cc b/base/strings/pattern_unittest.cc deleted file mode 100644 index 8ec5495..0000000 --- a/base/strings/pattern_unittest.cc +++ /dev/null
@@ -1,52 +0,0 @@ -// 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/strings/pattern.h" -#include "base/strings/utf_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(StringUtilTest, MatchPatternTest) { - EXPECT_TRUE(MatchPattern("www.google.com", "*.com")); - EXPECT_TRUE(MatchPattern("www.google.com", "*")); - EXPECT_FALSE(MatchPattern("www.google.com", "www*.g*.org")); - EXPECT_TRUE(MatchPattern("Hello", "H?l?o")); - EXPECT_FALSE(MatchPattern("www.google.com", "http://*)")); - EXPECT_FALSE(MatchPattern("www.msn.com", "*.COM")); - EXPECT_TRUE(MatchPattern("Hello*1234", "He??o\\*1*")); - EXPECT_FALSE(MatchPattern("", "*.*")); - EXPECT_TRUE(MatchPattern("", "*")); - EXPECT_TRUE(MatchPattern("", "?")); - EXPECT_TRUE(MatchPattern("", "")); - EXPECT_FALSE(MatchPattern("Hello", "")); - EXPECT_TRUE(MatchPattern("Hello*", "Hello*")); - EXPECT_TRUE(MatchPattern("abcd", "*???")); - EXPECT_FALSE(MatchPattern("abcd", "???")); - EXPECT_TRUE(MatchPattern("abcb", "a*b")); - EXPECT_FALSE(MatchPattern("abcb", "a?b")); - - // Test UTF8 matching. - EXPECT_TRUE(MatchPattern("heart: \xe2\x99\xa0", "*\xe2\x99\xa0")); - EXPECT_TRUE(MatchPattern("heart: \xe2\x99\xa0.", "heart: ?.")); - EXPECT_TRUE(MatchPattern("hearts: \xe2\x99\xa0\xe2\x99\xa0", "*")); - // Invalid sequences should be handled as a single invalid character. - EXPECT_TRUE(MatchPattern("invalid: \xef\xbf\xbe", "invalid: ?")); - // If the pattern has invalid characters, it shouldn't match anything. - EXPECT_FALSE(MatchPattern("\xf4\x90\x80\x80", "\xf4\x90\x80\x80")); - - // Test UTF16 character matching. - EXPECT_TRUE(MatchPattern(UTF8ToUTF16("www.google.com"), - UTF8ToUTF16("*.com"))); - EXPECT_TRUE(MatchPattern(UTF8ToUTF16("Hello*1234"), - UTF8ToUTF16("He??o\\*1*"))); - - // Some test cases that might cause naive implementations to exhibit - // exponential run time or fail. - EXPECT_TRUE(MatchPattern("Hello", "He********************************o")); - EXPECT_TRUE(MatchPattern("123456789012345678", "?????????????????*")); - EXPECT_TRUE(MatchPattern("aaaaaaaaaaab", "a*a*a*a*a*a*a*a*a*a*a*b")); -} - -} // namespace base
diff --git a/base/strings/safe_sprintf_unittest.cc b/base/strings/safe_sprintf_unittest.cc deleted file mode 100644 index 4a0948b..0000000 --- a/base/strings/safe_sprintf_unittest.cc +++ /dev/null
@@ -1,765 +0,0 @@ -// 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/strings/safe_sprintf.h" - -#include <stddef.h> -#include <stdint.h> -#include <stdio.h> -#include <string.h> - -#include <limits> -#include <memory> - -#include "base/logging.h" -#include "base/macros.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -// Death tests on Android are currently very flaky. No need to add more flaky -// tests, as they just make it hard to spot real problems. -// TODO(markus): See if the restrictions on Android can eventually be lifted. -#if defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID) -#define ALLOW_DEATH_TEST -#endif - -namespace base { -namespace strings { - -TEST(SafeSPrintfTest, Empty) { - char buf[2] = { 'X', 'X' }; - - // Negative buffer size should always result in an error. - EXPECT_EQ(-1, SafeSNPrintf(buf, static_cast<size_t>(-1), "")); - EXPECT_EQ('X', buf[0]); - EXPECT_EQ('X', buf[1]); - - // Zero buffer size should always result in an error. - EXPECT_EQ(-1, SafeSNPrintf(buf, 0, "")); - EXPECT_EQ('X', buf[0]); - EXPECT_EQ('X', buf[1]); - - // A one-byte buffer should always print a single NUL byte. - EXPECT_EQ(0, SafeSNPrintf(buf, 1, "")); - EXPECT_EQ(0, buf[0]); - EXPECT_EQ('X', buf[1]); - buf[0] = 'X'; - - // A larger buffer should leave the trailing bytes unchanged. - EXPECT_EQ(0, SafeSNPrintf(buf, 2, "")); - EXPECT_EQ(0, buf[0]); - EXPECT_EQ('X', buf[1]); - buf[0] = 'X'; - - // The same test using SafeSPrintf() instead of SafeSNPrintf(). - EXPECT_EQ(0, SafeSPrintf(buf, "")); - EXPECT_EQ(0, buf[0]); - EXPECT_EQ('X', buf[1]); - buf[0] = 'X'; -} - -TEST(SafeSPrintfTest, NoArguments) { - // Output a text message that doesn't require any substitutions. This - // is roughly equivalent to calling strncpy() (but unlike strncpy(), it does - // always add a trailing NUL; it always deduplicates '%' characters). - static const char text[] = "hello world"; - char ref[20], buf[20]; - memset(ref, 'X', sizeof(ref)); - memcpy(buf, ref, sizeof(buf)); - - // A negative buffer size should always result in an error. - EXPECT_EQ(-1, SafeSNPrintf(buf, static_cast<size_t>(-1), text)); - EXPECT_TRUE(!memcmp(buf, ref, sizeof(buf))); - - // Zero buffer size should always result in an error. - EXPECT_EQ(-1, SafeSNPrintf(buf, 0, text)); - EXPECT_TRUE(!memcmp(buf, ref, sizeof(buf))); - - // A one-byte buffer should always print a single NUL byte. - EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1, SafeSNPrintf(buf, 1, text)); - EXPECT_EQ(0, buf[0]); - EXPECT_TRUE(!memcmp(buf+1, ref+1, sizeof(buf)-1)); - memcpy(buf, ref, sizeof(buf)); - - // A larger (but limited) buffer should always leave the trailing bytes - // unchanged. - EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1, SafeSNPrintf(buf, 2, text)); - EXPECT_EQ(text[0], buf[0]); - EXPECT_EQ(0, buf[1]); - EXPECT_TRUE(!memcmp(buf+2, ref+2, sizeof(buf)-2)); - memcpy(buf, ref, sizeof(buf)); - - // A unrestricted buffer length should always leave the trailing bytes - // unchanged. - EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1, - SafeSNPrintf(buf, sizeof(buf), text)); - EXPECT_EQ(std::string(text), std::string(buf)); - EXPECT_TRUE(!memcmp(buf + sizeof(text), ref + sizeof(text), - sizeof(buf) - sizeof(text))); - memcpy(buf, ref, sizeof(buf)); - - // The same test using SafeSPrintf() instead of SafeSNPrintf(). - EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1, SafeSPrintf(buf, text)); - EXPECT_EQ(std::string(text), std::string(buf)); - EXPECT_TRUE(!memcmp(buf + sizeof(text), ref + sizeof(text), - sizeof(buf) - sizeof(text))); - memcpy(buf, ref, sizeof(buf)); - - // Check for deduplication of '%' percent characters. - EXPECT_EQ(1, SafeSPrintf(buf, "%%")); - EXPECT_EQ(2, SafeSPrintf(buf, "%%%%")); - EXPECT_EQ(2, SafeSPrintf(buf, "%%X")); - EXPECT_EQ(3, SafeSPrintf(buf, "%%%%X")); -#if defined(NDEBUG) - EXPECT_EQ(1, SafeSPrintf(buf, "%")); - EXPECT_EQ(2, SafeSPrintf(buf, "%%%")); - EXPECT_EQ(2, SafeSPrintf(buf, "%X")); - EXPECT_EQ(3, SafeSPrintf(buf, "%%%X")); -#elif defined(ALLOW_DEATH_TEST) - EXPECT_DEATH(SafeSPrintf(buf, "%"), "src.1. == '%'"); - EXPECT_DEATH(SafeSPrintf(buf, "%%%"), "src.1. == '%'"); - EXPECT_DEATH(SafeSPrintf(buf, "%X"), "src.1. == '%'"); - EXPECT_DEATH(SafeSPrintf(buf, "%%%X"), "src.1. == '%'"); -#endif -} - -TEST(SafeSPrintfTest, OneArgument) { - // Test basic single-argument single-character substitution. - const char text[] = "hello world"; - const char fmt[] = "hello%cworld"; - char ref[20], buf[20]; - memset(ref, 'X', sizeof(buf)); - memcpy(buf, ref, sizeof(buf)); - - // A negative buffer size should always result in an error. - EXPECT_EQ(-1, SafeSNPrintf(buf, static_cast<size_t>(-1), fmt, ' ')); - EXPECT_TRUE(!memcmp(buf, ref, sizeof(buf))); - - // Zero buffer size should always result in an error. - EXPECT_EQ(-1, SafeSNPrintf(buf, 0, fmt, ' ')); - EXPECT_TRUE(!memcmp(buf, ref, sizeof(buf))); - - // A one-byte buffer should always print a single NUL byte. - EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1, - SafeSNPrintf(buf, 1, fmt, ' ')); - EXPECT_EQ(0, buf[0]); - EXPECT_TRUE(!memcmp(buf+1, ref+1, sizeof(buf)-1)); - memcpy(buf, ref, sizeof(buf)); - - // A larger (but limited) buffer should always leave the trailing bytes - // unchanged. - EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1, - SafeSNPrintf(buf, 2, fmt, ' ')); - EXPECT_EQ(text[0], buf[0]); - EXPECT_EQ(0, buf[1]); - EXPECT_TRUE(!memcmp(buf+2, ref+2, sizeof(buf)-2)); - memcpy(buf, ref, sizeof(buf)); - - // A unrestricted buffer length should always leave the trailing bytes - // unchanged. - EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1, - SafeSNPrintf(buf, sizeof(buf), fmt, ' ')); - EXPECT_EQ(std::string(text), std::string(buf)); - EXPECT_TRUE(!memcmp(buf + sizeof(text), ref + sizeof(text), - sizeof(buf) - sizeof(text))); - memcpy(buf, ref, sizeof(buf)); - - // The same test using SafeSPrintf() instead of SafeSNPrintf(). - EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1, SafeSPrintf(buf, fmt, ' ')); - EXPECT_EQ(std::string(text), std::string(buf)); - EXPECT_TRUE(!memcmp(buf + sizeof(text), ref + sizeof(text), - sizeof(buf) - sizeof(text))); - memcpy(buf, ref, sizeof(buf)); - - // Check for deduplication of '%' percent characters. - EXPECT_EQ(1, SafeSPrintf(buf, "%%", 0)); - EXPECT_EQ(2, SafeSPrintf(buf, "%%%%", 0)); - EXPECT_EQ(2, SafeSPrintf(buf, "%Y", 0)); - EXPECT_EQ(2, SafeSPrintf(buf, "%%Y", 0)); - EXPECT_EQ(3, SafeSPrintf(buf, "%%%Y", 0)); - EXPECT_EQ(3, SafeSPrintf(buf, "%%%%Y", 0)); -#if defined(NDEBUG) - EXPECT_EQ(1, SafeSPrintf(buf, "%", 0)); - EXPECT_EQ(2, SafeSPrintf(buf, "%%%", 0)); -#elif defined(ALLOW_DEATH_TEST) - EXPECT_DEATH(SafeSPrintf(buf, "%", 0), "ch"); - EXPECT_DEATH(SafeSPrintf(buf, "%%%", 0), "ch"); -#endif -} - -TEST(SafeSPrintfTest, MissingArg) { -#if defined(NDEBUG) - char buf[20]; - EXPECT_EQ(3, SafeSPrintf(buf, "%c%c", 'A')); - EXPECT_EQ("A%c", std::string(buf)); -#elif defined(ALLOW_DEATH_TEST) - char buf[20]; - EXPECT_DEATH(SafeSPrintf(buf, "%c%c", 'A'), "cur_arg < max_args"); -#endif -} - -TEST(SafeSPrintfTest, ASANFriendlyBufferTest) { - // Print into a buffer that is sized exactly to size. ASAN can verify that - // nobody attempts to write past the end of the buffer. - // There is a more complicated test in PrintLongString() that covers a lot - // more edge case, but it is also harder to debug in case of a failure. - const char kTestString[] = "This is a test"; - std::unique_ptr<char[]> buf(new char[sizeof(kTestString)]); - EXPECT_EQ(static_cast<ssize_t>(sizeof(kTestString) - 1), - SafeSNPrintf(buf.get(), sizeof(kTestString), kTestString)); - EXPECT_EQ(std::string(kTestString), std::string(buf.get())); - EXPECT_EQ(static_cast<ssize_t>(sizeof(kTestString) - 1), - SafeSNPrintf(buf.get(), sizeof(kTestString), "%s", kTestString)); - EXPECT_EQ(std::string(kTestString), std::string(buf.get())); -} - -TEST(SafeSPrintfTest, NArgs) { - // Pre-C++11 compilers have a different code path, that can only print - // up to ten distinct arguments. - // We test both SafeSPrintf() and SafeSNPrintf(). This makes sure we don't - // have typos in the copy-n-pasted code that is needed to deal with various - // numbers of arguments. - char buf[12]; - EXPECT_EQ(1, SafeSPrintf(buf, "%c", 1)); - EXPECT_EQ("\1", std::string(buf)); - EXPECT_EQ(2, SafeSPrintf(buf, "%c%c", 1, 2)); - EXPECT_EQ("\1\2", std::string(buf)); - EXPECT_EQ(3, SafeSPrintf(buf, "%c%c%c", 1, 2, 3)); - EXPECT_EQ("\1\2\3", std::string(buf)); - EXPECT_EQ(4, SafeSPrintf(buf, "%c%c%c%c", 1, 2, 3, 4)); - EXPECT_EQ("\1\2\3\4", std::string(buf)); - EXPECT_EQ(5, SafeSPrintf(buf, "%c%c%c%c%c", 1, 2, 3, 4, 5)); - EXPECT_EQ("\1\2\3\4\5", std::string(buf)); - EXPECT_EQ(6, SafeSPrintf(buf, "%c%c%c%c%c%c", 1, 2, 3, 4, 5, 6)); - EXPECT_EQ("\1\2\3\4\5\6", std::string(buf)); - EXPECT_EQ(7, SafeSPrintf(buf, "%c%c%c%c%c%c%c", 1, 2, 3, 4, 5, 6, 7)); - EXPECT_EQ("\1\2\3\4\5\6\7", std::string(buf)); - EXPECT_EQ(8, SafeSPrintf(buf, "%c%c%c%c%c%c%c%c", 1, 2, 3, 4, 5, 6, 7, 8)); - EXPECT_EQ("\1\2\3\4\5\6\7\10", std::string(buf)); - EXPECT_EQ(9, SafeSPrintf(buf, "%c%c%c%c%c%c%c%c%c", - 1, 2, 3, 4, 5, 6, 7, 8, 9)); - EXPECT_EQ("\1\2\3\4\5\6\7\10\11", std::string(buf)); - EXPECT_EQ(10, SafeSPrintf(buf, "%c%c%c%c%c%c%c%c%c%c", - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); - - // Repeat all the tests with SafeSNPrintf() instead of SafeSPrintf(). - EXPECT_EQ("\1\2\3\4\5\6\7\10\11\12", std::string(buf)); - EXPECT_EQ(1, SafeSNPrintf(buf, 11, "%c", 1)); - EXPECT_EQ("\1", std::string(buf)); - EXPECT_EQ(2, SafeSNPrintf(buf, 11, "%c%c", 1, 2)); - EXPECT_EQ("\1\2", std::string(buf)); - EXPECT_EQ(3, SafeSNPrintf(buf, 11, "%c%c%c", 1, 2, 3)); - EXPECT_EQ("\1\2\3", std::string(buf)); - EXPECT_EQ(4, SafeSNPrintf(buf, 11, "%c%c%c%c", 1, 2, 3, 4)); - EXPECT_EQ("\1\2\3\4", std::string(buf)); - EXPECT_EQ(5, SafeSNPrintf(buf, 11, "%c%c%c%c%c", 1, 2, 3, 4, 5)); - EXPECT_EQ("\1\2\3\4\5", std::string(buf)); - EXPECT_EQ(6, SafeSNPrintf(buf, 11, "%c%c%c%c%c%c", 1, 2, 3, 4, 5, 6)); - EXPECT_EQ("\1\2\3\4\5\6", std::string(buf)); - EXPECT_EQ(7, SafeSNPrintf(buf, 11, "%c%c%c%c%c%c%c", 1, 2, 3, 4, 5, 6, 7)); - EXPECT_EQ("\1\2\3\4\5\6\7", std::string(buf)); - EXPECT_EQ(8, SafeSNPrintf(buf, 11, "%c%c%c%c%c%c%c%c", - 1, 2, 3, 4, 5, 6, 7, 8)); - EXPECT_EQ("\1\2\3\4\5\6\7\10", std::string(buf)); - EXPECT_EQ(9, SafeSNPrintf(buf, 11, "%c%c%c%c%c%c%c%c%c", - 1, 2, 3, 4, 5, 6, 7, 8, 9)); - EXPECT_EQ("\1\2\3\4\5\6\7\10\11", std::string(buf)); - EXPECT_EQ(10, SafeSNPrintf(buf, 11, "%c%c%c%c%c%c%c%c%c%c", - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); - EXPECT_EQ("\1\2\3\4\5\6\7\10\11\12", std::string(buf)); - - EXPECT_EQ(11, SafeSPrintf(buf, "%c%c%c%c%c%c%c%c%c%c%c", - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)); - EXPECT_EQ("\1\2\3\4\5\6\7\10\11\12\13", std::string(buf)); - EXPECT_EQ(11, SafeSNPrintf(buf, 12, "%c%c%c%c%c%c%c%c%c%c%c", - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)); - EXPECT_EQ("\1\2\3\4\5\6\7\10\11\12\13", std::string(buf)); -} - -TEST(SafeSPrintfTest, DataTypes) { - char buf[40]; - - // Bytes - EXPECT_EQ(1, SafeSPrintf(buf, "%d", (uint8_t)1)); - EXPECT_EQ("1", std::string(buf)); - EXPECT_EQ(3, SafeSPrintf(buf, "%d", (uint8_t)-1)); - EXPECT_EQ("255", std::string(buf)); - EXPECT_EQ(1, SafeSPrintf(buf, "%d", (int8_t)1)); - EXPECT_EQ("1", std::string(buf)); - EXPECT_EQ(2, SafeSPrintf(buf, "%d", (int8_t)-1)); - EXPECT_EQ("-1", std::string(buf)); - EXPECT_EQ(4, SafeSPrintf(buf, "%d", (int8_t)-128)); - EXPECT_EQ("-128", std::string(buf)); - - // Half-words - EXPECT_EQ(1, SafeSPrintf(buf, "%d", (uint16_t)1)); - EXPECT_EQ("1", std::string(buf)); - EXPECT_EQ(5, SafeSPrintf(buf, "%d", (uint16_t)-1)); - EXPECT_EQ("65535", std::string(buf)); - EXPECT_EQ(1, SafeSPrintf(buf, "%d", (int16_t)1)); - EXPECT_EQ("1", std::string(buf)); - EXPECT_EQ(2, SafeSPrintf(buf, "%d", (int16_t)-1)); - EXPECT_EQ("-1", std::string(buf)); - EXPECT_EQ(6, SafeSPrintf(buf, "%d", (int16_t)-32768)); - EXPECT_EQ("-32768", std::string(buf)); - - // Words - EXPECT_EQ(1, SafeSPrintf(buf, "%d", (uint32_t)1)); - EXPECT_EQ("1", std::string(buf)); - EXPECT_EQ(10, SafeSPrintf(buf, "%d", (uint32_t)-1)); - EXPECT_EQ("4294967295", std::string(buf)); - EXPECT_EQ(1, SafeSPrintf(buf, "%d", (int32_t)1)); - EXPECT_EQ("1", std::string(buf)); - EXPECT_EQ(2, SafeSPrintf(buf, "%d", (int32_t)-1)); - EXPECT_EQ("-1", std::string(buf)); - // Work-around for an limitation of C90 - EXPECT_EQ(11, SafeSPrintf(buf, "%d", (int32_t)-2147483647-1)); - EXPECT_EQ("-2147483648", std::string(buf)); - - // Quads - EXPECT_EQ(1, SafeSPrintf(buf, "%d", (uint64_t)1)); - EXPECT_EQ("1", std::string(buf)); - EXPECT_EQ(20, SafeSPrintf(buf, "%d", (uint64_t)-1)); - EXPECT_EQ("18446744073709551615", std::string(buf)); - EXPECT_EQ(1, SafeSPrintf(buf, "%d", (int64_t)1)); - EXPECT_EQ("1", std::string(buf)); - EXPECT_EQ(2, SafeSPrintf(buf, "%d", (int64_t)-1)); - EXPECT_EQ("-1", std::string(buf)); - // Work-around for an limitation of C90 - EXPECT_EQ(20, SafeSPrintf(buf, "%d", (int64_t)-9223372036854775807LL-1)); - EXPECT_EQ("-9223372036854775808", std::string(buf)); - - // Strings (both const and mutable). - EXPECT_EQ(4, SafeSPrintf(buf, "test")); - EXPECT_EQ("test", std::string(buf)); - EXPECT_EQ(4, SafeSPrintf(buf, buf)); - EXPECT_EQ("test", std::string(buf)); - - // Pointer - char addr[20]; - sprintf(addr, "0x%llX", (unsigned long long)(uintptr_t)buf); - SafeSPrintf(buf, "%p", buf); - EXPECT_EQ(std::string(addr), std::string(buf)); - SafeSPrintf(buf, "%p", (const char *)buf); - EXPECT_EQ(std::string(addr), std::string(buf)); - sprintf(addr, "0x%llX", (unsigned long long)(uintptr_t)sprintf); - SafeSPrintf(buf, "%p", sprintf); - EXPECT_EQ(std::string(addr), std::string(buf)); - - // Padding for pointers is a little more complicated because of the "0x" - // prefix. Padding with '0' zeros is relatively straight-forward, but - // padding with ' ' spaces requires more effort. - sprintf(addr, "0x%017llX", (unsigned long long)(uintptr_t)buf); - SafeSPrintf(buf, "%019p", buf); - EXPECT_EQ(std::string(addr), std::string(buf)); - sprintf(addr, "0x%llX", (unsigned long long)(uintptr_t)buf); - memset(addr, ' ', - (char*)memmove(addr + sizeof(addr) - strlen(addr) - 1, - addr, strlen(addr)+1) - addr); - SafeSPrintf(buf, "%19p", buf); - EXPECT_EQ(std::string(addr), std::string(buf)); -} - -namespace { -void PrintLongString(char* buf, size_t sz) { - // Output a reasonably complex expression into a limited-size buffer. - // At least one byte is available for writing the NUL character. - CHECK_GT(sz, static_cast<size_t>(0)); - - // Allocate slightly more space, so that we can verify that SafeSPrintf() - // never writes past the end of the buffer. - std::unique_ptr<char[]> tmp(new char[sz + 2]); - memset(tmp.get(), 'X', sz+2); - - // Use SafeSPrintf() to output a complex list of arguments: - // - test padding and truncating %c single characters. - // - test truncating %s simple strings. - // - test mismatching arguments and truncating (for %d != %s). - // - test zero-padding and truncating %x hexadecimal numbers. - // - test outputting and truncating %d MININT. - // - test outputting and truncating %p arbitrary pointer values. - // - test outputting, padding and truncating NULL-pointer %s strings. - char* out = tmp.get(); - size_t out_sz = sz; - size_t len; - for (std::unique_ptr<char[]> perfect_buf;;) { - size_t needed = - SafeSNPrintf(out, out_sz, -#if defined(NDEBUG) - "A%2cong %s: %d %010X %d %p%7s", 'l', "string", "", -#else - "A%2cong %s: %%d %010X %d %p%7s", 'l', "string", -#endif - 0xDEADBEEF, std::numeric_limits<intptr_t>::min(), - PrintLongString, static_cast<char*>(nullptr)) + - 1; - - // Various sanity checks: - // The numbered of characters needed to print the full string should always - // be bigger or equal to the bytes that have actually been output. - len = strlen(tmp.get()); - CHECK_GE(needed, len+1); - - // The number of characters output should always fit into the buffer that - // was passed into SafeSPrintf(). - CHECK_LT(len, out_sz); - - // The output is always terminated with a NUL byte (actually, this test is - // always going to pass, as strlen() already verified this) - EXPECT_FALSE(tmp[len]); - - // ASAN can check that we are not overwriting buffers, iff we make sure the - // buffer is exactly the size that we are expecting to be written. After - // running SafeSNPrintf() the first time, it is possible to compute the - // correct buffer size for this test. So, allocate a second buffer and run - // the exact same SafeSNPrintf() command again. - if (!perfect_buf.get()) { - out_sz = std::min(needed, sz); - out = new char[out_sz]; - perfect_buf.reset(out); - } else { - break; - } - } - - // All trailing bytes are unchanged. - for (size_t i = len+1; i < sz+2; ++i) - EXPECT_EQ('X', tmp[i]); - - // The text that was generated by SafeSPrintf() should always match the - // equivalent text generated by sprintf(). Please note that the format - // string for sprintf() is not complicated, as it does not have the - // benefit of getting type information from the C++ compiler. - // - // N.B.: It would be so much cleaner to use snprintf(). But unfortunately, - // Visual Studio doesn't support this function, and the work-arounds - // are all really awkward. - char ref[256]; - CHECK_LE(sz, sizeof(ref)); - sprintf(ref, "A long string: %%d 00DEADBEEF %lld 0x%llX <NULL>", - static_cast<long long>(std::numeric_limits<intptr_t>::min()), - static_cast<unsigned long long>( - reinterpret_cast<uintptr_t>(PrintLongString))); - ref[sz-1] = '\000'; - -#if defined(NDEBUG) - const size_t kSSizeMax = std::numeric_limits<ssize_t>::max(); -#else - const size_t kSSizeMax = internal::GetSafeSPrintfSSizeMaxForTest(); -#endif - - // Compare the output from SafeSPrintf() to the one from sprintf(). - EXPECT_EQ(std::string(ref).substr(0, kSSizeMax-1), std::string(tmp.get())); - - // We allocated a slightly larger buffer, so that we could perform some - // extra sanity checks. Now that the tests have all passed, we copy the - // data to the output buffer that the caller provided. - memcpy(buf, tmp.get(), len+1); -} - -#if !defined(NDEBUG) -class ScopedSafeSPrintfSSizeMaxSetter { - public: - ScopedSafeSPrintfSSizeMaxSetter(size_t sz) { - old_ssize_max_ = internal::GetSafeSPrintfSSizeMaxForTest(); - internal::SetSafeSPrintfSSizeMaxForTest(sz); - } - - ~ScopedSafeSPrintfSSizeMaxSetter() { - internal::SetSafeSPrintfSSizeMaxForTest(old_ssize_max_); - } - - private: - size_t old_ssize_max_; - - DISALLOW_COPY_AND_ASSIGN(ScopedSafeSPrintfSSizeMaxSetter); -}; -#endif - -} // anonymous namespace - -TEST(SafeSPrintfTest, Truncation) { - // We use PrintLongString() to print a complex long string and then - // truncate to all possible lengths. This ends up exercising a lot of - // different code paths in SafeSPrintf() and IToASCII(), as truncation can - // happen in a lot of different states. - char ref[256]; - PrintLongString(ref, sizeof(ref)); - for (size_t i = strlen(ref)+1; i; --i) { - char buf[sizeof(ref)]; - PrintLongString(buf, i); - EXPECT_EQ(std::string(ref, i - 1), std::string(buf)); - } - - // When compiling in debug mode, we have the ability to fake a small - // upper limit for the maximum value that can be stored in an ssize_t. - // SafeSPrintf() uses this upper limit to determine how many bytes it will - // write to the buffer, even if the caller claimed a bigger buffer size. - // Repeat the truncation test and verify that this other code path in - // SafeSPrintf() works correctly, too. -#if !defined(NDEBUG) - for (size_t i = strlen(ref)+1; i > 1; --i) { - ScopedSafeSPrintfSSizeMaxSetter ssize_max_setter(i); - char buf[sizeof(ref)]; - PrintLongString(buf, sizeof(buf)); - EXPECT_EQ(std::string(ref, i - 1), std::string(buf)); - } - - // kSSizeMax is also used to constrain the maximum amount of padding, before - // SafeSPrintf() detects an error in the format string. - ScopedSafeSPrintfSSizeMaxSetter ssize_max_setter(100); - char buf[256]; - EXPECT_EQ(99, SafeSPrintf(buf, "%99c", ' ')); - EXPECT_EQ(std::string(99, ' '), std::string(buf)); - *buf = '\000'; -#if defined(ALLOW_DEATH_TEST) - EXPECT_DEATH(SafeSPrintf(buf, "%100c", ' '), "padding <= max_padding"); -#endif - EXPECT_EQ(0, *buf); -#endif -} - -TEST(SafeSPrintfTest, Padding) { - char buf[40], fmt[40]; - - // Chars %c - EXPECT_EQ(1, SafeSPrintf(buf, "%c", 'A')); - EXPECT_EQ("A", std::string(buf)); - EXPECT_EQ(2, SafeSPrintf(buf, "%2c", 'A')); - EXPECT_EQ(" A", std::string(buf)); - EXPECT_EQ(2, SafeSPrintf(buf, "%02c", 'A')); - EXPECT_EQ(" A", std::string(buf)); - EXPECT_EQ(4, SafeSPrintf(buf, "%-2c", 'A')); - EXPECT_EQ("%-2c", std::string(buf)); - SafeSPrintf(fmt, "%%%dc", std::numeric_limits<ssize_t>::max() - 1); - EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1, SafeSPrintf(buf, fmt, 'A')); - SafeSPrintf(fmt, "%%%dc", - static_cast<size_t>(std::numeric_limits<ssize_t>::max())); -#if defined(NDEBUG) - EXPECT_EQ(2, SafeSPrintf(buf, fmt, 'A')); - EXPECT_EQ("%c", std::string(buf)); -#elif defined(ALLOW_DEATH_TEST) - EXPECT_DEATH(SafeSPrintf(buf, fmt, 'A'), "padding <= max_padding"); -#endif - - // Octal %o - EXPECT_EQ(1, SafeSPrintf(buf, "%o", 1)); - EXPECT_EQ("1", std::string(buf)); - EXPECT_EQ(2, SafeSPrintf(buf, "%2o", 1)); - EXPECT_EQ(" 1", std::string(buf)); - EXPECT_EQ(2, SafeSPrintf(buf, "%02o", 1)); - EXPECT_EQ("01", std::string(buf)); - EXPECT_EQ(12, SafeSPrintf(buf, "%12o", -1)); - EXPECT_EQ(" 37777777777", std::string(buf)); - EXPECT_EQ(12, SafeSPrintf(buf, "%012o", -1)); - EXPECT_EQ("037777777777", std::string(buf)); - EXPECT_EQ(23, SafeSPrintf(buf, "%23o", -1LL)); - EXPECT_EQ(" 1777777777777777777777", std::string(buf)); - EXPECT_EQ(23, SafeSPrintf(buf, "%023o", -1LL)); - EXPECT_EQ("01777777777777777777777", std::string(buf)); - EXPECT_EQ(3, SafeSPrintf(buf, "%2o", 0111)); - EXPECT_EQ("111", std::string(buf)); - EXPECT_EQ(4, SafeSPrintf(buf, "%-2o", 1)); - EXPECT_EQ("%-2o", std::string(buf)); - SafeSPrintf(fmt, "%%%do", std::numeric_limits<ssize_t>::max()-1); - EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1, - SafeSNPrintf(buf, 4, fmt, 1)); - EXPECT_EQ(" ", std::string(buf)); - SafeSPrintf(fmt, "%%0%do", std::numeric_limits<ssize_t>::max()-1); - EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1, - SafeSNPrintf(buf, 4, fmt, 1)); - EXPECT_EQ("000", std::string(buf)); - SafeSPrintf(fmt, "%%%do", - static_cast<size_t>(std::numeric_limits<ssize_t>::max())); -#if defined(NDEBUG) - EXPECT_EQ(2, SafeSPrintf(buf, fmt, 1)); - EXPECT_EQ("%o", std::string(buf)); -#elif defined(ALLOW_DEATH_TEST) - EXPECT_DEATH(SafeSPrintf(buf, fmt, 1), "padding <= max_padding"); -#endif - - // Decimals %d - EXPECT_EQ(1, SafeSPrintf(buf, "%d", 1)); - EXPECT_EQ("1", std::string(buf)); - EXPECT_EQ(2, SafeSPrintf(buf, "%2d", 1)); - EXPECT_EQ(" 1", std::string(buf)); - EXPECT_EQ(2, SafeSPrintf(buf, "%02d", 1)); - EXPECT_EQ("01", std::string(buf)); - EXPECT_EQ(3, SafeSPrintf(buf, "%3d", -1)); - EXPECT_EQ(" -1", std::string(buf)); - EXPECT_EQ(3, SafeSPrintf(buf, "%03d", -1)); - EXPECT_EQ("-01", std::string(buf)); - EXPECT_EQ(3, SafeSPrintf(buf, "%2d", 111)); - EXPECT_EQ("111", std::string(buf)); - EXPECT_EQ(4, SafeSPrintf(buf, "%2d", -111)); - EXPECT_EQ("-111", std::string(buf)); - EXPECT_EQ(4, SafeSPrintf(buf, "%-2d", 1)); - EXPECT_EQ("%-2d", std::string(buf)); - SafeSPrintf(fmt, "%%%dd", std::numeric_limits<ssize_t>::max()-1); - EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1, - SafeSNPrintf(buf, 4, fmt, 1)); - EXPECT_EQ(" ", std::string(buf)); - SafeSPrintf(fmt, "%%0%dd", std::numeric_limits<ssize_t>::max()-1); - EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1, - SafeSNPrintf(buf, 4, fmt, 1)); - EXPECT_EQ("000", std::string(buf)); - SafeSPrintf(fmt, "%%%dd", - static_cast<size_t>(std::numeric_limits<ssize_t>::max())); -#if defined(NDEBUG) - EXPECT_EQ(2, SafeSPrintf(buf, fmt, 1)); - EXPECT_EQ("%d", std::string(buf)); -#elif defined(ALLOW_DEATH_TEST) - EXPECT_DEATH(SafeSPrintf(buf, fmt, 1), "padding <= max_padding"); -#endif - - // Hex %X - EXPECT_EQ(1, SafeSPrintf(buf, "%X", 1)); - EXPECT_EQ("1", std::string(buf)); - EXPECT_EQ(2, SafeSPrintf(buf, "%2X", 1)); - EXPECT_EQ(" 1", std::string(buf)); - EXPECT_EQ(2, SafeSPrintf(buf, "%02X", 1)); - EXPECT_EQ("01", std::string(buf)); - EXPECT_EQ(9, SafeSPrintf(buf, "%9X", -1)); - EXPECT_EQ(" FFFFFFFF", std::string(buf)); - EXPECT_EQ(9, SafeSPrintf(buf, "%09X", -1)); - EXPECT_EQ("0FFFFFFFF", std::string(buf)); - EXPECT_EQ(17, SafeSPrintf(buf, "%17X", -1LL)); - EXPECT_EQ(" FFFFFFFFFFFFFFFF", std::string(buf)); - EXPECT_EQ(17, SafeSPrintf(buf, "%017X", -1LL)); - EXPECT_EQ("0FFFFFFFFFFFFFFFF", std::string(buf)); - EXPECT_EQ(3, SafeSPrintf(buf, "%2X", 0x111)); - EXPECT_EQ("111", std::string(buf)); - EXPECT_EQ(4, SafeSPrintf(buf, "%-2X", 1)); - EXPECT_EQ("%-2X", std::string(buf)); - SafeSPrintf(fmt, "%%%dX", std::numeric_limits<ssize_t>::max()-1); - EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1, - SafeSNPrintf(buf, 4, fmt, 1)); - EXPECT_EQ(" ", std::string(buf)); - SafeSPrintf(fmt, "%%0%dX", std::numeric_limits<ssize_t>::max()-1); - EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1, - SafeSNPrintf(buf, 4, fmt, 1)); - EXPECT_EQ("000", std::string(buf)); - SafeSPrintf(fmt, "%%%dX", - static_cast<size_t>(std::numeric_limits<ssize_t>::max())); -#if defined(NDEBUG) - EXPECT_EQ(2, SafeSPrintf(buf, fmt, 1)); - EXPECT_EQ("%X", std::string(buf)); -#elif defined(ALLOW_DEATH_TEST) - EXPECT_DEATH(SafeSPrintf(buf, fmt, 1), "padding <= max_padding"); -#endif - - // Pointer %p - EXPECT_EQ(3, SafeSPrintf(buf, "%p", (void*)1)); - EXPECT_EQ("0x1", std::string(buf)); - EXPECT_EQ(4, SafeSPrintf(buf, "%4p", (void*)1)); - EXPECT_EQ(" 0x1", std::string(buf)); - EXPECT_EQ(4, SafeSPrintf(buf, "%04p", (void*)1)); - EXPECT_EQ("0x01", std::string(buf)); - EXPECT_EQ(5, SafeSPrintf(buf, "%4p", (void*)0x111)); - EXPECT_EQ("0x111", std::string(buf)); - EXPECT_EQ(4, SafeSPrintf(buf, "%-2p", (void*)1)); - EXPECT_EQ("%-2p", std::string(buf)); - SafeSPrintf(fmt, "%%%dp", std::numeric_limits<ssize_t>::max()-1); - EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1, - SafeSNPrintf(buf, 4, fmt, (void*)1)); - EXPECT_EQ(" ", std::string(buf)); - SafeSPrintf(fmt, "%%0%dp", std::numeric_limits<ssize_t>::max()-1); - EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1, - SafeSNPrintf(buf, 4, fmt, (void*)1)); - EXPECT_EQ("0x0", std::string(buf)); - SafeSPrintf(fmt, "%%%dp", - static_cast<size_t>(std::numeric_limits<ssize_t>::max())); -#if defined(NDEBUG) - EXPECT_EQ(2, SafeSPrintf(buf, fmt, 1)); - EXPECT_EQ("%p", std::string(buf)); -#elif defined(ALLOW_DEATH_TEST) - EXPECT_DEATH(SafeSPrintf(buf, fmt, 1), "padding <= max_padding"); -#endif - - // String - EXPECT_EQ(1, SafeSPrintf(buf, "%s", "A")); - EXPECT_EQ("A", std::string(buf)); - EXPECT_EQ(2, SafeSPrintf(buf, "%2s", "A")); - EXPECT_EQ(" A", std::string(buf)); - EXPECT_EQ(2, SafeSPrintf(buf, "%02s", "A")); - EXPECT_EQ(" A", std::string(buf)); - EXPECT_EQ(3, SafeSPrintf(buf, "%2s", "AAA")); - EXPECT_EQ("AAA", std::string(buf)); - EXPECT_EQ(4, SafeSPrintf(buf, "%-2s", "A")); - EXPECT_EQ("%-2s", std::string(buf)); - SafeSPrintf(fmt, "%%%ds", std::numeric_limits<ssize_t>::max()-1); - EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1, - SafeSNPrintf(buf, 4, fmt, "A")); - EXPECT_EQ(" ", std::string(buf)); - SafeSPrintf(fmt, "%%0%ds", std::numeric_limits<ssize_t>::max()-1); - EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1, - SafeSNPrintf(buf, 4, fmt, "A")); - EXPECT_EQ(" ", std::string(buf)); - SafeSPrintf(fmt, "%%%ds", - static_cast<size_t>(std::numeric_limits<ssize_t>::max())); -#if defined(NDEBUG) - EXPECT_EQ(2, SafeSPrintf(buf, fmt, "A")); - EXPECT_EQ("%s", std::string(buf)); -#elif defined(ALLOW_DEATH_TEST) - EXPECT_DEATH(SafeSPrintf(buf, fmt, "A"), "padding <= max_padding"); -#endif -} - -TEST(SafeSPrintfTest, EmbeddedNul) { - char buf[] = { 'X', 'X', 'X', 'X' }; - EXPECT_EQ(2, SafeSPrintf(buf, "%3c", 0)); - EXPECT_EQ(' ', buf[0]); - EXPECT_EQ(' ', buf[1]); - EXPECT_EQ(0, buf[2]); - EXPECT_EQ('X', buf[3]); - - // Check handling of a NUL format character. N.B. this takes two different - // code paths depending on whether we are actually passing arguments. If - // we don't have any arguments, we are running in the fast-path code, that - // looks (almost) like a strncpy(). -#if defined(NDEBUG) - EXPECT_EQ(2, SafeSPrintf(buf, "%%%")); - EXPECT_EQ("%%", std::string(buf)); - EXPECT_EQ(2, SafeSPrintf(buf, "%%%", 0)); - EXPECT_EQ("%%", std::string(buf)); -#elif defined(ALLOW_DEATH_TEST) - EXPECT_DEATH(SafeSPrintf(buf, "%%%"), "src.1. == '%'"); - EXPECT_DEATH(SafeSPrintf(buf, "%%%", 0), "ch"); -#endif -} - -TEST(SafeSPrintfTest, EmitNULL) { - char buf[40]; -#if defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wconversion-null" -#endif - EXPECT_EQ(1, SafeSPrintf(buf, "%d", NULL)); - EXPECT_EQ("0", std::string(buf)); - EXPECT_EQ(3, SafeSPrintf(buf, "%p", NULL)); - EXPECT_EQ("0x0", std::string(buf)); - EXPECT_EQ(6, SafeSPrintf(buf, "%s", NULL)); - EXPECT_EQ("<NULL>", std::string(buf)); -#if defined(__GCC__) -#pragma GCC diagnostic pop -#endif -} - -TEST(SafeSPrintfTest, PointerSize) { - // The internal data representation is a 64bit value, independent of the - // native word size. We want to perform sign-extension for signed integers, - // but we want to avoid doing so for pointer types. This could be a - // problem on systems, where pointers are only 32bit. This tests verifies - // that there is no such problem. - char *str = reinterpret_cast<char *>(0x80000000u); - void *ptr = str; - char buf[40]; - EXPECT_EQ(10, SafeSPrintf(buf, "%p", str)); - EXPECT_EQ("0x80000000", std::string(buf)); - EXPECT_EQ(10, SafeSPrintf(buf, "%p", ptr)); - EXPECT_EQ("0x80000000", std::string(buf)); -} - -} // namespace strings -} // namespace base
diff --git a/base/strings/strcat_unittest.cc b/base/strings/strcat_unittest.cc deleted file mode 100644 index cf2db51..0000000 --- a/base/strings/strcat_unittest.cc +++ /dev/null
@@ -1,67 +0,0 @@ -// 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/strings/strcat.h" -#include "base/strings/utf_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(StrCat, 8Bit) { - EXPECT_EQ("", StrCat({""})); - EXPECT_EQ("1", StrCat({"1"})); - EXPECT_EQ("122", StrCat({"1", "22"})); - EXPECT_EQ("122333", StrCat({"1", "22", "333"})); - EXPECT_EQ("1223334444", StrCat({"1", "22", "333", "4444"})); - EXPECT_EQ("122333444455555", StrCat({"1", "22", "333", "4444", "55555"})); -} - -TEST(StrCat, 16Bit) { - string16 arg1 = ASCIIToUTF16("1"); - string16 arg2 = ASCIIToUTF16("22"); - string16 arg3 = ASCIIToUTF16("333"); - - EXPECT_EQ(ASCIIToUTF16(""), StrCat({string16()})); - EXPECT_EQ(ASCIIToUTF16("1"), StrCat({arg1})); - EXPECT_EQ(ASCIIToUTF16("122"), StrCat({arg1, arg2})); - EXPECT_EQ(ASCIIToUTF16("122333"), StrCat({arg1, arg2, arg3})); -} - -TEST(StrAppend, 8Bit) { - std::string result; - - result = "foo"; - StrAppend(&result, {std::string()}); - EXPECT_EQ("foo", result); - - result = "foo"; - StrAppend(&result, {"1"}); - EXPECT_EQ("foo1", result); - - result = "foo"; - StrAppend(&result, {"1", "22", "333"}); - EXPECT_EQ("foo122333", result); -} - -TEST(StrAppend, 16Bit) { - string16 arg1 = ASCIIToUTF16("1"); - string16 arg2 = ASCIIToUTF16("22"); - string16 arg3 = ASCIIToUTF16("333"); - - string16 result; - - result = ASCIIToUTF16("foo"); - StrAppend(&result, {string16()}); - EXPECT_EQ(ASCIIToUTF16("foo"), result); - - result = ASCIIToUTF16("foo"); - StrAppend(&result, {arg1}); - EXPECT_EQ(ASCIIToUTF16("foo1"), result); - - result = ASCIIToUTF16("foo"); - StrAppend(&result, {arg1, arg2, arg3}); - EXPECT_EQ(ASCIIToUTF16("foo122333"), result); -} - -} // namespace base
diff --git a/base/strings/string16_unittest.cc b/base/strings/string16_unittest.cc deleted file mode 100644 index 0d2ca80..0000000 --- a/base/strings/string16_unittest.cc +++ /dev/null
@@ -1,66 +0,0 @@ -// 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 <sstream> -#include <unordered_set> - -#include "base/strings/string16.h" - -#include "base/strings/utf_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -// We define a custom operator<< for string16 so we can use it with logging. -// This tests that conversion. -TEST(String16Test, OutputStream) { - // Basic stream test. - { - std::ostringstream stream; - stream << "Empty '" << string16() << "' standard '" - << string16(ASCIIToUTF16("Hello, world")) << "'"; - EXPECT_STREQ("Empty '' standard 'Hello, world'", - stream.str().c_str()); - } - - // Interesting edge cases. - { - // These should each get converted to the invalid character: EF BF BD. - string16 initial_surrogate; - initial_surrogate.push_back(0xd800); - string16 final_surrogate; - final_surrogate.push_back(0xdc00); - - // Old italic A = U+10300, will get converted to: F0 90 8C 80 'z'. - string16 surrogate_pair; - surrogate_pair.push_back(0xd800); - surrogate_pair.push_back(0xdf00); - surrogate_pair.push_back('z'); - - // Will get converted to the invalid char + 's': EF BF BD 's'. - string16 unterminated_surrogate; - unterminated_surrogate.push_back(0xd800); - unterminated_surrogate.push_back('s'); - - std::ostringstream stream; - stream << initial_surrogate << "," << final_surrogate << "," - << surrogate_pair << "," << unterminated_surrogate; - - EXPECT_STREQ("\xef\xbf\xbd,\xef\xbf\xbd,\xf0\x90\x8c\x80z,\xef\xbf\xbds", - stream.str().c_str()); - } -} - -TEST(String16Test, Hash) { - string16 str1 = ASCIIToUTF16("hello"); - string16 str2 = ASCIIToUTF16("world"); - - std::unordered_set<string16> set; - - set.insert(str1); - EXPECT_EQ(1u, set.count(str1)); - EXPECT_EQ(0u, set.count(str2)); -} - -} // namespace base
diff --git a/base/strings/string16_unittest.nc b/base/strings/string16_unittest.nc deleted file mode 100644 index 5186a45..0000000 --- a/base/strings/string16_unittest.nc +++ /dev/null
@@ -1,25 +0,0 @@ -// 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. - -// This is a "No Compile Test". -// http://dev.chromium.org/developers/testing/no-compile-tests - -#include "base/strings/string16.h" - -#if defined(NCTEST_NO_KOENIG_LOOKUP_FOR_STRING16) // [r"use of undeclared identifier 'ShouldNotBeFound'"] - -// base::string16 is declared as a typedef. It should not cause other functions -// in base to be found via Argument-dependent lookup. - -namespace base { -void ShouldNotBeFound(const base::string16& arg) {} -} - -// Intentionally not in base:: namespace. -void WontCompile() { - base::string16 s; - ShouldNotBeFound(s); -} - -#endif
diff --git a/base/strings/string_number_conversions_unittest.cc b/base/strings/string_number_conversions_unittest.cc deleted file mode 100644 index d969450..0000000 --- a/base/strings/string_number_conversions_unittest.cc +++ /dev/null
@@ -1,905 +0,0 @@ -// 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/strings/string_number_conversions.h" - -#include <errno.h> -#include <limits.h> -#include <stddef.h> -#include <stdint.h> -#include <stdio.h> - -#include <cmath> -#include <limits> - -#include "base/bit_cast.h" -#include "base/format_macros.h" -#include "base/macros.h" -#include "base/strings/stringprintf.h" -#include "base/strings/utf_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -template <typename INT> -struct NumberToStringTest { - INT num; - const char* sexpected; - const char* uexpected; -}; - -} // namespace - -TEST(StringNumberConversionsTest, NumberToString) { - static const NumberToStringTest<int> int_tests[] = { - {0, "0", "0"}, - {-1, "-1", "4294967295"}, - {std::numeric_limits<int>::max(), "2147483647", "2147483647"}, - {std::numeric_limits<int>::min(), "-2147483648", "2147483648"}, - }; - static const NumberToStringTest<int64_t> int64_tests[] = { - {0, "0", "0"}, - {-1, "-1", "18446744073709551615"}, - { - std::numeric_limits<int64_t>::max(), "9223372036854775807", - "9223372036854775807", - }, - {std::numeric_limits<int64_t>::min(), "-9223372036854775808", - "9223372036854775808"}, - }; - - for (size_t i = 0; i < arraysize(int_tests); ++i) { - const NumberToStringTest<int>& test = int_tests[i]; - EXPECT_EQ(NumberToString(test.num), test.sexpected); - EXPECT_EQ(NumberToString16(test.num), UTF8ToUTF16(test.sexpected)); - EXPECT_EQ(NumberToString(static_cast<unsigned>(test.num)), test.uexpected); - EXPECT_EQ(NumberToString16(static_cast<unsigned>(test.num)), - UTF8ToUTF16(test.uexpected)); - } - for (size_t i = 0; i < arraysize(int64_tests); ++i) { - const NumberToStringTest<int64_t>& test = int64_tests[i]; - EXPECT_EQ(NumberToString(test.num), test.sexpected); - EXPECT_EQ(NumberToString16(test.num), UTF8ToUTF16(test.sexpected)); - EXPECT_EQ(NumberToString(static_cast<uint64_t>(test.num)), test.uexpected); - EXPECT_EQ(NumberToString16(static_cast<uint64_t>(test.num)), - UTF8ToUTF16(test.uexpected)); - } -} - -TEST(StringNumberConversionsTest, Uint64ToString) { - static const struct { - uint64_t input; - std::string output; - } cases[] = { - {0, "0"}, - {42, "42"}, - {INT_MAX, "2147483647"}, - {std::numeric_limits<uint64_t>::max(), "18446744073709551615"}, - }; - - for (size_t i = 0; i < arraysize(cases); ++i) - EXPECT_EQ(cases[i].output, NumberToString(cases[i].input)); -} - -TEST(StringNumberConversionsTest, SizeTToString) { - size_t size_t_max = std::numeric_limits<size_t>::max(); - std::string size_t_max_string = StringPrintf("%" PRIuS, size_t_max); - - static const struct { - size_t input; - std::string output; - } cases[] = { - {0, "0"}, - {9, "9"}, - {42, "42"}, - {INT_MAX, "2147483647"}, - {2147483648U, "2147483648"}, -#if SIZE_MAX > 4294967295U - {99999999999U, "99999999999"}, -#endif - {size_t_max, size_t_max_string}, - }; - - for (size_t i = 0; i < arraysize(cases); ++i) - EXPECT_EQ(cases[i].output, NumberToString(cases[i].input)); -} - -TEST(StringNumberConversionsTest, StringToInt) { - static const struct { - std::string input; - int output; - bool success; - } cases[] = { - {"0", 0, true}, - {"42", 42, true}, - {"42\x99", 42, false}, - {"\x99" "42\x99", 0, false}, - {"-2147483648", INT_MIN, true}, - {"2147483647", INT_MAX, true}, - {"", 0, false}, - {" 42", 42, false}, - {"42 ", 42, false}, - {"\t\n\v\f\r 42", 42, false}, - {"blah42", 0, false}, - {"42blah", 42, false}, - {"blah42blah", 0, false}, - {"-273.15", -273, false}, - {"+98.6", 98, false}, - {"--123", 0, false}, - {"++123", 0, false}, - {"-+123", 0, false}, - {"+-123", 0, false}, - {"-", 0, false}, - {"-2147483649", INT_MIN, false}, - {"-99999999999", INT_MIN, false}, - {"2147483648", INT_MAX, false}, - {"99999999999", INT_MAX, false}, - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - int output = cases[i].output ^ 1; // Ensure StringToInt wrote something. - EXPECT_EQ(cases[i].success, StringToInt(cases[i].input, &output)); - EXPECT_EQ(cases[i].output, output); - - string16 utf16_input = UTF8ToUTF16(cases[i].input); - output = cases[i].output ^ 1; // Ensure StringToInt wrote something. - EXPECT_EQ(cases[i].success, StringToInt(utf16_input, &output)); - EXPECT_EQ(cases[i].output, output); - } - - // One additional test to verify that conversion of numbers in strings with - // embedded NUL characters. The NUL and extra data after it should be - // interpreted as junk after the number. - const char input[] = "6\06"; - std::string input_string(input, arraysize(input) - 1); - int output; - EXPECT_FALSE(StringToInt(input_string, &output)); - EXPECT_EQ(6, output); - - string16 utf16_input = UTF8ToUTF16(input_string); - output = 0; - EXPECT_FALSE(StringToInt(utf16_input, &output)); - EXPECT_EQ(6, output); - - output = 0; - const char16 negative_wide_input[] = { 0xFF4D, '4', '2', 0}; - EXPECT_FALSE(StringToInt(string16(negative_wide_input), &output)); - EXPECT_EQ(0, output); -} - -TEST(StringNumberConversionsTest, StringToUint) { - static const struct { - std::string input; - unsigned output; - bool success; - } cases[] = { - {"0", 0, true}, - {"42", 42, true}, - {"42\x99", 42, false}, - {"\x99" "42\x99", 0, false}, - {"-2147483648", 0, false}, - {"2147483647", INT_MAX, true}, - {"", 0, false}, - {" 42", 42, false}, - {"42 ", 42, false}, - {"\t\n\v\f\r 42", 42, false}, - {"blah42", 0, false}, - {"42blah", 42, false}, - {"blah42blah", 0, false}, - {"-273.15", 0, false}, - {"+98.6", 98, false}, - {"--123", 0, false}, - {"++123", 0, false}, - {"-+123", 0, false}, - {"+-123", 0, false}, - {"-", 0, false}, - {"-2147483649", 0, false}, - {"-99999999999", 0, false}, - {"4294967295", UINT_MAX, true}, - {"4294967296", UINT_MAX, false}, - {"99999999999", UINT_MAX, false}, - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - unsigned output = - cases[i].output ^ 1; // Ensure StringToUint wrote something. - EXPECT_EQ(cases[i].success, StringToUint(cases[i].input, &output)); - EXPECT_EQ(cases[i].output, output); - - string16 utf16_input = UTF8ToUTF16(cases[i].input); - output = cases[i].output ^ 1; // Ensure StringToUint wrote something. - EXPECT_EQ(cases[i].success, StringToUint(utf16_input, &output)); - EXPECT_EQ(cases[i].output, output); - } - - // One additional test to verify that conversion of numbers in strings with - // embedded NUL characters. The NUL and extra data after it should be - // interpreted as junk after the number. - const char input[] = "6\06"; - std::string input_string(input, arraysize(input) - 1); - unsigned output; - EXPECT_FALSE(StringToUint(input_string, &output)); - EXPECT_EQ(6U, output); - - string16 utf16_input = UTF8ToUTF16(input_string); - output = 0; - EXPECT_FALSE(StringToUint(utf16_input, &output)); - EXPECT_EQ(6U, output); - - output = 0; - const char16 negative_wide_input[] = { 0xFF4D, '4', '2', 0}; - EXPECT_FALSE(StringToUint(string16(negative_wide_input), &output)); - EXPECT_EQ(0U, output); -} - -TEST(StringNumberConversionsTest, StringToInt64) { - static const struct { - std::string input; - int64_t output; - bool success; - } cases[] = { - {"0", 0, true}, - {"42", 42, true}, - {"-2147483648", INT_MIN, true}, - {"2147483647", INT_MAX, true}, - {"-2147483649", INT64_C(-2147483649), true}, - {"-99999999999", INT64_C(-99999999999), true}, - {"2147483648", INT64_C(2147483648), true}, - {"99999999999", INT64_C(99999999999), true}, - {"9223372036854775807", std::numeric_limits<int64_t>::max(), true}, - {"-9223372036854775808", std::numeric_limits<int64_t>::min(), true}, - {"09", 9, true}, - {"-09", -9, true}, - {"", 0, false}, - {" 42", 42, false}, - {"42 ", 42, false}, - {"0x42", 0, false}, - {"\t\n\v\f\r 42", 42, false}, - {"blah42", 0, false}, - {"42blah", 42, false}, - {"blah42blah", 0, false}, - {"-273.15", -273, false}, - {"+98.6", 98, false}, - {"--123", 0, false}, - {"++123", 0, false}, - {"-+123", 0, false}, - {"+-123", 0, false}, - {"-", 0, false}, - {"-9223372036854775809", std::numeric_limits<int64_t>::min(), false}, - {"-99999999999999999999", std::numeric_limits<int64_t>::min(), false}, - {"9223372036854775808", std::numeric_limits<int64_t>::max(), false}, - {"99999999999999999999", std::numeric_limits<int64_t>::max(), false}, - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - int64_t output = 0; - EXPECT_EQ(cases[i].success, StringToInt64(cases[i].input, &output)); - EXPECT_EQ(cases[i].output, output); - - string16 utf16_input = UTF8ToUTF16(cases[i].input); - output = 0; - EXPECT_EQ(cases[i].success, StringToInt64(utf16_input, &output)); - EXPECT_EQ(cases[i].output, output); - } - - // One additional test to verify that conversion of numbers in strings with - // embedded NUL characters. The NUL and extra data after it should be - // interpreted as junk after the number. - const char input[] = "6\06"; - std::string input_string(input, arraysize(input) - 1); - int64_t output; - EXPECT_FALSE(StringToInt64(input_string, &output)); - EXPECT_EQ(6, output); - - string16 utf16_input = UTF8ToUTF16(input_string); - output = 0; - EXPECT_FALSE(StringToInt64(utf16_input, &output)); - EXPECT_EQ(6, output); -} - -TEST(StringNumberConversionsTest, StringToUint64) { - static const struct { - std::string input; - uint64_t output; - bool success; - } cases[] = { - {"0", 0, true}, - {"42", 42, true}, - {"-2147483648", 0, false}, - {"2147483647", INT_MAX, true}, - {"-2147483649", 0, false}, - {"-99999999999", 0, false}, - {"2147483648", UINT64_C(2147483648), true}, - {"99999999999", UINT64_C(99999999999), true}, - {"9223372036854775807", std::numeric_limits<int64_t>::max(), true}, - {"-9223372036854775808", 0, false}, - {"09", 9, true}, - {"-09", 0, false}, - {"", 0, false}, - {" 42", 42, false}, - {"42 ", 42, false}, - {"0x42", 0, false}, - {"\t\n\v\f\r 42", 42, false}, - {"blah42", 0, false}, - {"42blah", 42, false}, - {"blah42blah", 0, false}, - {"-273.15", 0, false}, - {"+98.6", 98, false}, - {"--123", 0, false}, - {"++123", 0, false}, - {"-+123", 0, false}, - {"+-123", 0, false}, - {"-", 0, false}, - {"-9223372036854775809", 0, false}, - {"-99999999999999999999", 0, false}, - {"9223372036854775808", UINT64_C(9223372036854775808), true}, - {"99999999999999999999", std::numeric_limits<uint64_t>::max(), false}, - {"18446744073709551615", std::numeric_limits<uint64_t>::max(), true}, - {"18446744073709551616", std::numeric_limits<uint64_t>::max(), false}, - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - uint64_t output = 0; - EXPECT_EQ(cases[i].success, StringToUint64(cases[i].input, &output)); - EXPECT_EQ(cases[i].output, output); - - string16 utf16_input = UTF8ToUTF16(cases[i].input); - output = 0; - EXPECT_EQ(cases[i].success, StringToUint64(utf16_input, &output)); - EXPECT_EQ(cases[i].output, output); - } - - // One additional test to verify that conversion of numbers in strings with - // embedded NUL characters. The NUL and extra data after it should be - // interpreted as junk after the number. - const char input[] = "6\06"; - std::string input_string(input, arraysize(input) - 1); - uint64_t output; - EXPECT_FALSE(StringToUint64(input_string, &output)); - EXPECT_EQ(6U, output); - - string16 utf16_input = UTF8ToUTF16(input_string); - output = 0; - EXPECT_FALSE(StringToUint64(utf16_input, &output)); - EXPECT_EQ(6U, output); -} - -TEST(StringNumberConversionsTest, StringToSizeT) { - size_t size_t_max = std::numeric_limits<size_t>::max(); - std::string size_t_max_string = StringPrintf("%" PRIuS, size_t_max); - - static const struct { - std::string input; - size_t output; - bool success; - } cases[] = { - {"0", 0, true}, - {"42", 42, true}, - {"-2147483648", 0, false}, - {"2147483647", INT_MAX, true}, - {"-2147483649", 0, false}, - {"-99999999999", 0, false}, - {"2147483648", 2147483648U, true}, -#if SIZE_MAX > 4294967295U - {"99999999999", 99999999999U, true}, -#endif - {"-9223372036854775808", 0, false}, - {"09", 9, true}, - {"-09", 0, false}, - {"", 0, false}, - {" 42", 42, false}, - {"42 ", 42, false}, - {"0x42", 0, false}, - {"\t\n\v\f\r 42", 42, false}, - {"blah42", 0, false}, - {"42blah", 42, false}, - {"blah42blah", 0, false}, - {"-273.15", 0, false}, - {"+98.6", 98, false}, - {"--123", 0, false}, - {"++123", 0, false}, - {"-+123", 0, false}, - {"+-123", 0, false}, - {"-", 0, false}, - {"-9223372036854775809", 0, false}, - {"-99999999999999999999", 0, false}, - {"999999999999999999999999", size_t_max, false}, - {size_t_max_string, size_t_max, true}, - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - size_t output = 0; - EXPECT_EQ(cases[i].success, StringToSizeT(cases[i].input, &output)); - EXPECT_EQ(cases[i].output, output); - - string16 utf16_input = UTF8ToUTF16(cases[i].input); - output = 0; - EXPECT_EQ(cases[i].success, StringToSizeT(utf16_input, &output)); - EXPECT_EQ(cases[i].output, output); - } - - // One additional test to verify that conversion of numbers in strings with - // embedded NUL characters. The NUL and extra data after it should be - // interpreted as junk after the number. - const char input[] = "6\06"; - std::string input_string(input, arraysize(input) - 1); - size_t output; - EXPECT_FALSE(StringToSizeT(input_string, &output)); - EXPECT_EQ(6U, output); - - string16 utf16_input = UTF8ToUTF16(input_string); - output = 0; - EXPECT_FALSE(StringToSizeT(utf16_input, &output)); - EXPECT_EQ(6U, output); -} - -TEST(StringNumberConversionsTest, HexStringToInt) { - static const struct { - std::string input; - int64_t output; - bool success; - } cases[] = { - {"0", 0, true}, - {"42", 66, true}, - {"-42", -66, true}, - {"+42", 66, true}, - {"7fffffff", INT_MAX, true}, - {"-80000000", INT_MIN, true}, - {"80000000", INT_MAX, false}, // Overflow test. - {"-80000001", INT_MIN, false}, // Underflow test. - {"0x42", 66, true}, - {"-0x42", -66, true}, - {"+0x42", 66, true}, - {"0x7fffffff", INT_MAX, true}, - {"-0x80000000", INT_MIN, true}, - {"-80000000", INT_MIN, true}, - {"80000000", INT_MAX, false}, // Overflow test. - {"-80000001", INT_MIN, false}, // Underflow test. - {"0x0f", 15, true}, - {"0f", 15, true}, - {" 45", 0x45, false}, - {"\t\n\v\f\r 0x45", 0x45, false}, - {" 45", 0x45, false}, - {"45 ", 0x45, false}, - {"45:", 0x45, false}, - {"efgh", 0xef, false}, - {"0xefgh", 0xef, false}, - {"hgfe", 0, false}, - {"-", 0, false}, - {"", 0, false}, - {"0x", 0, false}, - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - int output = 0; - EXPECT_EQ(cases[i].success, HexStringToInt(cases[i].input, &output)); - EXPECT_EQ(cases[i].output, output); - } - // One additional test to verify that conversion of numbers in strings with - // embedded NUL characters. The NUL and extra data after it should be - // interpreted as junk after the number. - const char input[] = "0xc0ffee\0" "9"; - std::string input_string(input, arraysize(input) - 1); - int output; - EXPECT_FALSE(HexStringToInt(input_string, &output)); - EXPECT_EQ(0xc0ffee, output); -} - -TEST(StringNumberConversionsTest, HexStringToUInt) { - static const struct { - std::string input; - uint32_t output; - bool success; - } cases[] = { - {"0", 0, true}, - {"42", 0x42, true}, - {"-42", 0, false}, - {"+42", 0x42, true}, - {"7fffffff", INT_MAX, true}, - {"-80000000", 0, false}, - {"ffffffff", 0xffffffff, true}, - {"DeadBeef", 0xdeadbeef, true}, - {"0x42", 0x42, true}, - {"-0x42", 0, false}, - {"+0x42", 0x42, true}, - {"0x7fffffff", INT_MAX, true}, - {"-0x80000000", 0, false}, - {"0xffffffff", std::numeric_limits<uint32_t>::max(), true}, - {"0XDeadBeef", 0xdeadbeef, true}, - {"0x7fffffffffffffff", std::numeric_limits<uint32_t>::max(), - false}, // Overflow test. - {"-0x8000000000000000", 0, false}, - {"0x8000000000000000", std::numeric_limits<uint32_t>::max(), - false}, // Overflow test. - {"-0x8000000000000001", 0, false}, - {"0xFFFFFFFFFFFFFFFF", std::numeric_limits<uint32_t>::max(), - false}, // Overflow test. - {"FFFFFFFFFFFFFFFF", std::numeric_limits<uint32_t>::max(), - false}, // Overflow test. - {"0x0000000000000000", 0, true}, - {"0000000000000000", 0, true}, - {"1FFFFFFFFFFFFFFFF", std::numeric_limits<uint32_t>::max(), - false}, // Overflow test. - {"0x0f", 0x0f, true}, - {"0f", 0x0f, true}, - {" 45", 0x45, false}, - {"\t\n\v\f\r 0x45", 0x45, false}, - {" 45", 0x45, false}, - {"45 ", 0x45, false}, - {"45:", 0x45, false}, - {"efgh", 0xef, false}, - {"0xefgh", 0xef, false}, - {"hgfe", 0, false}, - {"-", 0, false}, - {"", 0, false}, - {"0x", 0, false}, - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - uint32_t output = 0; - EXPECT_EQ(cases[i].success, HexStringToUInt(cases[i].input, &output)); - EXPECT_EQ(cases[i].output, output); - } - // One additional test to verify that conversion of numbers in strings with - // embedded NUL characters. The NUL and extra data after it should be - // interpreted as junk after the number. - const char input[] = "0xc0ffee\0" "9"; - std::string input_string(input, arraysize(input) - 1); - uint32_t output; - EXPECT_FALSE(HexStringToUInt(input_string, &output)); - EXPECT_EQ(0xc0ffeeU, output); -} - -TEST(StringNumberConversionsTest, HexStringToInt64) { - static const struct { - std::string input; - int64_t output; - bool success; - } cases[] = { - {"0", 0, true}, - {"42", 66, true}, - {"-42", -66, true}, - {"+42", 66, true}, - {"40acd88557b", INT64_C(4444444448123), true}, - {"7fffffff", INT_MAX, true}, - {"-80000000", INT_MIN, true}, - {"ffffffff", 0xffffffff, true}, - {"DeadBeef", 0xdeadbeef, true}, - {"0x42", 66, true}, - {"-0x42", -66, true}, - {"+0x42", 66, true}, - {"0x40acd88557b", INT64_C(4444444448123), true}, - {"0x7fffffff", INT_MAX, true}, - {"-0x80000000", INT_MIN, true}, - {"0xffffffff", 0xffffffff, true}, - {"0XDeadBeef", 0xdeadbeef, true}, - {"0x7fffffffffffffff", std::numeric_limits<int64_t>::max(), true}, - {"-0x8000000000000000", std::numeric_limits<int64_t>::min(), true}, - {"0x8000000000000000", std::numeric_limits<int64_t>::max(), - false}, // Overflow test. - {"-0x8000000000000001", std::numeric_limits<int64_t>::min(), - false}, // Underflow test. - {"0x0f", 15, true}, - {"0f", 15, true}, - {" 45", 0x45, false}, - {"\t\n\v\f\r 0x45", 0x45, false}, - {" 45", 0x45, false}, - {"45 ", 0x45, false}, - {"45:", 0x45, false}, - {"efgh", 0xef, false}, - {"0xefgh", 0xef, false}, - {"hgfe", 0, false}, - {"-", 0, false}, - {"", 0, false}, - {"0x", 0, false}, - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - int64_t output = 0; - EXPECT_EQ(cases[i].success, HexStringToInt64(cases[i].input, &output)); - EXPECT_EQ(cases[i].output, output); - } - // One additional test to verify that conversion of numbers in strings with - // embedded NUL characters. The NUL and extra data after it should be - // interpreted as junk after the number. - const char input[] = "0xc0ffee\0" "9"; - std::string input_string(input, arraysize(input) - 1); - int64_t output; - EXPECT_FALSE(HexStringToInt64(input_string, &output)); - EXPECT_EQ(0xc0ffee, output); -} - -TEST(StringNumberConversionsTest, HexStringToUInt64) { - static const struct { - std::string input; - uint64_t output; - bool success; - } cases[] = { - {"0", 0, true}, - {"42", 66, true}, - {"-42", 0, false}, - {"+42", 66, true}, - {"40acd88557b", INT64_C(4444444448123), true}, - {"7fffffff", INT_MAX, true}, - {"-80000000", 0, false}, - {"ffffffff", 0xffffffff, true}, - {"DeadBeef", 0xdeadbeef, true}, - {"0x42", 66, true}, - {"-0x42", 0, false}, - {"+0x42", 66, true}, - {"0x40acd88557b", INT64_C(4444444448123), true}, - {"0x7fffffff", INT_MAX, true}, - {"-0x80000000", 0, false}, - {"0xffffffff", 0xffffffff, true}, - {"0XDeadBeef", 0xdeadbeef, true}, - {"0x7fffffffffffffff", std::numeric_limits<int64_t>::max(), true}, - {"-0x8000000000000000", 0, false}, - {"0x8000000000000000", UINT64_C(0x8000000000000000), true}, - {"-0x8000000000000001", 0, false}, - {"0xFFFFFFFFFFFFFFFF", std::numeric_limits<uint64_t>::max(), true}, - {"FFFFFFFFFFFFFFFF", std::numeric_limits<uint64_t>::max(), true}, - {"0x0000000000000000", 0, true}, - {"0000000000000000", 0, true}, - {"1FFFFFFFFFFFFFFFF", std::numeric_limits<uint64_t>::max(), - false}, // Overflow test. - {"0x0f", 15, true}, - {"0f", 15, true}, - {" 45", 0x45, false}, - {"\t\n\v\f\r 0x45", 0x45, false}, - {" 45", 0x45, false}, - {"45 ", 0x45, false}, - {"45:", 0x45, false}, - {"efgh", 0xef, false}, - {"0xefgh", 0xef, false}, - {"hgfe", 0, false}, - {"-", 0, false}, - {"", 0, false}, - {"0x", 0, false}, - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - uint64_t output = 0; - EXPECT_EQ(cases[i].success, HexStringToUInt64(cases[i].input, &output)); - EXPECT_EQ(cases[i].output, output); - } - // One additional test to verify that conversion of numbers in strings with - // embedded NUL characters. The NUL and extra data after it should be - // interpreted as junk after the number. - const char input[] = "0xc0ffee\0" "9"; - std::string input_string(input, arraysize(input) - 1); - uint64_t output; - EXPECT_FALSE(HexStringToUInt64(input_string, &output)); - EXPECT_EQ(0xc0ffeeU, output); -} - -TEST(StringNumberConversionsTest, HexStringToBytes) { - static const struct { - const std::string input; - const char* output; - size_t output_len; - bool success; - } cases[] = { - {"0", "", 0, false}, // odd number of characters fails - {"00", "\0", 1, true}, - {"42", "\x42", 1, true}, - {"-42", "", 0, false}, // any non-hex value fails - {"+42", "", 0, false}, - {"7fffffff", "\x7f\xff\xff\xff", 4, true}, - {"80000000", "\x80\0\0\0", 4, true}, - {"deadbeef", "\xde\xad\xbe\xef", 4, true}, - {"DeadBeef", "\xde\xad\xbe\xef", 4, true}, - {"0x42", "", 0, false}, // leading 0x fails (x is not hex) - {"0f", "\xf", 1, true}, - {"45 ", "\x45", 1, false}, - {"efgh", "\xef", 1, false}, - {"", "", 0, false}, - {"0123456789ABCDEF", "\x01\x23\x45\x67\x89\xAB\xCD\xEF", 8, true}, - {"0123456789ABCDEF012345", - "\x01\x23\x45\x67\x89\xAB\xCD\xEF\x01\x23\x45", 11, true}, - }; - - - for (size_t i = 0; i < arraysize(cases); ++i) { - std::vector<uint8_t> output; - std::vector<uint8_t> compare; - EXPECT_EQ(cases[i].success, HexStringToBytes(cases[i].input, &output)) << - i << ": " << cases[i].input; - for (size_t j = 0; j < cases[i].output_len; ++j) - compare.push_back(static_cast<uint8_t>(cases[i].output[j])); - ASSERT_EQ(output.size(), compare.size()) << i << ": " << cases[i].input; - EXPECT_TRUE(std::equal(output.begin(), output.end(), compare.begin())) << - i << ": " << cases[i].input; - } -} - -TEST(StringNumberConversionsTest, StringToDouble) { - static const struct { - std::string input; - double output; - bool success; - } cases[] = { - // Test different forms of zero. - {"0", 0.0, true}, - {"+0", 0.0, true}, - {"-0", 0.0, true}, - {"0.0", 0.0, true}, - {"000000000000000000000000000000.0", 0.0, true}, - {"0.000000000000000000000000000", 0.0, true}, - - // Test the answer. - {"42", 42.0, true}, - {"-42", -42.0, true}, - - // Test variances of an ordinary number. - {"123.45", 123.45, true}, - {"-123.45", -123.45, true}, - {"+123.45", 123.45, true}, - - // Test different forms of representation. - {"2.99792458e8", 299792458.0, true}, - {"149597870.691E+3", 149597870691.0, true}, - {"6.", 6.0, true}, - - // Test around the largest/smallest value that a double can represent. - {"9e307", 9e307, true}, - {"1.7976e308", 1.7976e308, true}, - {"1.7977e308", HUGE_VAL, false}, - {"1.797693134862315807e+308", HUGE_VAL, true}, - {"1.797693134862315808e+308", HUGE_VAL, false}, - {"9e308", HUGE_VAL, false}, - {"9e309", HUGE_VAL, false}, - {"9e999", HUGE_VAL, false}, - {"9e1999", HUGE_VAL, false}, - {"9e19999", HUGE_VAL, false}, - {"9e99999999999999999999", HUGE_VAL, false}, - {"-9e307", -9e307, true}, - {"-1.7976e308", -1.7976e308, true}, - {"-1.7977e308", -HUGE_VAL, false}, - {"-1.797693134862315807e+308", -HUGE_VAL, true}, - {"-1.797693134862315808e+308", -HUGE_VAL, false}, - {"-9e308", -HUGE_VAL, false}, - {"-9e309", -HUGE_VAL, false}, - {"-9e999", -HUGE_VAL, false}, - {"-9e1999", -HUGE_VAL, false}, - {"-9e19999", -HUGE_VAL, false}, - {"-9e99999999999999999999", -HUGE_VAL, false}, - - // Test more exponents. - {"1e-2", 0.01, true}, - {"42 ", 42.0, false}, - {" 1e-2", 0.01, false}, - {"1e-2 ", 0.01, false}, - {"-1E-7", -0.0000001, true}, - {"01e02", 100, true}, - {"2.3e15", 2.3e15, true}, - {"100e-309", 100e-309, true}, - - // Test some invalid cases. - {"\t\n\v\f\r -123.45e2", -12345.0, false}, - {"+123 e4", 123.0, false}, - {"123e ", 123.0, false}, - {"123e", 123.0, false}, - {" 2.99", 2.99, false}, - {"1e3.4", 1000.0, false}, - {"nothing", 0.0, false}, - {"-", 0.0, false}, - {"+", 0.0, false}, - {"", 0.0, false}, - - // crbug.org/588726 - {"-0.0010000000000000000000000000000000000000001e-256", - -1.0000000000000001e-259, true}, - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - double output; - errno = 1; - EXPECT_EQ(cases[i].success, StringToDouble(cases[i].input, &output)); - if (cases[i].success) - EXPECT_EQ(1, errno) << i; // confirm that errno is unchanged. - EXPECT_DOUBLE_EQ(cases[i].output, output); - } - - // One additional test to verify that conversion of numbers in strings with - // embedded NUL characters. The NUL and extra data after it should be - // interpreted as junk after the number. - const char input[] = "3.14\0" "159"; - std::string input_string(input, arraysize(input) - 1); - double output; - EXPECT_FALSE(StringToDouble(input_string, &output)); - EXPECT_DOUBLE_EQ(3.14, output); -} - -TEST(StringNumberConversionsTest, DoubleToString) { - static const struct { - double input; - const char* expected; - } cases[] = { - {0.0, "0"}, - {1.25, "1.25"}, - {1.33518e+012, "1.33518e+12"}, - {1.33489e+012, "1.33489e+12"}, - {1.33505e+012, "1.33505e+12"}, - {1.33545e+009, "1335450000"}, - {1.33503e+009, "1335030000"}, - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - EXPECT_EQ(cases[i].expected, NumberToString(cases[i].input)); - EXPECT_EQ(cases[i].expected, UTF16ToUTF8(NumberToString16(cases[i].input))); - } - - // The following two values were seen in crashes in the wild. - const char input_bytes[8] = {0, 0, 0, 0, '\xee', '\x6d', '\x73', '\x42'}; - double input = 0; - memcpy(&input, input_bytes, arraysize(input_bytes)); - EXPECT_EQ("1335179083776", NumberToString(input)); - const char input_bytes2[8] = - {0, 0, 0, '\xa0', '\xda', '\x6c', '\x73', '\x42'}; - input = 0; - memcpy(&input, input_bytes2, arraysize(input_bytes2)); - EXPECT_EQ("1334890332160", NumberToString(input)); -} - -TEST(StringNumberConversionsTest, HexEncode) { - std::string hex(HexEncode(nullptr, 0)); - EXPECT_EQ(hex.length(), 0U); - unsigned char bytes[] = {0x01, 0xff, 0x02, 0xfe, 0x03, 0x80, 0x81}; - hex = HexEncode(bytes, sizeof(bytes)); - EXPECT_EQ(hex.compare("01FF02FE038081"), 0); -} - -// Test cases of known-bad strtod conversions that motivated the use of dmg_fp. -// See https://bugs.chromium.org/p/chromium/issues/detail?id=593512. -TEST(StringNumberConversionsTest, StrtodFailures) { - static const struct { - const char* input; - uint64_t expected; - } cases[] = { - // http://www.exploringbinary.com/incorrectly-rounded-conversions-in-visual-c-plus-plus/ - {"9214843084008499", 0x43405e6cec57761aULL}, - {"0.500000000000000166533453693773481063544750213623046875", - 0x3fe0000000000002ULL}, - {"30078505129381147446200", 0x44997a3c7271b021ULL}, - {"1777820000000000000001", 0x4458180d5bad2e3eULL}, - {"0.500000000000000166547006220929549868969843373633921146392822265625", - 0x3fe0000000000002ULL}, - {"0.50000000000000016656055874808561867439493653364479541778564453125", - 0x3fe0000000000002ULL}, - {"0.3932922657273", 0x3fd92bb352c4623aULL}, - - // http://www.exploringbinary.com/incorrectly-rounded-conversions-in-gcc-and-glibc/ - {"0.500000000000000166533453693773481063544750213623046875", - 0x3fe0000000000002ULL}, - {"3.518437208883201171875e13", 0x42c0000000000002ULL}, - {"62.5364939768271845828", 0x404f44abd5aa7ca4ULL}, - {"8.10109172351e-10", 0x3e0bd5cbaef0fd0cULL}, - {"1.50000000000000011102230246251565404236316680908203125", - 0x3ff8000000000000ULL}, - {"9007199254740991.4999999999999999999999999999999995", - 0x433fffffffffffffULL}, - - // http://www.exploringbinary.com/incorrect-decimal-to-floating-point-conversion-in-sqlite/ - {"1e-23", 0x3b282db34012b251ULL}, - {"8.533e+68", 0x4e3fa69165a8eea2ULL}, - {"4.1006e-184", 0x19dbe0d1c7ea60c9ULL}, - {"9.998e+307", 0x7fe1cc0a350ca87bULL}, - {"9.9538452227e-280", 0x0602117ae45cde43ULL}, - {"6.47660115e-260", 0x0a1fdd9e333badadULL}, - {"7.4e+47", 0x49e033d7eca0adefULL}, - {"5.92e+48", 0x4a1033d7eca0adefULL}, - {"7.35e+66", 0x4dd172b70eababa9ULL}, - {"8.32116e+55", 0x4b8b2628393e02cdULL}, - }; - - for (const auto& test : cases) { - double output; - EXPECT_TRUE(StringToDouble(test.input, &output)); - EXPECT_EQ(bit_cast<uint64_t>(output), test.expected); - } -} - -} // namespace base
diff --git a/base/strings/string_piece_unittest.cc b/base/strings/string_piece_unittest.cc deleted file mode 100644 index 17d0897..0000000 --- a/base/strings/string_piece_unittest.cc +++ /dev/null
@@ -1,805 +0,0 @@ -// 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 <stddef.h> - -#include <string> - -#include "base/strings/string16.h" -#include "base/strings/string_piece.h" -#include "base/strings/utf_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -template <typename T> -class CommonStringPieceTest : public ::testing::Test { - public: - static const T as_string(const char* input) { - return T(input); - } - static const T& as_string(const T& input) { - return input; - } -}; - -template <> -class CommonStringPieceTest<string16> : public ::testing::Test { - public: - static const string16 as_string(const char* input) { - return ASCIIToUTF16(input); - } - static const string16 as_string(const std::string& input) { - return ASCIIToUTF16(input); - } -}; - -typedef ::testing::Types<std::string, string16> SupportedStringTypes; - -TYPED_TEST_CASE(CommonStringPieceTest, SupportedStringTypes); - -TYPED_TEST(CommonStringPieceTest, CheckComparisonOperators) { -#define CMP_Y(op, x, y) \ - { \ - TypeParam lhs(TestFixture::as_string(x)); \ - TypeParam rhs(TestFixture::as_string(y)); \ - ASSERT_TRUE( (BasicStringPiece<TypeParam>((lhs.c_str())) op \ - BasicStringPiece<TypeParam>((rhs.c_str())))); \ - ASSERT_TRUE( (BasicStringPiece<TypeParam>((lhs.c_str())).compare( \ - BasicStringPiece<TypeParam>((rhs.c_str()))) op 0)); \ - } - -#define CMP_N(op, x, y) \ - { \ - TypeParam lhs(TestFixture::as_string(x)); \ - TypeParam rhs(TestFixture::as_string(y)); \ - ASSERT_FALSE( (BasicStringPiece<TypeParam>((lhs.c_str())) op \ - BasicStringPiece<TypeParam>((rhs.c_str())))); \ - ASSERT_FALSE( (BasicStringPiece<TypeParam>((lhs.c_str())).compare( \ - BasicStringPiece<TypeParam>((rhs.c_str()))) op 0)); \ - } - - CMP_Y(==, "", ""); - CMP_Y(==, "a", "a"); - CMP_Y(==, "aa", "aa"); - CMP_N(==, "a", ""); - CMP_N(==, "", "a"); - CMP_N(==, "a", "b"); - CMP_N(==, "a", "aa"); - CMP_N(==, "aa", "a"); - - CMP_N(!=, "", ""); - CMP_N(!=, "a", "a"); - CMP_N(!=, "aa", "aa"); - CMP_Y(!=, "a", ""); - CMP_Y(!=, "", "a"); - CMP_Y(!=, "a", "b"); - CMP_Y(!=, "a", "aa"); - CMP_Y(!=, "aa", "a"); - - CMP_Y(<, "a", "b"); - CMP_Y(<, "a", "aa"); - CMP_Y(<, "aa", "b"); - CMP_Y(<, "aa", "bb"); - CMP_N(<, "a", "a"); - CMP_N(<, "b", "a"); - CMP_N(<, "aa", "a"); - CMP_N(<, "b", "aa"); - CMP_N(<, "bb", "aa"); - - CMP_Y(<=, "a", "a"); - CMP_Y(<=, "a", "b"); - CMP_Y(<=, "a", "aa"); - CMP_Y(<=, "aa", "b"); - CMP_Y(<=, "aa", "bb"); - CMP_N(<=, "b", "a"); - CMP_N(<=, "aa", "a"); - CMP_N(<=, "b", "aa"); - CMP_N(<=, "bb", "aa"); - - CMP_N(>=, "a", "b"); - CMP_N(>=, "a", "aa"); - CMP_N(>=, "aa", "b"); - CMP_N(>=, "aa", "bb"); - CMP_Y(>=, "a", "a"); - CMP_Y(>=, "b", "a"); - CMP_Y(>=, "aa", "a"); - CMP_Y(>=, "b", "aa"); - CMP_Y(>=, "bb", "aa"); - - CMP_N(>, "a", "a"); - CMP_N(>, "a", "b"); - CMP_N(>, "a", "aa"); - CMP_N(>, "aa", "b"); - CMP_N(>, "aa", "bb"); - CMP_Y(>, "b", "a"); - CMP_Y(>, "aa", "a"); - CMP_Y(>, "b", "aa"); - CMP_Y(>, "bb", "aa"); - - std::string x; - for (int i = 0; i < 256; i++) { - x += 'a'; - std::string y = x; - CMP_Y(==, x, y); - for (int j = 0; j < i; j++) { - std::string z = x; - z[j] = 'b'; // Differs in position 'j' - CMP_N(==, x, z); - } - } - -#undef CMP_Y -#undef CMP_N -} - -TYPED_TEST(CommonStringPieceTest, CheckSTL) { - TypeParam alphabet(TestFixture::as_string("abcdefghijklmnopqrstuvwxyz")); - TypeParam abc(TestFixture::as_string("abc")); - TypeParam xyz(TestFixture::as_string("xyz")); - TypeParam foobar(TestFixture::as_string("foobar")); - - BasicStringPiece<TypeParam> a(alphabet); - BasicStringPiece<TypeParam> b(abc); - BasicStringPiece<TypeParam> c(xyz); - BasicStringPiece<TypeParam> d(foobar); - BasicStringPiece<TypeParam> e; - TypeParam temp(TestFixture::as_string("123")); - temp += static_cast<typename TypeParam::value_type>(0); - temp += TestFixture::as_string("456"); - BasicStringPiece<TypeParam> f(temp); - - ASSERT_EQ(a[6], static_cast<typename TypeParam::value_type>('g')); - ASSERT_EQ(b[0], static_cast<typename TypeParam::value_type>('a')); - ASSERT_EQ(c[2], static_cast<typename TypeParam::value_type>('z')); - ASSERT_EQ(f[3], static_cast<typename TypeParam::value_type>('\0')); - ASSERT_EQ(f[5], static_cast<typename TypeParam::value_type>('5')); - - ASSERT_EQ(*d.data(), static_cast<typename TypeParam::value_type>('f')); - ASSERT_EQ(d.data()[5], static_cast<typename TypeParam::value_type>('r')); - ASSERT_EQ(e.data(), nullptr); - - ASSERT_EQ(*a.begin(), static_cast<typename TypeParam::value_type>('a')); - ASSERT_EQ(*(b.begin() + 2), static_cast<typename TypeParam::value_type>('c')); - ASSERT_EQ(*(c.end() - 1), static_cast<typename TypeParam::value_type>('z')); - - ASSERT_EQ(*a.rbegin(), static_cast<typename TypeParam::value_type>('z')); - ASSERT_EQ(*(b.rbegin() + 2), - static_cast<typename TypeParam::value_type>('a')); - ASSERT_EQ(*(c.rend() - 1), static_cast<typename TypeParam::value_type>('x')); - ASSERT_EQ(a.rbegin() + 26, a.rend()); - - ASSERT_EQ(a.size(), 26U); - ASSERT_EQ(b.size(), 3U); - ASSERT_EQ(c.size(), 3U); - ASSERT_EQ(d.size(), 6U); - ASSERT_EQ(e.size(), 0U); - ASSERT_EQ(f.size(), 7U); - - ASSERT_TRUE(!d.empty()); - ASSERT_TRUE(d.begin() != d.end()); - ASSERT_EQ(d.begin() + 6, d.end()); - - ASSERT_TRUE(e.empty()); - ASSERT_EQ(e.begin(), e.end()); - - d.clear(); - ASSERT_EQ(d.size(), 0U); - ASSERT_TRUE(d.empty()); - ASSERT_EQ(d.data(), nullptr); - ASSERT_EQ(d.begin(), d.end()); - - ASSERT_GE(a.max_size(), a.capacity()); - ASSERT_GE(a.capacity(), a.size()); -} - -TYPED_TEST(CommonStringPieceTest, CheckFind) { - typedef BasicStringPiece<TypeParam> Piece; - - TypeParam alphabet(TestFixture::as_string("abcdefghijklmnopqrstuvwxyz")); - TypeParam abc(TestFixture::as_string("abc")); - TypeParam xyz(TestFixture::as_string("xyz")); - TypeParam foobar(TestFixture::as_string("foobar")); - - BasicStringPiece<TypeParam> a(alphabet); - BasicStringPiece<TypeParam> b(abc); - BasicStringPiece<TypeParam> c(xyz); - BasicStringPiece<TypeParam> d(foobar); - - d.clear(); - Piece e; - TypeParam temp(TestFixture::as_string("123")); - temp.push_back('\0'); - temp += TestFixture::as_string("456"); - Piece f(temp); - - typename TypeParam::value_type buf[4] = { '%', '%', '%', '%' }; - ASSERT_EQ(a.copy(buf, 4), 4U); - ASSERT_EQ(buf[0], a[0]); - ASSERT_EQ(buf[1], a[1]); - ASSERT_EQ(buf[2], a[2]); - ASSERT_EQ(buf[3], a[3]); - ASSERT_EQ(a.copy(buf, 3, 7), 3U); - ASSERT_EQ(buf[0], a[7]); - ASSERT_EQ(buf[1], a[8]); - ASSERT_EQ(buf[2], a[9]); - ASSERT_EQ(buf[3], a[3]); - ASSERT_EQ(c.copy(buf, 99), 3U); - ASSERT_EQ(buf[0], c[0]); - ASSERT_EQ(buf[1], c[1]); - ASSERT_EQ(buf[2], c[2]); - ASSERT_EQ(buf[3], a[3]); - - ASSERT_EQ(Piece::npos, TypeParam::npos); - - ASSERT_EQ(a.find(b), 0U); - ASSERT_EQ(a.find(b, 1), Piece::npos); - ASSERT_EQ(a.find(c), 23U); - ASSERT_EQ(a.find(c, 9), 23U); - ASSERT_EQ(a.find(c, Piece::npos), Piece::npos); - ASSERT_EQ(b.find(c), Piece::npos); - ASSERT_EQ(b.find(c, Piece::npos), Piece::npos); - ASSERT_EQ(a.find(d), 0U); - ASSERT_EQ(a.find(e), 0U); - ASSERT_EQ(a.find(d, 12), 12U); - ASSERT_EQ(a.find(e, 17), 17U); - TypeParam not_found(TestFixture::as_string("xx not found bb")); - Piece g(not_found); - ASSERT_EQ(a.find(g), Piece::npos); - // empty string nonsense - ASSERT_EQ(d.find(b), Piece::npos); - ASSERT_EQ(e.find(b), Piece::npos); - ASSERT_EQ(d.find(b, 4), Piece::npos); - ASSERT_EQ(e.find(b, 7), Piece::npos); - - size_t empty_search_pos = TypeParam().find(TypeParam()); - ASSERT_EQ(d.find(d), empty_search_pos); - ASSERT_EQ(d.find(e), empty_search_pos); - ASSERT_EQ(e.find(d), empty_search_pos); - ASSERT_EQ(e.find(e), empty_search_pos); - ASSERT_EQ(d.find(d, 4), std::string().find(std::string(), 4)); - ASSERT_EQ(d.find(e, 4), std::string().find(std::string(), 4)); - ASSERT_EQ(e.find(d, 4), std::string().find(std::string(), 4)); - ASSERT_EQ(e.find(e, 4), std::string().find(std::string(), 4)); - - ASSERT_EQ(a.find('a'), 0U); - ASSERT_EQ(a.find('c'), 2U); - ASSERT_EQ(a.find('z'), 25U); - ASSERT_EQ(a.find('$'), Piece::npos); - ASSERT_EQ(a.find('\0'), Piece::npos); - ASSERT_EQ(f.find('\0'), 3U); - ASSERT_EQ(f.find('3'), 2U); - ASSERT_EQ(f.find('5'), 5U); - ASSERT_EQ(g.find('o'), 4U); - ASSERT_EQ(g.find('o', 4), 4U); - ASSERT_EQ(g.find('o', 5), 8U); - ASSERT_EQ(a.find('b', 5), Piece::npos); - // empty string nonsense - ASSERT_EQ(d.find('\0'), Piece::npos); - ASSERT_EQ(e.find('\0'), Piece::npos); - ASSERT_EQ(d.find('\0', 4), Piece::npos); - ASSERT_EQ(e.find('\0', 7), Piece::npos); - ASSERT_EQ(d.find('x'), Piece::npos); - ASSERT_EQ(e.find('x'), Piece::npos); - ASSERT_EQ(d.find('x', 4), Piece::npos); - ASSERT_EQ(e.find('x', 7), Piece::npos); - - ASSERT_EQ(a.rfind(b), 0U); - ASSERT_EQ(a.rfind(b, 1), 0U); - ASSERT_EQ(a.rfind(c), 23U); - ASSERT_EQ(a.rfind(c, 22U), Piece::npos); - ASSERT_EQ(a.rfind(c, 1U), Piece::npos); - ASSERT_EQ(a.rfind(c, 0U), Piece::npos); - ASSERT_EQ(b.rfind(c), Piece::npos); - ASSERT_EQ(b.rfind(c, 0U), Piece::npos); - ASSERT_EQ(a.rfind(d), static_cast<size_t>(a.as_string().rfind(TypeParam()))); - ASSERT_EQ(a.rfind(e), a.as_string().rfind(TypeParam())); - ASSERT_EQ(a.rfind(d), static_cast<size_t>(TypeParam(a).rfind(TypeParam()))); - ASSERT_EQ(a.rfind(e), TypeParam(a).rfind(TypeParam())); - ASSERT_EQ(a.rfind(d, 12), 12U); - ASSERT_EQ(a.rfind(e, 17), 17U); - ASSERT_EQ(a.rfind(g), Piece::npos); - ASSERT_EQ(d.rfind(b), Piece::npos); - ASSERT_EQ(e.rfind(b), Piece::npos); - ASSERT_EQ(d.rfind(b, 4), Piece::npos); - ASSERT_EQ(e.rfind(b, 7), Piece::npos); - // empty string nonsense - ASSERT_EQ(d.rfind(d, 4), std::string().rfind(std::string())); - ASSERT_EQ(e.rfind(d, 7), std::string().rfind(std::string())); - ASSERT_EQ(d.rfind(e, 4), std::string().rfind(std::string())); - ASSERT_EQ(e.rfind(e, 7), std::string().rfind(std::string())); - ASSERT_EQ(d.rfind(d), std::string().rfind(std::string())); - ASSERT_EQ(e.rfind(d), std::string().rfind(std::string())); - ASSERT_EQ(d.rfind(e), std::string().rfind(std::string())); - ASSERT_EQ(e.rfind(e), std::string().rfind(std::string())); - - ASSERT_EQ(g.rfind('o'), 8U); - ASSERT_EQ(g.rfind('q'), Piece::npos); - ASSERT_EQ(g.rfind('o', 8), 8U); - ASSERT_EQ(g.rfind('o', 7), 4U); - ASSERT_EQ(g.rfind('o', 3), Piece::npos); - ASSERT_EQ(f.rfind('\0'), 3U); - ASSERT_EQ(f.rfind('\0', 12), 3U); - ASSERT_EQ(f.rfind('3'), 2U); - ASSERT_EQ(f.rfind('5'), 5U); - // empty string nonsense - ASSERT_EQ(d.rfind('o'), Piece::npos); - ASSERT_EQ(e.rfind('o'), Piece::npos); - ASSERT_EQ(d.rfind('o', 4), Piece::npos); - ASSERT_EQ(e.rfind('o', 7), Piece::npos); - - TypeParam one_two_three_four(TestFixture::as_string("one,two:three;four")); - TypeParam comma_colon(TestFixture::as_string(",:")); - ASSERT_EQ(3U, Piece(one_two_three_four).find_first_of(comma_colon)); - ASSERT_EQ(a.find_first_of(b), 0U); - ASSERT_EQ(a.find_first_of(b, 0), 0U); - ASSERT_EQ(a.find_first_of(b, 1), 1U); - ASSERT_EQ(a.find_first_of(b, 2), 2U); - ASSERT_EQ(a.find_first_of(b, 3), Piece::npos); - ASSERT_EQ(a.find_first_of(c), 23U); - ASSERT_EQ(a.find_first_of(c, 23), 23U); - ASSERT_EQ(a.find_first_of(c, 24), 24U); - ASSERT_EQ(a.find_first_of(c, 25), 25U); - ASSERT_EQ(a.find_first_of(c, 26), Piece::npos); - ASSERT_EQ(g.find_first_of(b), 13U); - ASSERT_EQ(g.find_first_of(c), 0U); - ASSERT_EQ(a.find_first_of(f), Piece::npos); - ASSERT_EQ(f.find_first_of(a), Piece::npos); - // empty string nonsense - ASSERT_EQ(a.find_first_of(d), Piece::npos); - ASSERT_EQ(a.find_first_of(e), Piece::npos); - ASSERT_EQ(d.find_first_of(b), Piece::npos); - ASSERT_EQ(e.find_first_of(b), Piece::npos); - ASSERT_EQ(d.find_first_of(d), Piece::npos); - ASSERT_EQ(e.find_first_of(d), Piece::npos); - ASSERT_EQ(d.find_first_of(e), Piece::npos); - ASSERT_EQ(e.find_first_of(e), Piece::npos); - - ASSERT_EQ(a.find_first_not_of(b), 3U); - ASSERT_EQ(a.find_first_not_of(c), 0U); - ASSERT_EQ(b.find_first_not_of(a), Piece::npos); - ASSERT_EQ(c.find_first_not_of(a), Piece::npos); - ASSERT_EQ(f.find_first_not_of(a), 0U); - ASSERT_EQ(a.find_first_not_of(f), 0U); - ASSERT_EQ(a.find_first_not_of(d), 0U); - ASSERT_EQ(a.find_first_not_of(e), 0U); - // empty string nonsense - ASSERT_EQ(d.find_first_not_of(a), Piece::npos); - ASSERT_EQ(e.find_first_not_of(a), Piece::npos); - ASSERT_EQ(d.find_first_not_of(d), Piece::npos); - ASSERT_EQ(e.find_first_not_of(d), Piece::npos); - ASSERT_EQ(d.find_first_not_of(e), Piece::npos); - ASSERT_EQ(e.find_first_not_of(e), Piece::npos); - - TypeParam equals(TestFixture::as_string("====")); - Piece h(equals); - ASSERT_EQ(h.find_first_not_of('='), Piece::npos); - ASSERT_EQ(h.find_first_not_of('=', 3), Piece::npos); - ASSERT_EQ(h.find_first_not_of('\0'), 0U); - ASSERT_EQ(g.find_first_not_of('x'), 2U); - ASSERT_EQ(f.find_first_not_of('\0'), 0U); - ASSERT_EQ(f.find_first_not_of('\0', 3), 4U); - ASSERT_EQ(f.find_first_not_of('\0', 2), 2U); - // empty string nonsense - ASSERT_EQ(d.find_first_not_of('x'), Piece::npos); - ASSERT_EQ(e.find_first_not_of('x'), Piece::npos); - ASSERT_EQ(d.find_first_not_of('\0'), Piece::npos); - ASSERT_EQ(e.find_first_not_of('\0'), Piece::npos); - - // Piece g("xx not found bb"); - TypeParam fifty_six(TestFixture::as_string("56")); - Piece i(fifty_six); - ASSERT_EQ(h.find_last_of(a), Piece::npos); - ASSERT_EQ(g.find_last_of(a), g.size()-1); - ASSERT_EQ(a.find_last_of(b), 2U); - ASSERT_EQ(a.find_last_of(c), a.size()-1); - ASSERT_EQ(f.find_last_of(i), 6U); - ASSERT_EQ(a.find_last_of('a'), 0U); - ASSERT_EQ(a.find_last_of('b'), 1U); - ASSERT_EQ(a.find_last_of('z'), 25U); - ASSERT_EQ(a.find_last_of('a', 5), 0U); - ASSERT_EQ(a.find_last_of('b', 5), 1U); - ASSERT_EQ(a.find_last_of('b', 0), Piece::npos); - ASSERT_EQ(a.find_last_of('z', 25), 25U); - ASSERT_EQ(a.find_last_of('z', 24), Piece::npos); - ASSERT_EQ(f.find_last_of(i, 5), 5U); - ASSERT_EQ(f.find_last_of(i, 6), 6U); - ASSERT_EQ(f.find_last_of(a, 4), Piece::npos); - // empty string nonsense - ASSERT_EQ(f.find_last_of(d), Piece::npos); - ASSERT_EQ(f.find_last_of(e), Piece::npos); - ASSERT_EQ(f.find_last_of(d, 4), Piece::npos); - ASSERT_EQ(f.find_last_of(e, 4), Piece::npos); - ASSERT_EQ(d.find_last_of(d), Piece::npos); - ASSERT_EQ(d.find_last_of(e), Piece::npos); - ASSERT_EQ(e.find_last_of(d), Piece::npos); - ASSERT_EQ(e.find_last_of(e), Piece::npos); - ASSERT_EQ(d.find_last_of(f), Piece::npos); - ASSERT_EQ(e.find_last_of(f), Piece::npos); - ASSERT_EQ(d.find_last_of(d, 4), Piece::npos); - ASSERT_EQ(d.find_last_of(e, 4), Piece::npos); - ASSERT_EQ(e.find_last_of(d, 4), Piece::npos); - ASSERT_EQ(e.find_last_of(e, 4), Piece::npos); - ASSERT_EQ(d.find_last_of(f, 4), Piece::npos); - ASSERT_EQ(e.find_last_of(f, 4), Piece::npos); - - ASSERT_EQ(a.find_last_not_of(b), a.size()-1); - ASSERT_EQ(a.find_last_not_of(c), 22U); - ASSERT_EQ(b.find_last_not_of(a), Piece::npos); - ASSERT_EQ(b.find_last_not_of(b), Piece::npos); - ASSERT_EQ(f.find_last_not_of(i), 4U); - ASSERT_EQ(a.find_last_not_of(c, 24), 22U); - ASSERT_EQ(a.find_last_not_of(b, 3), 3U); - ASSERT_EQ(a.find_last_not_of(b, 2), Piece::npos); - // empty string nonsense - ASSERT_EQ(f.find_last_not_of(d), f.size()-1); - ASSERT_EQ(f.find_last_not_of(e), f.size()-1); - ASSERT_EQ(f.find_last_not_of(d, 4), 4U); - ASSERT_EQ(f.find_last_not_of(e, 4), 4U); - ASSERT_EQ(d.find_last_not_of(d), Piece::npos); - ASSERT_EQ(d.find_last_not_of(e), Piece::npos); - ASSERT_EQ(e.find_last_not_of(d), Piece::npos); - ASSERT_EQ(e.find_last_not_of(e), Piece::npos); - ASSERT_EQ(d.find_last_not_of(f), Piece::npos); - ASSERT_EQ(e.find_last_not_of(f), Piece::npos); - ASSERT_EQ(d.find_last_not_of(d, 4), Piece::npos); - ASSERT_EQ(d.find_last_not_of(e, 4), Piece::npos); - ASSERT_EQ(e.find_last_not_of(d, 4), Piece::npos); - ASSERT_EQ(e.find_last_not_of(e, 4), Piece::npos); - ASSERT_EQ(d.find_last_not_of(f, 4), Piece::npos); - ASSERT_EQ(e.find_last_not_of(f, 4), Piece::npos); - - ASSERT_EQ(h.find_last_not_of('x'), h.size() - 1); - ASSERT_EQ(h.find_last_not_of('='), Piece::npos); - ASSERT_EQ(b.find_last_not_of('c'), 1U); - ASSERT_EQ(h.find_last_not_of('x', 2), 2U); - ASSERT_EQ(h.find_last_not_of('=', 2), Piece::npos); - ASSERT_EQ(b.find_last_not_of('b', 1), 0U); - // empty string nonsense - ASSERT_EQ(d.find_last_not_of('x'), Piece::npos); - ASSERT_EQ(e.find_last_not_of('x'), Piece::npos); - ASSERT_EQ(d.find_last_not_of('\0'), Piece::npos); - ASSERT_EQ(e.find_last_not_of('\0'), Piece::npos); - - ASSERT_EQ(a.substr(0, 3), b); - ASSERT_EQ(a.substr(23), c); - ASSERT_EQ(a.substr(23, 3), c); - ASSERT_EQ(a.substr(23, 99), c); - ASSERT_EQ(a.substr(0), a); - ASSERT_EQ(a.substr(3, 2), TestFixture::as_string("de")); - // empty string nonsense - ASSERT_EQ(a.substr(99, 2), e); - ASSERT_EQ(d.substr(99), e); - ASSERT_EQ(d.substr(0, 99), e); - ASSERT_EQ(d.substr(99, 99), e); -} - -TYPED_TEST(CommonStringPieceTest, CheckCustom) { - TypeParam foobar(TestFixture::as_string("foobar")); - BasicStringPiece<TypeParam> a(foobar); - TypeParam s1(TestFixture::as_string("123")); - s1 += static_cast<typename TypeParam::value_type>('\0'); - s1 += TestFixture::as_string("456"); - BasicStringPiece<TypeParam> b(s1); - BasicStringPiece<TypeParam> e; - TypeParam s2; - - // remove_prefix - BasicStringPiece<TypeParam> c(a); - c.remove_prefix(3); - ASSERT_EQ(c, TestFixture::as_string("bar")); - c = a; - c.remove_prefix(0); - ASSERT_EQ(c, a); - c.remove_prefix(c.size()); - ASSERT_EQ(c, e); - - // remove_suffix - c = a; - c.remove_suffix(3); - ASSERT_EQ(c, TestFixture::as_string("foo")); - c = a; - c.remove_suffix(0); - ASSERT_EQ(c, a); - c.remove_suffix(c.size()); - ASSERT_EQ(c, e); - - // set - c.set(foobar.c_str()); - ASSERT_EQ(c, a); - c.set(foobar.c_str(), 6); - ASSERT_EQ(c, a); - c.set(foobar.c_str(), 0); - ASSERT_EQ(c, e); - c.set(foobar.c_str(), 7); // Note, has an embedded NULL - ASSERT_NE(c, a); - - // as_string - TypeParam s3(a.as_string().c_str(), 7); // Note, has an embedded NULL - ASSERT_EQ(c, s3); - TypeParam s4(e.as_string()); - ASSERT_TRUE(s4.empty()); - - // operator STRING_TYPE() - TypeParam s5(TypeParam(a).c_str(), 7); // Note, has an embedded NULL - ASSERT_EQ(c, s5); - TypeParam s6(e); - ASSERT_TRUE(s6.empty()); -} - -TEST(StringPieceTest, CheckCustom) { - StringPiece a("foobar"); - std::string s1("123"); - s1 += '\0'; - s1 += "456"; - StringPiece b(s1); - StringPiece e; - std::string s2; - - // CopyToString - a.CopyToString(&s2); - ASSERT_EQ(s2.size(), 6U); - ASSERT_EQ(s2, "foobar"); - b.CopyToString(&s2); - ASSERT_EQ(s2.size(), 7U); - ASSERT_EQ(s1, s2); - e.CopyToString(&s2); - ASSERT_TRUE(s2.empty()); - - // AppendToString - s2.erase(); - a.AppendToString(&s2); - ASSERT_EQ(s2.size(), 6U); - ASSERT_EQ(s2, "foobar"); - a.AppendToString(&s2); - ASSERT_EQ(s2.size(), 12U); - ASSERT_EQ(s2, "foobarfoobar"); - - // starts_with - ASSERT_TRUE(a.starts_with(a)); - ASSERT_TRUE(a.starts_with("foo")); - ASSERT_TRUE(a.starts_with(e)); - ASSERT_TRUE(b.starts_with(s1)); - ASSERT_TRUE(b.starts_with(b)); - ASSERT_TRUE(b.starts_with(e)); - ASSERT_TRUE(e.starts_with("")); - ASSERT_TRUE(!a.starts_with(b)); - ASSERT_TRUE(!b.starts_with(a)); - ASSERT_TRUE(!e.starts_with(a)); - - // ends with - ASSERT_TRUE(a.ends_with(a)); - ASSERT_TRUE(a.ends_with("bar")); - ASSERT_TRUE(a.ends_with(e)); - ASSERT_TRUE(b.ends_with(s1)); - ASSERT_TRUE(b.ends_with(b)); - ASSERT_TRUE(b.ends_with(e)); - ASSERT_TRUE(e.ends_with("")); - ASSERT_TRUE(!a.ends_with(b)); - ASSERT_TRUE(!b.ends_with(a)); - ASSERT_TRUE(!e.ends_with(a)); - - StringPiece c; - c.set("foobar", 6); - ASSERT_EQ(c, a); - c.set("foobar", 0); - ASSERT_EQ(c, e); - c.set("foobar", 7); - ASSERT_NE(c, a); -} - -TYPED_TEST(CommonStringPieceTest, CheckNULL) { - // we used to crash here, but now we don't. - BasicStringPiece<TypeParam> s(nullptr); - ASSERT_EQ(s.data(), nullptr); - ASSERT_EQ(s.size(), 0U); - - s.set(nullptr); - ASSERT_EQ(s.data(), nullptr); - ASSERT_EQ(s.size(), 0U); - - TypeParam str(s); - ASSERT_EQ(str.length(), 0U); - ASSERT_EQ(str, TypeParam()); - - str = s.as_string(); - ASSERT_EQ(str.length(), 0U); - ASSERT_EQ(str, TypeParam()); -} - -TYPED_TEST(CommonStringPieceTest, CheckComparisons2) { - TypeParam alphabet(TestFixture::as_string("abcdefghijklmnopqrstuvwxyz")); - TypeParam alphabet_z(TestFixture::as_string("abcdefghijklmnopqrstuvwxyzz")); - TypeParam alphabet_y(TestFixture::as_string("abcdefghijklmnopqrstuvwxyy")); - BasicStringPiece<TypeParam> abc(alphabet); - - // check comparison operations on strings longer than 4 bytes. - ASSERT_EQ(abc, BasicStringPiece<TypeParam>(alphabet)); - ASSERT_EQ(abc.compare(BasicStringPiece<TypeParam>(alphabet)), 0); - - ASSERT_TRUE(abc < BasicStringPiece<TypeParam>(alphabet_z)); - ASSERT_LT(abc.compare(BasicStringPiece<TypeParam>(alphabet_z)), 0); - - ASSERT_TRUE(abc > BasicStringPiece<TypeParam>(alphabet_y)); - ASSERT_GT(abc.compare(BasicStringPiece<TypeParam>(alphabet_y)), 0); -} - -// Test operations only supported by std::string version. -TEST(StringPieceTest, CheckComparisons2) { - StringPiece abc("abcdefghijklmnopqrstuvwxyz"); - - // starts_with - ASSERT_TRUE(abc.starts_with(abc)); - ASSERT_TRUE(abc.starts_with("abcdefghijklm")); - ASSERT_TRUE(!abc.starts_with("abcdefguvwxyz")); - - // ends_with - ASSERT_TRUE(abc.ends_with(abc)); - ASSERT_TRUE(!abc.ends_with("abcdefguvwxyz")); - ASSERT_TRUE(abc.ends_with("nopqrstuvwxyz")); -} - -TYPED_TEST(CommonStringPieceTest, StringCompareNotAmbiguous) { - ASSERT_TRUE(TestFixture::as_string("hello").c_str() == - TestFixture::as_string("hello")); - ASSERT_TRUE(TestFixture::as_string("hello").c_str() < - TestFixture::as_string("world")); -} - -TYPED_TEST(CommonStringPieceTest, HeterogenousStringPieceEquals) { - TypeParam hello(TestFixture::as_string("hello")); - - ASSERT_EQ(BasicStringPiece<TypeParam>(hello), hello); - ASSERT_EQ(hello.c_str(), BasicStringPiece<TypeParam>(hello)); -} - -// string16-specific stuff -TEST(StringPiece16Test, CheckSTL) { - // Check some non-ascii characters. - string16 fifth(ASCIIToUTF16("123")); - fifth.push_back(0x0000); - fifth.push_back(0xd8c5); - fifth.push_back(0xdffe); - StringPiece16 f(fifth); - - ASSERT_EQ(f[3], '\0'); - ASSERT_EQ(f[5], static_cast<char16>(0xdffe)); - - ASSERT_EQ(f.size(), 6U); -} - - - -TEST(StringPiece16Test, CheckConversion) { - // Make sure that we can convert from UTF8 to UTF16 and back. We use a two - // byte character (G clef) to test this. - ASSERT_EQ( - UTF16ToUTF8( - StringPiece16(UTF8ToUTF16("\xf0\x9d\x84\x9e")).as_string()), - "\xf0\x9d\x84\x9e"); -} - -TYPED_TEST(CommonStringPieceTest, CheckConstructors) { - TypeParam str(TestFixture::as_string("hello world")); - TypeParam empty; - - ASSERT_EQ(str, BasicStringPiece<TypeParam>(str)); - ASSERT_EQ(str, BasicStringPiece<TypeParam>(str.c_str())); - ASSERT_TRUE(TestFixture::as_string("hello") == - BasicStringPiece<TypeParam>(str.c_str(), 5)); - ASSERT_EQ( - empty, - BasicStringPiece<TypeParam>( - str.c_str(), - static_cast<typename BasicStringPiece<TypeParam>::size_type>(0))); - ASSERT_EQ(empty, BasicStringPiece<TypeParam>(nullptr)); - ASSERT_TRUE( - empty == - BasicStringPiece<TypeParam>( - nullptr, - static_cast<typename BasicStringPiece<TypeParam>::size_type>(0))); - ASSERT_EQ(empty, BasicStringPiece<TypeParam>()); - ASSERT_EQ(str, BasicStringPiece<TypeParam>(str.begin(), str.end())); - ASSERT_EQ(empty, BasicStringPiece<TypeParam>(str.begin(), str.begin())); - ASSERT_EQ(empty, BasicStringPiece<TypeParam>(empty)); - ASSERT_EQ(empty, BasicStringPiece<TypeParam>(empty.begin(), empty.end())); -} - -TEST(StringPieceTest, ConstexprCtor) { - { - constexpr StringPiece piece; - std::ignore = piece; - } - - { - constexpr StringPiece piece("abc"); - std::ignore = piece; - } - - { - constexpr StringPiece piece("abc", 2); - std::ignore = piece; - } -} - -TEST(StringPieceTest, ConstexprData) { - { - constexpr StringPiece piece; - static_assert(piece.data() == nullptr, ""); - } - - { - constexpr StringPiece piece("abc"); - static_assert(piece.data()[0] == 'a', ""); - static_assert(piece.data()[1] == 'b', ""); - static_assert(piece.data()[2] == 'c', ""); - } - - { - constexpr StringPiece piece("def", 2); - static_assert(piece.data()[0] == 'd', ""); - static_assert(piece.data()[1] == 'e', ""); - } -} - -TEST(StringPieceTest, ConstexprSize) { - { - constexpr StringPiece piece; - static_assert(piece.size() == 0, ""); - } - - { - constexpr StringPiece piece("abc"); - static_assert(piece.size() == 3, ""); - } - - { - constexpr StringPiece piece("def", 2); - static_assert(piece.size() == 2, ""); - } -} - -TEST(StringPieceTest, Compare) { - constexpr StringPiece piece = "def"; - - static_assert(piece.compare("ab") == 1, ""); - static_assert(piece.compare("abc") == 1, ""); - static_assert(piece.compare("abcd") == 1, ""); - static_assert(piece.compare("de") == 1, ""); - static_assert(piece.compare("def") == 0, ""); - static_assert(piece.compare("defg") == -1, ""); - static_assert(piece.compare("gh") == -1, ""); - static_assert(piece.compare("ghi") == -1, ""); - static_assert(piece.compare("ghij") == -1, ""); -} - -TEST(StringPieceTest, StartsWith) { - constexpr StringPiece piece("abc"); - - static_assert(piece.starts_with(""), ""); - static_assert(piece.starts_with("a"), ""); - static_assert(piece.starts_with("ab"), ""); - static_assert(piece.starts_with("abc"), ""); - - static_assert(!piece.starts_with("b"), ""); - static_assert(!piece.starts_with("bc"), ""); - - static_assert(!piece.starts_with("abcd"), ""); -} - -TEST(StringPieceTest, EndsWith) { - constexpr StringPiece piece("abc"); - - static_assert(piece.ends_with(""), ""); - static_assert(piece.ends_with("c"), ""); - static_assert(piece.ends_with("bc"), ""); - static_assert(piece.ends_with("abc"), ""); - - static_assert(!piece.ends_with("a"), ""); - static_assert(!piece.ends_with("ab"), ""); - - static_assert(!piece.ends_with("abcd"), ""); -} - -} // namespace base
diff --git a/base/strings/string_split_unittest.cc b/base/strings/string_split_unittest.cc deleted file mode 100644 index bf09aa5..0000000 --- a/base/strings/string_split_unittest.cc +++ /dev/null
@@ -1,386 +0,0 @@ -// 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/strings/string_split.h" - -#include <stddef.h> - -#include "base/macros.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using ::testing::ElementsAre; - -namespace base { - -class SplitStringIntoKeyValuePairsTest : public testing::Test { - protected: - base::StringPairs kv_pairs; -}; - -TEST_F(SplitStringIntoKeyValuePairsTest, EmptyString) { - EXPECT_TRUE(SplitStringIntoKeyValuePairs(std::string(), - ':', // Key-value delimiter - ',', // Key-value pair delimiter - &kv_pairs)); - EXPECT_TRUE(kv_pairs.empty()); -} - -TEST_F(SplitStringIntoKeyValuePairsTest, MissingKeyValueDelimiter) { - EXPECT_FALSE(SplitStringIntoKeyValuePairs("key1,key2:value2", - ':', // Key-value delimiter - ',', // Key-value pair delimiter - &kv_pairs)); - ASSERT_EQ(2U, kv_pairs.size()); - EXPECT_TRUE(kv_pairs[0].first.empty()); - EXPECT_TRUE(kv_pairs[0].second.empty()); - EXPECT_EQ("key2", kv_pairs[1].first); - EXPECT_EQ("value2", kv_pairs[1].second); -} - -TEST_F(SplitStringIntoKeyValuePairsTest, EmptyKeyWithKeyValueDelimiter) { - EXPECT_TRUE(SplitStringIntoKeyValuePairs(":value1,key2:value2", - ':', // Key-value delimiter - ',', // Key-value pair delimiter - &kv_pairs)); - ASSERT_EQ(2U, kv_pairs.size()); - EXPECT_TRUE(kv_pairs[0].first.empty()); - EXPECT_EQ("value1", kv_pairs[0].second); - EXPECT_EQ("key2", kv_pairs[1].first); - EXPECT_EQ("value2", kv_pairs[1].second); -} - -TEST_F(SplitStringIntoKeyValuePairsTest, TrailingAndLeadingPairDelimiter) { - EXPECT_TRUE(SplitStringIntoKeyValuePairs(",key1:value1,key2:value2,", - ':', // Key-value delimiter - ',', // Key-value pair delimiter - &kv_pairs)); - ASSERT_EQ(2U, kv_pairs.size()); - EXPECT_EQ("key1", kv_pairs[0].first); - EXPECT_EQ("value1", kv_pairs[0].second); - EXPECT_EQ("key2", kv_pairs[1].first); - EXPECT_EQ("value2", kv_pairs[1].second); -} - -TEST_F(SplitStringIntoKeyValuePairsTest, EmptyPair) { - EXPECT_TRUE(SplitStringIntoKeyValuePairs("key1:value1,,key3:value3", - ':', // Key-value delimiter - ',', // Key-value pair delimiter - &kv_pairs)); - ASSERT_EQ(2U, kv_pairs.size()); - EXPECT_EQ("key1", kv_pairs[0].first); - EXPECT_EQ("value1", kv_pairs[0].second); - EXPECT_EQ("key3", kv_pairs[1].first); - EXPECT_EQ("value3", kv_pairs[1].second); -} - -TEST_F(SplitStringIntoKeyValuePairsTest, EmptyValue) { - EXPECT_FALSE(SplitStringIntoKeyValuePairs("key1:,key2:value2", - ':', // Key-value delimiter - ',', // Key-value pair delimiter - &kv_pairs)); - ASSERT_EQ(2U, kv_pairs.size()); - EXPECT_EQ("key1", kv_pairs[0].first); - EXPECT_EQ("", kv_pairs[0].second); - EXPECT_EQ("key2", kv_pairs[1].first); - EXPECT_EQ("value2", kv_pairs[1].second); -} - -TEST_F(SplitStringIntoKeyValuePairsTest, UntrimmedWhitespace) { - EXPECT_TRUE(SplitStringIntoKeyValuePairs("key1 : value1", - ':', // Key-value delimiter - ',', // Key-value pair delimiter - &kv_pairs)); - ASSERT_EQ(1U, kv_pairs.size()); - EXPECT_EQ("key1 ", kv_pairs[0].first); - EXPECT_EQ(" value1", kv_pairs[0].second); -} - -TEST_F(SplitStringIntoKeyValuePairsTest, TrimmedWhitespace) { - EXPECT_TRUE(SplitStringIntoKeyValuePairs("key1:value1 , key2:value2", - ':', // Key-value delimiter - ',', // Key-value pair delimiter - &kv_pairs)); - ASSERT_EQ(2U, kv_pairs.size()); - EXPECT_EQ("key1", kv_pairs[0].first); - EXPECT_EQ("value1", kv_pairs[0].second); - EXPECT_EQ("key2", kv_pairs[1].first); - EXPECT_EQ("value2", kv_pairs[1].second); -} - -TEST_F(SplitStringIntoKeyValuePairsTest, MultipleKeyValueDelimiters) { - EXPECT_TRUE(SplitStringIntoKeyValuePairs("key1:::value1,key2:value2", - ':', // Key-value delimiter - ',', // Key-value pair delimiter - &kv_pairs)); - ASSERT_EQ(2U, kv_pairs.size()); - EXPECT_EQ("key1", kv_pairs[0].first); - EXPECT_EQ("value1", kv_pairs[0].second); - EXPECT_EQ("key2", kv_pairs[1].first); - EXPECT_EQ("value2", kv_pairs[1].second); -} - -TEST_F(SplitStringIntoKeyValuePairsTest, OnlySplitAtGivenSeparator) { - std::string a("a ?!@#$%^&*()_+:/{}\\\t\nb"); - EXPECT_TRUE(SplitStringIntoKeyValuePairs(a + "X" + a + "Y" + a + "X" + a, - 'X', // Key-value delimiter - 'Y', // Key-value pair delimiter - &kv_pairs)); - ASSERT_EQ(2U, kv_pairs.size()); - EXPECT_EQ(a, kv_pairs[0].first); - EXPECT_EQ(a, kv_pairs[0].second); - EXPECT_EQ(a, kv_pairs[1].first); - EXPECT_EQ(a, kv_pairs[1].second); -} - - -TEST_F(SplitStringIntoKeyValuePairsTest, DelimiterInValue) { - EXPECT_TRUE(SplitStringIntoKeyValuePairs("key1:va:ue1,key2:value2", - ':', // Key-value delimiter - ',', // Key-value pair delimiter - &kv_pairs)); - ASSERT_EQ(2U, kv_pairs.size()); - EXPECT_EQ("key1", kv_pairs[0].first); - EXPECT_EQ("va:ue1", kv_pairs[0].second); - EXPECT_EQ("key2", kv_pairs[1].first); - EXPECT_EQ("value2", kv_pairs[1].second); -} - -TEST(SplitStringUsingSubstrTest, EmptyString) { - std::vector<std::string> results = SplitStringUsingSubstr( - std::string(), "DELIMITER", TRIM_WHITESPACE, SPLIT_WANT_ALL); - ASSERT_EQ(1u, results.size()); - EXPECT_THAT(results, ElementsAre("")); -} - -TEST(StringUtilTest, SplitString_Basics) { - std::vector<std::string> r; - - r = SplitString(std::string(), ",:;", KEEP_WHITESPACE, SPLIT_WANT_ALL); - EXPECT_TRUE(r.empty()); - - // Empty separator list - r = SplitString("hello, world", "", KEEP_WHITESPACE, SPLIT_WANT_ALL); - ASSERT_EQ(1u, r.size()); - EXPECT_EQ("hello, world", r[0]); - - // Should split on any of the separators. - r = SplitString("::,,;;", ",:;", KEEP_WHITESPACE, SPLIT_WANT_ALL); - ASSERT_EQ(7u, r.size()); - for (auto str : r) - ASSERT_TRUE(str.empty()); - - r = SplitString("red, green; blue:", ",:;", TRIM_WHITESPACE, - SPLIT_WANT_NONEMPTY); - ASSERT_EQ(3u, r.size()); - EXPECT_EQ("red", r[0]); - EXPECT_EQ("green", r[1]); - EXPECT_EQ("blue", r[2]); - - // Want to split a string along whitespace sequences. - r = SplitString(" red green \tblue\n", " \t\n", TRIM_WHITESPACE, - SPLIT_WANT_NONEMPTY); - ASSERT_EQ(3u, r.size()); - EXPECT_EQ("red", r[0]); - EXPECT_EQ("green", r[1]); - EXPECT_EQ("blue", r[2]); - - // Weird case of splitting on spaces but not trimming. - r = SplitString(" red ", " ", TRIM_WHITESPACE, SPLIT_WANT_ALL); - ASSERT_EQ(3u, r.size()); - EXPECT_EQ("", r[0]); // Before the first space. - EXPECT_EQ("red", r[1]); - EXPECT_EQ("", r[2]); // After the last space. -} - -TEST(StringUtilTest, SplitString_WhitespaceAndResultType) { - std::vector<std::string> r; - - // Empty input handling. - r = SplitString(std::string(), ",", KEEP_WHITESPACE, SPLIT_WANT_ALL); - EXPECT_TRUE(r.empty()); - r = SplitString(std::string(), ",", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY); - EXPECT_TRUE(r.empty()); - - // Input string is space and we're trimming. - r = SplitString(" ", ",", TRIM_WHITESPACE, SPLIT_WANT_ALL); - ASSERT_EQ(1u, r.size()); - EXPECT_EQ("", r[0]); - r = SplitString(" ", ",", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY); - EXPECT_TRUE(r.empty()); - - // Test all 4 combinations of flags on ", ,". - r = SplitString(", ,", ",", KEEP_WHITESPACE, SPLIT_WANT_ALL); - ASSERT_EQ(3u, r.size()); - EXPECT_EQ("", r[0]); - EXPECT_EQ(" ", r[1]); - EXPECT_EQ("", r[2]); - r = SplitString(", ,", ",", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY); - ASSERT_EQ(1u, r.size()); - ASSERT_EQ(" ", r[0]); - r = SplitString(", ,", ",", TRIM_WHITESPACE, SPLIT_WANT_ALL); - ASSERT_EQ(3u, r.size()); - EXPECT_EQ("", r[0]); - EXPECT_EQ("", r[1]); - EXPECT_EQ("", r[2]); - r = SplitString(", ,", ",", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY); - ASSERT_TRUE(r.empty()); -} - -TEST(SplitStringUsingSubstrTest, StringWithNoDelimiter) { - std::vector<std::string> results = SplitStringUsingSubstr( - "alongwordwithnodelimiter", "DELIMITER", TRIM_WHITESPACE, - SPLIT_WANT_ALL); - ASSERT_EQ(1u, results.size()); - EXPECT_THAT(results, ElementsAre("alongwordwithnodelimiter")); -} - -TEST(SplitStringUsingSubstrTest, LeadingDelimitersSkipped) { - std::vector<std::string> results = SplitStringUsingSubstr( - "DELIMITERDELIMITERDELIMITERoneDELIMITERtwoDELIMITERthree", - "DELIMITER", TRIM_WHITESPACE, SPLIT_WANT_ALL); - ASSERT_EQ(6u, results.size()); - EXPECT_THAT(results, ElementsAre("", "", "", "one", "two", "three")); -} - -TEST(SplitStringUsingSubstrTest, ConsecutiveDelimitersSkipped) { - std::vector<std::string> results = SplitStringUsingSubstr( - "unoDELIMITERDELIMITERDELIMITERdosDELIMITERtresDELIMITERDELIMITERcuatro", - "DELIMITER", TRIM_WHITESPACE, SPLIT_WANT_ALL); - ASSERT_EQ(7u, results.size()); - EXPECT_THAT(results, ElementsAre("uno", "", "", "dos", "tres", "", "cuatro")); -} - -TEST(SplitStringUsingSubstrTest, TrailingDelimitersSkipped) { - std::vector<std::string> results = SplitStringUsingSubstr( - "unDELIMITERdeuxDELIMITERtroisDELIMITERquatreDELIMITERDELIMITERDELIMITER", - "DELIMITER", TRIM_WHITESPACE, SPLIT_WANT_ALL); - ASSERT_EQ(7u, results.size()); - EXPECT_THAT( - results, ElementsAre("un", "deux", "trois", "quatre", "", "", "")); -} - -TEST(SplitStringPieceUsingSubstrTest, StringWithNoDelimiter) { - std::vector<base::StringPiece> results = - SplitStringPieceUsingSubstr("alongwordwithnodelimiter", "DELIMITER", - base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); - ASSERT_EQ(1u, results.size()); - EXPECT_THAT(results, ElementsAre("alongwordwithnodelimiter")); -} - -TEST(SplitStringPieceUsingSubstrTest, LeadingDelimitersSkipped) { - std::vector<base::StringPiece> results = SplitStringPieceUsingSubstr( - "DELIMITERDELIMITERDELIMITERoneDELIMITERtwoDELIMITERthree", "DELIMITER", - base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); - ASSERT_EQ(6u, results.size()); - EXPECT_THAT(results, ElementsAre("", "", "", "one", "two", "three")); -} - -TEST(SplitStringPieceUsingSubstrTest, ConsecutiveDelimitersSkipped) { - std::vector<base::StringPiece> results = SplitStringPieceUsingSubstr( - "unoDELIMITERDELIMITERDELIMITERdosDELIMITERtresDELIMITERDELIMITERcuatro", - "DELIMITER", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); - ASSERT_EQ(7u, results.size()); - EXPECT_THAT(results, ElementsAre("uno", "", "", "dos", "tres", "", "cuatro")); -} - -TEST(SplitStringPieceUsingSubstrTest, TrailingDelimitersSkipped) { - std::vector<base::StringPiece> results = SplitStringPieceUsingSubstr( - "unDELIMITERdeuxDELIMITERtroisDELIMITERquatreDELIMITERDELIMITERDELIMITER", - "DELIMITER", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); - ASSERT_EQ(7u, results.size()); - EXPECT_THAT(results, - ElementsAre("un", "deux", "trois", "quatre", "", "", "")); -} - -TEST(SplitStringPieceUsingSubstrTest, KeepWhitespace) { - std::vector<base::StringPiece> results = SplitStringPieceUsingSubstr( - "un DELIMITERdeux\tDELIMITERtrois\nDELIMITERquatre", "DELIMITER", - base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); - ASSERT_EQ(4u, results.size()); - EXPECT_THAT(results, ElementsAre("un ", "deux\t", "trois\n", "quatre")); -} - -TEST(SplitStringPieceUsingSubstrTest, TrimWhitespace) { - std::vector<base::StringPiece> results = SplitStringPieceUsingSubstr( - "un DELIMITERdeux\tDELIMITERtrois\nDELIMITERquatre", "DELIMITER", - base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); - ASSERT_EQ(4u, results.size()); - EXPECT_THAT(results, ElementsAre("un", "deux", "trois", "quatre")); -} - -TEST(SplitStringPieceUsingSubstrTest, SplitWantAll) { - std::vector<base::StringPiece> results = SplitStringPieceUsingSubstr( - "unDELIMITERdeuxDELIMITERtroisDELIMITERDELIMITER", "DELIMITER", - base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); - ASSERT_EQ(5u, results.size()); - EXPECT_THAT(results, ElementsAre("un", "deux", "trois", "", "")); -} - -TEST(SplitStringPieceUsingSubstrTest, SplitWantNonEmpty) { - std::vector<base::StringPiece> results = SplitStringPieceUsingSubstr( - "unDELIMITERdeuxDELIMITERtroisDELIMITERDELIMITER", "DELIMITER", - base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); - ASSERT_EQ(3u, results.size()); - EXPECT_THAT(results, ElementsAre("un", "deux", "trois")); -} - -TEST(StringSplitTest, StringSplitKeepWhitespace) { - std::vector<std::string> r; - - r = SplitString(" ", "*", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); - ASSERT_EQ(1U, r.size()); - EXPECT_EQ(r[0], " "); - - r = SplitString("\t \ta\t ", "\t", base::KEEP_WHITESPACE, - base::SPLIT_WANT_ALL); - ASSERT_EQ(4U, r.size()); - EXPECT_EQ(r[0], ""); - EXPECT_EQ(r[1], " "); - EXPECT_EQ(r[2], "a"); - EXPECT_EQ(r[3], " "); - - r = SplitString("\ta\t\nb\tcc", "\n", base::KEEP_WHITESPACE, - base::SPLIT_WANT_ALL); - ASSERT_EQ(2U, r.size()); - EXPECT_EQ(r[0], "\ta\t"); - EXPECT_EQ(r[1], "b\tcc"); -} - -TEST(StringSplitTest, SplitStringAlongWhitespace) { - struct TestData { - const char* input; - const size_t expected_result_count; - const char* output1; - const char* output2; - } data[] = { - { "a", 1, "a", "" }, - { " ", 0, "", "" }, - { " a", 1, "a", "" }, - { " ab ", 1, "ab", "" }, - { " ab c", 2, "ab", "c" }, - { " ab c ", 2, "ab", "c" }, - { " ab cd", 2, "ab", "cd" }, - { " ab cd ", 2, "ab", "cd" }, - { " \ta\t", 1, "a", "" }, - { " b\ta\t", 2, "b", "a" }, - { " b\tat", 2, "b", "at" }, - { "b\tat", 2, "b", "at" }, - { "b\t at", 2, "b", "at" }, - }; - for (size_t i = 0; i < arraysize(data); ++i) { - std::vector<std::string> results = base::SplitString( - data[i].input, kWhitespaceASCII, base::KEEP_WHITESPACE, - base::SPLIT_WANT_NONEMPTY); - ASSERT_EQ(data[i].expected_result_count, results.size()); - if (data[i].expected_result_count > 0) - ASSERT_EQ(data[i].output1, results[0]); - if (data[i].expected_result_count > 1) - ASSERT_EQ(data[i].output2, results[1]); - } -} - -} // namespace base
diff --git a/base/strings/string_tokenizer_unittest.cc b/base/strings/string_tokenizer_unittest.cc deleted file mode 100644 index d391845..0000000 --- a/base/strings/string_tokenizer_unittest.cc +++ /dev/null
@@ -1,234 +0,0 @@ -// Copyright (c) 2006-2008 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/strings/string_tokenizer.h" - -#include "testing/gtest/include/gtest/gtest.h" - -using std::string; - -namespace base { - -namespace { - -TEST(StringTokenizerTest, Simple) { - string input = "this is a test"; - StringTokenizer t(input, " "); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("this"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("is"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("a"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("test"), t.token()); - - EXPECT_FALSE(t.GetNext()); -} - -TEST(StringTokenizerTest, Reset) { - string input = "this is a test"; - StringTokenizer t(input, " "); - - for (int i = 0; i < 2; ++i) { - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("this"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("is"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("a"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("test"), t.token()); - - EXPECT_FALSE(t.GetNext()); - t.Reset(); - } -} - -TEST(StringTokenizerTest, RetDelims) { - string input = "this is a test"; - StringTokenizer t(input, " "); - t.set_options(StringTokenizer::RETURN_DELIMS); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("this"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string(" "), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("is"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string(" "), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("a"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string(" "), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("test"), t.token()); - - EXPECT_FALSE(t.GetNext()); -} - -TEST(StringTokenizerTest, ManyDelims) { - string input = "this: is, a-test"; - StringTokenizer t(input, ": ,-"); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("this"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("is"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("a"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("test"), t.token()); - - EXPECT_FALSE(t.GetNext()); -} - -TEST(StringTokenizerTest, ParseHeader) { - string input = "Content-Type: text/html ; charset=UTF-8"; - StringTokenizer t(input, ": ;="); - t.set_options(StringTokenizer::RETURN_DELIMS); - - EXPECT_TRUE(t.GetNext()); - EXPECT_FALSE(t.token_is_delim()); - EXPECT_EQ(string("Content-Type"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_TRUE(t.token_is_delim()); - EXPECT_EQ(string(":"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_TRUE(t.token_is_delim()); - EXPECT_EQ(string(" "), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_FALSE(t.token_is_delim()); - EXPECT_EQ(string("text/html"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_TRUE(t.token_is_delim()); - EXPECT_EQ(string(" "), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_TRUE(t.token_is_delim()); - EXPECT_EQ(string(";"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_TRUE(t.token_is_delim()); - EXPECT_EQ(string(" "), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_FALSE(t.token_is_delim()); - EXPECT_EQ(string("charset"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_TRUE(t.token_is_delim()); - EXPECT_EQ(string("="), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_FALSE(t.token_is_delim()); - EXPECT_EQ(string("UTF-8"), t.token()); - - EXPECT_FALSE(t.GetNext()); - EXPECT_FALSE(t.token_is_delim()); -} - -TEST(StringTokenizerTest, ParseQuotedString) { - string input = "foo bar 'hello world' baz"; - StringTokenizer t(input, " "); - t.set_quote_chars("'"); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("foo"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("bar"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("'hello world'"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("baz"), t.token()); - - EXPECT_FALSE(t.GetNext()); -} - -TEST(StringTokenizerTest, ParseQuotedString_Malformed) { - string input = "bar 'hello wo"; - StringTokenizer t(input, " "); - t.set_quote_chars("'"); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("bar"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("'hello wo"), t.token()); - - EXPECT_FALSE(t.GetNext()); -} - -TEST(StringTokenizerTest, ParseQuotedString_Multiple) { - string input = "bar 'hel\"lo\" wo' baz\""; - StringTokenizer t(input, " "); - t.set_quote_chars("'\""); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("bar"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("'hel\"lo\" wo'"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("baz\""), t.token()); - - EXPECT_FALSE(t.GetNext()); -} - -TEST(StringTokenizerTest, ParseQuotedString_EscapedQuotes) { - string input = "foo 'don\\'t do that'"; - StringTokenizer t(input, " "); - t.set_quote_chars("'"); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("foo"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("'don\\'t do that'"), t.token()); - - EXPECT_FALSE(t.GetNext()); -} - -TEST(StringTokenizerTest, ParseQuotedString_EscapedQuotes2) { - string input = "foo='a, b', bar"; - StringTokenizer t(input, ", "); - t.set_quote_chars("'"); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("foo='a, b'"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("bar"), t.token()); - - EXPECT_FALSE(t.GetNext()); -} - -} // namespace - -} // namespace base
diff --git a/base/strings/string_util_unittest.cc b/base/strings/string_util_unittest.cc deleted file mode 100644 index 509889e..0000000 --- a/base/strings/string_util_unittest.cc +++ /dev/null
@@ -1,1379 +0,0 @@ -// 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/strings/string_util.h" - -#include <math.h> -#include <stdarg.h> -#include <stddef.h> -#include <stdint.h> - -#include <algorithm> - -#include "base/macros.h" -#include "base/strings/string16.h" -#include "base/strings/utf_string_conversions.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using ::testing::ElementsAre; - -namespace base { - -static const struct trim_case { - const wchar_t* input; - const TrimPositions positions; - const wchar_t* output; - const TrimPositions return_value; -} trim_cases[] = { - {L" Google Video ", TRIM_LEADING, L"Google Video ", TRIM_LEADING}, - {L" Google Video ", TRIM_TRAILING, L" Google Video", TRIM_TRAILING}, - {L" Google Video ", TRIM_ALL, L"Google Video", TRIM_ALL}, - {L"Google Video", TRIM_ALL, L"Google Video", TRIM_NONE}, - {L"", TRIM_ALL, L"", TRIM_NONE}, - {L" ", TRIM_LEADING, L"", TRIM_LEADING}, - {L" ", TRIM_TRAILING, L"", TRIM_TRAILING}, - {L" ", TRIM_ALL, L"", TRIM_ALL}, - {L"\t\rTest String\n", TRIM_ALL, L"Test String", TRIM_ALL}, - {L"\x2002Test String\x00A0\x3000", TRIM_ALL, L"Test String", TRIM_ALL}, -}; - -static const struct trim_case_ascii { - const char* input; - const TrimPositions positions; - const char* output; - const TrimPositions return_value; -} trim_cases_ascii[] = { - {" Google Video ", TRIM_LEADING, "Google Video ", TRIM_LEADING}, - {" Google Video ", TRIM_TRAILING, " Google Video", TRIM_TRAILING}, - {" Google Video ", TRIM_ALL, "Google Video", TRIM_ALL}, - {"Google Video", TRIM_ALL, "Google Video", TRIM_NONE}, - {"", TRIM_ALL, "", TRIM_NONE}, - {" ", TRIM_LEADING, "", TRIM_LEADING}, - {" ", TRIM_TRAILING, "", TRIM_TRAILING}, - {" ", TRIM_ALL, "", TRIM_ALL}, - {"\t\rTest String\n", TRIM_ALL, "Test String", TRIM_ALL}, -}; - -namespace { - -// Helper used to test TruncateUTF8ToByteSize. -bool Truncated(const std::string& input, - const size_t byte_size, - std::string* output) { - size_t prev = input.length(); - TruncateUTF8ToByteSize(input, byte_size, output); - return prev != output->length(); -} - -} // namespace - -TEST(StringUtilTest, TruncateUTF8ToByteSize) { - std::string output; - - // Empty strings and invalid byte_size arguments - EXPECT_FALSE(Truncated(std::string(), 0, &output)); - EXPECT_EQ(output, ""); - EXPECT_TRUE(Truncated("\xe1\x80\xbf", 0, &output)); - EXPECT_EQ(output, ""); - EXPECT_FALSE(Truncated("\xe1\x80\xbf", static_cast<size_t>(-1), &output)); - EXPECT_FALSE(Truncated("\xe1\x80\xbf", 4, &output)); - - // Testing the truncation of valid UTF8 correctly - EXPECT_TRUE(Truncated("abc", 2, &output)); - EXPECT_EQ(output, "ab"); - EXPECT_TRUE(Truncated("\xc2\x81\xc2\x81", 2, &output)); - EXPECT_EQ(output.compare("\xc2\x81"), 0); - EXPECT_TRUE(Truncated("\xc2\x81\xc2\x81", 3, &output)); - EXPECT_EQ(output.compare("\xc2\x81"), 0); - EXPECT_FALSE(Truncated("\xc2\x81\xc2\x81", 4, &output)); - EXPECT_EQ(output.compare("\xc2\x81\xc2\x81"), 0); - - { - const char array[] = "\x00\x00\xc2\x81\xc2\x81"; - const std::string array_string(array, arraysize(array)); - EXPECT_TRUE(Truncated(array_string, 4, &output)); - EXPECT_EQ(output.compare(std::string("\x00\x00\xc2\x81", 4)), 0); - } - - { - const char array[] = "\x00\xc2\x81\xc2\x81"; - const std::string array_string(array, arraysize(array)); - EXPECT_TRUE(Truncated(array_string, 4, &output)); - EXPECT_EQ(output.compare(std::string("\x00\xc2\x81", 3)), 0); - } - - // Testing invalid UTF8 - EXPECT_TRUE(Truncated("\xed\xa0\x80\xed\xbf\xbf", 6, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xed\xa0\x8f", 3, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xed\xbf\xbf", 3, &output)); - EXPECT_EQ(output.compare(""), 0); - - // Testing invalid UTF8 mixed with valid UTF8 - EXPECT_FALSE(Truncated("\xe1\x80\xbf", 3, &output)); - EXPECT_EQ(output.compare("\xe1\x80\xbf"), 0); - EXPECT_FALSE(Truncated("\xf1\x80\xa0\xbf", 4, &output)); - EXPECT_EQ(output.compare("\xf1\x80\xa0\xbf"), 0); - EXPECT_FALSE(Truncated("a\xc2\x81\xe1\x80\xbf\xf1\x80\xa0\xbf", - 10, &output)); - EXPECT_EQ(output.compare("a\xc2\x81\xe1\x80\xbf\xf1\x80\xa0\xbf"), 0); - EXPECT_TRUE(Truncated("a\xc2\x81\xe1\x80\xbf\xf1""a""\x80\xa0", - 10, &output)); - EXPECT_EQ(output.compare("a\xc2\x81\xe1\x80\xbf\xf1""a"), 0); - EXPECT_FALSE(Truncated("\xef\xbb\xbf" "abc", 6, &output)); - EXPECT_EQ(output.compare("\xef\xbb\xbf" "abc"), 0); - - // Overlong sequences - EXPECT_TRUE(Truncated("\xc0\x80", 2, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xc1\x80\xc1\x81", 4, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xe0\x80\x80", 3, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xe0\x82\x80", 3, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xe0\x9f\xbf", 3, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xf0\x80\x80\x8D", 4, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xf0\x80\x82\x91", 4, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xf0\x80\xa0\x80", 4, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xf0\x8f\xbb\xbf", 4, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xf8\x80\x80\x80\xbf", 5, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xfc\x80\x80\x80\xa0\xa5", 6, &output)); - EXPECT_EQ(output.compare(""), 0); - - // Beyond U+10FFFF (the upper limit of Unicode codespace) - EXPECT_TRUE(Truncated("\xf4\x90\x80\x80", 4, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xf8\xa0\xbf\x80\xbf", 5, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xfc\x9c\xbf\x80\xbf\x80", 6, &output)); - EXPECT_EQ(output.compare(""), 0); - - // BOMs in UTF-16(BE|LE) and UTF-32(BE|LE) - EXPECT_TRUE(Truncated("\xfe\xff", 2, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xff\xfe", 2, &output)); - EXPECT_EQ(output.compare(""), 0); - - { - const char array[] = "\x00\x00\xfe\xff"; - const std::string array_string(array, arraysize(array)); - EXPECT_TRUE(Truncated(array_string, 4, &output)); - EXPECT_EQ(output.compare(std::string("\x00\x00", 2)), 0); - } - - // Variants on the previous test - { - const char array[] = "\xff\xfe\x00\x00"; - const std::string array_string(array, 4); - EXPECT_FALSE(Truncated(array_string, 4, &output)); - EXPECT_EQ(output.compare(std::string("\xff\xfe\x00\x00", 4)), 0); - } - { - const char array[] = "\xff\x00\x00\xfe"; - const std::string array_string(array, arraysize(array)); - EXPECT_TRUE(Truncated(array_string, 4, &output)); - EXPECT_EQ(output.compare(std::string("\xff\x00\x00", 3)), 0); - } - - // Non-characters : U+xxFFF[EF] where xx is 0x00 through 0x10 and <FDD0,FDEF> - EXPECT_TRUE(Truncated("\xef\xbf\xbe", 3, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xf0\x8f\xbf\xbe", 4, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xf3\xbf\xbf\xbf", 4, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xef\xb7\x90", 3, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xef\xb7\xaf", 3, &output)); - EXPECT_EQ(output.compare(""), 0); - - // Strings in legacy encodings that are valid in UTF-8, but - // are invalid as UTF-8 in real data. - EXPECT_TRUE(Truncated("caf\xe9", 4, &output)); - EXPECT_EQ(output.compare("caf"), 0); - EXPECT_TRUE(Truncated("\xb0\xa1\xb0\xa2", 4, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_FALSE(Truncated("\xa7\x41\xa6\x6e", 4, &output)); - EXPECT_EQ(output.compare("\xa7\x41\xa6\x6e"), 0); - EXPECT_TRUE(Truncated("\xa7\x41\xa6\x6e\xd9\xee\xe4\xee", 7, - &output)); - EXPECT_EQ(output.compare("\xa7\x41\xa6\x6e"), 0); - - // Testing using the same string as input and output. - EXPECT_FALSE(Truncated(output, 4, &output)); - EXPECT_EQ(output.compare("\xa7\x41\xa6\x6e"), 0); - EXPECT_TRUE(Truncated(output, 3, &output)); - EXPECT_EQ(output.compare("\xa7\x41"), 0); - - // "abc" with U+201[CD] in windows-125[0-8] - EXPECT_TRUE(Truncated("\x93" "abc\x94", 5, &output)); - EXPECT_EQ(output.compare("\x93" "abc"), 0); - - // U+0639 U+064E U+0644 U+064E in ISO-8859-6 - EXPECT_TRUE(Truncated("\xd9\xee\xe4\xee", 4, &output)); - EXPECT_EQ(output.compare(""), 0); - - // U+03B3 U+03B5 U+03B9 U+03AC in ISO-8859-7 - EXPECT_TRUE(Truncated("\xe3\xe5\xe9\xdC", 4, &output)); - EXPECT_EQ(output.compare(""), 0); -} - -TEST(StringUtilTest, TrimWhitespace) { - string16 output; // Allow contents to carry over to next testcase - for (size_t i = 0; i < arraysize(trim_cases); ++i) { - const trim_case& value = trim_cases[i]; - EXPECT_EQ(value.return_value, - TrimWhitespace(WideToUTF16(value.input), value.positions, - &output)); - EXPECT_EQ(WideToUTF16(value.output), output); - } - - // Test that TrimWhitespace() can take the same string for input and output - output = ASCIIToUTF16(" This is a test \r\n"); - EXPECT_EQ(TRIM_ALL, TrimWhitespace(output, TRIM_ALL, &output)); - EXPECT_EQ(ASCIIToUTF16("This is a test"), output); - - // Once more, but with a string of whitespace - output = ASCIIToUTF16(" \r\n"); - EXPECT_EQ(TRIM_ALL, TrimWhitespace(output, TRIM_ALL, &output)); - EXPECT_EQ(string16(), output); - - std::string output_ascii; - for (size_t i = 0; i < arraysize(trim_cases_ascii); ++i) { - const trim_case_ascii& value = trim_cases_ascii[i]; - EXPECT_EQ(value.return_value, - TrimWhitespaceASCII(value.input, value.positions, &output_ascii)); - EXPECT_EQ(value.output, output_ascii); - } -} - -static const struct collapse_case { - const wchar_t* input; - const bool trim; - const wchar_t* output; -} collapse_cases[] = { - {L" Google Video ", false, L"Google Video"}, - {L"Google Video", false, L"Google Video"}, - {L"", false, L""}, - {L" ", false, L""}, - {L"\t\rTest String\n", false, L"Test String"}, - {L"\x2002Test String\x00A0\x3000", false, L"Test String"}, - {L" Test \n \t String ", false, L"Test String"}, - {L"\x2002Test\x1680 \x2028 \tString\x00A0\x3000", false, L"Test String"}, - {L" Test String", false, L"Test String"}, - {L"Test String ", false, L"Test String"}, - {L"Test String", false, L"Test String"}, - {L"", true, L""}, - {L"\n", true, L""}, - {L" \r ", true, L""}, - {L"\nFoo", true, L"Foo"}, - {L"\r Foo ", true, L"Foo"}, - {L" Foo bar ", true, L"Foo bar"}, - {L" \tFoo bar \n", true, L"Foo bar"}, - {L" a \r b\n c \r\n d \t\re \t f \n ", true, L"abcde f"}, -}; - -TEST(StringUtilTest, CollapseWhitespace) { - for (size_t i = 0; i < arraysize(collapse_cases); ++i) { - const collapse_case& value = collapse_cases[i]; - EXPECT_EQ(WideToUTF16(value.output), - CollapseWhitespace(WideToUTF16(value.input), value.trim)); - } -} - -static const struct collapse_case_ascii { - const char* input; - const bool trim; - const char* output; -} collapse_cases_ascii[] = { - {" Google Video ", false, "Google Video"}, - {"Google Video", false, "Google Video"}, - {"", false, ""}, - {" ", false, ""}, - {"\t\rTest String\n", false, "Test String"}, - {" Test \n \t String ", false, "Test String"}, - {" Test String", false, "Test String"}, - {"Test String ", false, "Test String"}, - {"Test String", false, "Test String"}, - {"", true, ""}, - {"\n", true, ""}, - {" \r ", true, ""}, - {"\nFoo", true, "Foo"}, - {"\r Foo ", true, "Foo"}, - {" Foo bar ", true, "Foo bar"}, - {" \tFoo bar \n", true, "Foo bar"}, - {" a \r b\n c \r\n d \t\re \t f \n ", true, "abcde f"}, -}; - -TEST(StringUtilTest, CollapseWhitespaceASCII) { - for (size_t i = 0; i < arraysize(collapse_cases_ascii); ++i) { - const collapse_case_ascii& value = collapse_cases_ascii[i]; - EXPECT_EQ(value.output, CollapseWhitespaceASCII(value.input, value.trim)); - } -} - -TEST(StringUtilTest, IsStringUTF8) { - EXPECT_TRUE(IsStringUTF8("abc")); - EXPECT_TRUE(IsStringUTF8("\xc2\x81")); - EXPECT_TRUE(IsStringUTF8("\xe1\x80\xbf")); - EXPECT_TRUE(IsStringUTF8("\xf1\x80\xa0\xbf")); - EXPECT_TRUE(IsStringUTF8("a\xc2\x81\xe1\x80\xbf\xf1\x80\xa0\xbf")); - EXPECT_TRUE(IsStringUTF8("\xef\xbb\xbf" "abc")); // UTF-8 BOM - - // surrogate code points - EXPECT_FALSE(IsStringUTF8("\xed\xa0\x80\xed\xbf\xbf")); - EXPECT_FALSE(IsStringUTF8("\xed\xa0\x8f")); - EXPECT_FALSE(IsStringUTF8("\xed\xbf\xbf")); - - // overlong sequences - EXPECT_FALSE(IsStringUTF8("\xc0\x80")); // U+0000 - EXPECT_FALSE(IsStringUTF8("\xc1\x80\xc1\x81")); // "AB" - EXPECT_FALSE(IsStringUTF8("\xe0\x80\x80")); // U+0000 - EXPECT_FALSE(IsStringUTF8("\xe0\x82\x80")); // U+0080 - EXPECT_FALSE(IsStringUTF8("\xe0\x9f\xbf")); // U+07ff - EXPECT_FALSE(IsStringUTF8("\xf0\x80\x80\x8D")); // U+000D - EXPECT_FALSE(IsStringUTF8("\xf0\x80\x82\x91")); // U+0091 - EXPECT_FALSE(IsStringUTF8("\xf0\x80\xa0\x80")); // U+0800 - EXPECT_FALSE(IsStringUTF8("\xf0\x8f\xbb\xbf")); // U+FEFF (BOM) - EXPECT_FALSE(IsStringUTF8("\xf8\x80\x80\x80\xbf")); // U+003F - EXPECT_FALSE(IsStringUTF8("\xfc\x80\x80\x80\xa0\xa5")); // U+00A5 - - // Beyond U+10FFFF (the upper limit of Unicode codespace) - EXPECT_FALSE(IsStringUTF8("\xf4\x90\x80\x80")); // U+110000 - EXPECT_FALSE(IsStringUTF8("\xf8\xa0\xbf\x80\xbf")); // 5 bytes - EXPECT_FALSE(IsStringUTF8("\xfc\x9c\xbf\x80\xbf\x80")); // 6 bytes - - // BOMs in UTF-16(BE|LE) and UTF-32(BE|LE) - EXPECT_FALSE(IsStringUTF8("\xfe\xff")); - EXPECT_FALSE(IsStringUTF8("\xff\xfe")); - EXPECT_FALSE(IsStringUTF8(std::string("\x00\x00\xfe\xff", 4))); - EXPECT_FALSE(IsStringUTF8("\xff\xfe\x00\x00")); - - // Non-characters : U+xxFFF[EF] where xx is 0x00 through 0x10 and <FDD0,FDEF> - EXPECT_FALSE(IsStringUTF8("\xef\xbf\xbe")); // U+FFFE) - EXPECT_FALSE(IsStringUTF8("\xf0\x8f\xbf\xbe")); // U+1FFFE - EXPECT_FALSE(IsStringUTF8("\xf3\xbf\xbf\xbf")); // U+10FFFF - EXPECT_FALSE(IsStringUTF8("\xef\xb7\x90")); // U+FDD0 - EXPECT_FALSE(IsStringUTF8("\xef\xb7\xaf")); // U+FDEF - // Strings in legacy encodings. We can certainly make up strings - // in a legacy encoding that are valid in UTF-8, but in real data, - // most of them are invalid as UTF-8. - EXPECT_FALSE(IsStringUTF8("caf\xe9")); // cafe with U+00E9 in ISO-8859-1 - EXPECT_FALSE(IsStringUTF8("\xb0\xa1\xb0\xa2")); // U+AC00, U+AC001 in EUC-KR - EXPECT_FALSE(IsStringUTF8("\xa7\x41\xa6\x6e")); // U+4F60 U+597D in Big5 - // "abc" with U+201[CD] in windows-125[0-8] - EXPECT_FALSE(IsStringUTF8("\x93" "abc\x94")); - // U+0639 U+064E U+0644 U+064E in ISO-8859-6 - EXPECT_FALSE(IsStringUTF8("\xd9\xee\xe4\xee")); - // U+03B3 U+03B5 U+03B9 U+03AC in ISO-8859-7 - EXPECT_FALSE(IsStringUTF8("\xe3\xe5\xe9\xdC")); - - // Check that we support Embedded Nulls. The first uses the canonical UTF-8 - // representation, and the second uses a 2-byte sequence. The second version - // is invalid UTF-8 since UTF-8 states that the shortest encoding for a - // given codepoint must be used. - static const char kEmbeddedNull[] = "embedded\0null"; - EXPECT_TRUE(IsStringUTF8( - std::string(kEmbeddedNull, sizeof(kEmbeddedNull)))); - EXPECT_FALSE(IsStringUTF8("embedded\xc0\x80U+0000")); -} - -TEST(StringUtilTest, IsStringASCII) { - static char char_ascii[] = - "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF"; - static char16 char16_ascii[] = { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'A', - 'B', 'C', 'D', 'E', 'F', '0', '1', '2', '3', '4', '5', '6', - '7', '8', '9', '0', 'A', 'B', 'C', 'D', 'E', 'F', 0 }; - static std::wstring wchar_ascii( - L"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF"); - - // Test a variety of the fragment start positions and lengths in order to make - // sure that bit masking in IsStringASCII works correctly. - // Also, test that a non-ASCII character will be detected regardless of its - // position inside the string. - { - const size_t string_length = arraysize(char_ascii) - 1; - for (size_t offset = 0; offset < 8; ++offset) { - for (size_t len = 0, max_len = string_length - offset; len < max_len; - ++len) { - EXPECT_TRUE(IsStringASCII(StringPiece(char_ascii + offset, len))); - for (size_t char_pos = offset; char_pos < len; ++char_pos) { - char_ascii[char_pos] |= '\x80'; - EXPECT_FALSE(IsStringASCII(StringPiece(char_ascii + offset, len))); - char_ascii[char_pos] &= ~'\x80'; - } - } - } - } - - { - const size_t string_length = arraysize(char16_ascii) - 1; - for (size_t offset = 0; offset < 4; ++offset) { - for (size_t len = 0, max_len = string_length - offset; len < max_len; - ++len) { - EXPECT_TRUE(IsStringASCII(StringPiece16(char16_ascii + offset, len))); - for (size_t char_pos = offset; char_pos < len; ++char_pos) { - char16_ascii[char_pos] |= 0x80; - EXPECT_FALSE( - IsStringASCII(StringPiece16(char16_ascii + offset, len))); - char16_ascii[char_pos] &= ~0x80; - // Also test when the upper half is non-zero. - char16_ascii[char_pos] |= 0x100; - EXPECT_FALSE( - IsStringASCII(StringPiece16(char16_ascii + offset, len))); - char16_ascii[char_pos] &= ~0x100; - } - } - } - } - - { - const size_t string_length = wchar_ascii.length(); - for (size_t len = 0; len < string_length; ++len) { - EXPECT_TRUE(IsStringASCII(wchar_ascii.substr(0, len))); - for (size_t char_pos = 0; char_pos < len; ++char_pos) { - wchar_ascii[char_pos] |= 0x80; - EXPECT_FALSE( - IsStringASCII(wchar_ascii.substr(0, len))); - wchar_ascii[char_pos] &= ~0x80; - wchar_ascii[char_pos] |= 0x100; - EXPECT_FALSE( - IsStringASCII(wchar_ascii.substr(0, len))); - wchar_ascii[char_pos] &= ~0x100; -#if defined(WCHAR_T_IS_UTF32) - wchar_ascii[char_pos] |= 0x10000; - EXPECT_FALSE( - IsStringASCII(wchar_ascii.substr(0, len))); - wchar_ascii[char_pos] &= ~0x10000; -#endif // WCHAR_T_IS_UTF32 - } - } - } -} - -TEST(StringUtilTest, ConvertASCII) { - static const char* const char_cases[] = { - "Google Video", - "Hello, world\n", - "0123ABCDwxyz \a\b\t\r\n!+,.~" - }; - - static const wchar_t* const wchar_cases[] = { - L"Google Video", - L"Hello, world\n", - L"0123ABCDwxyz \a\b\t\r\n!+,.~" - }; - - for (size_t i = 0; i < arraysize(char_cases); ++i) { - EXPECT_TRUE(IsStringASCII(char_cases[i])); - string16 utf16 = ASCIIToUTF16(char_cases[i]); - EXPECT_EQ(WideToUTF16(wchar_cases[i]), utf16); - - std::string ascii = UTF16ToASCII(WideToUTF16(wchar_cases[i])); - EXPECT_EQ(char_cases[i], ascii); - } - - EXPECT_FALSE(IsStringASCII("Google \x80Video")); - - // Convert empty strings. - string16 empty16; - std::string empty; - EXPECT_EQ(empty, UTF16ToASCII(empty16)); - EXPECT_EQ(empty16, ASCIIToUTF16(empty)); - - // Convert strings with an embedded NUL character. - const char chars_with_nul[] = "test\0string"; - const int length_with_nul = arraysize(chars_with_nul) - 1; - std::string string_with_nul(chars_with_nul, length_with_nul); - string16 string16_with_nul = ASCIIToUTF16(string_with_nul); - EXPECT_EQ(static_cast<string16::size_type>(length_with_nul), - string16_with_nul.length()); - std::string narrow_with_nul = UTF16ToASCII(string16_with_nul); - EXPECT_EQ(static_cast<std::string::size_type>(length_with_nul), - narrow_with_nul.length()); - EXPECT_EQ(0, string_with_nul.compare(narrow_with_nul)); -} - -TEST(StringUtilTest, ToLowerASCII) { - EXPECT_EQ('c', ToLowerASCII('C')); - EXPECT_EQ('c', ToLowerASCII('c')); - EXPECT_EQ('2', ToLowerASCII('2')); - - EXPECT_EQ(static_cast<char16>('c'), ToLowerASCII(static_cast<char16>('C'))); - EXPECT_EQ(static_cast<char16>('c'), ToLowerASCII(static_cast<char16>('c'))); - EXPECT_EQ(static_cast<char16>('2'), ToLowerASCII(static_cast<char16>('2'))); - - EXPECT_EQ("cc2", ToLowerASCII("Cc2")); - EXPECT_EQ(ASCIIToUTF16("cc2"), ToLowerASCII(ASCIIToUTF16("Cc2"))); -} - -TEST(StringUtilTest, ToUpperASCII) { - EXPECT_EQ('C', ToUpperASCII('C')); - EXPECT_EQ('C', ToUpperASCII('c')); - EXPECT_EQ('2', ToUpperASCII('2')); - - EXPECT_EQ(static_cast<char16>('C'), ToUpperASCII(static_cast<char16>('C'))); - EXPECT_EQ(static_cast<char16>('C'), ToUpperASCII(static_cast<char16>('c'))); - EXPECT_EQ(static_cast<char16>('2'), ToUpperASCII(static_cast<char16>('2'))); - - EXPECT_EQ("CC2", ToUpperASCII("Cc2")); - EXPECT_EQ(ASCIIToUTF16("CC2"), ToUpperASCII(ASCIIToUTF16("Cc2"))); -} - -TEST(StringUtilTest, LowerCaseEqualsASCII) { - static const struct { - const char* src_a; - const char* dst; - } lowercase_cases[] = { - { "FoO", "foo" }, - { "foo", "foo" }, - { "FOO", "foo" }, - }; - - for (size_t i = 0; i < arraysize(lowercase_cases); ++i) { - EXPECT_TRUE(LowerCaseEqualsASCII(ASCIIToUTF16(lowercase_cases[i].src_a), - lowercase_cases[i].dst)); - EXPECT_TRUE(LowerCaseEqualsASCII(lowercase_cases[i].src_a, - lowercase_cases[i].dst)); - } -} - -TEST(StringUtilTest, FormatBytesUnlocalized) { - static const struct { - int64_t bytes; - const char* expected; - } cases[] = { - // Expected behavior: we show one post-decimal digit when we have - // under two pre-decimal digits, except in cases where it makes no - // sense (zero or bytes). - // Since we switch units once we cross the 1000 mark, this keeps - // the display of file sizes or bytes consistently around three - // digits. - {0, "0 B"}, - {512, "512 B"}, - {1024*1024, "1.0 MB"}, - {1024*1024*1024, "1.0 GB"}, - {10LL*1024*1024*1024, "10.0 GB"}, - {99LL*1024*1024*1024, "99.0 GB"}, - {105LL*1024*1024*1024, "105 GB"}, - {105LL*1024*1024*1024 + 500LL*1024*1024, "105 GB"}, - {~(1LL << 63), "8192 PB"}, - - {99*1024 + 103, "99.1 kB"}, - {1024*1024 + 103, "1.0 MB"}, - {1024*1024 + 205 * 1024, "1.2 MB"}, - {1024*1024*1024 + (927 * 1024*1024), "1.9 GB"}, - {10LL*1024*1024*1024, "10.0 GB"}, - {100LL*1024*1024*1024, "100 GB"}, - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - EXPECT_EQ(ASCIIToUTF16(cases[i].expected), - FormatBytesUnlocalized(cases[i].bytes)); - } -} -TEST(StringUtilTest, ReplaceSubstringsAfterOffset) { - static const struct { - StringPiece str; - size_t start_offset; - StringPiece find_this; - StringPiece replace_with; - StringPiece expected; - } cases[] = { - {"aaa", 0, "", "b", "aaa"}, - {"aaa", 1, "", "b", "aaa"}, - {"aaa", 0, "a", "b", "bbb"}, - {"aaa", 0, "aa", "b", "ba"}, - {"aaa", 0, "aa", "bbb", "bbba"}, - {"aaaaa", 0, "aa", "b", "bba"}, - {"ababaaababa", 0, "aba", "", "baaba"}, - {"ababaaababa", 0, "aba", "_", "_baa_ba"}, - {"ababaaababa", 0, "aba", "__", "__baa__ba"}, - {"ababaaababa", 0, "aba", "___", "___baa___ba"}, - {"ababaaababa", 0, "aba", "____", "____baa____ba"}, - {"ababaaababa", 0, "aba", "_____", "_____baa_____ba"}, - {"abb", 0, "ab", "a", "ab"}, - {"Removing some substrings inging", 0, "ing", "", "Remov some substrs "}, - {"Not found", 0, "x", "0", "Not found"}, - {"Not found again", 5, "x", "0", "Not found again"}, - {" Making it much longer ", 0, " ", "Four score and seven years ago", - "Four score and seven years agoMakingFour score and seven years agoit" - "Four score and seven years agomuchFour score and seven years agolonger" - "Four score and seven years ago"}, - {" Making it much much much much shorter ", 0, - "Making it much much much much shorter", "", " "}, - {"so much much much much much very much much much shorter", 0, "much ", - "", "so very shorter"}, - {"Invalid offset", 9999, "t", "foobar", "Invalid offset"}, - {"Replace me only me once", 9, "me ", "", "Replace me only once"}, - {"abababab", 2, "ab", "c", "abccc"}, - {"abababab", 1, "ab", "c", "abccc"}, - {"abababab", 1, "aba", "c", "abcbab"}, - }; - - // base::string16 variant - for (const auto& scenario : cases) { - string16 str = ASCIIToUTF16(scenario.str); - ReplaceSubstringsAfterOffset(&str, scenario.start_offset, - ASCIIToUTF16(scenario.find_this), - ASCIIToUTF16(scenario.replace_with)); - EXPECT_EQ(ASCIIToUTF16(scenario.expected), str); - } - - // std::string with insufficient capacity: expansion must realloc the buffer. - for (const auto& scenario : cases) { - std::string str = scenario.str.as_string(); - str.shrink_to_fit(); // This is nonbinding, but it's the best we've got. - ReplaceSubstringsAfterOffset(&str, scenario.start_offset, - scenario.find_this, scenario.replace_with); - EXPECT_EQ(scenario.expected, str); - } - - // std::string with ample capacity: should be possible to grow in-place. - for (const auto& scenario : cases) { - std::string str = scenario.str.as_string(); - str.reserve(std::max(scenario.str.length(), scenario.expected.length()) * - 2); - - ReplaceSubstringsAfterOffset(&str, scenario.start_offset, - scenario.find_this, scenario.replace_with); - EXPECT_EQ(scenario.expected, str); - } -} - -TEST(StringUtilTest, ReplaceFirstSubstringAfterOffset) { - static const struct { - const char* str; - string16::size_type start_offset; - const char* find_this; - const char* replace_with; - const char* expected; - } cases[] = { - {"aaa", 0, "a", "b", "baa"}, - {"abb", 0, "ab", "a", "ab"}, - {"Removing some substrings inging", 0, "ing", "", - "Remov some substrings inging"}, - {"Not found", 0, "x", "0", "Not found"}, - {"Not found again", 5, "x", "0", "Not found again"}, - {" Making it much longer ", 0, " ", "Four score and seven years ago", - "Four score and seven years agoMaking it much longer "}, - {"Invalid offset", 9999, "t", "foobar", "Invalid offset"}, - {"Replace me only me once", 4, "me ", "", "Replace only me once"}, - {"abababab", 2, "ab", "c", "abcabab"}, - }; - - for (size_t i = 0; i < arraysize(cases); i++) { - string16 str = ASCIIToUTF16(cases[i].str); - ReplaceFirstSubstringAfterOffset(&str, cases[i].start_offset, - ASCIIToUTF16(cases[i].find_this), - ASCIIToUTF16(cases[i].replace_with)); - EXPECT_EQ(ASCIIToUTF16(cases[i].expected), str); - } -} - -TEST(StringUtilTest, HexDigitToInt) { - EXPECT_EQ(0, HexDigitToInt('0')); - EXPECT_EQ(1, HexDigitToInt('1')); - EXPECT_EQ(2, HexDigitToInt('2')); - EXPECT_EQ(3, HexDigitToInt('3')); - EXPECT_EQ(4, HexDigitToInt('4')); - EXPECT_EQ(5, HexDigitToInt('5')); - EXPECT_EQ(6, HexDigitToInt('6')); - EXPECT_EQ(7, HexDigitToInt('7')); - EXPECT_EQ(8, HexDigitToInt('8')); - EXPECT_EQ(9, HexDigitToInt('9')); - EXPECT_EQ(10, HexDigitToInt('A')); - EXPECT_EQ(11, HexDigitToInt('B')); - EXPECT_EQ(12, HexDigitToInt('C')); - EXPECT_EQ(13, HexDigitToInt('D')); - EXPECT_EQ(14, HexDigitToInt('E')); - EXPECT_EQ(15, HexDigitToInt('F')); - - // Verify the lower case as well. - EXPECT_EQ(10, HexDigitToInt('a')); - EXPECT_EQ(11, HexDigitToInt('b')); - EXPECT_EQ(12, HexDigitToInt('c')); - EXPECT_EQ(13, HexDigitToInt('d')); - EXPECT_EQ(14, HexDigitToInt('e')); - EXPECT_EQ(15, HexDigitToInt('f')); -} - -TEST(StringUtilTest, JoinString) { - std::string separator(", "); - std::vector<std::string> parts; - EXPECT_EQ(std::string(), JoinString(parts, separator)); - - parts.push_back(std::string()); - EXPECT_EQ(std::string(), JoinString(parts, separator)); - parts.clear(); - - parts.push_back("a"); - EXPECT_EQ("a", JoinString(parts, separator)); - - parts.push_back("b"); - parts.push_back("c"); - EXPECT_EQ("a, b, c", JoinString(parts, separator)); - - parts.push_back(std::string()); - EXPECT_EQ("a, b, c, ", JoinString(parts, separator)); - parts.push_back(" "); - EXPECT_EQ("a|b|c|| ", JoinString(parts, "|")); -} - -TEST(StringUtilTest, JoinString16) { - string16 separator = ASCIIToUTF16(", "); - std::vector<string16> parts; - EXPECT_EQ(string16(), JoinString(parts, separator)); - - parts.push_back(string16()); - EXPECT_EQ(string16(), JoinString(parts, separator)); - parts.clear(); - - parts.push_back(ASCIIToUTF16("a")); - EXPECT_EQ(ASCIIToUTF16("a"), JoinString(parts, separator)); - - parts.push_back(ASCIIToUTF16("b")); - parts.push_back(ASCIIToUTF16("c")); - EXPECT_EQ(ASCIIToUTF16("a, b, c"), JoinString(parts, separator)); - - parts.push_back(ASCIIToUTF16("")); - EXPECT_EQ(ASCIIToUTF16("a, b, c, "), JoinString(parts, separator)); - parts.push_back(ASCIIToUTF16(" ")); - EXPECT_EQ(ASCIIToUTF16("a|b|c|| "), JoinString(parts, ASCIIToUTF16("|"))); -} - -TEST(StringUtilTest, JoinStringPiece) { - std::string separator(", "); - std::vector<StringPiece> parts; - EXPECT_EQ(std::string(), JoinString(parts, separator)); - - // Test empty first part (https://crbug.com/698073). - parts.push_back(StringPiece()); - EXPECT_EQ(std::string(), JoinString(parts, separator)); - parts.clear(); - - parts.push_back("a"); - EXPECT_EQ("a", JoinString(parts, separator)); - - parts.push_back("b"); - parts.push_back("c"); - EXPECT_EQ("a, b, c", JoinString(parts, separator)); - - parts.push_back(StringPiece()); - EXPECT_EQ("a, b, c, ", JoinString(parts, separator)); - parts.push_back(" "); - EXPECT_EQ("a|b|c|| ", JoinString(parts, "|")); -} - -TEST(StringUtilTest, JoinStringPiece16) { - string16 separator = ASCIIToUTF16(", "); - std::vector<StringPiece16> parts; - EXPECT_EQ(string16(), JoinString(parts, separator)); - - // Test empty first part (https://crbug.com/698073). - parts.push_back(StringPiece16()); - EXPECT_EQ(string16(), JoinString(parts, separator)); - parts.clear(); - - const string16 kA = ASCIIToUTF16("a"); - parts.push_back(kA); - EXPECT_EQ(ASCIIToUTF16("a"), JoinString(parts, separator)); - - const string16 kB = ASCIIToUTF16("b"); - parts.push_back(kB); - const string16 kC = ASCIIToUTF16("c"); - parts.push_back(kC); - EXPECT_EQ(ASCIIToUTF16("a, b, c"), JoinString(parts, separator)); - - parts.push_back(StringPiece16()); - EXPECT_EQ(ASCIIToUTF16("a, b, c, "), JoinString(parts, separator)); - const string16 kSpace = ASCIIToUTF16(" "); - parts.push_back(kSpace); - EXPECT_EQ(ASCIIToUTF16("a|b|c|| "), JoinString(parts, ASCIIToUTF16("|"))); -} - -TEST(StringUtilTest, JoinStringInitializerList) { - std::string separator(", "); - EXPECT_EQ(std::string(), JoinString({}, separator)); - - // Test empty first part (https://crbug.com/698073). - EXPECT_EQ(std::string(), JoinString({StringPiece()}, separator)); - - // With const char*s. - EXPECT_EQ("a", JoinString({"a"}, separator)); - EXPECT_EQ("a, b, c", JoinString({"a", "b", "c"}, separator)); - EXPECT_EQ("a, b, c, ", JoinString({"a", "b", "c", StringPiece()}, separator)); - EXPECT_EQ("a|b|c|| ", JoinString({"a", "b", "c", StringPiece(), " "}, "|")); - - // With std::strings. - const std::string kA = "a"; - const std::string kB = "b"; - EXPECT_EQ("a, b", JoinString({kA, kB}, separator)); - - // With StringPieces. - const StringPiece kPieceA = kA; - const StringPiece kPieceB = kB; - EXPECT_EQ("a, b", JoinString({kPieceA, kPieceB}, separator)); -} - -TEST(StringUtilTest, JoinStringInitializerList16) { - string16 separator = ASCIIToUTF16(", "); - EXPECT_EQ(string16(), JoinString({}, separator)); - - // Test empty first part (https://crbug.com/698073). - EXPECT_EQ(string16(), JoinString({StringPiece16()}, separator)); - - // With string16s. - const string16 kA = ASCIIToUTF16("a"); - EXPECT_EQ(ASCIIToUTF16("a"), JoinString({kA}, separator)); - - const string16 kB = ASCIIToUTF16("b"); - const string16 kC = ASCIIToUTF16("c"); - EXPECT_EQ(ASCIIToUTF16("a, b, c"), JoinString({kA, kB, kC}, separator)); - - EXPECT_EQ(ASCIIToUTF16("a, b, c, "), - JoinString({kA, kB, kC, StringPiece16()}, separator)); - const string16 kSpace = ASCIIToUTF16(" "); - EXPECT_EQ( - ASCIIToUTF16("a|b|c|| "), - JoinString({kA, kB, kC, StringPiece16(), kSpace}, ASCIIToUTF16("|"))); - - // With StringPiece16s. - const StringPiece16 kPieceA = kA; - const StringPiece16 kPieceB = kB; - EXPECT_EQ(ASCIIToUTF16("a, b"), JoinString({kPieceA, kPieceB}, separator)); -} - -TEST(StringUtilTest, StartsWith) { - EXPECT_TRUE(StartsWith("javascript:url", "javascript", - base::CompareCase::SENSITIVE)); - EXPECT_FALSE(StartsWith("JavaScript:url", "javascript", - base::CompareCase::SENSITIVE)); - EXPECT_TRUE(StartsWith("javascript:url", "javascript", - base::CompareCase::INSENSITIVE_ASCII)); - EXPECT_TRUE(StartsWith("JavaScript:url", "javascript", - base::CompareCase::INSENSITIVE_ASCII)); - EXPECT_FALSE(StartsWith("java", "javascript", base::CompareCase::SENSITIVE)); - EXPECT_FALSE(StartsWith("java", "javascript", - base::CompareCase::INSENSITIVE_ASCII)); - EXPECT_FALSE(StartsWith(std::string(), "javascript", - base::CompareCase::INSENSITIVE_ASCII)); - EXPECT_FALSE(StartsWith(std::string(), "javascript", - base::CompareCase::SENSITIVE)); - EXPECT_TRUE(StartsWith("java", std::string(), - base::CompareCase::INSENSITIVE_ASCII)); - EXPECT_TRUE(StartsWith("java", std::string(), base::CompareCase::SENSITIVE)); - - EXPECT_TRUE(StartsWith(ASCIIToUTF16("javascript:url"), - ASCIIToUTF16("javascript"), - base::CompareCase::SENSITIVE)); - EXPECT_FALSE(StartsWith(ASCIIToUTF16("JavaScript:url"), - ASCIIToUTF16("javascript"), - base::CompareCase::SENSITIVE)); - EXPECT_TRUE(StartsWith(ASCIIToUTF16("javascript:url"), - ASCIIToUTF16("javascript"), - base::CompareCase::INSENSITIVE_ASCII)); - EXPECT_TRUE(StartsWith(ASCIIToUTF16("JavaScript:url"), - ASCIIToUTF16("javascript"), - base::CompareCase::INSENSITIVE_ASCII)); - EXPECT_FALSE(StartsWith(ASCIIToUTF16("java"), ASCIIToUTF16("javascript"), - base::CompareCase::SENSITIVE)); - EXPECT_FALSE(StartsWith(ASCIIToUTF16("java"), ASCIIToUTF16("javascript"), - base::CompareCase::INSENSITIVE_ASCII)); - EXPECT_FALSE(StartsWith(string16(), ASCIIToUTF16("javascript"), - base::CompareCase::INSENSITIVE_ASCII)); - EXPECT_FALSE(StartsWith(string16(), ASCIIToUTF16("javascript"), - base::CompareCase::SENSITIVE)); - EXPECT_TRUE(StartsWith(ASCIIToUTF16("java"), string16(), - base::CompareCase::INSENSITIVE_ASCII)); - EXPECT_TRUE(StartsWith(ASCIIToUTF16("java"), string16(), - base::CompareCase::SENSITIVE)); -} - -TEST(StringUtilTest, EndsWith) { - EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"), ASCIIToUTF16(".plugin"), - base::CompareCase::SENSITIVE)); - EXPECT_FALSE(EndsWith(ASCIIToUTF16("Foo.Plugin"), ASCIIToUTF16(".plugin"), - base::CompareCase::SENSITIVE)); - EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"), ASCIIToUTF16(".plugin"), - base::CompareCase::INSENSITIVE_ASCII)); - EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.Plugin"), ASCIIToUTF16(".plugin"), - base::CompareCase::INSENSITIVE_ASCII)); - EXPECT_FALSE(EndsWith(ASCIIToUTF16(".plug"), ASCIIToUTF16(".plugin"), - base::CompareCase::SENSITIVE)); - EXPECT_FALSE(EndsWith(ASCIIToUTF16(".plug"), ASCIIToUTF16(".plugin"), - base::CompareCase::INSENSITIVE_ASCII)); - EXPECT_FALSE(EndsWith(ASCIIToUTF16("Foo.plugin Bar"), ASCIIToUTF16(".plugin"), - base::CompareCase::SENSITIVE)); - EXPECT_FALSE(EndsWith(ASCIIToUTF16("Foo.plugin Bar"), ASCIIToUTF16(".plugin"), - base::CompareCase::INSENSITIVE_ASCII)); - EXPECT_FALSE(EndsWith(string16(), ASCIIToUTF16(".plugin"), - base::CompareCase::INSENSITIVE_ASCII)); - EXPECT_FALSE(EndsWith(string16(), ASCIIToUTF16(".plugin"), - base::CompareCase::SENSITIVE)); - EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"), string16(), - base::CompareCase::INSENSITIVE_ASCII)); - EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"), string16(), - base::CompareCase::SENSITIVE)); - EXPECT_TRUE(EndsWith(ASCIIToUTF16(".plugin"), ASCIIToUTF16(".plugin"), - base::CompareCase::INSENSITIVE_ASCII)); - EXPECT_TRUE(EndsWith(ASCIIToUTF16(".plugin"), ASCIIToUTF16(".plugin"), - base::CompareCase::SENSITIVE)); - EXPECT_TRUE( - EndsWith(string16(), string16(), base::CompareCase::INSENSITIVE_ASCII)); - EXPECT_TRUE(EndsWith(string16(), string16(), base::CompareCase::SENSITIVE)); -} - -TEST(StringUtilTest, GetStringFWithOffsets) { - std::vector<string16> subst; - subst.push_back(ASCIIToUTF16("1")); - subst.push_back(ASCIIToUTF16("2")); - std::vector<size_t> offsets; - - ReplaceStringPlaceholders(ASCIIToUTF16("Hello, $1. Your number is $2."), - subst, - &offsets); - EXPECT_EQ(2U, offsets.size()); - EXPECT_EQ(7U, offsets[0]); - EXPECT_EQ(25U, offsets[1]); - offsets.clear(); - - ReplaceStringPlaceholders(ASCIIToUTF16("Hello, $2. Your number is $1."), - subst, - &offsets); - EXPECT_EQ(2U, offsets.size()); - EXPECT_EQ(25U, offsets[0]); - EXPECT_EQ(7U, offsets[1]); - offsets.clear(); -} - -TEST(StringUtilTest, ReplaceStringPlaceholdersTooFew) { - // Test whether replacestringplaceholders works as expected when there - // are fewer inputs than outputs. - std::vector<string16> subst; - subst.push_back(ASCIIToUTF16("9a")); - subst.push_back(ASCIIToUTF16("8b")); - subst.push_back(ASCIIToUTF16("7c")); - - string16 formatted = - ReplaceStringPlaceholders( - ASCIIToUTF16("$1a,$2b,$3c,$4d,$5e,$6f,$1g,$2h,$3i"), subst, nullptr); - - EXPECT_EQ(ASCIIToUTF16("9aa,8bb,7cc,d,e,f,9ag,8bh,7ci"), formatted); -} - -TEST(StringUtilTest, ReplaceStringPlaceholders) { - std::vector<string16> subst; - subst.push_back(ASCIIToUTF16("9a")); - subst.push_back(ASCIIToUTF16("8b")); - subst.push_back(ASCIIToUTF16("7c")); - subst.push_back(ASCIIToUTF16("6d")); - subst.push_back(ASCIIToUTF16("5e")); - subst.push_back(ASCIIToUTF16("4f")); - subst.push_back(ASCIIToUTF16("3g")); - subst.push_back(ASCIIToUTF16("2h")); - subst.push_back(ASCIIToUTF16("1i")); - - string16 formatted = - ReplaceStringPlaceholders( - ASCIIToUTF16("$1a,$2b,$3c,$4d,$5e,$6f,$7g,$8h,$9i"), subst, nullptr); - - EXPECT_EQ(ASCIIToUTF16("9aa,8bb,7cc,6dd,5ee,4ff,3gg,2hh,1ii"), formatted); -} - -TEST(StringUtilTest, ReplaceStringPlaceholdersNetExpansionWithContraction) { - // In this test, some of the substitutions are shorter than the placeholders, - // but overall the string gets longer. - std::vector<string16> subst; - subst.push_back(ASCIIToUTF16("9a____")); - subst.push_back(ASCIIToUTF16("B")); - subst.push_back(ASCIIToUTF16("7c___")); - subst.push_back(ASCIIToUTF16("d")); - subst.push_back(ASCIIToUTF16("5e____")); - subst.push_back(ASCIIToUTF16("F")); - subst.push_back(ASCIIToUTF16("3g___")); - subst.push_back(ASCIIToUTF16("h")); - subst.push_back(ASCIIToUTF16("1i_____")); - - string16 original = ASCIIToUTF16("$1a,$2b,$3c,$4d,$5e,$6f,$7g,$8h,$9i"); - string16 expected = - ASCIIToUTF16("9a____a,Bb,7c___c,dd,5e____e,Ff,3g___g,hh,1i_____i"); - - EXPECT_EQ(expected, ReplaceStringPlaceholders(original, subst, nullptr)); - - std::vector<size_t> offsets; - EXPECT_EQ(expected, ReplaceStringPlaceholders(original, subst, &offsets)); - std::vector<size_t> expected_offsets = {0, 8, 11, 18, 21, 29, 32, 39, 42}; - EXPECT_EQ(offsets.size(), subst.size()); - EXPECT_EQ(expected_offsets, offsets); - for (size_t i = 0; i < offsets.size(); i++) { - EXPECT_EQ(expected.substr(expected_offsets[i], subst[i].length()), - subst[i]); - } -} - -TEST(StringUtilTest, ReplaceStringPlaceholdersNetContractionWithExpansion) { - // In this test, some of the substitutions are longer than the placeholders, - // but overall the string gets smaller. Additionally, the placeholders appear - // in a permuted order. - std::vector<string16> subst; - subst.push_back(ASCIIToUTF16("z")); - subst.push_back(ASCIIToUTF16("y")); - subst.push_back(ASCIIToUTF16("XYZW")); - subst.push_back(ASCIIToUTF16("x")); - subst.push_back(ASCIIToUTF16("w")); - - string16 formatted = - ReplaceStringPlaceholders(ASCIIToUTF16("$3_$4$2$1$5"), subst, nullptr); - - EXPECT_EQ(ASCIIToUTF16("XYZW_xyzw"), formatted); -} - -TEST(StringUtilTest, ReplaceStringPlaceholdersOneDigit) { - std::vector<string16> subst; - subst.push_back(ASCIIToUTF16("1a")); - string16 formatted = - ReplaceStringPlaceholders(ASCIIToUTF16(" $16 "), subst, nullptr); - EXPECT_EQ(ASCIIToUTF16(" 1a6 "), formatted); -} - -TEST(StringUtilTest, ReplaceStringPlaceholdersInvalidPlaceholder) { - std::vector<string16> subst; - subst.push_back(ASCIIToUTF16("1a")); - string16 formatted = - ReplaceStringPlaceholders(ASCIIToUTF16("+$-+$A+$1+"), subst, nullptr); - EXPECT_EQ(ASCIIToUTF16("+++1a+"), formatted); -} - -TEST(StringUtilTest, StdStringReplaceStringPlaceholders) { - std::vector<std::string> subst; - subst.push_back("9a"); - subst.push_back("8b"); - subst.push_back("7c"); - subst.push_back("6d"); - subst.push_back("5e"); - subst.push_back("4f"); - subst.push_back("3g"); - subst.push_back("2h"); - subst.push_back("1i"); - - std::string formatted = - ReplaceStringPlaceholders( - "$1a,$2b,$3c,$4d,$5e,$6f,$7g,$8h,$9i", subst, nullptr); - - EXPECT_EQ("9aa,8bb,7cc,6dd,5ee,4ff,3gg,2hh,1ii", formatted); -} - -TEST(StringUtilTest, StdStringReplaceStringPlaceholdersMultipleMatches) { - std::vector<std::string> subst; - subst.push_back("4"); // Referenced twice. - subst.push_back("?"); // Unreferenced. - subst.push_back("!"); // Unreferenced. - subst.push_back("16"); // Referenced once. - - std::string original = "$1 * $1 == $4"; - std::string expected = "4 * 4 == 16"; - EXPECT_EQ(expected, ReplaceStringPlaceholders(original, subst, nullptr)); - std::vector<size_t> offsets; - EXPECT_EQ(expected, ReplaceStringPlaceholders(original, subst, &offsets)); - std::vector<size_t> expected_offsets = {0, 4, 9}; - EXPECT_EQ(expected_offsets, offsets); -} - -TEST(StringUtilTest, ReplaceStringPlaceholdersConsecutiveDollarSigns) { - std::vector<std::string> subst; - subst.push_back("a"); - subst.push_back("b"); - subst.push_back("c"); - EXPECT_EQ(ReplaceStringPlaceholders("$$1 $$$2 $$$$3", subst, nullptr), - "$1 $$2 $$$3"); -} - -TEST(StringUtilTest, LcpyTest) { - // Test the normal case where we fit in our buffer. - { - char dst[10]; - wchar_t wdst[10]; - EXPECT_EQ(7U, strlcpy(dst, "abcdefg", arraysize(dst))); - EXPECT_EQ(0, memcmp(dst, "abcdefg", 8)); - EXPECT_EQ(7U, wcslcpy(wdst, L"abcdefg", arraysize(wdst))); - EXPECT_EQ(0, memcmp(wdst, L"abcdefg", sizeof(wchar_t) * 8)); - } - - // Test dst_size == 0, nothing should be written to |dst| and we should - // have the equivalent of strlen(src). - { - char dst[2] = {1, 2}; - wchar_t wdst[2] = {1, 2}; - EXPECT_EQ(7U, strlcpy(dst, "abcdefg", 0)); - EXPECT_EQ(1, dst[0]); - EXPECT_EQ(2, dst[1]); - EXPECT_EQ(7U, wcslcpy(wdst, L"abcdefg", 0)); - EXPECT_EQ(static_cast<wchar_t>(1), wdst[0]); - EXPECT_EQ(static_cast<wchar_t>(2), wdst[1]); - } - - // Test the case were we _just_ competely fit including the null. - { - char dst[8]; - wchar_t wdst[8]; - EXPECT_EQ(7U, strlcpy(dst, "abcdefg", arraysize(dst))); - EXPECT_EQ(0, memcmp(dst, "abcdefg", 8)); - EXPECT_EQ(7U, wcslcpy(wdst, L"abcdefg", arraysize(wdst))); - EXPECT_EQ(0, memcmp(wdst, L"abcdefg", sizeof(wchar_t) * 8)); - } - - // Test the case were we we are one smaller, so we can't fit the null. - { - char dst[7]; - wchar_t wdst[7]; - EXPECT_EQ(7U, strlcpy(dst, "abcdefg", arraysize(dst))); - EXPECT_EQ(0, memcmp(dst, "abcdef", 7)); - EXPECT_EQ(7U, wcslcpy(wdst, L"abcdefg", arraysize(wdst))); - EXPECT_EQ(0, memcmp(wdst, L"abcdef", sizeof(wchar_t) * 7)); - } - - // Test the case were we are just too small. - { - char dst[3]; - wchar_t wdst[3]; - EXPECT_EQ(7U, strlcpy(dst, "abcdefg", arraysize(dst))); - EXPECT_EQ(0, memcmp(dst, "ab", 3)); - EXPECT_EQ(7U, wcslcpy(wdst, L"abcdefg", arraysize(wdst))); - EXPECT_EQ(0, memcmp(wdst, L"ab", sizeof(wchar_t) * 3)); - } -} - -TEST(StringUtilTest, WprintfFormatPortabilityTest) { - static const struct { - const wchar_t* input; - bool portable; - } cases[] = { - { L"%ls", true }, - { L"%s", false }, - { L"%S", false }, - { L"%lS", false }, - { L"Hello, %s", false }, - { L"%lc", true }, - { L"%c", false }, - { L"%C", false }, - { L"%lC", false }, - { L"%ls %s", false }, - { L"%s %ls", false }, - { L"%s %ls %s", false }, - { L"%f", true }, - { L"%f %F", false }, - { L"%d %D", false }, - { L"%o %O", false }, - { L"%u %U", false }, - { L"%f %d %o %u", true }, - { L"%-8d (%02.1f%)", true }, - { L"% 10s", false }, - { L"% 10ls", true } - }; - for (size_t i = 0; i < arraysize(cases); ++i) - EXPECT_EQ(cases[i].portable, IsWprintfFormatPortable(cases[i].input)); -} - -TEST(StringUtilTest, RemoveChars) { - const char kRemoveChars[] = "-/+*"; - std::string input = "A-+bc/d!*"; - EXPECT_TRUE(RemoveChars(input, kRemoveChars, &input)); - EXPECT_EQ("Abcd!", input); - - // No characters match kRemoveChars. - EXPECT_FALSE(RemoveChars(input, kRemoveChars, &input)); - EXPECT_EQ("Abcd!", input); - - // Empty string. - input.clear(); - EXPECT_FALSE(RemoveChars(input, kRemoveChars, &input)); - EXPECT_EQ(std::string(), input); -} - -TEST(StringUtilTest, ReplaceChars) { - struct TestData { - const char* input; - const char* replace_chars; - const char* replace_with; - const char* output; - bool result; - } cases[] = { - {"", "", "", "", false}, - {"t", "t", "t", "t", true}, - {"a", "b", "c", "a", false}, - {"b", "b", "c", "c", true}, - {"bob", "b", "p", "pop", true}, - {"bob", "o", "i", "bib", true}, - {"test", "", "", "test", false}, - {"test", "", "!", "test", false}, - {"test", "z", "!", "test", false}, - {"test", "e", "!", "t!st", true}, - {"test", "e", "!?", "t!?st", true}, - {"test", "ez", "!", "t!st", true}, - {"test", "zed", "!?", "t!?st", true}, - {"test", "t", "!?", "!?es!?", true}, - {"test", "et", "!>", "!>!>s!>", true}, - {"test", "zest", "!", "!!!!", true}, - {"test", "szt", "!", "!e!!", true}, - {"test", "t", "test", "testestest", true}, - {"tetst", "t", "test", "testeteststest", true}, - {"ttttttt", "t", "-", "-------", true}, - {"aAaAaAAaAAa", "A", "", "aaaaa", true}, - {"xxxxxxxxxx", "x", "", "", true}, - {"xxxxxxxxxx", "x", "x", "xxxxxxxxxx", true}, - {"xxxxxxxxxx", "x", "y-", "y-y-y-y-y-y-y-y-y-y-", true}, - {"xxxxxxxxxx", "x", "xy", "xyxyxyxyxyxyxyxyxyxy", true}, - {"xxxxxxxxxx", "x", "zyx", "zyxzyxzyxzyxzyxzyxzyxzyxzyxzyx", true}, - {"xaxxaxxxaxxxax", "x", "xy", "xyaxyxyaxyxyxyaxyxyxyaxy", true}, - {"-xaxxaxxxaxxxax-", "x", "xy", "-xyaxyxyaxyxyxyaxyxyxyaxy-", true}, - }; - - for (const TestData& scenario : cases) { - // Test with separate output and input vars. - std::string output; - bool result = ReplaceChars(scenario.input, scenario.replace_chars, - scenario.replace_with, &output); - EXPECT_EQ(scenario.result, result) << scenario.input; - EXPECT_EQ(scenario.output, output); - } - - for (const TestData& scenario : cases) { - // Test with an input/output var of limited capacity. - std::string input_output = scenario.input; - input_output.shrink_to_fit(); - bool result = ReplaceChars(input_output, scenario.replace_chars, - scenario.replace_with, &input_output); - EXPECT_EQ(scenario.result, result) << scenario.input; - EXPECT_EQ(scenario.output, input_output); - } - - for (const TestData& scenario : cases) { - // Test with an input/output var of ample capacity; should - // not realloc. - std::string input_output = scenario.input; - input_output.reserve(strlen(scenario.output) * 2); - const void* original_buffer = input_output.data(); - bool result = ReplaceChars(input_output, scenario.replace_chars, - scenario.replace_with, &input_output); - EXPECT_EQ(scenario.result, result) << scenario.input; - EXPECT_EQ(scenario.output, input_output); - EXPECT_EQ(original_buffer, input_output.data()); - } -} - -TEST(StringUtilTest, ContainsOnlyChars) { - // Providing an empty list of characters should return false but for the empty - // string. - EXPECT_TRUE(ContainsOnlyChars(std::string(), std::string())); - EXPECT_FALSE(ContainsOnlyChars("Hello", std::string())); - - EXPECT_TRUE(ContainsOnlyChars(std::string(), "1234")); - EXPECT_TRUE(ContainsOnlyChars("1", "1234")); - EXPECT_TRUE(ContainsOnlyChars("1", "4321")); - EXPECT_TRUE(ContainsOnlyChars("123", "4321")); - EXPECT_FALSE(ContainsOnlyChars("123a", "4321")); - - EXPECT_TRUE(ContainsOnlyChars(std::string(), kWhitespaceASCII)); - EXPECT_TRUE(ContainsOnlyChars(" ", kWhitespaceASCII)); - EXPECT_TRUE(ContainsOnlyChars("\t", kWhitespaceASCII)); - EXPECT_TRUE(ContainsOnlyChars("\t \r \n ", kWhitespaceASCII)); - EXPECT_FALSE(ContainsOnlyChars("a", kWhitespaceASCII)); - EXPECT_FALSE(ContainsOnlyChars("\thello\r \n ", kWhitespaceASCII)); - - EXPECT_TRUE(ContainsOnlyChars(string16(), kWhitespaceUTF16)); - EXPECT_TRUE(ContainsOnlyChars(ASCIIToUTF16(" "), kWhitespaceUTF16)); - EXPECT_TRUE(ContainsOnlyChars(ASCIIToUTF16("\t"), kWhitespaceUTF16)); - EXPECT_TRUE(ContainsOnlyChars(ASCIIToUTF16("\t \r \n "), kWhitespaceUTF16)); - EXPECT_FALSE(ContainsOnlyChars(ASCIIToUTF16("a"), kWhitespaceUTF16)); - EXPECT_FALSE(ContainsOnlyChars(ASCIIToUTF16("\thello\r \n "), - kWhitespaceUTF16)); -} - -TEST(StringUtilTest, CompareCaseInsensitiveASCII) { - EXPECT_EQ(0, CompareCaseInsensitiveASCII("", "")); - EXPECT_EQ(0, CompareCaseInsensitiveASCII("Asdf", "aSDf")); - - // Differing lengths. - EXPECT_EQ(-1, CompareCaseInsensitiveASCII("Asdf", "aSDfA")); - EXPECT_EQ(1, CompareCaseInsensitiveASCII("AsdfA", "aSDf")); - - // Differing values. - EXPECT_EQ(-1, CompareCaseInsensitiveASCII("AsdfA", "aSDfb")); - EXPECT_EQ(1, CompareCaseInsensitiveASCII("Asdfb", "aSDfA")); -} - -TEST(StringUtilTest, EqualsCaseInsensitiveASCII) { - EXPECT_TRUE(EqualsCaseInsensitiveASCII("", "")); - EXPECT_TRUE(EqualsCaseInsensitiveASCII("Asdf", "aSDF")); - EXPECT_FALSE(EqualsCaseInsensitiveASCII("bsdf", "aSDF")); - EXPECT_FALSE(EqualsCaseInsensitiveASCII("Asdf", "aSDFz")); -} - -TEST(StringUtilTest, IsUnicodeWhitespace) { - // NOT unicode white space. - EXPECT_FALSE(IsUnicodeWhitespace(L'\0')); - EXPECT_FALSE(IsUnicodeWhitespace(L'A')); - EXPECT_FALSE(IsUnicodeWhitespace(L'0')); - EXPECT_FALSE(IsUnicodeWhitespace(L'.')); - EXPECT_FALSE(IsUnicodeWhitespace(L';')); - EXPECT_FALSE(IsUnicodeWhitespace(L'\x4100')); - - // Actual unicode whitespace. - EXPECT_TRUE(IsUnicodeWhitespace(L' ')); - EXPECT_TRUE(IsUnicodeWhitespace(L'\xa0')); - EXPECT_TRUE(IsUnicodeWhitespace(L'\x3000')); - EXPECT_TRUE(IsUnicodeWhitespace(L'\t')); - EXPECT_TRUE(IsUnicodeWhitespace(L'\r')); - EXPECT_TRUE(IsUnicodeWhitespace(L'\v')); - EXPECT_TRUE(IsUnicodeWhitespace(L'\f')); - EXPECT_TRUE(IsUnicodeWhitespace(L'\n')); -} - -class WriteIntoTest : public testing::Test { - protected: - static void WritesCorrectly(size_t num_chars) { - std::string buffer; - char kOriginal[] = "supercali"; - strncpy(WriteInto(&buffer, num_chars + 1), kOriginal, num_chars); - // Using std::string(buffer.c_str()) instead of |buffer| truncates the - // string at the first \0. - EXPECT_EQ(std::string(kOriginal, - std::min(num_chars, arraysize(kOriginal) - 1)), - std::string(buffer.c_str())); - EXPECT_EQ(num_chars, buffer.size()); - } -}; - -TEST_F(WriteIntoTest, WriteInto) { - // Validate that WriteInto reserves enough space and - // sizes a string correctly. - WritesCorrectly(1); - WritesCorrectly(2); - WritesCorrectly(5000); - - // Validate that WriteInto doesn't modify other strings - // when using a Copy-on-Write implementation. - const char kLive[] = "live"; - const char kDead[] = "dead"; - const std::string live = kLive; - std::string dead = live; - strncpy(WriteInto(&dead, 5), kDead, 4); - EXPECT_EQ(kDead, dead); - EXPECT_EQ(4u, dead.size()); - EXPECT_EQ(kLive, live); - EXPECT_EQ(4u, live.size()); -} - -} // namespace base
diff --git a/base/strings/stringize_macros_unittest.cc b/base/strings/stringize_macros_unittest.cc deleted file mode 100644 index d7f9e56..0000000 --- a/base/strings/stringize_macros_unittest.cc +++ /dev/null
@@ -1,29 +0,0 @@ -// 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/strings/stringize_macros.h" - -#include "testing/gtest/include/gtest/gtest.h" - -// Macros as per documentation in header file. -#define PREPROCESSOR_UTIL_UNITTEST_A FOO -#define PREPROCESSOR_UTIL_UNITTEST_B(x) myobj->FunctionCall(x) -#define PREPROCESSOR_UTIL_UNITTEST_C "foo" - -TEST(StringizeTest, Ansi) { - EXPECT_STREQ( - "PREPROCESSOR_UTIL_UNITTEST_A", - STRINGIZE_NO_EXPANSION(PREPROCESSOR_UTIL_UNITTEST_A)); - EXPECT_STREQ( - "PREPROCESSOR_UTIL_UNITTEST_B(y)", - STRINGIZE_NO_EXPANSION(PREPROCESSOR_UTIL_UNITTEST_B(y))); - EXPECT_STREQ( - "PREPROCESSOR_UTIL_UNITTEST_C", - STRINGIZE_NO_EXPANSION(PREPROCESSOR_UTIL_UNITTEST_C)); - - EXPECT_STREQ("FOO", STRINGIZE(PREPROCESSOR_UTIL_UNITTEST_A)); - EXPECT_STREQ("myobj->FunctionCall(y)", - STRINGIZE(PREPROCESSOR_UTIL_UNITTEST_B(y))); - EXPECT_STREQ("\"foo\"", STRINGIZE(PREPROCESSOR_UTIL_UNITTEST_C)); -}
diff --git a/base/strings/stringprintf_unittest.cc b/base/strings/stringprintf_unittest.cc deleted file mode 100644 index 02cd349..0000000 --- a/base/strings/stringprintf_unittest.cc +++ /dev/null
@@ -1,182 +0,0 @@ -// 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/strings/stringprintf.h" - -#include <errno.h> -#include <stddef.h> - -#include "base/macros.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -// A helper for the StringAppendV test that follows. -// -// Just forwards its args to StringAppendV. -static void StringAppendVTestHelper(std::string* out, const char* format, ...) { - va_list ap; - va_start(ap, format); - StringAppendV(out, format, ap); - va_end(ap); -} - -} // namespace - -TEST(StringPrintfTest, StringPrintfEmpty) { - EXPECT_EQ("", StringPrintf("%s", "")); -} - -TEST(StringPrintfTest, StringPrintfMisc) { - EXPECT_EQ("123hello w", StringPrintf("%3d%2s %1c", 123, "hello", 'w')); -#if defined(OS_WIN) - EXPECT_EQ(L"123hello w", StringPrintf(L"%3d%2ls %1lc", 123, L"hello", 'w')); -#endif -} - -TEST(StringPrintfTest, StringAppendfEmptyString) { - std::string value("Hello"); - StringAppendF(&value, "%s", ""); - EXPECT_EQ("Hello", value); - -#if defined(OS_WIN) - std::wstring valuew(L"Hello"); - StringAppendF(&valuew, L"%ls", L""); - EXPECT_EQ(L"Hello", valuew); -#endif -} - -TEST(StringPrintfTest, StringAppendfString) { - std::string value("Hello"); - StringAppendF(&value, " %s", "World"); - EXPECT_EQ("Hello World", value); - -#if defined(OS_WIN) - std::wstring valuew(L"Hello"); - StringAppendF(&valuew, L" %ls", L"World"); - EXPECT_EQ(L"Hello World", valuew); -#endif -} - -TEST(StringPrintfTest, StringAppendfInt) { - std::string value("Hello"); - StringAppendF(&value, " %d", 123); - EXPECT_EQ("Hello 123", value); - -#if defined(OS_WIN) - std::wstring valuew(L"Hello"); - StringAppendF(&valuew, L" %d", 123); - EXPECT_EQ(L"Hello 123", valuew); -#endif -} - -// Make sure that lengths exactly around the initial buffer size are handled -// correctly. -TEST(StringPrintfTest, StringPrintfBounds) { - const int kSrcLen = 1026; - char src[kSrcLen]; - for (size_t i = 0; i < arraysize(src); i++) - src[i] = 'A'; - - wchar_t srcw[kSrcLen]; - for (size_t i = 0; i < arraysize(srcw); i++) - srcw[i] = 'A'; - - for (int i = 1; i < 3; i++) { - src[kSrcLen - i] = 0; - std::string out; - SStringPrintf(&out, "%s", src); - EXPECT_STREQ(src, out.c_str()); - -#if defined(OS_WIN) - srcw[kSrcLen - i] = 0; - std::wstring outw; - SStringPrintf(&outw, L"%ls", srcw); - EXPECT_STREQ(srcw, outw.c_str()); -#endif - } -} - -// Test very large sprintfs that will cause the buffer to grow. -TEST(StringPrintfTest, Grow) { - char src[1026]; - for (size_t i = 0; i < arraysize(src); i++) - src[i] = 'A'; - src[1025] = 0; - - const char fmt[] = "%sB%sB%sB%sB%sB%sB%s"; - - std::string out; - SStringPrintf(&out, fmt, src, src, src, src, src, src, src); - - const int kRefSize = 320000; - char* ref = new char[kRefSize]; -#if defined(OS_WIN) - sprintf_s(ref, kRefSize, fmt, src, src, src, src, src, src, src); -#elif defined(OS_POSIX) || defined(OS_FUCHSIA) - snprintf(ref, kRefSize, fmt, src, src, src, src, src, src, src); -#endif - - EXPECT_STREQ(ref, out.c_str()); - delete[] ref; -} - -TEST(StringPrintfTest, StringAppendV) { - std::string out; - StringAppendVTestHelper(&out, "%d foo %s", 1, "bar"); - EXPECT_EQ("1 foo bar", out); -} - -// Test the boundary condition for the size of the string_util's -// internal buffer. -TEST(StringPrintfTest, GrowBoundary) { - const int kStringUtilBufLen = 1024; - // Our buffer should be one larger than the size of StringAppendVT's stack - // buffer. - // And need extra one for NULL-terminator. - const int kBufLen = kStringUtilBufLen + 1 + 1; - char src[kBufLen]; - for (int i = 0; i < kBufLen - 1; ++i) - src[i] = 'a'; - src[kBufLen - 1] = 0; - - std::string out; - SStringPrintf(&out, "%s", src); - - EXPECT_STREQ(src, out.c_str()); -} - -#if defined(OS_WIN) -// vswprintf in Visual Studio 2013 fails when given U+FFFF. This tests that the -// failure case is gracefuly handled. In Visual Studio 2015 the bad character -// is passed through. -TEST(StringPrintfTest, Invalid) { - wchar_t invalid[2]; - invalid[0] = 0xffff; - invalid[1] = 0; - - std::wstring out; - SStringPrintf(&out, L"%ls", invalid); -#if _MSC_VER >= 1900 - EXPECT_STREQ(invalid, out.c_str()); -#else - EXPECT_STREQ(L"", out.c_str()); -#endif -} -#endif - -// Test that StringPrintf and StringAppendV do not change errno. -TEST(StringPrintfTest, StringPrintfErrno) { - errno = 1; - EXPECT_EQ("", StringPrintf("%s", "")); - EXPECT_EQ(1, errno); - std::string out; - StringAppendVTestHelper(&out, "%d foo %s", 1, "bar"); - EXPECT_EQ(1, errno); -} - -} // namespace base
diff --git a/base/strings/sys_string_conversions_unittest.cc b/base/strings/sys_string_conversions_unittest.cc deleted file mode 100644 index 0f4eddd..0000000 --- a/base/strings/sys_string_conversions_unittest.cc +++ /dev/null
@@ -1,196 +0,0 @@ -// 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 <stddef.h> - -#include <string> - -#include "base/macros.h" -#include "base/strings/string_piece.h" -#include "base/strings/sys_string_conversions.h" -#include "base/strings/utf_string_conversions.h" -#include "base/test/scoped_locale.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -#ifdef WCHAR_T_IS_UTF32 -static const std::wstring kSysWideOldItalicLetterA = L"\x10300"; -#else -static const std::wstring kSysWideOldItalicLetterA = L"\xd800\xdf00"; -#endif - -namespace base { - -TEST(SysStrings, SysWideToUTF8) { - EXPECT_EQ("Hello, world", SysWideToUTF8(L"Hello, world")); - EXPECT_EQ("\xe4\xbd\xa0\xe5\xa5\xbd", SysWideToUTF8(L"\x4f60\x597d")); - - // >16 bits - EXPECT_EQ("\xF0\x90\x8C\x80", SysWideToUTF8(kSysWideOldItalicLetterA)); - - // Error case. When Windows finds a UTF-16 character going off the end of - // a string, it just converts that literal value to UTF-8, even though this - // is invalid. - // - // This is what XP does, but Vista has different behavior, so we don't bother - // verifying it: - // EXPECT_EQ("\xE4\xBD\xA0\xED\xA0\x80zyxw", - // SysWideToUTF8(L"\x4f60\xd800zyxw")); - - // Test embedded NULLs. - std::wstring wide_null(L"a"); - wide_null.push_back(0); - wide_null.push_back('b'); - - std::string expected_null("a"); - expected_null.push_back(0); - expected_null.push_back('b'); - - EXPECT_EQ(expected_null, SysWideToUTF8(wide_null)); -} - -TEST(SysStrings, SysUTF8ToWide) { - EXPECT_EQ(L"Hello, world", SysUTF8ToWide("Hello, world")); - EXPECT_EQ(L"\x4f60\x597d", SysUTF8ToWide("\xe4\xbd\xa0\xe5\xa5\xbd")); - // >16 bits - EXPECT_EQ(kSysWideOldItalicLetterA, SysUTF8ToWide("\xF0\x90\x8C\x80")); - - // Error case. When Windows finds an invalid UTF-8 character, it just skips - // it. This seems weird because it's inconsistent with the reverse conversion. - // - // This is what XP does, but Vista has different behavior, so we don't bother - // verifying it: - // EXPECT_EQ(L"\x4f60zyxw", SysUTF8ToWide("\xe4\xbd\xa0\xe5\xa5zyxw")); - - // Test embedded NULLs. - std::string utf8_null("a"); - utf8_null.push_back(0); - utf8_null.push_back('b'); - - std::wstring expected_null(L"a"); - expected_null.push_back(0); - expected_null.push_back('b'); - - EXPECT_EQ(expected_null, SysUTF8ToWide(utf8_null)); -} - -#if defined(OS_LINUX) // Tests depend on setting a specific Linux locale. - -TEST(SysStrings, SysWideToNativeMB) { -#if !defined(SYSTEM_NATIVE_UTF8) - ScopedLocale locale("en_US.UTF-8"); -#endif - EXPECT_EQ("Hello, world", SysWideToNativeMB(L"Hello, world")); - EXPECT_EQ("\xe4\xbd\xa0\xe5\xa5\xbd", SysWideToNativeMB(L"\x4f60\x597d")); - - // >16 bits - EXPECT_EQ("\xF0\x90\x8C\x80", SysWideToNativeMB(kSysWideOldItalicLetterA)); - - // Error case. When Windows finds a UTF-16 character going off the end of - // a string, it just converts that literal value to UTF-8, even though this - // is invalid. - // - // This is what XP does, but Vista has different behavior, so we don't bother - // verifying it: - // EXPECT_EQ("\xE4\xBD\xA0\xED\xA0\x80zyxw", - // SysWideToNativeMB(L"\x4f60\xd800zyxw")); - - // Test embedded NULLs. - std::wstring wide_null(L"a"); - wide_null.push_back(0); - wide_null.push_back('b'); - - std::string expected_null("a"); - expected_null.push_back(0); - expected_null.push_back('b'); - - EXPECT_EQ(expected_null, SysWideToNativeMB(wide_null)); -} - -// We assume the test is running in a UTF8 locale. -TEST(SysStrings, SysNativeMBToWide) { -#if !defined(SYSTEM_NATIVE_UTF8) - ScopedLocale locale("en_US.UTF-8"); -#endif - EXPECT_EQ(L"Hello, world", SysNativeMBToWide("Hello, world")); - EXPECT_EQ(L"\x4f60\x597d", SysNativeMBToWide("\xe4\xbd\xa0\xe5\xa5\xbd")); - // >16 bits - EXPECT_EQ(kSysWideOldItalicLetterA, SysNativeMBToWide("\xF0\x90\x8C\x80")); - - // Error case. When Windows finds an invalid UTF-8 character, it just skips - // it. This seems weird because it's inconsistent with the reverse conversion. - // - // This is what XP does, but Vista has different behavior, so we don't bother - // verifying it: - // EXPECT_EQ(L"\x4f60zyxw", SysNativeMBToWide("\xe4\xbd\xa0\xe5\xa5zyxw")); - - // Test embedded NULLs. - std::string utf8_null("a"); - utf8_null.push_back(0); - utf8_null.push_back('b'); - - std::wstring expected_null(L"a"); - expected_null.push_back(0); - expected_null.push_back('b'); - - EXPECT_EQ(expected_null, SysNativeMBToWide(utf8_null)); -} - -static const wchar_t* const kConvertRoundtripCases[] = { - L"Google Video", - // "网页 图片 资讯更多 »" - L"\x7f51\x9875\x0020\x56fe\x7247\x0020\x8d44\x8baf\x66f4\x591a\x0020\x00bb", - // "Παγκόσμιος Ιστός" - L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9" - L"\x03bf\x03c2\x0020\x0399\x03c3\x03c4\x03cc\x03c2", - // "Поиск страниц на русском" - L"\x041f\x043e\x0438\x0441\x043a\x0020\x0441\x0442" - L"\x0440\x0430\x043d\x0438\x0446\x0020\x043d\x0430" - L"\x0020\x0440\x0443\x0441\x0441\x043a\x043e\x043c", - // "전체서비스" - L"\xc804\xccb4\xc11c\xbe44\xc2a4", - - // Test characters that take more than 16 bits. This will depend on whether - // wchar_t is 16 or 32 bits. -#if defined(WCHAR_T_IS_UTF16) - L"\xd800\xdf00", - // ????? (Mathematical Alphanumeric Symbols (U+011d40 - U+011d44 : A,B,C,D,E) - L"\xd807\xdd40\xd807\xdd41\xd807\xdd42\xd807\xdd43\xd807\xdd44", -#elif defined(WCHAR_T_IS_UTF32) - L"\x10300", - // ????? (Mathematical Alphanumeric Symbols (U+011d40 - U+011d44 : A,B,C,D,E) - L"\x11d40\x11d41\x11d42\x11d43\x11d44", -#endif -}; - - -TEST(SysStrings, SysNativeMBAndWide) { -#if !defined(SYSTEM_NATIVE_UTF8) - ScopedLocale locale("en_US.UTF-8"); -#endif - for (size_t i = 0; i < arraysize(kConvertRoundtripCases); ++i) { - std::wstring wide = kConvertRoundtripCases[i]; - std::wstring trip = SysNativeMBToWide(SysWideToNativeMB(wide)); - EXPECT_EQ(wide.size(), trip.size()); - EXPECT_EQ(wide, trip); - } - - // We assume our test is running in UTF-8, so double check through ICU. - for (size_t i = 0; i < arraysize(kConvertRoundtripCases); ++i) { - std::wstring wide = kConvertRoundtripCases[i]; - std::wstring trip = SysNativeMBToWide(WideToUTF8(wide)); - EXPECT_EQ(wide.size(), trip.size()); - EXPECT_EQ(wide, trip); - } - - for (size_t i = 0; i < arraysize(kConvertRoundtripCases); ++i) { - std::wstring wide = kConvertRoundtripCases[i]; - std::wstring trip = UTF8ToWide(SysWideToNativeMB(wide)); - EXPECT_EQ(wide.size(), trip.size()); - EXPECT_EQ(wide, trip); - } -} -#endif // OS_LINUX - -} // namespace base
diff --git a/base/strings/utf_offset_string_conversions_unittest.cc b/base/strings/utf_offset_string_conversions_unittest.cc deleted file mode 100644 index c5ce647..0000000 --- a/base/strings/utf_offset_string_conversions_unittest.cc +++ /dev/null
@@ -1,300 +0,0 @@ -// 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 <stddef.h> - -#include <algorithm> - -#include "base/logging.h" -#include "base/macros.h" -#include "base/strings/string_piece.h" -#include "base/strings/utf_offset_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -static const size_t kNpos = string16::npos; - -} // namespace - -TEST(UTFOffsetStringConversionsTest, AdjustOffset) { - struct UTF8ToUTF16Case { - const char* utf8; - size_t input_offset; - size_t output_offset; - } utf8_to_utf16_cases[] = { - {"", 0, 0}, - {"", kNpos, kNpos}, - {"\xe4\xbd\xa0\xe5\xa5\xbd", 1, kNpos}, - {"\xe4\xbd\xa0\xe5\xa5\xbd", 3, 1}, - {"\xed\xb0\x80z", 3, 3}, - {"A\xF0\x90\x8C\x80z", 1, 1}, - {"A\xF0\x90\x8C\x80z", 2, kNpos}, - {"A\xF0\x90\x8C\x80z", 5, 3}, - {"A\xF0\x90\x8C\x80z", 6, 4}, - {"A\xF0\x90\x8C\x80z", kNpos, kNpos}, - }; - for (size_t i = 0; i < arraysize(utf8_to_utf16_cases); ++i) { - const size_t offset = utf8_to_utf16_cases[i].input_offset; - std::vector<size_t> offsets; - offsets.push_back(offset); - UTF8ToUTF16AndAdjustOffsets(utf8_to_utf16_cases[i].utf8, &offsets); - EXPECT_EQ(utf8_to_utf16_cases[i].output_offset, offsets[0]); - } - - struct UTF16ToUTF8Case { - char16 utf16[10]; - size_t input_offset; - size_t output_offset; - } utf16_to_utf8_cases[] = { - {{}, 0, 0}, - // Converted to 3-byte utf-8 sequences - {{0x5909, 0x63DB}, 3, kNpos}, - {{0x5909, 0x63DB}, 2, 6}, - {{0x5909, 0x63DB}, 1, 3}, - {{0x5909, 0x63DB}, 0, 0}, - // Converted to 2-byte utf-8 sequences - {{'A', 0x00bc, 0x00be, 'z'}, 1, 1}, - {{'A', 0x00bc, 0x00be, 'z'}, 2, 3}, - {{'A', 0x00bc, 0x00be, 'z'}, 3, 5}, - {{'A', 0x00bc, 0x00be, 'z'}, 4, 6}, - // Surrogate pair - {{'A', 0xd800, 0xdf00, 'z'}, 1, 1}, - {{'A', 0xd800, 0xdf00, 'z'}, 2, kNpos}, - {{'A', 0xd800, 0xdf00, 'z'}, 3, 5}, - {{'A', 0xd800, 0xdf00, 'z'}, 4, 6}, - }; - for (size_t i = 0; i < arraysize(utf16_to_utf8_cases); ++i) { - size_t offset = utf16_to_utf8_cases[i].input_offset; - std::vector<size_t> offsets; - offsets.push_back(offset); - UTF16ToUTF8AndAdjustOffsets(utf16_to_utf8_cases[i].utf16, &offsets); - EXPECT_EQ(utf16_to_utf8_cases[i].output_offset, offsets[0]) << i; - } -} - -TEST(UTFOffsetStringConversionsTest, LimitOffsets) { - const OffsetAdjuster::Adjustments kNoAdjustments; - const size_t kLimit = 10; - const size_t kItems = 20; - std::vector<size_t> size_ts; - for (size_t t = 0; t < kItems; ++t) { - size_ts.push_back(t); - OffsetAdjuster::AdjustOffset(kNoAdjustments, &size_ts.back(), kLimit); - } - size_t unlimited_count = 0; - for (std::vector<size_t>::iterator ti = size_ts.begin(); ti != size_ts.end(); - ++ti) { - if (*ti != kNpos) - ++unlimited_count; - } - EXPECT_EQ(11U, unlimited_count); - - // Reverse the values in the vector and try again. - size_ts.clear(); - for (size_t t = kItems; t > 0; --t) { - size_ts.push_back(t - 1); - OffsetAdjuster::AdjustOffset(kNoAdjustments, &size_ts.back(), kLimit); - } - unlimited_count = 0; - for (std::vector<size_t>::iterator ti = size_ts.begin(); ti != size_ts.end(); - ++ti) { - if (*ti != kNpos) - ++unlimited_count; - } - EXPECT_EQ(11U, unlimited_count); -} - -TEST(UTFOffsetStringConversionsTest, AdjustOffsets) { - // Imagine we have strings as shown in the following cases where the - // X's represent encoded characters. - // 1: abcXXXdef ==> abcXdef - { - std::vector<size_t> offsets; - for (size_t t = 0; t <= 9; ++t) - offsets.push_back(t); - OffsetAdjuster::Adjustments adjustments; - adjustments.push_back(OffsetAdjuster::Adjustment(3, 3, 1)); - OffsetAdjuster::AdjustOffsets(adjustments, &offsets); - size_t expected_1[] = {0, 1, 2, 3, kNpos, kNpos, 4, 5, 6, 7}; - EXPECT_EQ(offsets.size(), arraysize(expected_1)); - for (size_t i = 0; i < arraysize(expected_1); ++i) - EXPECT_EQ(expected_1[i], offsets[i]); - } - - // 2: XXXaXXXXbcXXXXXXXdefXXX ==> XaXXbcXXXXdefX - { - std::vector<size_t> offsets; - for (size_t t = 0; t <= 23; ++t) - offsets.push_back(t); - OffsetAdjuster::Adjustments adjustments; - adjustments.push_back(OffsetAdjuster::Adjustment(0, 3, 1)); - adjustments.push_back(OffsetAdjuster::Adjustment(4, 4, 2)); - adjustments.push_back(OffsetAdjuster::Adjustment(10, 7, 4)); - adjustments.push_back(OffsetAdjuster::Adjustment(20, 3, 1)); - OffsetAdjuster::AdjustOffsets(adjustments, &offsets); - size_t expected_2[] = { - 0, kNpos, kNpos, 1, 2, kNpos, kNpos, kNpos, 4, 5, 6, kNpos, kNpos, kNpos, - kNpos, kNpos, kNpos, 10, 11, 12, 13, kNpos, kNpos, 14 - }; - EXPECT_EQ(offsets.size(), arraysize(expected_2)); - for (size_t i = 0; i < arraysize(expected_2); ++i) - EXPECT_EQ(expected_2[i], offsets[i]); - } - - // 3: XXXaXXXXbcdXXXeXX ==> aXXXXbcdXXXe - { - std::vector<size_t> offsets; - for (size_t t = 0; t <= 17; ++t) - offsets.push_back(t); - OffsetAdjuster::Adjustments adjustments; - adjustments.push_back(OffsetAdjuster::Adjustment(0, 3, 0)); - adjustments.push_back(OffsetAdjuster::Adjustment(4, 4, 4)); - adjustments.push_back(OffsetAdjuster::Adjustment(11, 3, 3)); - adjustments.push_back(OffsetAdjuster::Adjustment(15, 2, 0)); - OffsetAdjuster::AdjustOffsets(adjustments, &offsets); - size_t expected_3[] = { - 0, kNpos, kNpos, 0, 1, kNpos, kNpos, kNpos, 5, 6, 7, 8, kNpos, kNpos, 11, - 12, kNpos, 12 - }; - EXPECT_EQ(offsets.size(), arraysize(expected_3)); - for (size_t i = 0; i < arraysize(expected_3); ++i) - EXPECT_EQ(expected_3[i], offsets[i]); - } -} - -TEST(UTFOffsetStringConversionsTest, UnadjustOffsets) { - // Imagine we have strings as shown in the following cases where the - // X's represent encoded characters. - // 1: abcXXXdef ==> abcXdef - { - std::vector<size_t> offsets; - for (size_t t = 0; t <= 7; ++t) - offsets.push_back(t); - OffsetAdjuster::Adjustments adjustments; - adjustments.push_back(OffsetAdjuster::Adjustment(3, 3, 1)); - OffsetAdjuster::UnadjustOffsets(adjustments, &offsets); - size_t expected_1[] = {0, 1, 2, 3, 6, 7, 8, 9}; - EXPECT_EQ(offsets.size(), arraysize(expected_1)); - for (size_t i = 0; i < arraysize(expected_1); ++i) - EXPECT_EQ(expected_1[i], offsets[i]); - } - - // 2: XXXaXXXXbcXXXXXXXdefXXX ==> XaXXbcXXXXdefX - { - std::vector<size_t> offsets; - for (size_t t = 0; t <= 14; ++t) - offsets.push_back(t); - OffsetAdjuster::Adjustments adjustments; - adjustments.push_back(OffsetAdjuster::Adjustment(0, 3, 1)); - adjustments.push_back(OffsetAdjuster::Adjustment(4, 4, 2)); - adjustments.push_back(OffsetAdjuster::Adjustment(10, 7, 4)); - adjustments.push_back(OffsetAdjuster::Adjustment(20, 3, 1)); - OffsetAdjuster::UnadjustOffsets(adjustments, &offsets); - size_t expected_2[] = { - 0, 3, 4, kNpos, 8, 9, 10, kNpos, kNpos, kNpos, 17, 18, 19, 20, 23 - }; - EXPECT_EQ(offsets.size(), arraysize(expected_2)); - for (size_t i = 0; i < arraysize(expected_2); ++i) - EXPECT_EQ(expected_2[i], offsets[i]); - } - - // 3: XXXaXXXXbcdXXXeXX ==> aXXXXbcdXXXe - { - std::vector<size_t> offsets; - for (size_t t = 0; t <= 12; ++t) - offsets.push_back(t); - OffsetAdjuster::Adjustments adjustments; - adjustments.push_back(OffsetAdjuster::Adjustment(0, 3, 0)); - adjustments.push_back(OffsetAdjuster::Adjustment(4, 4, 4)); - adjustments.push_back(OffsetAdjuster::Adjustment(11, 3, 3)); - adjustments.push_back(OffsetAdjuster::Adjustment(15, 2, 0)); - OffsetAdjuster::UnadjustOffsets(adjustments, &offsets); - size_t expected_3[] = { - 0, // this could just as easily be 3 - 4, kNpos, kNpos, kNpos, 8, 9, 10, 11, kNpos, kNpos, 14, - 15 // this could just as easily be 17 - }; - EXPECT_EQ(offsets.size(), arraysize(expected_3)); - for (size_t i = 0; i < arraysize(expected_3); ++i) - EXPECT_EQ(expected_3[i], offsets[i]); - } -} - -// MergeSequentialAdjustments is used by net/base/escape.{h,cc} and -// net/base/net_util.{h,cc}. The two tests EscapeTest.AdjustOffset and -// NetUtilTest.FormatUrlWithOffsets test its behavior extensively. This -// is simply a short, additional test. -TEST(UTFOffsetStringConversionsTest, MergeSequentialAdjustments) { - // Pretend the input string is "abcdefghijklmnopqrstuvwxyz". - - // Set up |first_adjustments| to - // - remove the leading "a" - // - combine the "bc" into one character (call it ".") - // - remove the "f" - // - remove the "tuv" - // The resulting string should be ".deghijklmnopqrswxyz". - OffsetAdjuster::Adjustments first_adjustments; - first_adjustments.push_back(OffsetAdjuster::Adjustment(0, 1, 0)); - first_adjustments.push_back(OffsetAdjuster::Adjustment(1, 2, 1)); - first_adjustments.push_back(OffsetAdjuster::Adjustment(5, 1, 0)); - first_adjustments.push_back(OffsetAdjuster::Adjustment(19, 3, 0)); - - // Set up |adjustments_on_adjusted_string| to - // - combine the "." character that replaced "bc" with "d" into one character - // (call it "?") - // - remove the "egh" - // - expand the "i" into two characters (call them "12") - // - combine the "jkl" into one character (call it "@") - // - expand the "z" into two characters (call it "34") - // The resulting string should be "?12@mnopqrswxy34". - OffsetAdjuster::Adjustments adjustments_on_adjusted_string; - adjustments_on_adjusted_string.push_back(OffsetAdjuster::Adjustment( - 0, 2, 1)); - adjustments_on_adjusted_string.push_back(OffsetAdjuster::Adjustment( - 2, 3, 0)); - adjustments_on_adjusted_string.push_back(OffsetAdjuster::Adjustment( - 5, 1, 2)); - adjustments_on_adjusted_string.push_back(OffsetAdjuster::Adjustment( - 6, 3, 1)); - adjustments_on_adjusted_string.push_back(OffsetAdjuster::Adjustment( - 19, 1, 2)); - - // Now merge the adjustments and check the results. - OffsetAdjuster::MergeSequentialAdjustments(first_adjustments, - &adjustments_on_adjusted_string); - // The merged adjustments should look like - // - combine abcd into "?" - // - note: it's also reasonable for the Merge function to instead produce - // two adjustments instead of this, one to remove a and another to - // combine bcd into "?". This test verifies the current behavior. - // - remove efgh - // - expand i into "12" - // - combine jkl into "@" - // - remove tuv - // - expand z into "34" - ASSERT_EQ(6u, adjustments_on_adjusted_string.size()); - EXPECT_EQ(0u, adjustments_on_adjusted_string[0].original_offset); - EXPECT_EQ(4u, adjustments_on_adjusted_string[0].original_length); - EXPECT_EQ(1u, adjustments_on_adjusted_string[0].output_length); - EXPECT_EQ(4u, adjustments_on_adjusted_string[1].original_offset); - EXPECT_EQ(4u, adjustments_on_adjusted_string[1].original_length); - EXPECT_EQ(0u, adjustments_on_adjusted_string[1].output_length); - EXPECT_EQ(8u, adjustments_on_adjusted_string[2].original_offset); - EXPECT_EQ(1u, adjustments_on_adjusted_string[2].original_length); - EXPECT_EQ(2u, adjustments_on_adjusted_string[2].output_length); - EXPECT_EQ(9u, adjustments_on_adjusted_string[3].original_offset); - EXPECT_EQ(3u, adjustments_on_adjusted_string[3].original_length); - EXPECT_EQ(1u, adjustments_on_adjusted_string[3].output_length); - EXPECT_EQ(19u, adjustments_on_adjusted_string[4].original_offset); - EXPECT_EQ(3u, adjustments_on_adjusted_string[4].original_length); - EXPECT_EQ(0u, adjustments_on_adjusted_string[4].output_length); - EXPECT_EQ(25u, adjustments_on_adjusted_string[5].original_offset); - EXPECT_EQ(1u, adjustments_on_adjusted_string[5].original_length); - EXPECT_EQ(2u, adjustments_on_adjusted_string[5].output_length); -} - -} // namespace base
diff --git a/base/strings/utf_string_conversions_unittest.cc b/base/strings/utf_string_conversions_unittest.cc deleted file mode 100644 index ce776c8..0000000 --- a/base/strings/utf_string_conversions_unittest.cc +++ /dev/null
@@ -1,211 +0,0 @@ -// 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 <stddef.h> - -#include "base/logging.h" -#include "base/macros.h" -#include "base/strings/string_piece.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -const wchar_t* const kConvertRoundtripCases[] = { - L"Google Video", - // "网页 图片 资讯更多 »" - L"\x7f51\x9875\x0020\x56fe\x7247\x0020\x8d44\x8baf\x66f4\x591a\x0020\x00bb", - // "Παγκόσμιος Ιστός" - L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9" - L"\x03bf\x03c2\x0020\x0399\x03c3\x03c4\x03cc\x03c2", - // "Поиск страниц на русском" - L"\x041f\x043e\x0438\x0441\x043a\x0020\x0441\x0442" - L"\x0440\x0430\x043d\x0438\x0446\x0020\x043d\x0430" - L"\x0020\x0440\x0443\x0441\x0441\x043a\x043e\x043c", - // "전체서비스" - L"\xc804\xccb4\xc11c\xbe44\xc2a4", - - // Test characters that take more than 16 bits. This will depend on whether - // wchar_t is 16 or 32 bits. -#if defined(WCHAR_T_IS_UTF16) - L"\xd800\xdf00", - // ????? (Mathematical Alphanumeric Symbols (U+011d40 - U+011d44 : A,B,C,D,E) - L"\xd807\xdd40\xd807\xdd41\xd807\xdd42\xd807\xdd43\xd807\xdd44", -#elif defined(WCHAR_T_IS_UTF32) - L"\x10300", - // ????? (Mathematical Alphanumeric Symbols (U+011d40 - U+011d44 : A,B,C,D,E) - L"\x11d40\x11d41\x11d42\x11d43\x11d44", -#endif -}; - -} // namespace - -TEST(UTFStringConversionsTest, ConvertUTF8AndWide) { - // we round-trip all the wide strings through UTF-8 to make sure everything - // agrees on the conversion. This uses the stream operators to test them - // simultaneously. - for (size_t i = 0; i < arraysize(kConvertRoundtripCases); ++i) { - std::ostringstream utf8; - utf8 << WideToUTF8(kConvertRoundtripCases[i]); - std::wostringstream wide; - wide << UTF8ToWide(utf8.str()); - - EXPECT_EQ(kConvertRoundtripCases[i], wide.str()); - } -} - -TEST(UTFStringConversionsTest, ConvertUTF8AndWideEmptyString) { - // An empty std::wstring should be converted to an empty std::string, - // and vice versa. - std::wstring wempty; - std::string empty; - EXPECT_EQ(empty, WideToUTF8(wempty)); - EXPECT_EQ(wempty, UTF8ToWide(empty)); -} - -TEST(UTFStringConversionsTest, ConvertUTF8ToWide) { - struct UTF8ToWideCase { - const char* utf8; - const wchar_t* wide; - bool success; - } convert_cases[] = { - // Regular UTF-8 input. - {"\xe4\xbd\xa0\xe5\xa5\xbd", L"\x4f60\x597d", true}, - // Non-character is passed through. - {"\xef\xbf\xbfHello", L"\xffffHello", true}, - // Truncated UTF-8 sequence. - {"\xe4\xa0\xe5\xa5\xbd", L"\xfffd\x597d", false}, - // Truncated off the end. - {"\xe5\xa5\xbd\xe4\xa0", L"\x597d\xfffd", false}, - // Non-shortest-form UTF-8. - {"\xf0\x84\xbd\xa0\xe5\xa5\xbd", L"\xfffd\xfffd\xfffd\xfffd\x597d", false}, - // This UTF-8 character decodes to a UTF-16 surrogate, which is illegal. - {"\xed\xb0\x80", L"\xfffd\xfffd\xfffd", false}, - // Non-BMP characters. The second is a non-character regarded as valid. - // The result will either be in UTF-16 or UTF-32. -#if defined(WCHAR_T_IS_UTF16) - {"A\xF0\x90\x8C\x80z", L"A\xd800\xdf00z", true}, - {"A\xF4\x8F\xBF\xBEz", L"A\xdbff\xdffez", true}, -#elif defined(WCHAR_T_IS_UTF32) - {"A\xF0\x90\x8C\x80z", L"A\x10300z", true}, - {"A\xF4\x8F\xBF\xBEz", L"A\x10fffez", true}, -#endif - }; - - for (size_t i = 0; i < arraysize(convert_cases); i++) { - std::wstring converted; - EXPECT_EQ(convert_cases[i].success, - UTF8ToWide(convert_cases[i].utf8, - strlen(convert_cases[i].utf8), - &converted)); - std::wstring expected(convert_cases[i].wide); - EXPECT_EQ(expected, converted); - } - - // Manually test an embedded NULL. - std::wstring converted; - EXPECT_TRUE(UTF8ToWide("\00Z\t", 3, &converted)); - ASSERT_EQ(3U, converted.length()); - EXPECT_EQ(static_cast<wchar_t>(0), converted[0]); - EXPECT_EQ('Z', converted[1]); - EXPECT_EQ('\t', converted[2]); - - // Make sure that conversion replaces, not appends. - EXPECT_TRUE(UTF8ToWide("B", 1, &converted)); - ASSERT_EQ(1U, converted.length()); - EXPECT_EQ('B', converted[0]); -} - -#if defined(WCHAR_T_IS_UTF16) -// This test is only valid when wchar_t == UTF-16. -TEST(UTFStringConversionsTest, ConvertUTF16ToUTF8) { - struct WideToUTF8Case { - const wchar_t* utf16; - const char* utf8; - bool success; - } convert_cases[] = { - // Regular UTF-16 input. - {L"\x4f60\x597d", "\xe4\xbd\xa0\xe5\xa5\xbd", true}, - // Test a non-BMP character. - {L"\xd800\xdf00", "\xF0\x90\x8C\x80", true}, - // Non-characters are passed through. - {L"\xffffHello", "\xEF\xBF\xBFHello", true}, - {L"\xdbff\xdffeHello", "\xF4\x8F\xBF\xBEHello", true}, - // The first character is a truncated UTF-16 character. - {L"\xd800\x597d", "\xef\xbf\xbd\xe5\xa5\xbd", false}, - // Truncated at the end. - {L"\x597d\xd800", "\xe5\xa5\xbd\xef\xbf\xbd", false}, - }; - - for (const auto& test : convert_cases) { - std::string converted; - EXPECT_EQ(test.success, - WideToUTF8(test.utf16, wcslen(test.utf16), &converted)); - std::string expected(test.utf8); - EXPECT_EQ(expected, converted); - } -} - -#elif defined(WCHAR_T_IS_UTF32) -// This test is only valid when wchar_t == UTF-32. -TEST(UTFStringConversionsTest, ConvertUTF32ToUTF8) { - struct WideToUTF8Case { - const wchar_t* utf32; - const char* utf8; - bool success; - } convert_cases[] = { - // Regular 16-bit input. - {L"\x4f60\x597d", "\xe4\xbd\xa0\xe5\xa5\xbd", true}, - // Test a non-BMP character. - {L"A\x10300z", "A\xF0\x90\x8C\x80z", true}, - // Non-characters are passed through. - {L"\xffffHello", "\xEF\xBF\xBFHello", true}, - {L"\x10fffeHello", "\xF4\x8F\xBF\xBEHello", true}, - // Invalid Unicode code points. - {L"\xfffffffHello", "\xEF\xBF\xBDHello", false}, - // The first character is a truncated UTF-16 character. - {L"\xd800\x597d", "\xef\xbf\xbd\xe5\xa5\xbd", false}, - {L"\xdc01Hello", "\xef\xbf\xbdHello", false}, - }; - - for (const auto& test : convert_cases) { - std::string converted; - EXPECT_EQ(test.success, - WideToUTF8(test.utf32, wcslen(test.utf32), &converted)); - std::string expected(test.utf8); - EXPECT_EQ(expected, converted); - } -} -#endif // defined(WCHAR_T_IS_UTF32) - -TEST(UTFStringConversionsTest, ConvertMultiString) { - static char16 multi16[] = { - 'f', 'o', 'o', '\0', - 'b', 'a', 'r', '\0', - 'b', 'a', 'z', '\0', - '\0' - }; - static char multi[] = { - 'f', 'o', 'o', '\0', - 'b', 'a', 'r', '\0', - 'b', 'a', 'z', '\0', - '\0' - }; - string16 multistring16; - memcpy(WriteInto(&multistring16, arraysize(multi16)), multi16, - sizeof(multi16)); - EXPECT_EQ(arraysize(multi16) - 1, multistring16.length()); - std::string expected; - memcpy(WriteInto(&expected, arraysize(multi)), multi, sizeof(multi)); - EXPECT_EQ(arraysize(multi) - 1, expected.length()); - const std::string& converted = UTF16ToUTF8(multistring16); - EXPECT_EQ(arraysize(multi) - 1, converted.length()); - EXPECT_EQ(expected, converted); -} - -} // namespace base
diff --git a/base/supports_user_data_unittest.cc b/base/supports_user_data_unittest.cc deleted file mode 100644 index 2e0a724..0000000 --- a/base/supports_user_data_unittest.cc +++ /dev/null
@@ -1,40 +0,0 @@ -// 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/supports_user_data.h" - -#include <vector> - -#include "base/memory/ptr_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -struct TestSupportsUserData : public SupportsUserData {}; - -struct UsesItself : public SupportsUserData::Data { - UsesItself(SupportsUserData* supports_user_data, const void* key) - : supports_user_data_(supports_user_data), - key_(key) { - } - - ~UsesItself() override { - EXPECT_EQ(nullptr, supports_user_data_->GetUserData(key_)); - } - - SupportsUserData* supports_user_data_; - const void* key_; -}; - -TEST(SupportsUserDataTest, ClearWorksRecursively) { - TestSupportsUserData supports_user_data; - char key = 0; - supports_user_data.SetUserData( - &key, std::make_unique<UsesItself>(&supports_user_data, &key)); - // Destruction of supports_user_data runs the actual test. -} - -} // namespace -} // namespace base
diff --git a/base/sync_socket_unittest.cc b/base/sync_socket_unittest.cc deleted file mode 100644 index fdcd9a1..0000000 --- a/base/sync_socket_unittest.cc +++ /dev/null
@@ -1,190 +0,0 @@ -// 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/sync_socket.h" - -#include "base/macros.h" -#include "base/synchronization/waitable_event.h" -#include "base/threading/platform_thread.h" -#include "base/threading/simple_thread.h" -#include "base/time/time.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -constexpr TimeDelta kReceiveTimeout = base::TimeDelta::FromMilliseconds(750); - -class HangingReceiveThread : public DelegateSimpleThread::Delegate { - public: - explicit HangingReceiveThread(SyncSocket* socket, bool with_timeout) - : socket_(socket), - thread_(this, "HangingReceiveThread"), - with_timeout_(with_timeout), - started_event_(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED), - done_event_(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED) { - thread_.Start(); - } - - ~HangingReceiveThread() override = default; - - void Run() override { - int data = 0; - ASSERT_EQ(socket_->Peek(), 0u); - - started_event_.Signal(); - - if (with_timeout_) { - ASSERT_EQ(0u, socket_->ReceiveWithTimeout(&data, sizeof(data), - kReceiveTimeout)); - } else { - ASSERT_EQ(0u, socket_->Receive(&data, sizeof(data))); - } - - done_event_.Signal(); - } - - void Stop() { - thread_.Join(); - } - - WaitableEvent* started_event() { return &started_event_; } - WaitableEvent* done_event() { return &done_event_; } - - private: - SyncSocket* socket_; - DelegateSimpleThread thread_; - bool with_timeout_; - WaitableEvent started_event_; - WaitableEvent done_event_; - - DISALLOW_COPY_AND_ASSIGN(HangingReceiveThread); -}; - -// Tests sending data between two SyncSockets. Uses ASSERT() and thus will exit -// early upon failure. Callers should use ASSERT_NO_FATAL_FAILURE() if testing -// continues after return. -void SendReceivePeek(SyncSocket* socket_a, SyncSocket* socket_b) { - int received = 0; - const int kSending = 123; - static_assert(sizeof(kSending) == sizeof(received), "invalid data size"); - - ASSERT_EQ(0u, socket_a->Peek()); - ASSERT_EQ(0u, socket_b->Peek()); - - // Verify |socket_a| can send to |socket_a| and |socket_a| can Receive from - // |socket_a|. - ASSERT_EQ(sizeof(kSending), socket_a->Send(&kSending, sizeof(kSending))); - ASSERT_EQ(sizeof(kSending), socket_b->Peek()); - ASSERT_EQ(sizeof(kSending), socket_b->Receive(&received, sizeof(kSending))); - ASSERT_EQ(kSending, received); - - ASSERT_EQ(0u, socket_a->Peek()); - ASSERT_EQ(0u, socket_b->Peek()); - - // Now verify the reverse. - received = 0; - ASSERT_EQ(sizeof(kSending), socket_b->Send(&kSending, sizeof(kSending))); - ASSERT_EQ(sizeof(kSending), socket_a->Peek()); - ASSERT_EQ(sizeof(kSending), socket_a->Receive(&received, sizeof(kSending))); - ASSERT_EQ(kSending, received); - - ASSERT_EQ(0u, socket_a->Peek()); - ASSERT_EQ(0u, socket_b->Peek()); - - ASSERT_TRUE(socket_a->Close()); - ASSERT_TRUE(socket_b->Close()); -} - -} // namespace - -class SyncSocketTest : public testing::Test { - public: - void SetUp() override { - ASSERT_TRUE(SyncSocket::CreatePair(&socket_a_, &socket_b_)); - } - - protected: - SyncSocket socket_a_; - SyncSocket socket_b_; -}; - -TEST_F(SyncSocketTest, NormalSendReceivePeek) { - SendReceivePeek(&socket_a_, &socket_b_); -} - -TEST_F(SyncSocketTest, ClonedSendReceivePeek) { - SyncSocket socket_c(socket_a_.Release()); - SyncSocket socket_d(socket_b_.Release()); - SendReceivePeek(&socket_c, &socket_d); -}; - -class CancelableSyncSocketTest : public testing::Test { - public: - void SetUp() override { - ASSERT_TRUE(CancelableSyncSocket::CreatePair(&socket_a_, &socket_b_)); - } - - protected: - CancelableSyncSocket socket_a_; - CancelableSyncSocket socket_b_; -}; - -TEST_F(CancelableSyncSocketTest, NormalSendReceivePeek) { - SendReceivePeek(&socket_a_, &socket_b_); -} - -TEST_F(CancelableSyncSocketTest, ClonedSendReceivePeek) { - CancelableSyncSocket socket_c(socket_a_.Release()); - CancelableSyncSocket socket_d(socket_b_.Release()); - SendReceivePeek(&socket_c, &socket_d); -} - -TEST_F(CancelableSyncSocketTest, ShutdownCancelsReceive) { - HangingReceiveThread thread(&socket_b_, /* with_timeout = */ false); - - // Wait for the thread to be started. Note that this doesn't guarantee that - // Receive() is called before Shutdown(). - thread.started_event()->Wait(); - - EXPECT_TRUE(socket_b_.Shutdown()); - EXPECT_TRUE(thread.done_event()->TimedWait(kReceiveTimeout)); - - thread.Stop(); -} - -TEST_F(CancelableSyncSocketTest, ShutdownCancelsReceiveWithTimeout) { - HangingReceiveThread thread(&socket_b_, /* with_timeout = */ true); - - // Wait for the thread to be started. Note that this doesn't guarantee that - // Receive() is called before Shutdown(). - thread.started_event()->Wait(); - - EXPECT_TRUE(socket_b_.Shutdown()); - EXPECT_TRUE(thread.done_event()->TimedWait(kReceiveTimeout)); - - thread.Stop(); -} - -TEST_F(CancelableSyncSocketTest, ReceiveAfterShutdown) { - socket_a_.Shutdown(); - int data = 0; - EXPECT_EQ(0u, socket_a_.Receive(&data, sizeof(data))); -} - -TEST_F(CancelableSyncSocketTest, ReceiveWithTimeoutAfterShutdown) { - socket_a_.Shutdown(); - TimeTicks start = TimeTicks::Now(); - int data = 0; - EXPECT_EQ(0u, - socket_a_.ReceiveWithTimeout(&data, sizeof(data), kReceiveTimeout)); - - // Ensure the receive didn't just timeout. - EXPECT_LT(TimeTicks::Now() - start, kReceiveTimeout); -} - -} // namespace base
diff --git a/base/synchronization/atomic_flag_unittest.cc b/base/synchronization/atomic_flag_unittest.cc deleted file mode 100644 index 1a3da7f..0000000 --- a/base/synchronization/atomic_flag_unittest.cc +++ /dev/null
@@ -1,135 +0,0 @@ -// 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/synchronization/atomic_flag.h" - -#include "base/bind.h" -#include "base/logging.h" -#include "base/single_thread_task_runner.h" -#include "base/synchronization/waitable_event.h" -#include "base/test/gtest_util.h" -#include "base/threading/platform_thread.h" -#include "base/threading/thread.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -void ExpectSetFlagDeath(AtomicFlag* flag) { - ASSERT_TRUE(flag); - EXPECT_DCHECK_DEATH(flag->Set()); -} - -// Busy waits (to explicitly avoid using synchronization constructs that would -// defeat the purpose of testing atomics) until |tested_flag| is set and then -// verifies that non-atomic |*expected_after_flag| is true and sets |*done_flag| -// before returning if it's non-null. -void BusyWaitUntilFlagIsSet(AtomicFlag* tested_flag, bool* expected_after_flag, - AtomicFlag* done_flag) { - while (!tested_flag->IsSet()) - PlatformThread::YieldCurrentThread(); - - EXPECT_TRUE(*expected_after_flag); - if (done_flag) - done_flag->Set(); -} - -} // namespace - -TEST(AtomicFlagTest, SimpleSingleThreadedTest) { - AtomicFlag flag; - ASSERT_FALSE(flag.IsSet()); - flag.Set(); - ASSERT_TRUE(flag.IsSet()); -} - -TEST(AtomicFlagTest, DoubleSetTest) { - AtomicFlag flag; - ASSERT_FALSE(flag.IsSet()); - flag.Set(); - ASSERT_TRUE(flag.IsSet()); - flag.Set(); - ASSERT_TRUE(flag.IsSet()); -} - -TEST(AtomicFlagTest, ReadFromDifferentThread) { - // |tested_flag| is the one being tested below. - AtomicFlag tested_flag; - // |expected_after_flag| is used to confirm that sequential consistency is - // obtained around |tested_flag|. - bool expected_after_flag = false; - // |reset_flag| is used to confirm the test flows as intended without using - // synchronization constructs which would defeat the purpose of exercising - // atomics. - AtomicFlag reset_flag; - - Thread thread("AtomicFlagTest.ReadFromDifferentThread"); - ASSERT_TRUE(thread.Start()); - thread.task_runner()->PostTask(FROM_HERE, - BindOnce(&BusyWaitUntilFlagIsSet, &tested_flag, - &expected_after_flag, &reset_flag)); - - // To verify that IsSet() fetches the flag's value from memory every time it - // is called (not just the first time that it is called on a thread), sleep - // before setting the flag. - PlatformThread::Sleep(TimeDelta::FromMilliseconds(20)); - - // |expected_after_flag| is used to verify that all memory operations - // performed before |tested_flag| is Set() are visible to threads that can see - // IsSet(). - expected_after_flag = true; - tested_flag.Set(); - - // Sleep again to give the busy loop time to observe the flag and verify - // expectations. - PlatformThread::Sleep(TimeDelta::FromMilliseconds(20)); - - // Use |reset_flag| to confirm that the above completed (which the rest of - // this test assumes). - while (!reset_flag.IsSet()) - PlatformThread::YieldCurrentThread(); - - tested_flag.UnsafeResetForTesting(); - EXPECT_FALSE(tested_flag.IsSet()); - expected_after_flag = false; - - // Perform the same test again after the controlled UnsafeResetForTesting(), - // |thread| is guaranteed to be synchronized past the - // |UnsafeResetForTesting()| call when the task runs per the implicit - // synchronization in the post task mechanism. - thread.task_runner()->PostTask(FROM_HERE, - BindOnce(&BusyWaitUntilFlagIsSet, &tested_flag, - &expected_after_flag, nullptr)); - - PlatformThread::Sleep(TimeDelta::FromMilliseconds(20)); - - expected_after_flag = true; - tested_flag.Set(); - - // The |thread|'s destructor will block until the posted task completes, so - // the test will time out if it fails to see the flag be set. -} - -TEST(AtomicFlagTest, SetOnDifferentSequenceDeathTest) { - // Checks that Set() can't be called from another sequence after being called - // on this one. AtomicFlag should die on a DCHECK if Set() is called again - // from another sequence. - - // Note: flag must be declared before the Thread so that its destructor runs - // later. Otherwise there's a race between destructing flag and running - // ExpectSetFlagDeath. - AtomicFlag flag; - - ::testing::FLAGS_gtest_death_test_style = "threadsafe"; - Thread t("AtomicFlagTest.SetOnDifferentThreadDeathTest"); - ASSERT_TRUE(t.Start()); - EXPECT_TRUE(t.WaitUntilThreadStarted()); - - flag.Set(); - t.task_runner()->PostTask(FROM_HERE, BindOnce(&ExpectSetFlagDeath, &flag)); -} - -} // namespace base
diff --git a/base/synchronization/condition_variable_unittest.cc b/base/synchronization/condition_variable_unittest.cc deleted file mode 100644 index 929060a..0000000 --- a/base/synchronization/condition_variable_unittest.cc +++ /dev/null
@@ -1,768 +0,0 @@ -// 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. - -// Multi-threaded tests of ConditionVariable class. - -#include "base/synchronization/condition_variable.h" - -#include <time.h> - -#include <algorithm> -#include <memory> -#include <vector> - -#include "base/bind.h" -#include "base/location.h" -#include "base/logging.h" -#include "base/single_thread_task_runner.h" -#include "base/synchronization/lock.h" -#include "base/synchronization/spin_wait.h" -#include "base/threading/platform_thread.h" -#include "base/threading/thread.h" -#include "base/threading/thread_collision_warner.h" -#include "base/time/time.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/platform_test.h" - -namespace base { - -namespace { -//------------------------------------------------------------------------------ -// Define our test class, with several common variables. -//------------------------------------------------------------------------------ - -class ConditionVariableTest : public PlatformTest { - public: - const TimeDelta kZeroMs; - const TimeDelta kTenMs; - const TimeDelta kThirtyMs; - const TimeDelta kFortyFiveMs; - const TimeDelta kSixtyMs; - const TimeDelta kOneHundredMs; - - ConditionVariableTest() - : kZeroMs(TimeDelta::FromMilliseconds(0)), - kTenMs(TimeDelta::FromMilliseconds(10)), - kThirtyMs(TimeDelta::FromMilliseconds(30)), - kFortyFiveMs(TimeDelta::FromMilliseconds(45)), - kSixtyMs(TimeDelta::FromMilliseconds(60)), - kOneHundredMs(TimeDelta::FromMilliseconds(100)) { - } -}; - -//------------------------------------------------------------------------------ -// Define a class that will control activities an several multi-threaded tests. -// The general structure of multi-threaded tests is that a test case will -// construct an instance of a WorkQueue. The WorkQueue will spin up some -// threads and control them throughout their lifetime, as well as maintaining -// a central repository of the work thread's activity. Finally, the WorkQueue -// will command the the worker threads to terminate. At that point, the test -// cases will validate that the WorkQueue has records showing that the desired -// activities were performed. -//------------------------------------------------------------------------------ - -// Callers are responsible for synchronizing access to the following class. -// The WorkQueue::lock_, as accessed via WorkQueue::lock(), should be used for -// all synchronized access. -class WorkQueue : public PlatformThread::Delegate { - public: - explicit WorkQueue(int thread_count); - ~WorkQueue() override; - - // PlatformThread::Delegate interface. - void ThreadMain() override; - - //---------------------------------------------------------------------------- - // Worker threads only call the following methods. - // They should use the lock to get exclusive access. - int GetThreadId(); // Get an ID assigned to a thread.. - bool EveryIdWasAllocated() const; // Indicates that all IDs were handed out. - TimeDelta GetAnAssignment(int thread_id); // Get a work task duration. - void WorkIsCompleted(int thread_id); - - int task_count() const; - bool allow_help_requests() const; // Workers can signal more workers. - bool shutdown() const; // Check if shutdown has been requested. - - void thread_shutting_down(); - - - //---------------------------------------------------------------------------- - // Worker threads can call them but not needed to acquire a lock. - Lock* lock(); - - ConditionVariable* work_is_available(); - ConditionVariable* all_threads_have_ids(); - ConditionVariable* no_more_tasks(); - - //---------------------------------------------------------------------------- - // The rest of the methods are for use by the controlling master thread (the - // test case code). - void ResetHistory(); - int GetMinCompletionsByWorkerThread() const; - int GetMaxCompletionsByWorkerThread() const; - int GetNumThreadsTakingAssignments() const; - int GetNumThreadsCompletingTasks() const; - int GetNumberOfCompletedTasks() const; - - void SetWorkTime(TimeDelta delay); - void SetTaskCount(int count); - void SetAllowHelp(bool allow); - - // The following must be called without locking, and will spin wait until the - // threads are all in a wait state. - void SpinUntilAllThreadsAreWaiting(); - void SpinUntilTaskCountLessThan(int task_count); - - // Caller must acquire lock before calling. - void SetShutdown(); - - // Compares the |shutdown_task_count_| to the |thread_count| and returns true - // if they are equal. This check will acquire the |lock_| so the caller - // should not hold the lock when calling this method. - bool ThreadSafeCheckShutdown(int thread_count); - - private: - // Both worker threads and controller use the following to synchronize. - Lock lock_; - ConditionVariable work_is_available_; // To tell threads there is work. - - // Conditions to notify the controlling process (if it is interested). - ConditionVariable all_threads_have_ids_; // All threads are running. - ConditionVariable no_more_tasks_; // Task count is zero. - - const int thread_count_; - int waiting_thread_count_; - std::unique_ptr<PlatformThreadHandle[]> thread_handles_; - std::vector<int> assignment_history_; // Number of assignment per worker. - std::vector<int> completion_history_; // Number of completions per worker. - int thread_started_counter_; // Used to issue unique id to workers. - int shutdown_task_count_; // Number of tasks told to shutdown - int task_count_; // Number of assignment tasks waiting to be processed. - TimeDelta worker_delay_; // Time each task takes to complete. - bool allow_help_requests_; // Workers can signal more workers. - bool shutdown_; // Set when threads need to terminate. - - DFAKE_MUTEX(locked_methods_); -}; - -//------------------------------------------------------------------------------ -// The next section contains the actual tests. -//------------------------------------------------------------------------------ - -TEST_F(ConditionVariableTest, StartupShutdownTest) { - Lock lock; - - // First try trivial startup/shutdown. - { - ConditionVariable cv1(&lock); - } // Call for cv1 destruction. - - // Exercise with at least a few waits. - ConditionVariable cv(&lock); - - lock.Acquire(); - cv.TimedWait(kTenMs); // Wait for 10 ms. - cv.TimedWait(kTenMs); // Wait for 10 ms. - lock.Release(); - - lock.Acquire(); - cv.TimedWait(kTenMs); // Wait for 10 ms. - cv.TimedWait(kTenMs); // Wait for 10 ms. - cv.TimedWait(kTenMs); // Wait for 10 ms. - lock.Release(); -} // Call for cv destruction. - -TEST_F(ConditionVariableTest, TimeoutTest) { - Lock lock; - ConditionVariable cv(&lock); - lock.Acquire(); - - TimeTicks start = TimeTicks::Now(); - const TimeDelta WAIT_TIME = TimeDelta::FromMilliseconds(300); - // Allow for clocking rate granularity. - const TimeDelta FUDGE_TIME = TimeDelta::FromMilliseconds(50); - - cv.TimedWait(WAIT_TIME + FUDGE_TIME); - TimeDelta duration = TimeTicks::Now() - start; - // We can't use EXPECT_GE here as the TimeDelta class does not support the - // required stream conversion. - EXPECT_TRUE(duration >= WAIT_TIME); - - lock.Release(); -} - -#if defined(OS_POSIX) && !defined(OS_FUCHSIA) -const int kDiscontinuitySeconds = 2; - -void BackInTime(Lock* lock) { - AutoLock auto_lock(*lock); - - timeval tv; - gettimeofday(&tv, nullptr); - tv.tv_sec -= kDiscontinuitySeconds; - settimeofday(&tv, nullptr); -} - -// Tests that TimedWait ignores changes to the system clock. -// Test is disabled by default, because it needs to run as root to muck with the -// system clock. -// http://crbug.com/293736 -TEST_F(ConditionVariableTest, DISABLED_TimeoutAcrossSetTimeOfDay) { - timeval tv; - gettimeofday(&tv, nullptr); - tv.tv_sec += kDiscontinuitySeconds; - if (settimeofday(&tv, nullptr) < 0) { - PLOG(ERROR) << "Could not set time of day. Run as root?"; - return; - } - - Lock lock; - ConditionVariable cv(&lock); - lock.Acquire(); - - Thread thread("Helper"); - thread.Start(); - thread.task_runner()->PostTask(FROM_HERE, base::BindOnce(&BackInTime, &lock)); - - TimeTicks start = TimeTicks::Now(); - const TimeDelta kWaitTime = TimeDelta::FromMilliseconds(300); - // Allow for clocking rate granularity. - const TimeDelta kFudgeTime = TimeDelta::FromMilliseconds(50); - - cv.TimedWait(kWaitTime + kFudgeTime); - TimeDelta duration = TimeTicks::Now() - start; - - thread.Stop(); - // We can't use EXPECT_GE here as the TimeDelta class does not support the - // required stream conversion. - EXPECT_TRUE(duration >= kWaitTime); - EXPECT_TRUE(duration <= TimeDelta::FromSeconds(kDiscontinuitySeconds)); - - lock.Release(); -} -#endif - - -// Suddenly got flaky on Win, see http://crbug.com/10607 (starting at -// comment #15). -#if defined(OS_WIN) -#define MAYBE_MultiThreadConsumerTest DISABLED_MultiThreadConsumerTest -#else -#define MAYBE_MultiThreadConsumerTest MultiThreadConsumerTest -#endif -// Test serial task servicing, as well as two parallel task servicing methods. -TEST_F(ConditionVariableTest, MAYBE_MultiThreadConsumerTest) { - const int kThreadCount = 10; - WorkQueue queue(kThreadCount); // Start the threads. - - const int kTaskCount = 10; // Number of tasks in each mini-test here. - - Time start_time; // Used to time task processing. - - { - base::AutoLock auto_lock(*queue.lock()); - while (!queue.EveryIdWasAllocated()) - queue.all_threads_have_ids()->Wait(); - } - - // If threads aren't in a wait state, they may start to gobble up tasks in - // parallel, short-circuiting (breaking) this test. - queue.SpinUntilAllThreadsAreWaiting(); - - { - // Since we have no tasks yet, all threads should be waiting by now. - base::AutoLock auto_lock(*queue.lock()); - EXPECT_EQ(0, queue.GetNumThreadsTakingAssignments()); - EXPECT_EQ(0, queue.GetNumThreadsCompletingTasks()); - EXPECT_EQ(0, queue.task_count()); - EXPECT_EQ(0, queue.GetMaxCompletionsByWorkerThread()); - EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread()); - EXPECT_EQ(0, queue.GetNumberOfCompletedTasks()); - - // Set up to make each task include getting help from another worker, so - // so that the work gets done in paralell. - queue.ResetHistory(); - queue.SetTaskCount(kTaskCount); - queue.SetWorkTime(kThirtyMs); - queue.SetAllowHelp(true); - - start_time = Time::Now(); - } - - queue.work_is_available()->Signal(); // But each worker can signal another. - // Wait till we at least start to handle tasks (and we're not all waiting). - queue.SpinUntilTaskCountLessThan(kTaskCount); - // Wait to allow the all workers to get done. - queue.SpinUntilAllThreadsAreWaiting(); - - { - // Wait until all work tasks have at least been assigned. - base::AutoLock auto_lock(*queue.lock()); - while (queue.task_count()) - queue.no_more_tasks()->Wait(); - - // To avoid racy assumptions, we'll just assert that at least 2 threads - // did work. We know that the first worker should have gone to sleep, and - // hence a second worker should have gotten an assignment. - EXPECT_LE(2, queue.GetNumThreadsTakingAssignments()); - EXPECT_EQ(kTaskCount, queue.GetNumberOfCompletedTasks()); - - // Try to ask all workers to help, and only a few will do the work. - queue.ResetHistory(); - queue.SetTaskCount(3); - queue.SetWorkTime(kThirtyMs); - queue.SetAllowHelp(false); - } - queue.work_is_available()->Broadcast(); // Make them all try. - // Wait till we at least start to handle tasks (and we're not all waiting). - queue.SpinUntilTaskCountLessThan(3); - // Wait to allow the 3 workers to get done. - queue.SpinUntilAllThreadsAreWaiting(); - - { - base::AutoLock auto_lock(*queue.lock()); - EXPECT_EQ(3, queue.GetNumThreadsTakingAssignments()); - EXPECT_EQ(3, queue.GetNumThreadsCompletingTasks()); - EXPECT_EQ(0, queue.task_count()); - EXPECT_EQ(1, queue.GetMaxCompletionsByWorkerThread()); - EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread()); - EXPECT_EQ(3, queue.GetNumberOfCompletedTasks()); - - // Set up to make each task get help from another worker. - queue.ResetHistory(); - queue.SetTaskCount(3); - queue.SetWorkTime(kThirtyMs); - queue.SetAllowHelp(true); // Allow (unnecessary) help requests. - } - queue.work_is_available()->Broadcast(); // Signal all threads. - // Wait till we at least start to handle tasks (and we're not all waiting). - queue.SpinUntilTaskCountLessThan(3); - // Wait to allow the 3 workers to get done. - queue.SpinUntilAllThreadsAreWaiting(); - - { - base::AutoLock auto_lock(*queue.lock()); - EXPECT_EQ(3, queue.GetNumThreadsTakingAssignments()); - EXPECT_EQ(3, queue.GetNumThreadsCompletingTasks()); - EXPECT_EQ(0, queue.task_count()); - EXPECT_EQ(1, queue.GetMaxCompletionsByWorkerThread()); - EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread()); - EXPECT_EQ(3, queue.GetNumberOfCompletedTasks()); - - // Set up to make each task get help from another worker. - queue.ResetHistory(); - queue.SetTaskCount(20); // 2 tasks per thread. - queue.SetWorkTime(kThirtyMs); - queue.SetAllowHelp(true); - } - queue.work_is_available()->Signal(); // But each worker can signal another. - // Wait till we at least start to handle tasks (and we're not all waiting). - queue.SpinUntilTaskCountLessThan(20); - // Wait to allow the 10 workers to get done. - queue.SpinUntilAllThreadsAreWaiting(); // Should take about 60 ms. - - { - base::AutoLock auto_lock(*queue.lock()); - EXPECT_EQ(10, queue.GetNumThreadsTakingAssignments()); - EXPECT_EQ(10, queue.GetNumThreadsCompletingTasks()); - EXPECT_EQ(0, queue.task_count()); - EXPECT_EQ(20, queue.GetNumberOfCompletedTasks()); - - // Same as last test, but with Broadcast(). - queue.ResetHistory(); - queue.SetTaskCount(20); // 2 tasks per thread. - queue.SetWorkTime(kThirtyMs); - queue.SetAllowHelp(true); - } - queue.work_is_available()->Broadcast(); - // Wait till we at least start to handle tasks (and we're not all waiting). - queue.SpinUntilTaskCountLessThan(20); - // Wait to allow the 10 workers to get done. - queue.SpinUntilAllThreadsAreWaiting(); // Should take about 60 ms. - - { - base::AutoLock auto_lock(*queue.lock()); - EXPECT_EQ(10, queue.GetNumThreadsTakingAssignments()); - EXPECT_EQ(10, queue.GetNumThreadsCompletingTasks()); - EXPECT_EQ(0, queue.task_count()); - EXPECT_EQ(20, queue.GetNumberOfCompletedTasks()); - - queue.SetShutdown(); - } - queue.work_is_available()->Broadcast(); // Force check for shutdown. - - SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(1), - queue.ThreadSafeCheckShutdown(kThreadCount)); -} - -TEST_F(ConditionVariableTest, LargeFastTaskTest) { - const int kThreadCount = 200; - WorkQueue queue(kThreadCount); // Start the threads. - - Lock private_lock; // Used locally for master to wait. - base::AutoLock private_held_lock(private_lock); - ConditionVariable private_cv(&private_lock); - - { - base::AutoLock auto_lock(*queue.lock()); - while (!queue.EveryIdWasAllocated()) - queue.all_threads_have_ids()->Wait(); - } - - // Wait a bit more to allow threads to reach their wait state. - queue.SpinUntilAllThreadsAreWaiting(); - - { - // Since we have no tasks, all threads should be waiting by now. - base::AutoLock auto_lock(*queue.lock()); - EXPECT_EQ(0, queue.GetNumThreadsTakingAssignments()); - EXPECT_EQ(0, queue.GetNumThreadsCompletingTasks()); - EXPECT_EQ(0, queue.task_count()); - EXPECT_EQ(0, queue.GetMaxCompletionsByWorkerThread()); - EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread()); - EXPECT_EQ(0, queue.GetNumberOfCompletedTasks()); - - // Set up to make all workers do (an average of) 20 tasks. - queue.ResetHistory(); - queue.SetTaskCount(20 * kThreadCount); - queue.SetWorkTime(kFortyFiveMs); - queue.SetAllowHelp(false); - } - queue.work_is_available()->Broadcast(); // Start up all threads. - // Wait until we've handed out all tasks. - { - base::AutoLock auto_lock(*queue.lock()); - while (queue.task_count() != 0) - queue.no_more_tasks()->Wait(); - } - - // Wait till the last of the tasks complete. - queue.SpinUntilAllThreadsAreWaiting(); - - { - // With Broadcast(), every thread should have participated. - // but with racing.. they may not all have done equal numbers of tasks. - base::AutoLock auto_lock(*queue.lock()); - EXPECT_EQ(kThreadCount, queue.GetNumThreadsTakingAssignments()); - EXPECT_EQ(kThreadCount, queue.GetNumThreadsCompletingTasks()); - EXPECT_EQ(0, queue.task_count()); - EXPECT_LE(20, queue.GetMaxCompletionsByWorkerThread()); - EXPECT_EQ(20 * kThreadCount, queue.GetNumberOfCompletedTasks()); - - // Set up to make all workers do (an average of) 4 tasks. - queue.ResetHistory(); - queue.SetTaskCount(kThreadCount * 4); - queue.SetWorkTime(kFortyFiveMs); - queue.SetAllowHelp(true); // Might outperform Broadcast(). - } - queue.work_is_available()->Signal(); // Start up one thread. - - // Wait until we've handed out all tasks - { - base::AutoLock auto_lock(*queue.lock()); - while (queue.task_count() != 0) - queue.no_more_tasks()->Wait(); - } - - // Wait till the last of the tasks complete. - queue.SpinUntilAllThreadsAreWaiting(); - - { - // With Signal(), every thread should have participated. - // but with racing.. they may not all have done four tasks. - base::AutoLock auto_lock(*queue.lock()); - EXPECT_EQ(kThreadCount, queue.GetNumThreadsTakingAssignments()); - EXPECT_EQ(kThreadCount, queue.GetNumThreadsCompletingTasks()); - EXPECT_EQ(0, queue.task_count()); - EXPECT_LE(4, queue.GetMaxCompletionsByWorkerThread()); - EXPECT_EQ(4 * kThreadCount, queue.GetNumberOfCompletedTasks()); - - queue.SetShutdown(); - } - queue.work_is_available()->Broadcast(); // Force check for shutdown. - - // Wait for shutdowns to complete. - SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(1), - queue.ThreadSafeCheckShutdown(kThreadCount)); -} - -//------------------------------------------------------------------------------ -// Finally we provide the implementation for the methods in the WorkQueue class. -//------------------------------------------------------------------------------ - -WorkQueue::WorkQueue(int thread_count) - : lock_(), - work_is_available_(&lock_), - all_threads_have_ids_(&lock_), - no_more_tasks_(&lock_), - thread_count_(thread_count), - waiting_thread_count_(0), - thread_handles_(new PlatformThreadHandle[thread_count]), - assignment_history_(thread_count), - completion_history_(thread_count), - thread_started_counter_(0), - shutdown_task_count_(0), - task_count_(0), - allow_help_requests_(false), - shutdown_(false) { - EXPECT_GE(thread_count_, 1); - ResetHistory(); - SetTaskCount(0); - SetWorkTime(TimeDelta::FromMilliseconds(30)); - - for (int i = 0; i < thread_count_; ++i) { - PlatformThreadHandle pth; - EXPECT_TRUE(PlatformThread::Create(0, this, &pth)); - thread_handles_[i] = pth; - } -} - -WorkQueue::~WorkQueue() { - { - base::AutoLock auto_lock(lock_); - SetShutdown(); - } - work_is_available_.Broadcast(); // Tell them all to terminate. - - for (int i = 0; i < thread_count_; ++i) { - PlatformThread::Join(thread_handles_[i]); - } - EXPECT_EQ(0, waiting_thread_count_); -} - -int WorkQueue::GetThreadId() { - DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_); - DCHECK(!EveryIdWasAllocated()); - return thread_started_counter_++; // Give out Unique IDs. -} - -bool WorkQueue::EveryIdWasAllocated() const { - DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_); - return thread_count_ == thread_started_counter_; -} - -TimeDelta WorkQueue::GetAnAssignment(int thread_id) { - DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_); - DCHECK_LT(0, task_count_); - assignment_history_[thread_id]++; - if (0 == --task_count_) { - no_more_tasks_.Signal(); - } - return worker_delay_; -} - -void WorkQueue::WorkIsCompleted(int thread_id) { - DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_); - completion_history_[thread_id]++; -} - -int WorkQueue::task_count() const { - DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_); - return task_count_; -} - -bool WorkQueue::allow_help_requests() const { - DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_); - return allow_help_requests_; -} - -bool WorkQueue::shutdown() const { - lock_.AssertAcquired(); - DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_); - return shutdown_; -} - -// Because this method is called from the test's main thread we need to actually -// take the lock. Threads will call the thread_shutting_down() method with the -// lock already acquired. -bool WorkQueue::ThreadSafeCheckShutdown(int thread_count) { - bool all_shutdown; - base::AutoLock auto_lock(lock_); - { - // Declare in scope so DFAKE is guranteed to be destroyed before AutoLock. - DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_); - all_shutdown = (shutdown_task_count_ == thread_count); - } - return all_shutdown; -} - -void WorkQueue::thread_shutting_down() { - lock_.AssertAcquired(); - DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_); - shutdown_task_count_++; -} - -Lock* WorkQueue::lock() { - return &lock_; -} - -ConditionVariable* WorkQueue::work_is_available() { - return &work_is_available_; -} - -ConditionVariable* WorkQueue::all_threads_have_ids() { - return &all_threads_have_ids_; -} - -ConditionVariable* WorkQueue::no_more_tasks() { - return &no_more_tasks_; -} - -void WorkQueue::ResetHistory() { - for (int i = 0; i < thread_count_; ++i) { - assignment_history_[i] = 0; - completion_history_[i] = 0; - } -} - -int WorkQueue::GetMinCompletionsByWorkerThread() const { - int minumum = completion_history_[0]; - for (int i = 0; i < thread_count_; ++i) - minumum = std::min(minumum, completion_history_[i]); - return minumum; -} - -int WorkQueue::GetMaxCompletionsByWorkerThread() const { - int maximum = completion_history_[0]; - for (int i = 0; i < thread_count_; ++i) - maximum = std::max(maximum, completion_history_[i]); - return maximum; -} - -int WorkQueue::GetNumThreadsTakingAssignments() const { - int count = 0; - for (int i = 0; i < thread_count_; ++i) - if (assignment_history_[i]) - count++; - return count; -} - -int WorkQueue::GetNumThreadsCompletingTasks() const { - int count = 0; - for (int i = 0; i < thread_count_; ++i) - if (completion_history_[i]) - count++; - return count; -} - -int WorkQueue::GetNumberOfCompletedTasks() const { - int total = 0; - for (int i = 0; i < thread_count_; ++i) - total += completion_history_[i]; - return total; -} - -void WorkQueue::SetWorkTime(TimeDelta delay) { - worker_delay_ = delay; -} - -void WorkQueue::SetTaskCount(int count) { - task_count_ = count; -} - -void WorkQueue::SetAllowHelp(bool allow) { - allow_help_requests_ = allow; -} - -void WorkQueue::SetShutdown() { - lock_.AssertAcquired(); - shutdown_ = true; -} - -void WorkQueue::SpinUntilAllThreadsAreWaiting() { - while (true) { - { - base::AutoLock auto_lock(lock_); - if (waiting_thread_count_ == thread_count_) - break; - } - PlatformThread::Sleep(TimeDelta::FromMilliseconds(30)); - } -} - -void WorkQueue::SpinUntilTaskCountLessThan(int task_count) { - while (true) { - { - base::AutoLock auto_lock(lock_); - if (task_count_ < task_count) - break; - } - PlatformThread::Sleep(TimeDelta::FromMilliseconds(30)); - } -} - - -//------------------------------------------------------------------------------ -// Define the standard worker task. Several tests will spin out many of these -// threads. -//------------------------------------------------------------------------------ - -// The multithread tests involve several threads with a task to perform as -// directed by an instance of the class WorkQueue. -// The task is to: -// a) Check to see if there are more tasks (there is a task counter). -// a1) Wait on condition variable if there are no tasks currently. -// b) Call a function to see what should be done. -// c) Do some computation based on the number of milliseconds returned in (b). -// d) go back to (a). - -// WorkQueue::ThreadMain() implements the above task for all threads. -// It calls the controlling object to tell the creator about progress, and to -// ask about tasks. - -void WorkQueue::ThreadMain() { - int thread_id; - { - base::AutoLock auto_lock(lock_); - thread_id = GetThreadId(); - if (EveryIdWasAllocated()) - all_threads_have_ids()->Signal(); // Tell creator we're ready. - } - - Lock private_lock; // Used to waste time on "our work". - while (1) { // This is the main consumer loop. - TimeDelta work_time; - bool could_use_help; - { - base::AutoLock auto_lock(lock_); - while (0 == task_count() && !shutdown()) { - ++waiting_thread_count_; - work_is_available()->Wait(); - --waiting_thread_count_; - } - if (shutdown()) { - // Ack the notification of a shutdown message back to the controller. - thread_shutting_down(); - return; // Terminate. - } - // Get our task duration from the queue. - work_time = GetAnAssignment(thread_id); - could_use_help = (task_count() > 0) && allow_help_requests(); - } // Release lock - - // Do work (outside of locked region. - if (could_use_help) - work_is_available()->Signal(); // Get help from other threads. - - if (work_time > TimeDelta::FromMilliseconds(0)) { - // We could just sleep(), but we'll instead further exercise the - // condition variable class, and do a timed wait. - base::AutoLock auto_lock(private_lock); - ConditionVariable private_cv(&private_lock); - private_cv.TimedWait(work_time); // Unsynchronized waiting. - } - - { - base::AutoLock auto_lock(lock_); - // Send notification that we completed our "work." - WorkIsCompleted(thread_id); - } - } -} - -} // namespace - -} // namespace base
diff --git a/base/synchronization/lock_unittest.cc b/base/synchronization/lock_unittest.cc deleted file mode 100644 index 1e2f998..0000000 --- a/base/synchronization/lock_unittest.cc +++ /dev/null
@@ -1,257 +0,0 @@ -// 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/synchronization/lock.h" - -#include <stdlib.h> - -#include "base/compiler_specific.h" -#include "base/debug/activity_tracker.h" -#include "base/macros.h" -#include "base/threading/platform_thread.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -// Basic test to make sure that Acquire()/Release()/Try() don't crash ---------- - -class BasicLockTestThread : public PlatformThread::Delegate { - public: - explicit BasicLockTestThread(Lock* lock) : lock_(lock), acquired_(0) {} - - void ThreadMain() override { - for (int i = 0; i < 10; i++) { - lock_->Acquire(); - acquired_++; - lock_->Release(); - } - for (int i = 0; i < 10; i++) { - lock_->Acquire(); - acquired_++; - PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20)); - lock_->Release(); - } - for (int i = 0; i < 10; i++) { - if (lock_->Try()) { - acquired_++; - PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20)); - lock_->Release(); - } - } - } - - int acquired() const { return acquired_; } - - private: - Lock* lock_; - int acquired_; - - DISALLOW_COPY_AND_ASSIGN(BasicLockTestThread); -}; - -TEST(LockTest, Basic) { - Lock lock; - BasicLockTestThread thread(&lock); - PlatformThreadHandle handle; - - ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); - - int acquired = 0; - for (int i = 0; i < 5; i++) { - lock.Acquire(); - acquired++; - lock.Release(); - } - for (int i = 0; i < 10; i++) { - lock.Acquire(); - acquired++; - PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20)); - lock.Release(); - } - for (int i = 0; i < 10; i++) { - if (lock.Try()) { - acquired++; - PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20)); - lock.Release(); - } - } - for (int i = 0; i < 5; i++) { - lock.Acquire(); - acquired++; - PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20)); - lock.Release(); - } - - PlatformThread::Join(handle); - - EXPECT_GE(acquired, 20); - EXPECT_GE(thread.acquired(), 20); -} - -// Test that Try() works as expected ------------------------------------------- - -class TryLockTestThread : public PlatformThread::Delegate { - public: - explicit TryLockTestThread(Lock* lock) : lock_(lock), got_lock_(false) {} - - void ThreadMain() override { - got_lock_ = lock_->Try(); - if (got_lock_) - lock_->Release(); - } - - bool got_lock() const { return got_lock_; } - - private: - Lock* lock_; - bool got_lock_; - - DISALLOW_COPY_AND_ASSIGN(TryLockTestThread); -}; - -TEST(LockTest, TryLock) { - Lock lock; - - ASSERT_TRUE(lock.Try()); - // We now have the lock.... - - // This thread will not be able to get the lock. - { - TryLockTestThread thread(&lock); - PlatformThreadHandle handle; - - ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); - - PlatformThread::Join(handle); - - ASSERT_FALSE(thread.got_lock()); - } - - lock.Release(); - - // This thread will.... - { - TryLockTestThread thread(&lock); - PlatformThreadHandle handle; - - ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); - - PlatformThread::Join(handle); - - ASSERT_TRUE(thread.got_lock()); - // But it released it.... - ASSERT_TRUE(lock.Try()); - } - - lock.Release(); -} - -TEST(LockTest, TryTrackedLock) { - // Enable the activity tracker. - debug::GlobalActivityTracker::CreateWithLocalMemory(64 << 10, 0, "", 3, 0); - - Lock lock; - - ASSERT_TRUE(lock.Try()); - // We now have the lock.... - - // This thread will not be able to get the lock. - { - TryLockTestThread thread(&lock); - PlatformThreadHandle handle; - - ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); - - PlatformThread::Join(handle); - - ASSERT_FALSE(thread.got_lock()); - } - - lock.Release(); - - // This thread will.... - { - TryLockTestThread thread(&lock); - PlatformThreadHandle handle; - - ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); - - PlatformThread::Join(handle); - - ASSERT_TRUE(thread.got_lock()); - // But it released it.... - ASSERT_TRUE(lock.Try()); - } - - lock.Release(); - debug::GlobalActivityTracker::ReleaseForTesting(); -} - -// Tests that locks actually exclude ------------------------------------------- - -class MutexLockTestThread : public PlatformThread::Delegate { - public: - MutexLockTestThread(Lock* lock, int* value) : lock_(lock), value_(value) {} - - // Static helper which can also be called from the main thread. - static void DoStuff(Lock* lock, int* value) { - for (int i = 0; i < 40; i++) { - lock->Acquire(); - int v = *value; - PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 10)); - *value = v + 1; - lock->Release(); - } - } - - void ThreadMain() override { DoStuff(lock_, value_); } - - private: - Lock* lock_; - int* value_; - - DISALLOW_COPY_AND_ASSIGN(MutexLockTestThread); -}; - -TEST(LockTest, MutexTwoThreads) { - Lock lock; - int value = 0; - - MutexLockTestThread thread(&lock, &value); - PlatformThreadHandle handle; - - ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); - - MutexLockTestThread::DoStuff(&lock, &value); - - PlatformThread::Join(handle); - - EXPECT_EQ(2 * 40, value); -} - -TEST(LockTest, MutexFourThreads) { - Lock lock; - int value = 0; - - MutexLockTestThread thread1(&lock, &value); - MutexLockTestThread thread2(&lock, &value); - MutexLockTestThread thread3(&lock, &value); - PlatformThreadHandle handle1; - PlatformThreadHandle handle2; - PlatformThreadHandle handle3; - - ASSERT_TRUE(PlatformThread::Create(0, &thread1, &handle1)); - ASSERT_TRUE(PlatformThread::Create(0, &thread2, &handle2)); - ASSERT_TRUE(PlatformThread::Create(0, &thread3, &handle3)); - - MutexLockTestThread::DoStuff(&lock, &value); - - PlatformThread::Join(handle1); - PlatformThread::Join(handle2); - PlatformThread::Join(handle3); - - EXPECT_EQ(4 * 40, value); -} - -} // namespace base
diff --git a/base/synchronization/waitable_event_unittest.cc b/base/synchronization/waitable_event_unittest.cc deleted file mode 100644 index 9c981d8..0000000 --- a/base/synchronization/waitable_event_unittest.cc +++ /dev/null
@@ -1,274 +0,0 @@ -// 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/synchronization/waitable_event.h" - -#include <stddef.h> - -#include <algorithm> - -#include "base/compiler_specific.h" -#include "base/threading/platform_thread.h" -#include "base/time/time.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(WaitableEventTest, ManualBasics) { - WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - - EXPECT_FALSE(event.IsSignaled()); - - event.Signal(); - EXPECT_TRUE(event.IsSignaled()); - EXPECT_TRUE(event.IsSignaled()); - - event.Reset(); - EXPECT_FALSE(event.IsSignaled()); - EXPECT_FALSE(event.TimedWait(TimeDelta::FromMilliseconds(10))); - - event.Signal(); - event.Wait(); - EXPECT_TRUE(event.TimedWait(TimeDelta::FromMilliseconds(10))); -} - -TEST(WaitableEventTest, ManualInitiallySignaled) { - WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::SIGNALED); - - EXPECT_TRUE(event.IsSignaled()); - EXPECT_TRUE(event.IsSignaled()); - - event.Reset(); - - EXPECT_FALSE(event.IsSignaled()); - EXPECT_FALSE(event.IsSignaled()); - - event.Signal(); - - event.Wait(); - EXPECT_TRUE(event.IsSignaled()); - EXPECT_TRUE(event.IsSignaled()); -} - -TEST(WaitableEventTest, AutoBasics) { - WaitableEvent event(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - - EXPECT_FALSE(event.IsSignaled()); - - event.Signal(); - EXPECT_TRUE(event.IsSignaled()); - EXPECT_FALSE(event.IsSignaled()); - - event.Reset(); - EXPECT_FALSE(event.IsSignaled()); - EXPECT_FALSE(event.TimedWait(TimeDelta::FromMilliseconds(10))); - - event.Signal(); - event.Wait(); - EXPECT_FALSE(event.TimedWait(TimeDelta::FromMilliseconds(10))); - - event.Signal(); - EXPECT_TRUE(event.TimedWait(TimeDelta::FromMilliseconds(10))); -} - -TEST(WaitableEventTest, AutoInitiallySignaled) { - WaitableEvent event(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::SIGNALED); - - EXPECT_TRUE(event.IsSignaled()); - EXPECT_FALSE(event.IsSignaled()); - - event.Signal(); - - EXPECT_TRUE(event.IsSignaled()); - EXPECT_FALSE(event.IsSignaled()); -} - -TEST(WaitableEventTest, WaitManyShortcut) { - WaitableEvent* ev[5]; - for (unsigned i = 0; i < 5; ++i) { - ev[i] = new WaitableEvent(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - } - - ev[3]->Signal(); - EXPECT_EQ(WaitableEvent::WaitMany(ev, 5), 3u); - - ev[3]->Signal(); - EXPECT_EQ(WaitableEvent::WaitMany(ev, 5), 3u); - - ev[4]->Signal(); - EXPECT_EQ(WaitableEvent::WaitMany(ev, 5), 4u); - - ev[0]->Signal(); - EXPECT_EQ(WaitableEvent::WaitMany(ev, 5), 0u); - - for (unsigned i = 0; i < 5; ++i) - delete ev[i]; -} - -TEST(WaitableEventTest, WaitManyLeftToRight) { - WaitableEvent* ev[5]; - for (size_t i = 0; i < 5; ++i) { - ev[i] = new WaitableEvent(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - } - - // Test for consistent left-to-right return behavior across all permutations - // of the input array. This is to verify that only the indices -- and not - // the WaitableEvents' addresses -- are relevant in determining who wins when - // multiple events are signaled. - - std::sort(ev, ev + 5); - do { - ev[0]->Signal(); - ev[1]->Signal(); - EXPECT_EQ(0u, WaitableEvent::WaitMany(ev, 5)); - - ev[2]->Signal(); - EXPECT_EQ(1u, WaitableEvent::WaitMany(ev, 5)); - EXPECT_EQ(2u, WaitableEvent::WaitMany(ev, 5)); - - ev[3]->Signal(); - ev[4]->Signal(); - ev[0]->Signal(); - EXPECT_EQ(0u, WaitableEvent::WaitMany(ev, 5)); - EXPECT_EQ(3u, WaitableEvent::WaitMany(ev, 5)); - ev[2]->Signal(); - EXPECT_EQ(2u, WaitableEvent::WaitMany(ev, 5)); - EXPECT_EQ(4u, WaitableEvent::WaitMany(ev, 5)); - } while (std::next_permutation(ev, ev + 5)); - - for (size_t i = 0; i < 5; ++i) - delete ev[i]; -} - -class WaitableEventSignaler : public PlatformThread::Delegate { - public: - WaitableEventSignaler(TimeDelta delay, WaitableEvent* event) - : delay_(delay), - event_(event) { - } - - void ThreadMain() override { - PlatformThread::Sleep(delay_); - event_->Signal(); - } - - private: - const TimeDelta delay_; - WaitableEvent* event_; -}; - -// Tests that a WaitableEvent can be safely deleted when |Wait| is done without -// additional synchronization. -TEST(WaitableEventTest, WaitAndDelete) { - WaitableEvent* ev = - new WaitableEvent(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - - WaitableEventSignaler signaler(TimeDelta::FromMilliseconds(10), ev); - PlatformThreadHandle thread; - PlatformThread::Create(0, &signaler, &thread); - - ev->Wait(); - delete ev; - - PlatformThread::Join(thread); -} - -// Tests that a WaitableEvent can be safely deleted when |WaitMany| is done -// without additional synchronization. -TEST(WaitableEventTest, WaitMany) { - WaitableEvent* ev[5]; - for (unsigned i = 0; i < 5; ++i) { - ev[i] = new WaitableEvent(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - } - - WaitableEventSignaler signaler(TimeDelta::FromMilliseconds(10), ev[2]); - PlatformThreadHandle thread; - PlatformThread::Create(0, &signaler, &thread); - - size_t index = WaitableEvent::WaitMany(ev, 5); - - for (unsigned i = 0; i < 5; ++i) - delete ev[i]; - - PlatformThread::Join(thread); - EXPECT_EQ(2u, index); -} - -// Tests that using TimeDelta::Max() on TimedWait() is not the same as passing -// a timeout of 0. (crbug.com/465948) -TEST(WaitableEventTest, TimedWait) { - WaitableEvent* ev = - new WaitableEvent(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - - TimeDelta thread_delay = TimeDelta::FromMilliseconds(10); - WaitableEventSignaler signaler(thread_delay, ev); - PlatformThreadHandle thread; - TimeTicks start = TimeTicks::Now(); - PlatformThread::Create(0, &signaler, &thread); - - EXPECT_TRUE(ev->TimedWait(TimeDelta::Max())); - EXPECT_GE(TimeTicks::Now() - start, thread_delay); - delete ev; - - PlatformThread::Join(thread); -} - -// Tests that a sub-ms TimedWait doesn't time out promptly. -TEST(WaitableEventTest, SubMsTimedWait) { - WaitableEvent ev(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - - TimeDelta delay = TimeDelta::FromMicroseconds(900); - TimeTicks start_time = TimeTicks::Now(); - ev.TimedWait(delay); - EXPECT_GE(TimeTicks::Now() - start_time, delay); -} - -// Tests that TimedWaitUntil can be safely used with various end_time deadline -// values. -TEST(WaitableEventTest, TimedWaitUntil) { - WaitableEvent ev(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - - TimeTicks start_time(TimeTicks::Now()); - TimeDelta delay = TimeDelta::FromMilliseconds(10); - - // Should be OK to wait for the current time or time in the past. - // That should end promptly and be equivalent to IsSignalled. - EXPECT_FALSE(ev.TimedWaitUntil(start_time)); - EXPECT_FALSE(ev.TimedWaitUntil(start_time - delay)); - - // Should be OK to wait for zero TimeTicks(). - EXPECT_FALSE(ev.TimedWaitUntil(TimeTicks())); - - // Waiting for a time in the future shouldn't end before the deadline - // if the event isn't signalled. - EXPECT_FALSE(ev.TimedWaitUntil(start_time + delay)); - EXPECT_GE(TimeTicks::Now() - start_time, delay); - - // Test that passing TimeTicks::Max to TimedWaitUntil is valid and isn't - // the same as passing TimeTicks(). Also verifies that signaling event - // ends the wait promptly. - WaitableEventSignaler signaler(delay, &ev); - PlatformThreadHandle thread; - start_time = TimeTicks::Now(); - PlatformThread::Create(0, &signaler, &thread); - - EXPECT_TRUE(ev.TimedWaitUntil(TimeTicks::Max())); - EXPECT_GE(TimeTicks::Now() - start_time, delay); - - PlatformThread::Join(thread); -} - -} // namespace base
diff --git a/base/synchronization/waitable_event_watcher_unittest.cc b/base/synchronization/waitable_event_watcher_unittest.cc deleted file mode 100644 index bdb45a3..0000000 --- a/base/synchronization/waitable_event_watcher_unittest.cc +++ /dev/null
@@ -1,429 +0,0 @@ -// 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/synchronization/waitable_event_watcher.h" - -#include "base/bind.h" -#include "base/callback.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "base/synchronization/waitable_event.h" -#include "base/threading/platform_thread.h" -#include "base/threading/sequenced_task_runner_handle.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -// The message loops on which each waitable event timer should be tested. -const MessageLoop::Type testing_message_loops[] = { - MessageLoop::TYPE_DEFAULT, - MessageLoop::TYPE_IO, -#if !defined(OS_IOS) // iOS does not allow direct running of the UI loop. - MessageLoop::TYPE_UI, -#endif -}; - -void QuitWhenSignaled(WaitableEvent* event) { - RunLoop::QuitCurrentWhenIdleDeprecated(); -} - -class DecrementCountContainer { - public: - explicit DecrementCountContainer(int* counter) : counter_(counter) {} - void OnWaitableEventSignaled(WaitableEvent* object) { - // NOTE: |object| may be already deleted. - --(*counter_); - } - - private: - int* counter_; -}; - -} // namespace - -class WaitableEventWatcherTest - : public testing::TestWithParam<MessageLoop::Type> {}; - -TEST_P(WaitableEventWatcherTest, BasicSignalManual) { - MessageLoop message_loop(GetParam()); - - // A manual-reset event that is not yet signaled. - WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - - WaitableEventWatcher watcher; - watcher.StartWatching(&event, BindOnce(&QuitWhenSignaled), - SequencedTaskRunnerHandle::Get()); - - event.Signal(); - - RunLoop().Run(); - - EXPECT_TRUE(event.IsSignaled()); -} - -TEST_P(WaitableEventWatcherTest, BasicSignalAutomatic) { - MessageLoop message_loop(GetParam()); - - WaitableEvent event(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - - WaitableEventWatcher watcher; - watcher.StartWatching(&event, BindOnce(&QuitWhenSignaled), - SequencedTaskRunnerHandle::Get()); - - event.Signal(); - - RunLoop().Run(); - - // The WaitableEventWatcher consumes the event signal. - EXPECT_FALSE(event.IsSignaled()); -} - -TEST_P(WaitableEventWatcherTest, BasicCancel) { - MessageLoop message_loop(GetParam()); - - // A manual-reset event that is not yet signaled. - WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - - WaitableEventWatcher watcher; - - watcher.StartWatching(&event, BindOnce(&QuitWhenSignaled), - SequencedTaskRunnerHandle::Get()); - - watcher.StopWatching(); -} - -TEST_P(WaitableEventWatcherTest, CancelAfterSet) { - MessageLoop message_loop(GetParam()); - - // A manual-reset event that is not yet signaled. - WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - - WaitableEventWatcher watcher; - - int counter = 1; - DecrementCountContainer delegate(&counter); - WaitableEventWatcher::EventCallback callback = BindOnce( - &DecrementCountContainer::OnWaitableEventSignaled, Unretained(&delegate)); - watcher.StartWatching(&event, std::move(callback), - SequencedTaskRunnerHandle::Get()); - - event.Signal(); - - // Let the background thread do its business - PlatformThread::Sleep(TimeDelta::FromMilliseconds(30)); - - watcher.StopWatching(); - - RunLoop().RunUntilIdle(); - - // Our delegate should not have fired. - EXPECT_EQ(1, counter); -} - -TEST_P(WaitableEventWatcherTest, OutlivesMessageLoop) { - // Simulate a MessageLoop that dies before an WaitableEventWatcher. This - // ordinarily doesn't happen when people use the Thread class, but it can - // happen when people use the Singleton pattern or atexit. - WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - { - std::unique_ptr<WaitableEventWatcher> watcher; - { - MessageLoop message_loop(GetParam()); - watcher = std::make_unique<WaitableEventWatcher>(); - - watcher->StartWatching(&event, BindOnce(&QuitWhenSignaled), - SequencedTaskRunnerHandle::Get()); - } - } -} - -TEST_P(WaitableEventWatcherTest, SignaledAtStartManual) { - MessageLoop message_loop(GetParam()); - - WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::SIGNALED); - - WaitableEventWatcher watcher; - watcher.StartWatching(&event, BindOnce(&QuitWhenSignaled), - SequencedTaskRunnerHandle::Get()); - - RunLoop().Run(); - - EXPECT_TRUE(event.IsSignaled()); -} - -TEST_P(WaitableEventWatcherTest, SignaledAtStartAutomatic) { - MessageLoop message_loop(GetParam()); - - WaitableEvent event(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::SIGNALED); - - WaitableEventWatcher watcher; - watcher.StartWatching(&event, BindOnce(&QuitWhenSignaled), - SequencedTaskRunnerHandle::Get()); - - RunLoop().Run(); - - // The watcher consumes the event signal. - EXPECT_FALSE(event.IsSignaled()); -} - -TEST_P(WaitableEventWatcherTest, StartWatchingInCallback) { - MessageLoop message_loop(GetParam()); - - WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - - WaitableEventWatcher watcher; - watcher.StartWatching( - &event, - BindOnce( - [](WaitableEventWatcher* watcher, WaitableEvent* event) { - // |event| is manual, so the second watcher will run - // immediately. - watcher->StartWatching(event, BindOnce(&QuitWhenSignaled), - SequencedTaskRunnerHandle::Get()); - }, - &watcher), - SequencedTaskRunnerHandle::Get()); - - event.Signal(); - - RunLoop().Run(); -} - -TEST_P(WaitableEventWatcherTest, MultipleWatchersManual) { - MessageLoop message_loop(GetParam()); - - WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - - int counter1 = 0; - int counter2 = 0; - - auto callback = [](RunLoop* run_loop, int* counter, WaitableEvent* event) { - ++(*counter); - run_loop->QuitWhenIdle(); - }; - - RunLoop run_loop; - - WaitableEventWatcher watcher1; - watcher1.StartWatching( - &event, BindOnce(callback, Unretained(&run_loop), Unretained(&counter1)), - SequencedTaskRunnerHandle::Get()); - - WaitableEventWatcher watcher2; - watcher2.StartWatching( - &event, BindOnce(callback, Unretained(&run_loop), Unretained(&counter2)), - SequencedTaskRunnerHandle::Get()); - - event.Signal(); - run_loop.Run(); - - EXPECT_EQ(1, counter1); - EXPECT_EQ(1, counter2); - EXPECT_TRUE(event.IsSignaled()); -} - -// Tests that only one async waiter gets called back for an auto-reset event. -TEST_P(WaitableEventWatcherTest, MultipleWatchersAutomatic) { - MessageLoop message_loop(GetParam()); - - WaitableEvent event(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - - int counter1 = 0; - int counter2 = 0; - - auto callback = [](RunLoop** run_loop, int* counter, WaitableEvent* event) { - ++(*counter); - (*run_loop)->QuitWhenIdle(); - }; - - // The same RunLoop instance cannot be Run more than once, and it is - // undefined which watcher will get called back first. Have the callback - // dereference this pointer to quit the loop, which will be updated on each - // Run. - RunLoop* current_run_loop; - - WaitableEventWatcher watcher1; - watcher1.StartWatching( - &event, - BindOnce(callback, Unretained(¤t_run_loop), Unretained(&counter1)), - SequencedTaskRunnerHandle::Get()); - - WaitableEventWatcher watcher2; - watcher2.StartWatching( - &event, - BindOnce(callback, Unretained(¤t_run_loop), Unretained(&counter2)), - SequencedTaskRunnerHandle::Get()); - - event.Signal(); - { - RunLoop run_loop; - current_run_loop = &run_loop; - run_loop.Run(); - } - - // Only one of the waiters should have been signaled. - EXPECT_TRUE((counter1 == 1) ^ (counter2 == 1)); - - EXPECT_FALSE(event.IsSignaled()); - - event.Signal(); - { - RunLoop run_loop; - current_run_loop = &run_loop; - run_loop.Run(); - } - - EXPECT_FALSE(event.IsSignaled()); - - // The other watcher should have been signaled. - EXPECT_EQ(1, counter1); - EXPECT_EQ(1, counter2); -} - -// To help detect errors around deleting WaitableEventWatcher, an additional -// bool parameter is used to test sleeping between watching and deletion. -class WaitableEventWatcherDeletionTest - : public testing::TestWithParam<std::tuple<MessageLoop::Type, bool>> {}; - -TEST_P(WaitableEventWatcherDeletionTest, DeleteUnder) { - MessageLoop::Type message_loop_type; - bool delay_after_delete; - std::tie(message_loop_type, delay_after_delete) = GetParam(); - - // Delete the WaitableEvent out from under the Watcher. This is explictly - // allowed by the interface. - - MessageLoop message_loop(message_loop_type); - - { - WaitableEventWatcher watcher; - - auto* event = new WaitableEvent(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - - watcher.StartWatching(event, BindOnce(&QuitWhenSignaled), - SequencedTaskRunnerHandle::Get()); - - if (delay_after_delete) { - // On Windows that sleep() improves the chance to catch some problems. - // It postpones the dtor |watcher| (which immediately cancel the waiting) - // and gives some time to run to a created background thread. - // Unfortunately, that thread is under OS control and we can't - // manipulate it directly. - PlatformThread::Sleep(TimeDelta::FromMilliseconds(30)); - } - - delete event; - } -} - -TEST_P(WaitableEventWatcherDeletionTest, SignalAndDelete) { - MessageLoop::Type message_loop_type; - bool delay_after_delete; - std::tie(message_loop_type, delay_after_delete) = GetParam(); - - // Signal and immediately delete the WaitableEvent out from under the Watcher. - - MessageLoop message_loop(message_loop_type); - - { - WaitableEventWatcher watcher; - - auto event = std::make_unique<WaitableEvent>( - WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - - watcher.StartWatching(event.get(), BindOnce(&QuitWhenSignaled), - SequencedTaskRunnerHandle::Get()); - event->Signal(); - event.reset(); - - if (delay_after_delete) { - // On Windows that sleep() improves the chance to catch some problems. - // It postpones the dtor |watcher| (which immediately cancel the waiting) - // and gives some time to run to a created background thread. - // Unfortunately, that thread is under OS control and we can't - // manipulate it directly. - PlatformThread::Sleep(TimeDelta::FromMilliseconds(30)); - } - - // Wait for the watcher callback. - RunLoop().Run(); - } -} - -// Tests deleting the WaitableEventWatcher between signaling the event and -// when the callback should be run. -TEST_P(WaitableEventWatcherDeletionTest, DeleteWatcherBeforeCallback) { - MessageLoop::Type message_loop_type; - bool delay_after_delete; - std::tie(message_loop_type, delay_after_delete) = GetParam(); - - MessageLoop message_loop(message_loop_type); - scoped_refptr<SingleThreadTaskRunner> task_runner = - message_loop.task_runner(); - - // Flag used to esnure that the |watcher_callback| never runs. - bool did_callback = false; - - WaitableEvent event(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - auto watcher = std::make_unique<WaitableEventWatcher>(); - - // Queue up a series of tasks: - // 1. StartWatching the WaitableEvent - // 2. Signal the event (which will result in another task getting posted to - // the |task_runner|) - // 3. Delete the WaitableEventWatcher - // 4. WaitableEventWatcher callback should run (from #2) - - WaitableEventWatcher::EventCallback watcher_callback = BindOnce( - [](bool* did_callback, WaitableEvent*) { - *did_callback = true; - }, - Unretained(&did_callback)); - - task_runner->PostTask( - FROM_HERE, BindOnce(IgnoreResult(&WaitableEventWatcher::StartWatching), - Unretained(watcher.get()), Unretained(&event), - std::move(watcher_callback), task_runner)); - task_runner->PostTask(FROM_HERE, - BindOnce(&WaitableEvent::Signal, Unretained(&event))); - task_runner->DeleteSoon(FROM_HERE, std::move(watcher)); - if (delay_after_delete) { - task_runner->PostTask(FROM_HERE, BindOnce(&PlatformThread::Sleep, - TimeDelta::FromMilliseconds(30))); - } - - RunLoop().RunUntilIdle(); - - EXPECT_FALSE(did_callback); -} - -INSTANTIATE_TEST_CASE_P(, - WaitableEventWatcherTest, - testing::ValuesIn(testing_message_loops)); - -INSTANTIATE_TEST_CASE_P( - , - WaitableEventWatcherDeletionTest, - testing::Combine(testing::ValuesIn(testing_message_loops), - testing::Bool())); - -} // namespace base
diff --git a/base/sys_byteorder_unittest.cc b/base/sys_byteorder_unittest.cc deleted file mode 100644 index f5bad31..0000000 --- a/base/sys_byteorder_unittest.cc +++ /dev/null
@@ -1,142 +0,0 @@ -// Copyright (c) 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/sys_byteorder.h" - -#include <stdint.h> - -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -const uint16_t k16BitTestData = 0xaabb; -const uint16_t k16BitSwappedTestData = 0xbbaa; -const uint32_t k32BitTestData = 0xaabbccdd; -const uint32_t k32BitSwappedTestData = 0xddccbbaa; -const uint64_t k64BitTestData = 0xaabbccdd44332211; -const uint64_t k64BitSwappedTestData = 0x11223344ddccbbaa; - -} // namespace - -TEST(ByteOrderTest, ByteSwap16) { - uint16_t swapped = base::ByteSwap(k16BitTestData); - EXPECT_EQ(k16BitSwappedTestData, swapped); - uint16_t reswapped = base::ByteSwap(swapped); - EXPECT_EQ(k16BitTestData, reswapped); -} - -TEST(ByteOrderTest, ByteSwap32) { - uint32_t swapped = base::ByteSwap(k32BitTestData); - EXPECT_EQ(k32BitSwappedTestData, swapped); - uint32_t reswapped = base::ByteSwap(swapped); - EXPECT_EQ(k32BitTestData, reswapped); -} - -TEST(ByteOrderTest, ByteSwap64) { - uint64_t swapped = base::ByteSwap(k64BitTestData); - EXPECT_EQ(k64BitSwappedTestData, swapped); - uint64_t reswapped = base::ByteSwap(swapped); - EXPECT_EQ(k64BitTestData, reswapped); -} - -TEST(ByteOrderTest, ByteSwapUintPtrT) { -#if defined(ARCH_CPU_64_BITS) - const uintptr_t test_data = static_cast<uintptr_t>(k64BitTestData); - const uintptr_t swapped_test_data = - static_cast<uintptr_t>(k64BitSwappedTestData); -#elif defined(ARCH_CPU_32_BITS) - const uintptr_t test_data = static_cast<uintptr_t>(k32BitTestData); - const uintptr_t swapped_test_data = - static_cast<uintptr_t>(k32BitSwappedTestData); -#else -#error architecture not supported -#endif - - uintptr_t swapped = base::ByteSwapUintPtrT(test_data); - EXPECT_EQ(swapped_test_data, swapped); - uintptr_t reswapped = base::ByteSwapUintPtrT(swapped); - EXPECT_EQ(test_data, reswapped); -} - -TEST(ByteOrderTest, ByteSwapToLE16) { - uint16_t le = base::ByteSwapToLE16(k16BitTestData); -#if defined(ARCH_CPU_LITTLE_ENDIAN) - EXPECT_EQ(k16BitTestData, le); -#else - EXPECT_EQ(k16BitSwappedTestData, le); -#endif -} - -TEST(ByteOrderTest, ByteSwapToLE32) { - uint32_t le = base::ByteSwapToLE32(k32BitTestData); -#if defined(ARCH_CPU_LITTLE_ENDIAN) - EXPECT_EQ(k32BitTestData, le); -#else - EXPECT_EQ(k32BitSwappedTestData, le); -#endif -} - -TEST(ByteOrderTest, ByteSwapToLE64) { - uint64_t le = base::ByteSwapToLE64(k64BitTestData); -#if defined(ARCH_CPU_LITTLE_ENDIAN) - EXPECT_EQ(k64BitTestData, le); -#else - EXPECT_EQ(k64BitSwappedTestData, le); -#endif -} - -TEST(ByteOrderTest, NetToHost16) { - uint16_t h = base::NetToHost16(k16BitTestData); -#if defined(ARCH_CPU_LITTLE_ENDIAN) - EXPECT_EQ(k16BitSwappedTestData, h); -#else - EXPECT_EQ(k16BitTestData, h); -#endif -} - -TEST(ByteOrderTest, NetToHost32) { - uint32_t h = base::NetToHost32(k32BitTestData); -#if defined(ARCH_CPU_LITTLE_ENDIAN) - EXPECT_EQ(k32BitSwappedTestData, h); -#else - EXPECT_EQ(k32BitTestData, h); -#endif -} - -TEST(ByteOrderTest, NetToHost64) { - uint64_t h = base::NetToHost64(k64BitTestData); -#if defined(ARCH_CPU_LITTLE_ENDIAN) - EXPECT_EQ(k64BitSwappedTestData, h); -#else - EXPECT_EQ(k64BitTestData, h); -#endif -} - -TEST(ByteOrderTest, HostToNet16) { - uint16_t n = base::HostToNet16(k16BitTestData); -#if defined(ARCH_CPU_LITTLE_ENDIAN) - EXPECT_EQ(k16BitSwappedTestData, n); -#else - EXPECT_EQ(k16BitTestData, n); -#endif -} - -TEST(ByteOrderTest, HostToNet32) { - uint32_t n = base::HostToNet32(k32BitTestData); -#if defined(ARCH_CPU_LITTLE_ENDIAN) - EXPECT_EQ(k32BitSwappedTestData, n); -#else - EXPECT_EQ(k32BitTestData, n); -#endif -} - -TEST(ByteOrderTest, HostToNet64) { - uint64_t n = base::HostToNet64(k64BitTestData); -#if defined(ARCH_CPU_LITTLE_ENDIAN) - EXPECT_EQ(k64BitSwappedTestData, n); -#else - EXPECT_EQ(k64BitTestData, n); -#endif -}
diff --git a/base/sys_info_unittest.cc b/base/sys_info_unittest.cc deleted file mode 100644 index 7b2c458..0000000 --- a/base/sys_info_unittest.cc +++ /dev/null
@@ -1,212 +0,0 @@ -// 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 <stdint.h> - -#include "base/environment.h" -#include "base/files/file_util.h" -#include "base/process/process_metrics.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_split.h" -#include "base/sys_info.h" -#include "base/threading/platform_thread.h" -#include "base/time/time.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/platform_test.h" - -namespace base { - -using SysInfoTest = PlatformTest; - -TEST_F(SysInfoTest, NumProcs) { - // We aren't actually testing that it's correct, just that it's sane. - EXPECT_GE(SysInfo::NumberOfProcessors(), 1); -} - -TEST_F(SysInfoTest, AmountOfMem) { - // We aren't actually testing that it's correct, just that it's sane. - EXPECT_GT(SysInfo::AmountOfPhysicalMemory(), 0); - EXPECT_GT(SysInfo::AmountOfPhysicalMemoryMB(), 0); - // The maxmimal amount of virtual memory can be zero which means unlimited. - EXPECT_GE(SysInfo::AmountOfVirtualMemory(), 0); -} - -#if defined(OS_LINUX) || defined(OS_ANDROID) -#if defined(OS_LINUX) -#define MAYBE_AmountOfAvailablePhysicalMemory \ - DISABLED_AmountOfAvailablePhysicalMemory -#else -#define MAYBE_AmountOfAvailablePhysicalMemory AmountOfAvailablePhysicalMemory -#endif // defined(OS_LINUX) -TEST_F(SysInfoTest, MAYBE_AmountOfAvailablePhysicalMemory) { - // Note: info is in _K_bytes. - SystemMemoryInfoKB info; - ASSERT_TRUE(GetSystemMemoryInfo(&info)); - EXPECT_GT(info.free, 0); - - if (info.available != 0) { - // If there is MemAvailable from kernel. - EXPECT_LT(info.available, info.total); - const int64_t amount = SysInfo::AmountOfAvailablePhysicalMemory(info); - // We aren't actually testing that it's correct, just that it's sane. - EXPECT_GT(amount, static_cast<int64_t>(info.free) * 1024); - EXPECT_LT(amount / 1024, info.available); - // Simulate as if there is no MemAvailable. - info.available = 0; - } - - // There is no MemAvailable. Check the fallback logic. - const int64_t amount = SysInfo::AmountOfAvailablePhysicalMemory(info); - // We aren't actually testing that it's correct, just that it's sane. - EXPECT_GT(amount, static_cast<int64_t>(info.free) * 1024); - EXPECT_LT(amount / 1024, info.total); -} -#endif // defined(OS_LINUX) || defined(OS_ANDROID) - -TEST_F(SysInfoTest, AmountOfFreeDiskSpace) { - // We aren't actually testing that it's correct, just that it's sane. - FilePath tmp_path; - ASSERT_TRUE(GetTempDir(&tmp_path)); - EXPECT_GE(SysInfo::AmountOfFreeDiskSpace(tmp_path), 0) << tmp_path.value(); -} - -TEST_F(SysInfoTest, AmountOfTotalDiskSpace) { - // We aren't actually testing that it's correct, just that it's sane. - FilePath tmp_path; - ASSERT_TRUE(GetTempDir(&tmp_path)); - EXPECT_GT(SysInfo::AmountOfTotalDiskSpace(tmp_path), 0) << tmp_path.value(); -} - -#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) -TEST_F(SysInfoTest, OperatingSystemVersionNumbers) { - int32_t os_major_version = -1; - int32_t os_minor_version = -1; - int32_t os_bugfix_version = -1; - SysInfo::OperatingSystemVersionNumbers(&os_major_version, - &os_minor_version, - &os_bugfix_version); - EXPECT_GT(os_major_version, -1); - EXPECT_GT(os_minor_version, -1); - EXPECT_GT(os_bugfix_version, -1); -} -#endif - -TEST_F(SysInfoTest, Uptime) { - TimeDelta up_time_1 = SysInfo::Uptime(); - // UpTime() is implemented internally using TimeTicks::Now(), which documents - // system resolution as being 1-15ms. Sleep a little longer than that. - PlatformThread::Sleep(TimeDelta::FromMilliseconds(20)); - TimeDelta up_time_2 = SysInfo::Uptime(); - EXPECT_GT(up_time_1.InMicroseconds(), 0); - EXPECT_GT(up_time_2.InMicroseconds(), up_time_1.InMicroseconds()); -} - -#if defined(OS_MACOSX) -TEST_F(SysInfoTest, HardwareModelNameFormatMacAndiOS) { - std::string hardware_model = SysInfo::HardwareModelName(); - ASSERT_FALSE(hardware_model.empty()); - // Check that the model is of the expected format "Foo,Bar" where "Bar" is - // a number. - std::vector<StringPiece> pieces = - SplitStringPiece(hardware_model, ",", KEEP_WHITESPACE, SPLIT_WANT_ALL); - ASSERT_EQ(2u, pieces.size()) << hardware_model; - int value; - EXPECT_TRUE(StringToInt(pieces[1], &value)) << hardware_model; -} -#endif - -#if defined(OS_CHROMEOS) - -TEST_F(SysInfoTest, GoogleChromeOSVersionNumbers) { - int32_t os_major_version = -1; - int32_t os_minor_version = -1; - int32_t os_bugfix_version = -1; - const char kLsbRelease[] = - "FOO=1234123.34.5\n" - "CHROMEOS_RELEASE_VERSION=1.2.3.4\n"; - SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease, Time()); - SysInfo::OperatingSystemVersionNumbers(&os_major_version, - &os_minor_version, - &os_bugfix_version); - EXPECT_EQ(1, os_major_version); - EXPECT_EQ(2, os_minor_version); - EXPECT_EQ(3, os_bugfix_version); -} - -TEST_F(SysInfoTest, GoogleChromeOSVersionNumbersFirst) { - int32_t os_major_version = -1; - int32_t os_minor_version = -1; - int32_t os_bugfix_version = -1; - const char kLsbRelease[] = - "CHROMEOS_RELEASE_VERSION=1.2.3.4\n" - "FOO=1234123.34.5\n"; - SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease, Time()); - SysInfo::OperatingSystemVersionNumbers(&os_major_version, - &os_minor_version, - &os_bugfix_version); - EXPECT_EQ(1, os_major_version); - EXPECT_EQ(2, os_minor_version); - EXPECT_EQ(3, os_bugfix_version); -} - -TEST_F(SysInfoTest, GoogleChromeOSNoVersionNumbers) { - int32_t os_major_version = -1; - int32_t os_minor_version = -1; - int32_t os_bugfix_version = -1; - const char kLsbRelease[] = "FOO=1234123.34.5\n"; - SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease, Time()); - SysInfo::OperatingSystemVersionNumbers(&os_major_version, - &os_minor_version, - &os_bugfix_version); - EXPECT_EQ(0, os_major_version); - EXPECT_EQ(0, os_minor_version); - EXPECT_EQ(0, os_bugfix_version); -} - -TEST_F(SysInfoTest, GoogleChromeOSLsbReleaseTime) { - const char kLsbRelease[] = "CHROMEOS_RELEASE_VERSION=1.2.3.4"; - // Use a fake time that can be safely displayed as a string. - const Time lsb_release_time(Time::FromDoubleT(12345.6)); - SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease, lsb_release_time); - Time parsed_lsb_release_time = SysInfo::GetLsbReleaseTime(); - EXPECT_DOUBLE_EQ(lsb_release_time.ToDoubleT(), - parsed_lsb_release_time.ToDoubleT()); -} - -TEST_F(SysInfoTest, IsRunningOnChromeOS) { - SysInfo::SetChromeOSVersionInfoForTest("", Time()); - EXPECT_FALSE(SysInfo::IsRunningOnChromeOS()); - - const char kLsbRelease1[] = - "CHROMEOS_RELEASE_NAME=Non Chrome OS\n" - "CHROMEOS_RELEASE_VERSION=1.2.3.4\n"; - SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease1, Time()); - EXPECT_FALSE(SysInfo::IsRunningOnChromeOS()); - - const char kLsbRelease2[] = - "CHROMEOS_RELEASE_NAME=Chrome OS\n" - "CHROMEOS_RELEASE_VERSION=1.2.3.4\n"; - SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease2, Time()); - EXPECT_TRUE(SysInfo::IsRunningOnChromeOS()); - - const char kLsbRelease3[] = - "CHROMEOS_RELEASE_NAME=Chromium OS\n"; - SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease3, Time()); - EXPECT_TRUE(SysInfo::IsRunningOnChromeOS()); -} - -TEST_F(SysInfoTest, GetStrippedReleaseBoard) { - const char* kLsbRelease1 = "CHROMEOS_RELEASE_BOARD=Glimmer\n"; - SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease1, Time()); - EXPECT_EQ("glimmer", SysInfo::GetStrippedReleaseBoard()); - - const char* kLsbRelease2 = "CHROMEOS_RELEASE_BOARD=glimmer-signed-mp-v4keys"; - SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease2, Time()); - EXPECT_EQ("glimmer", SysInfo::GetStrippedReleaseBoard()); -} - -#endif // OS_CHROMEOS - -} // namespace base
diff --git a/base/system_monitor/system_monitor_unittest.cc b/base/system_monitor/system_monitor_unittest.cc deleted file mode 100644 index 8963f7b..0000000 --- a/base/system_monitor/system_monitor_unittest.cc +++ /dev/null
@@ -1,55 +0,0 @@ -// 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/system_monitor/system_monitor.h" - -#include "base/macros.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "base/test/mock_devices_changed_observer.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -class SystemMonitorTest : public testing::Test { - protected: - SystemMonitorTest() { - system_monitor_.reset(new SystemMonitor); - } - - MessageLoop message_loop_; - std::unique_ptr<SystemMonitor> system_monitor_; - - private: - DISALLOW_COPY_AND_ASSIGN(SystemMonitorTest); -}; - -TEST_F(SystemMonitorTest, DeviceChangeNotifications) { - const int kObservers = 5; - - testing::Sequence mock_sequencer[kObservers]; - MockDevicesChangedObserver observers[kObservers]; - for (int index = 0; index < kObservers; ++index) { - system_monitor_->AddDevicesChangedObserver(&observers[index]); - - EXPECT_CALL(observers[index], - OnDevicesChanged(SystemMonitor::DEVTYPE_UNKNOWN)) - .Times(3) - .InSequence(mock_sequencer[index]); - } - - system_monitor_->ProcessDevicesChanged(SystemMonitor::DEVTYPE_UNKNOWN); - RunLoop().RunUntilIdle(); - - system_monitor_->ProcessDevicesChanged(SystemMonitor::DEVTYPE_UNKNOWN); - system_monitor_->ProcessDevicesChanged(SystemMonitor::DEVTYPE_UNKNOWN); - RunLoop().RunUntilIdle(); -} - -} // namespace - -} // namespace base
diff --git a/base/task/cancelable_task_tracker_unittest.cc b/base/task/cancelable_task_tracker_unittest.cc deleted file mode 100644 index c75adc4..0000000 --- a/base/task/cancelable_task_tracker_unittest.cc +++ /dev/null
@@ -1,403 +0,0 @@ -// 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/task/cancelable_task_tracker.h" - -#include <cstddef> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/location.h" -#include "base/logging.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "base/single_thread_task_runner.h" -#include "base/test/gtest_util.h" -#include "base/test/test_simple_task_runner.h" -#include "base/threading/thread.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -class CancelableTaskTrackerTest : public testing::Test { - protected: - ~CancelableTaskTrackerTest() override { RunCurrentLoopUntilIdle(); } - - void RunCurrentLoopUntilIdle() { - RunLoop run_loop; - run_loop.RunUntilIdle(); - } - - CancelableTaskTracker task_tracker_; - - private: - // Needed by CancelableTaskTracker methods. - MessageLoop message_loop_; -}; - -void AddFailureAt(const Location& location) { - ADD_FAILURE_AT(location.file_name(), location.line_number()); -} - -// Returns a closure that fails if run. -Closure MakeExpectedNotRunClosure(const Location& location) { - return Bind(&AddFailureAt, location); -} - -// 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) - : location_(location), called_(false) {} - - ~RunChecker() { - if (!called_) { - ADD_FAILURE_AT(location_.file_name(), location_.line_number()); - } - } - - void Run() { called_ = true; } - - private: - Location location_; - bool called_; -}; - -// Returns a closure that fails on destruction if it hasn't been run. -Closure MakeExpectedRunClosure(const Location& location) { - return Bind(&RunChecker::Run, Owned(new RunChecker(location))); -} - -} // namespace - -// With the task tracker, post a task, a task with a reply, and get a -// new task id without canceling any of them. The tasks and the reply -// should run and the "is canceled" callback should return false. -TEST_F(CancelableTaskTrackerTest, NoCancel) { - Thread worker_thread("worker thread"); - ASSERT_TRUE(worker_thread.Start()); - - ignore_result(task_tracker_.PostTask(worker_thread.task_runner().get(), - FROM_HERE, - MakeExpectedRunClosure(FROM_HERE))); - - ignore_result(task_tracker_.PostTaskAndReply( - worker_thread.task_runner().get(), FROM_HERE, - MakeExpectedRunClosure(FROM_HERE), MakeExpectedRunClosure(FROM_HERE))); - - CancelableTaskTracker::IsCanceledCallback is_canceled; - ignore_result(task_tracker_.NewTrackedTaskId(&is_canceled)); - - worker_thread.Stop(); - - RunCurrentLoopUntilIdle(); - - EXPECT_FALSE(is_canceled.Run()); -} - -// Post a task with the task tracker but cancel it before running the -// task runner. The task should not run. -TEST_F(CancelableTaskTrackerTest, CancelPostedTask) { - scoped_refptr<TestSimpleTaskRunner> test_task_runner( - new TestSimpleTaskRunner()); - - CancelableTaskTracker::TaskId task_id = task_tracker_.PostTask( - test_task_runner.get(), FROM_HERE, MakeExpectedNotRunClosure(FROM_HERE)); - EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id); - - EXPECT_EQ(1U, test_task_runner->NumPendingTasks()); - - task_tracker_.TryCancel(task_id); - - test_task_runner->RunUntilIdle(); -} - -// Post a task with reply with the task tracker and cancel it before -// running the task runner. Neither the task nor the reply should -// run. -TEST_F(CancelableTaskTrackerTest, CancelPostedTaskAndReply) { - scoped_refptr<TestSimpleTaskRunner> test_task_runner( - new TestSimpleTaskRunner()); - - CancelableTaskTracker::TaskId task_id = - task_tracker_.PostTaskAndReply(test_task_runner.get(), - FROM_HERE, - MakeExpectedNotRunClosure(FROM_HERE), - MakeExpectedNotRunClosure(FROM_HERE)); - EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id); - - task_tracker_.TryCancel(task_id); - - test_task_runner->RunUntilIdle(); -} - -// Post a task with reply with the task tracker and cancel it after -// running the task runner but before running the current message -// loop. The task should run but the reply should not. -TEST_F(CancelableTaskTrackerTest, CancelReply) { - scoped_refptr<TestSimpleTaskRunner> test_task_runner( - new TestSimpleTaskRunner()); - - CancelableTaskTracker::TaskId task_id = - task_tracker_.PostTaskAndReply(test_task_runner.get(), - FROM_HERE, - MakeExpectedRunClosure(FROM_HERE), - MakeExpectedNotRunClosure(FROM_HERE)); - EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id); - - test_task_runner->RunUntilIdle(); - - task_tracker_.TryCancel(task_id); -} - -// Post a task with reply with the task tracker on a worker thread and -// cancel it before running the current message loop. The task should -// run but the reply should not. -TEST_F(CancelableTaskTrackerTest, CancelReplyDifferentThread) { - Thread worker_thread("worker thread"); - ASSERT_TRUE(worker_thread.Start()); - - CancelableTaskTracker::TaskId task_id = task_tracker_.PostTaskAndReply( - worker_thread.task_runner().get(), FROM_HERE, DoNothing(), - MakeExpectedNotRunClosure(FROM_HERE)); - EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id); - - task_tracker_.TryCancel(task_id); - - worker_thread.Stop(); -} - -void ExpectIsCanceled( - const CancelableTaskTracker::IsCanceledCallback& is_canceled, - bool expected_is_canceled) { - EXPECT_EQ(expected_is_canceled, is_canceled.Run()); -} - -// Create a new task ID and check its status on a separate thread -// before and after canceling. The is-canceled callback should be -// thread-safe (i.e., nothing should blow up). -TEST_F(CancelableTaskTrackerTest, NewTrackedTaskIdDifferentThread) { - CancelableTaskTracker::IsCanceledCallback is_canceled; - CancelableTaskTracker::TaskId task_id = - task_tracker_.NewTrackedTaskId(&is_canceled); - - EXPECT_FALSE(is_canceled.Run()); - - Thread other_thread("other thread"); - ASSERT_TRUE(other_thread.Start()); - other_thread.task_runner()->PostTask( - FROM_HERE, BindOnce(&ExpectIsCanceled, is_canceled, false)); - other_thread.Stop(); - - task_tracker_.TryCancel(task_id); - - ASSERT_TRUE(other_thread.Start()); - other_thread.task_runner()->PostTask( - FROM_HERE, BindOnce(&ExpectIsCanceled, is_canceled, true)); - other_thread.Stop(); -} - -// With the task tracker, post a task, a task with a reply, get a new -// task id, and then cancel all of them. None of the tasks nor the -// reply should run and the "is canceled" callback should return -// true. -TEST_F(CancelableTaskTrackerTest, CancelAll) { - scoped_refptr<TestSimpleTaskRunner> test_task_runner( - new TestSimpleTaskRunner()); - - ignore_result(task_tracker_.PostTask( - test_task_runner.get(), FROM_HERE, MakeExpectedNotRunClosure(FROM_HERE))); - - ignore_result( - task_tracker_.PostTaskAndReply(test_task_runner.get(), - FROM_HERE, - MakeExpectedNotRunClosure(FROM_HERE), - MakeExpectedNotRunClosure(FROM_HERE))); - - CancelableTaskTracker::IsCanceledCallback is_canceled; - ignore_result(task_tracker_.NewTrackedTaskId(&is_canceled)); - - task_tracker_.TryCancelAll(); - - test_task_runner->RunUntilIdle(); - - RunCurrentLoopUntilIdle(); - - EXPECT_TRUE(is_canceled.Run()); -} - -// With the task tracker, post a task, a task with a reply, get a new -// task id, and then cancel all of them. None of the tasks nor the -// reply should run and the "is canceled" callback should return -// true. -TEST_F(CancelableTaskTrackerTest, DestructionCancelsAll) { - scoped_refptr<TestSimpleTaskRunner> test_task_runner( - new TestSimpleTaskRunner()); - - CancelableTaskTracker::IsCanceledCallback is_canceled; - - { - // Create another task tracker with a smaller scope. - CancelableTaskTracker task_tracker; - - ignore_result(task_tracker.PostTask(test_task_runner.get(), - FROM_HERE, - MakeExpectedNotRunClosure(FROM_HERE))); - - ignore_result( - task_tracker.PostTaskAndReply(test_task_runner.get(), - FROM_HERE, - MakeExpectedNotRunClosure(FROM_HERE), - MakeExpectedNotRunClosure(FROM_HERE))); - - ignore_result(task_tracker_.NewTrackedTaskId(&is_canceled)); - } - - test_task_runner->RunUntilIdle(); - - RunCurrentLoopUntilIdle(); - - EXPECT_FALSE(is_canceled.Run()); -} - -// Post a task and cancel it. HasTrackedTasks() should return false as soon as -// TryCancelAll() is called. -TEST_F(CancelableTaskTrackerTest, HasTrackedTasksPost) { - scoped_refptr<TestSimpleTaskRunner> test_task_runner( - new TestSimpleTaskRunner()); - - EXPECT_FALSE(task_tracker_.HasTrackedTasks()); - - ignore_result(task_tracker_.PostTask( - test_task_runner.get(), FROM_HERE, MakeExpectedNotRunClosure(FROM_HERE))); - - task_tracker_.TryCancelAll(); - - EXPECT_FALSE(task_tracker_.HasTrackedTasks()); - - test_task_runner->RunUntilIdle(); - RunCurrentLoopUntilIdle(); -} - -// Post a task with a reply and cancel it. HasTrackedTasks() should return false -// as soon as TryCancelAll() is called. -TEST_F(CancelableTaskTrackerTest, HasTrackedTasksPostWithReply) { - scoped_refptr<TestSimpleTaskRunner> test_task_runner( - new TestSimpleTaskRunner()); - - EXPECT_FALSE(task_tracker_.HasTrackedTasks()); - - ignore_result( - task_tracker_.PostTaskAndReply(test_task_runner.get(), - FROM_HERE, - MakeExpectedNotRunClosure(FROM_HERE), - MakeExpectedNotRunClosure(FROM_HERE))); - - task_tracker_.TryCancelAll(); - - EXPECT_FALSE(task_tracker_.HasTrackedTasks()); - - test_task_runner->RunUntilIdle(); - RunCurrentLoopUntilIdle(); -} - -// Create a new tracked task ID. HasTrackedTasks() should return false as soon -// as TryCancelAll() is called. -TEST_F(CancelableTaskTrackerTest, HasTrackedTasksIsCancelled) { - EXPECT_FALSE(task_tracker_.HasTrackedTasks()); - - CancelableTaskTracker::IsCanceledCallback is_canceled; - ignore_result(task_tracker_.NewTrackedTaskId(&is_canceled)); - - task_tracker_.TryCancelAll(); - - EXPECT_FALSE(task_tracker_.HasTrackedTasks()); -} - -// The death tests below make sure that calling task tracker member -// functions from a thread different from its owner thread DCHECKs in -// debug mode. - -class CancelableTaskTrackerDeathTest : public CancelableTaskTrackerTest { - protected: - CancelableTaskTrackerDeathTest() { - // The default style "fast" does not support multi-threaded tests. - ::testing::FLAGS_gtest_death_test_style = "threadsafe"; - } -}; - -// Runs |fn| with |task_tracker|, expecting it to crash in debug mode. -void MaybeRunDeadlyTaskTrackerMemberFunction( - CancelableTaskTracker* task_tracker, - const Callback<void(CancelableTaskTracker*)>& fn) { - EXPECT_DCHECK_DEATH(fn.Run(task_tracker)); -} - -void PostDoNothingTask(CancelableTaskTracker* task_tracker) { - ignore_result(task_tracker->PostTask( - scoped_refptr<TestSimpleTaskRunner>(new TestSimpleTaskRunner()).get(), - FROM_HERE, DoNothing())); -} - -TEST_F(CancelableTaskTrackerDeathTest, PostFromDifferentThread) { - Thread bad_thread("bad thread"); - ASSERT_TRUE(bad_thread.Start()); - - bad_thread.task_runner()->PostTask( - FROM_HERE, - BindOnce(&MaybeRunDeadlyTaskTrackerMemberFunction, - Unretained(&task_tracker_), Bind(&PostDoNothingTask))); -} - -void TryCancel(CancelableTaskTracker::TaskId task_id, - CancelableTaskTracker* task_tracker) { - task_tracker->TryCancel(task_id); -} - -TEST_F(CancelableTaskTrackerDeathTest, CancelOnDifferentThread) { - scoped_refptr<TestSimpleTaskRunner> test_task_runner( - new TestSimpleTaskRunner()); - - Thread bad_thread("bad thread"); - ASSERT_TRUE(bad_thread.Start()); - - CancelableTaskTracker::TaskId task_id = - task_tracker_.PostTask(test_task_runner.get(), FROM_HERE, DoNothing()); - EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id); - - bad_thread.task_runner()->PostTask( - FROM_HERE, - BindOnce(&MaybeRunDeadlyTaskTrackerMemberFunction, - Unretained(&task_tracker_), Bind(&TryCancel, task_id))); - - test_task_runner->RunUntilIdle(); -} - -TEST_F(CancelableTaskTrackerDeathTest, CancelAllOnDifferentThread) { - scoped_refptr<TestSimpleTaskRunner> test_task_runner( - new TestSimpleTaskRunner()); - - Thread bad_thread("bad thread"); - ASSERT_TRUE(bad_thread.Start()); - - CancelableTaskTracker::TaskId task_id = - task_tracker_.PostTask(test_task_runner.get(), FROM_HERE, DoNothing()); - EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id); - - bad_thread.task_runner()->PostTask( - FROM_HERE, BindOnce(&MaybeRunDeadlyTaskTrackerMemberFunction, - Unretained(&task_tracker_), - Bind(&CancelableTaskTracker::TryCancelAll))); - - test_task_runner->RunUntilIdle(); -} - -} // namespace base
diff --git a/base/task_runner_util_unittest.cc b/base/task_runner_util_unittest.cc deleted file mode 100644 index 44baad4..0000000 --- a/base/task_runner_util_unittest.cc +++ /dev/null
@@ -1,125 +0,0 @@ -// 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/task_runner_util.h" - -#include <utility> - -#include "base/bind.h" -#include "base/location.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -int ReturnFourtyTwo() { - return 42; -} - -void StoreValue(int* destination, int value) { - *destination = value; -} - -void StoreDoubleValue(double* destination, double value) { - *destination = value; -} - -int g_foo_destruct_count = 0; -int g_foo_free_count = 0; - -struct Foo { - ~Foo() { - ++g_foo_destruct_count; - } -}; - -std::unique_ptr<Foo> CreateFoo() { - return std::unique_ptr<Foo>(new Foo); -} - -void ExpectFoo(std::unique_ptr<Foo> foo) { - EXPECT_TRUE(foo.get()); - std::unique_ptr<Foo> local_foo(std::move(foo)); - EXPECT_TRUE(local_foo.get()); - EXPECT_FALSE(foo.get()); -} - -struct FooDeleter { - void operator()(Foo* foo) const { - ++g_foo_free_count; - delete foo; - }; -}; - -std::unique_ptr<Foo, FooDeleter> CreateScopedFoo() { - return std::unique_ptr<Foo, FooDeleter>(new Foo); -} - -void ExpectScopedFoo(std::unique_ptr<Foo, FooDeleter> foo) { - EXPECT_TRUE(foo.get()); - std::unique_ptr<Foo, FooDeleter> local_foo(std::move(foo)); - EXPECT_TRUE(local_foo.get()); - EXPECT_FALSE(foo.get()); -} - -} // namespace - -TEST(TaskRunnerHelpersTest, PostTaskAndReplyWithResult) { - int result = 0; - - MessageLoop message_loop; - PostTaskAndReplyWithResult(message_loop.task_runner().get(), FROM_HERE, - Bind(&ReturnFourtyTwo), - Bind(&StoreValue, &result)); - - RunLoop().RunUntilIdle(); - - EXPECT_EQ(42, result); -} - -TEST(TaskRunnerHelpersTest, PostTaskAndReplyWithResultImplicitConvert) { - double result = 0; - - MessageLoop message_loop; - PostTaskAndReplyWithResult(message_loop.task_runner().get(), FROM_HERE, - Bind(&ReturnFourtyTwo), - Bind(&StoreDoubleValue, &result)); - - RunLoop().RunUntilIdle(); - - EXPECT_DOUBLE_EQ(42.0, result); -} - -TEST(TaskRunnerHelpersTest, PostTaskAndReplyWithResultPassed) { - g_foo_destruct_count = 0; - g_foo_free_count = 0; - - MessageLoop message_loop; - PostTaskAndReplyWithResult(message_loop.task_runner().get(), FROM_HERE, - Bind(&CreateFoo), Bind(&ExpectFoo)); - - RunLoop().RunUntilIdle(); - - EXPECT_EQ(1, g_foo_destruct_count); - EXPECT_EQ(0, g_foo_free_count); -} - -TEST(TaskRunnerHelpersTest, PostTaskAndReplyWithResultPassedFreeProc) { - g_foo_destruct_count = 0; - g_foo_free_count = 0; - - MessageLoop message_loop; - PostTaskAndReplyWithResult(message_loop.task_runner().get(), FROM_HERE, - Bind(&CreateScopedFoo), Bind(&ExpectScopedFoo)); - - RunLoop().RunUntilIdle(); - - EXPECT_EQ(1, g_foo_destruct_count); - EXPECT_EQ(1, g_foo_free_count); -} - -} // namespace base
diff --git a/base/task_scheduler/delayed_task_manager_unittest.cc b/base/task_scheduler/delayed_task_manager_unittest.cc deleted file mode 100644 index 67c797a..0000000 --- a/base/task_scheduler/delayed_task_manager_unittest.cc +++ /dev/null
@@ -1,209 +0,0 @@ -// 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/task_scheduler/delayed_task_manager.h" - -#include <memory> -#include <utility> - -#include "base/bind.h" -#include "base/memory/ptr_util.h" -#include "base/memory/ref_counted.h" -#include "base/synchronization/waitable_event.h" -#include "base/task_scheduler/task.h" -#include "base/test/bind_test_util.h" -#include "base/test/test_mock_time_task_runner.h" -#include "base/threading/thread.h" -#include "base/time/time.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace internal { -namespace { - -constexpr TimeDelta kLongDelay = TimeDelta::FromHours(1); - -class MockTask { - public: - MOCK_METHOD0(Run, void()); -}; - -void RunTask(Task task) { - std::move(task.task).Run(); -} - -class TaskSchedulerDelayedTaskManagerTest : public testing::Test { - protected: - TaskSchedulerDelayedTaskManagerTest() - : delayed_task_manager_( - service_thread_task_runner_->DeprecatedGetMockTickClock()), - task_(FROM_HERE, - BindOnce(&MockTask::Run, Unretained(&mock_task_)), - TaskTraits(), - kLongDelay) { - // The constructor of Task computes |delayed_run_time| by adding |delay| to - // the real time. Recompute it by adding |delay| to the mock time. - task_.delayed_run_time = - service_thread_task_runner_->GetMockTickClock()->NowTicks() + - kLongDelay; - } - ~TaskSchedulerDelayedTaskManagerTest() override = default; - - const scoped_refptr<TestMockTimeTaskRunner> service_thread_task_runner_ = - MakeRefCounted<TestMockTimeTaskRunner>(); - DelayedTaskManager delayed_task_manager_; - testing::StrictMock<MockTask> mock_task_; - Task task_; - - private: - DISALLOW_COPY_AND_ASSIGN(TaskSchedulerDelayedTaskManagerTest); -}; - -} // namespace - -// Verify that a delayed task isn't forwarded before Start(). -TEST_F(TaskSchedulerDelayedTaskManagerTest, DelayedTaskDoesNotRunBeforeStart) { - // Send |task| to the DelayedTaskManager. - delayed_task_manager_.AddDelayedTask(std::move(task_), BindOnce(&RunTask)); - - // Fast-forward time until the task is ripe for execution. Since Start() has - // not been called, the task should not be forwarded to RunTask() (MockTask is - // a StrictMock without expectations so test will fail if RunTask() runs it). - service_thread_task_runner_->FastForwardBy(kLongDelay); -} - -// Verify that a delayed task added before Start() and whose delay expires after -// Start() is forwarded when its delay expires. -TEST_F(TaskSchedulerDelayedTaskManagerTest, - DelayedTaskPostedBeforeStartExpiresAfterStartRunsOnExpire) { - // Send |task| to the DelayedTaskManager. - delayed_task_manager_.AddDelayedTask(std::move(task_), BindOnce(&RunTask)); - - delayed_task_manager_.Start(service_thread_task_runner_); - - // Run tasks on the service thread. Don't expect any forwarding to - // |task_target_| since the task isn't ripe for execution. - service_thread_task_runner_->RunUntilIdle(); - - // Fast-forward time until the task is ripe for execution. Expect the task to - // be forwarded to RunTask(). - EXPECT_CALL(mock_task_, Run()); - service_thread_task_runner_->FastForwardBy(kLongDelay); -} - -// Verify that a delayed task added before Start() and whose delay expires -// before Start() is forwarded when Start() is called. -TEST_F(TaskSchedulerDelayedTaskManagerTest, - DelayedTaskPostedBeforeStartExpiresBeforeStartRunsOnStart) { - // Send |task| to the DelayedTaskManager. - delayed_task_manager_.AddDelayedTask(std::move(task_), BindOnce(&RunTask)); - - // Run tasks on the service thread. Don't expect any forwarding to - // |task_target_| since the task isn't ripe for execution. - service_thread_task_runner_->RunUntilIdle(); - - // Fast-forward time until the task is ripe for execution. Don't expect the - // task to be forwarded since Start() hasn't been called yet. - service_thread_task_runner_->FastForwardBy(kLongDelay); - - // Start the DelayedTaskManager. Expect the task to be forwarded to RunTask(). - EXPECT_CALL(mock_task_, Run()); - delayed_task_manager_.Start(service_thread_task_runner_); - service_thread_task_runner_->RunUntilIdle(); -} - -// Verify that a delayed task added after Start() isn't forwarded before it is -// ripe for execution. -TEST_F(TaskSchedulerDelayedTaskManagerTest, DelayedTaskDoesNotRunTooEarly) { - delayed_task_manager_.Start(service_thread_task_runner_); - - // Send |task| to the DelayedTaskManager. - delayed_task_manager_.AddDelayedTask(std::move(task_), BindOnce(&RunTask)); - - // Run tasks that are ripe for execution. Don't expect any forwarding to - // RunTask(). - service_thread_task_runner_->RunUntilIdle(); -} - -// Verify that a delayed task added after Start() is forwarded when it is ripe -// for execution. -TEST_F(TaskSchedulerDelayedTaskManagerTest, DelayedTaskRunsAfterDelay) { - delayed_task_manager_.Start(service_thread_task_runner_); - - // Send |task| to the DelayedTaskManager. - delayed_task_manager_.AddDelayedTask(std::move(task_), BindOnce(&RunTask)); - - // Fast-forward time. Expect the task to be forwarded to RunTask(). - EXPECT_CALL(mock_task_, Run()); - service_thread_task_runner_->FastForwardBy(kLongDelay); -} - -// Verify that multiple delayed tasks added after Start() are forwarded when -// they are ripe for execution. -TEST_F(TaskSchedulerDelayedTaskManagerTest, DelayedTasksRunAfterDelay) { - delayed_task_manager_.Start(service_thread_task_runner_); - - testing::StrictMock<MockTask> mock_task_a; - Task task_a(FROM_HERE, BindOnce(&MockTask::Run, Unretained(&mock_task_a)), - TaskTraits(), TimeDelta::FromHours(1)); - - testing::StrictMock<MockTask> mock_task_b; - Task task_b(FROM_HERE, BindOnce(&MockTask::Run, Unretained(&mock_task_b)), - TaskTraits(), TimeDelta::FromHours(2)); - - testing::StrictMock<MockTask> mock_task_c; - Task task_c(FROM_HERE, BindOnce(&MockTask::Run, Unretained(&mock_task_c)), - TaskTraits(), TimeDelta::FromHours(1)); - - // Send tasks to the DelayedTaskManager. - delayed_task_manager_.AddDelayedTask(std::move(task_a), BindOnce(&RunTask)); - delayed_task_manager_.AddDelayedTask(std::move(task_b), BindOnce(&RunTask)); - delayed_task_manager_.AddDelayedTask(std::move(task_c), BindOnce(&RunTask)); - - // Run tasks that are ripe for execution on the service thread. Don't expect - // any call to RunTask(). - service_thread_task_runner_->RunUntilIdle(); - - // Fast-forward time. Expect |task_a| and |task_c| to be forwarded to - // |task_target_|. - EXPECT_CALL(mock_task_a, Run()); - EXPECT_CALL(mock_task_c, Run()); - service_thread_task_runner_->FastForwardBy(TimeDelta::FromHours(1)); - testing::Mock::VerifyAndClear(&mock_task_a); - testing::Mock::VerifyAndClear(&mock_task_c); - - // Fast-forward time. Expect |task_b| to be forwarded to RunTask(). - EXPECT_CALL(mock_task_b, Run()); - service_thread_task_runner_->FastForwardBy(TimeDelta::FromHours(1)); - testing::Mock::VerifyAndClear(&mock_task_b); -} - -TEST_F(TaskSchedulerDelayedTaskManagerTest, PostTaskDuringStart) { - Thread other_thread("Test"); - other_thread.StartAndWaitForTesting(); - - WaitableEvent task_posted; - - other_thread.task_runner()->PostTask(FROM_HERE, BindLambdaForTesting([&]() { - delayed_task_manager_.AddDelayedTask( - std::move(task_), - BindOnce(&RunTask)); - task_posted.Signal(); - })); - - delayed_task_manager_.Start(service_thread_task_runner_); - - // The test is testing a race between AddDelayedTask/Start but it still needs - // synchronization to ensure we don't do the final verification before the - // task itself is posted. - task_posted.Wait(); - - // Fast-forward time. Expect the task to be forwarded to RunTask(). - EXPECT_CALL(mock_task_, Run()); - service_thread_task_runner_->FastForwardBy(kLongDelay); -} - -} // namespace internal -} // namespace base
diff --git a/base/task_scheduler/lazy_task_runner_unittest.cc b/base/task_scheduler/lazy_task_runner_unittest.cc deleted file mode 100644 index e898a1e..0000000 --- a/base/task_scheduler/lazy_task_runner_unittest.cc +++ /dev/null
@@ -1,199 +0,0 @@ -// 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/task_scheduler/lazy_task_runner.h" - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/sequence_checker_impl.h" -#include "base/task_scheduler/scoped_set_task_priority_for_current_thread.h" -#include "base/test/scoped_task_environment.h" -#include "base/threading/thread_checker_impl.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(OS_WIN) -#include "base/win/com_init_util.h" -#endif - -namespace base { - -namespace { - -LazySequencedTaskRunner g_sequenced_task_runner_user_visible = - LAZY_SEQUENCED_TASK_RUNNER_INITIALIZER({TaskPriority::USER_VISIBLE}); -LazySequencedTaskRunner g_sequenced_task_runner_user_blocking = - LAZY_SEQUENCED_TASK_RUNNER_INITIALIZER({TaskPriority::USER_BLOCKING}); - -LazySingleThreadTaskRunner g_single_thread_task_runner_user_visible = - LAZY_SINGLE_THREAD_TASK_RUNNER_INITIALIZER( - {TaskPriority::USER_VISIBLE}, - SingleThreadTaskRunnerThreadMode::SHARED); -LazySingleThreadTaskRunner g_single_thread_task_runner_user_blocking = - LAZY_SINGLE_THREAD_TASK_RUNNER_INITIALIZER( - {TaskPriority::USER_BLOCKING}, - SingleThreadTaskRunnerThreadMode::SHARED); - -#if defined(OS_WIN) -LazyCOMSTATaskRunner g_com_sta_task_runner_user_visible = - LAZY_COM_STA_TASK_RUNNER_INITIALIZER( - {TaskPriority::USER_VISIBLE}, - SingleThreadTaskRunnerThreadMode::SHARED); -LazyCOMSTATaskRunner g_com_sta_task_runner_user_blocking = - LAZY_COM_STA_TASK_RUNNER_INITIALIZER( - {TaskPriority::USER_BLOCKING}, - SingleThreadTaskRunnerThreadMode::SHARED); -#endif // defined(OS_WIN) - -void InitCheckers(SequenceCheckerImpl* sequence_checker, - ThreadCheckerImpl* thread_checker) { - sequence_checker->DetachFromSequence(); - EXPECT_TRUE(sequence_checker->CalledOnValidSequence()); - thread_checker->DetachFromThread(); - EXPECT_TRUE(thread_checker->CalledOnValidThread()); -} - -void ExpectSequencedEnvironment(SequenceCheckerImpl* sequence_checker, - ThreadCheckerImpl* thread_checker, - TaskPriority expected_priority) { - EXPECT_TRUE(sequence_checker->CalledOnValidSequence()); - EXPECT_FALSE(thread_checker->CalledOnValidThread()); - EXPECT_EQ(expected_priority, internal::GetTaskPriorityForCurrentThread()); -} - -void ExpectSingleThreadEnvironment(SequenceCheckerImpl* sequence_checker, - ThreadCheckerImpl* thread_checker, - TaskPriority expected_priority -#if defined(OS_WIN) - , - bool expect_com_sta = false -#endif - ) { - EXPECT_TRUE(sequence_checker->CalledOnValidSequence()); - EXPECT_TRUE(thread_checker->CalledOnValidThread()); - EXPECT_EQ(expected_priority, internal::GetTaskPriorityForCurrentThread()); - -#if defined(OS_WIN) - if (expect_com_sta) - win::AssertComApartmentType(win::ComApartmentType::STA); -#endif -} - -class TaskSchedulerLazyTaskRunnerEnvironmentTest : public testing::Test { - protected: - TaskSchedulerLazyTaskRunnerEnvironmentTest() = default; - - void TestTaskRunnerEnvironment(scoped_refptr<SequencedTaskRunner> task_runner, - bool expect_single_thread, - TaskPriority expected_priority -#if defined(OS_WIN) - , - bool expect_com_sta = false -#endif - ) { - SequenceCheckerImpl sequence_checker; - ThreadCheckerImpl thread_checker; - task_runner->PostTask(FROM_HERE, - BindOnce(&InitCheckers, Unretained(&sequence_checker), - Unretained(&thread_checker))); - scoped_task_environment_.RunUntilIdle(); - - OnceClosure task = - expect_single_thread - ? BindOnce(&ExpectSingleThreadEnvironment, - Unretained(&sequence_checker), - Unretained(&thread_checker), expected_priority -#if defined(OS_WIN) - , - expect_com_sta -#endif - ) - : BindOnce(&ExpectSequencedEnvironment, - Unretained(&sequence_checker), - Unretained(&thread_checker), expected_priority); - task_runner->PostTask(FROM_HERE, std::move(task)); - scoped_task_environment_.RunUntilIdle(); - } - - test::ScopedTaskEnvironment scoped_task_environment_; - - private: - DISALLOW_COPY_AND_ASSIGN(TaskSchedulerLazyTaskRunnerEnvironmentTest); -}; - -} // namespace - -TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest, - LazySequencedTaskRunnerUserVisible) { - TestTaskRunnerEnvironment(g_sequenced_task_runner_user_visible.Get(), false, - TaskPriority::USER_VISIBLE); -} - -TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest, - LazySequencedTaskRunnerUserBlocking) { - TestTaskRunnerEnvironment(g_sequenced_task_runner_user_blocking.Get(), false, - TaskPriority::USER_BLOCKING); -} - -TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest, - LazySingleThreadTaskRunnerUserVisible) { - TestTaskRunnerEnvironment(g_single_thread_task_runner_user_visible.Get(), - true, TaskPriority::USER_VISIBLE); -} - -TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest, - LazySingleThreadTaskRunnerUserBlocking) { - TestTaskRunnerEnvironment(g_single_thread_task_runner_user_blocking.Get(), - true, TaskPriority::USER_BLOCKING); -} - -#if defined(OS_WIN) -TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest, - LazyCOMSTATaskRunnerUserVisible) { - TestTaskRunnerEnvironment(g_com_sta_task_runner_user_visible.Get(), true, - TaskPriority::USER_VISIBLE, true); -} - -TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest, - LazyCOMSTATaskRunnerUserBlocking) { - TestTaskRunnerEnvironment(g_com_sta_task_runner_user_blocking.Get(), true, - TaskPriority::USER_BLOCKING, true); -} -#endif // defined(OS_WIN) - -TEST(TaskSchdulerLazyTaskRunnerTest, LazySequencedTaskRunnerReset) { - for (int i = 0; i < 2; ++i) { - test::ScopedTaskEnvironment scoped_task_environment; - // If the TaskRunner isn't released when the test::ScopedTaskEnvironment - // goes out of scope, the second invocation of the line below will access a - // deleted TaskScheduler and crash. - g_sequenced_task_runner_user_visible.Get()->PostTask(FROM_HERE, - DoNothing()); - } -} - -TEST(TaskSchdulerLazyTaskRunnerTest, LazySingleThreadTaskRunnerReset) { - for (int i = 0; i < 2; ++i) { - test::ScopedTaskEnvironment scoped_task_environment; - // If the TaskRunner isn't released when the test::ScopedTaskEnvironment - // goes out of scope, the second invocation of the line below will access a - // deleted TaskScheduler and crash. - g_single_thread_task_runner_user_visible.Get()->PostTask(FROM_HERE, - DoNothing()); - } -} - -#if defined(OS_WIN) -TEST(TaskSchdulerLazyTaskRunnerTest, LazyCOMSTATaskRunnerReset) { - for (int i = 0; i < 2; ++i) { - test::ScopedTaskEnvironment scoped_task_environment; - // If the TaskRunner isn't released when the test::ScopedTaskEnvironment - // goes out of scope, the second invocation of the line below will access a - // deleted TaskScheduler and crash. - g_com_sta_task_runner_user_visible.Get()->PostTask(FROM_HERE, DoNothing()); - } -} -#endif // defined(OS_WIN) - -} // namespace base
diff --git a/base/task_scheduler/priority_queue_unittest.cc b/base/task_scheduler/priority_queue_unittest.cc deleted file mode 100644 index 9dc4d13..0000000 --- a/base/task_scheduler/priority_queue_unittest.cc +++ /dev/null
@@ -1,172 +0,0 @@ -// 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/task_scheduler/priority_queue.h" - -#include <memory> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/memory/ref_counted.h" -#include "base/synchronization/waitable_event.h" -#include "base/task_scheduler/sequence.h" -#include "base/task_scheduler/task.h" -#include "base/task_scheduler/task_traits.h" -#include "base/test/gtest_util.h" -#include "base/threading/platform_thread.h" -#include "base/threading/simple_thread.h" -#include "base/time/time.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace internal { - -namespace { - -class ThreadBeginningTransaction : public SimpleThread { - public: - explicit ThreadBeginningTransaction(PriorityQueue* priority_queue) - : SimpleThread("ThreadBeginningTransaction"), - priority_queue_(priority_queue), - transaction_began_(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED) {} - - // SimpleThread: - void Run() override { - std::unique_ptr<PriorityQueue::Transaction> transaction = - priority_queue_->BeginTransaction(); - transaction_began_.Signal(); - } - - void ExpectTransactionDoesNotBegin() { - // After a few milliseconds, the call to BeginTransaction() should not have - // returned. - EXPECT_FALSE( - transaction_began_.TimedWait(TimeDelta::FromMilliseconds(250))); - } - - private: - PriorityQueue* const priority_queue_; - WaitableEvent transaction_began_; - - DISALLOW_COPY_AND_ASSIGN(ThreadBeginningTransaction); -}; - -} // namespace - -TEST(TaskSchedulerPriorityQueueTest, PushPopPeek) { - // Create test sequences. - scoped_refptr<Sequence> sequence_a(new Sequence); - sequence_a->PushTask(Task(FROM_HERE, DoNothing(), - TaskTraits(TaskPriority::USER_VISIBLE), - TimeDelta())); - SequenceSortKey sort_key_a = sequence_a->GetSortKey(); - - scoped_refptr<Sequence> sequence_b(new Sequence); - sequence_b->PushTask(Task(FROM_HERE, DoNothing(), - TaskTraits(TaskPriority::USER_BLOCKING), - TimeDelta())); - SequenceSortKey sort_key_b = sequence_b->GetSortKey(); - - scoped_refptr<Sequence> sequence_c(new Sequence); - sequence_c->PushTask(Task(FROM_HERE, DoNothing(), - TaskTraits(TaskPriority::USER_BLOCKING), - TimeDelta())); - SequenceSortKey sort_key_c = sequence_c->GetSortKey(); - - scoped_refptr<Sequence> sequence_d(new Sequence); - sequence_d->PushTask(Task(FROM_HERE, DoNothing(), - TaskTraits(TaskPriority::BACKGROUND), TimeDelta())); - SequenceSortKey sort_key_d = sequence_d->GetSortKey(); - - // Create a PriorityQueue and a Transaction. - PriorityQueue pq; - auto transaction(pq.BeginTransaction()); - EXPECT_TRUE(transaction->IsEmpty()); - - // Push |sequence_a| in the PriorityQueue. It becomes the sequence with the - // highest priority. - transaction->Push(sequence_a, sort_key_a); - EXPECT_EQ(sort_key_a, transaction->PeekSortKey()); - - // Push |sequence_b| in the PriorityQueue. It becomes the sequence with the - // highest priority. - transaction->Push(sequence_b, sort_key_b); - EXPECT_EQ(sort_key_b, transaction->PeekSortKey()); - - // Push |sequence_c| in the PriorityQueue. |sequence_b| is still the sequence - // with the highest priority. - transaction->Push(sequence_c, sort_key_c); - EXPECT_EQ(sort_key_b, transaction->PeekSortKey()); - - // Push |sequence_d| in the PriorityQueue. |sequence_b| is still the sequence - // with the highest priority. - transaction->Push(sequence_d, sort_key_d); - EXPECT_EQ(sort_key_b, transaction->PeekSortKey()); - - // Pop |sequence_b| from the PriorityQueue. |sequence_c| becomes the sequence - // with the highest priority. - EXPECT_EQ(sequence_b, transaction->PopSequence()); - EXPECT_EQ(sort_key_c, transaction->PeekSortKey()); - - // Pop |sequence_c| from the PriorityQueue. |sequence_a| becomes the sequence - // with the highest priority. - EXPECT_EQ(sequence_c, transaction->PopSequence()); - EXPECT_EQ(sort_key_a, transaction->PeekSortKey()); - - // Pop |sequence_a| from the PriorityQueue. |sequence_d| becomes the sequence - // with the highest priority. - EXPECT_EQ(sequence_a, transaction->PopSequence()); - EXPECT_EQ(sort_key_d, transaction->PeekSortKey()); - - // Pop |sequence_d| from the PriorityQueue. It is now empty. - EXPECT_EQ(sequence_d, transaction->PopSequence()); - EXPECT_TRUE(transaction->IsEmpty()); -} - -// Check that creating Transactions on the same thread for 2 unrelated -// PriorityQueues causes a crash. -TEST(TaskSchedulerPriorityQueueTest, IllegalTwoTransactionsSameThread) { - PriorityQueue pq_a; - PriorityQueue pq_b; - - EXPECT_DCHECK_DEATH( - { - std::unique_ptr<PriorityQueue::Transaction> transaction_a = - pq_a.BeginTransaction(); - std::unique_ptr<PriorityQueue::Transaction> transaction_b = - pq_b.BeginTransaction(); - }); -} - -// Check that it is possible to begin multiple Transactions for the same -// PriorityQueue on different threads. The call to BeginTransaction() on the -// second thread should block until the Transaction has ended on the first -// thread. -TEST(TaskSchedulerPriorityQueueTest, TwoTransactionsTwoThreads) { - PriorityQueue pq; - - // Call BeginTransaction() on this thread and keep the Transaction alive. - std::unique_ptr<PriorityQueue::Transaction> transaction = - pq.BeginTransaction(); - - // Call BeginTransaction() on another thread. - ThreadBeginningTransaction thread_beginning_transaction(&pq); - thread_beginning_transaction.Start(); - - // After a few milliseconds, the call to BeginTransaction() on the other - // thread should not have returned. - thread_beginning_transaction.ExpectTransactionDoesNotBegin(); - - // End the Transaction on the current thread. - transaction.reset(); - - // The other thread should exit after its call to BeginTransaction() returns. - thread_beginning_transaction.Join(); -} - -} // namespace internal -} // namespace base
diff --git a/base/task_scheduler/scheduler_lock_unittest.cc b/base/task_scheduler/scheduler_lock_unittest.cc deleted file mode 100644 index 5518247..0000000 --- a/base/task_scheduler/scheduler_lock_unittest.cc +++ /dev/null
@@ -1,296 +0,0 @@ -// 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/task_scheduler/scheduler_lock.h" - -#include <stdlib.h> - -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "base/rand_util.h" -#include "base/synchronization/waitable_event.h" -#include "base/test/gtest_util.h" -#include "base/threading/platform_thread.h" -#include "base/threading/simple_thread.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace internal { -namespace { - -// Adapted from base::Lock's BasicLockTestThread to make sure -// Acquire()/Release() don't crash. -class BasicLockTestThread : public SimpleThread { - public: - explicit BasicLockTestThread(SchedulerLock* lock) - : SimpleThread("BasicLockTestThread"), - lock_(lock), - acquired_(0) {} - - int acquired() const { return acquired_; } - - private: - void Run() override { - for (int i = 0; i < 10; i++) { - lock_->Acquire(); - acquired_++; - lock_->Release(); - } - for (int i = 0; i < 10; i++) { - lock_->Acquire(); - acquired_++; - PlatformThread::Sleep(TimeDelta::FromMilliseconds(base::RandInt(0, 19))); - lock_->Release(); - } - } - - SchedulerLock* const lock_; - int acquired_; - - DISALLOW_COPY_AND_ASSIGN(BasicLockTestThread); -}; - -class BasicLockAcquireAndWaitThread : public SimpleThread { - public: - explicit BasicLockAcquireAndWaitThread(SchedulerLock* lock) - : SimpleThread("BasicLockAcquireAndWaitThread"), - lock_(lock), - lock_acquire_event_(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED), - main_thread_continue_event_(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED) { - } - - void WaitForLockAcquisition() { - lock_acquire_event_.Wait(); - } - - void ContinueMain() { - main_thread_continue_event_.Signal(); - } - - private: - void Run() override { - lock_->Acquire(); - lock_acquire_event_.Signal(); - main_thread_continue_event_.Wait(); - lock_->Release(); - } - - SchedulerLock* const lock_; - WaitableEvent lock_acquire_event_; - WaitableEvent main_thread_continue_event_; - - DISALLOW_COPY_AND_ASSIGN(BasicLockAcquireAndWaitThread); -}; - -TEST(TaskSchedulerLock, Basic) { - SchedulerLock lock; - BasicLockTestThread thread(&lock); - - thread.Start(); - - int acquired = 0; - for (int i = 0; i < 5; i++) { - lock.Acquire(); - acquired++; - lock.Release(); - } - for (int i = 0; i < 10; i++) { - lock.Acquire(); - acquired++; - PlatformThread::Sleep(TimeDelta::FromMilliseconds(base::RandInt(0, 19))); - lock.Release(); - } - for (int i = 0; i < 5; i++) { - lock.Acquire(); - acquired++; - PlatformThread::Sleep(TimeDelta::FromMilliseconds(base::RandInt(0, 19))); - lock.Release(); - } - - thread.Join(); - - EXPECT_EQ(acquired, 20); - EXPECT_EQ(thread.acquired(), 20); -} - -TEST(TaskSchedulerLock, AcquirePredecessor) { - SchedulerLock predecessor; - SchedulerLock lock(&predecessor); - predecessor.Acquire(); - lock.Acquire(); - lock.Release(); - predecessor.Release(); -} - -TEST(TaskSchedulerLock, AcquirePredecessorWrongOrder) { - SchedulerLock predecessor; - SchedulerLock lock(&predecessor); - EXPECT_DCHECK_DEATH({ - lock.Acquire(); - predecessor.Acquire(); - }); -} - -TEST(TaskSchedulerLock, AcquireNonPredecessor) { - SchedulerLock lock1; - SchedulerLock lock2; - EXPECT_DCHECK_DEATH({ - lock1.Acquire(); - lock2.Acquire(); - }); -} - -TEST(TaskSchedulerLock, AcquireMultipleLocksInOrder) { - SchedulerLock lock1; - SchedulerLock lock2(&lock1); - SchedulerLock lock3(&lock2); - lock1.Acquire(); - lock2.Acquire(); - lock3.Acquire(); - lock3.Release(); - lock2.Release(); - lock1.Release(); -} - -TEST(TaskSchedulerLock, AcquireMultipleLocksInTheMiddleOfAChain) { - SchedulerLock lock1; - SchedulerLock lock2(&lock1); - SchedulerLock lock3(&lock2); - lock2.Acquire(); - lock3.Acquire(); - lock3.Release(); - lock2.Release(); -} - -TEST(TaskSchedulerLock, AcquireMultipleLocksNoTransitivity) { - SchedulerLock lock1; - SchedulerLock lock2(&lock1); - SchedulerLock lock3(&lock2); - EXPECT_DCHECK_DEATH({ - lock1.Acquire(); - lock3.Acquire(); - }); -} - -TEST(TaskSchedulerLock, AcquireLocksDifferentThreadsSafely) { - SchedulerLock lock1; - SchedulerLock lock2; - BasicLockAcquireAndWaitThread thread(&lock1); - thread.Start(); - - lock2.Acquire(); - thread.WaitForLockAcquisition(); - thread.ContinueMain(); - thread.Join(); - lock2.Release(); -} - -TEST(TaskSchedulerLock, - AcquireLocksWithPredecessorDifferentThreadsSafelyPredecessorFirst) { - // A lock and its predecessor may be safely acquired on different threads. - // This Thread Other Thread - // predecessor.Acquire() - // lock.Acquire() - // predecessor.Release() - // lock.Release() - SchedulerLock predecessor; - SchedulerLock lock(&predecessor); - predecessor.Acquire(); - BasicLockAcquireAndWaitThread thread(&lock); - thread.Start(); - thread.WaitForLockAcquisition(); - predecessor.Release(); - thread.ContinueMain(); - thread.Join(); -} - -TEST(TaskSchedulerLock, - AcquireLocksWithPredecessorDifferentThreadsSafelyPredecessorLast) { - // A lock and its predecessor may be safely acquired on different threads. - // This Thread Other Thread - // lock.Acquire() - // predecessor.Acquire() - // lock.Release() - // predecessor.Release() - SchedulerLock predecessor; - SchedulerLock lock(&predecessor); - lock.Acquire(); - BasicLockAcquireAndWaitThread thread(&predecessor); - thread.Start(); - thread.WaitForLockAcquisition(); - lock.Release(); - thread.ContinueMain(); - thread.Join(); -} - -TEST(TaskSchedulerLock, - AcquireLocksWithPredecessorDifferentThreadsSafelyNoInterference) { - // Acquisition of an unrelated lock on another thread should not affect a - // legal lock acquisition with a predecessor on this thread. - // This Thread Other Thread - // predecessor.Acquire() - // unrelated.Acquire() - // lock.Acquire() - // unrelated.Release() - // lock.Release() - // predecessor.Release(); - SchedulerLock predecessor; - SchedulerLock lock(&predecessor); - predecessor.Acquire(); - SchedulerLock unrelated; - BasicLockAcquireAndWaitThread thread(&unrelated); - thread.Start(); - thread.WaitForLockAcquisition(); - lock.Acquire(); - thread.ContinueMain(); - thread.Join(); - lock.Release(); - predecessor.Release(); -} - -TEST(TaskSchedulerLock, SelfReferentialLock) { - struct SelfReferentialLock { - SelfReferentialLock() : lock(&lock) {} - - SchedulerLock lock; - }; - - EXPECT_DCHECK_DEATH({ SelfReferentialLock lock; }); -} - -TEST(TaskSchedulerLock, PredecessorCycle) { - struct LockCycle { - LockCycle() : lock1(&lock2), lock2(&lock1) {} - - SchedulerLock lock1; - SchedulerLock lock2; - }; - - EXPECT_DCHECK_DEATH({ LockCycle cycle; }); -} - -TEST(TaskSchedulerLock, PredecessorLongerCycle) { - struct LockCycle { - LockCycle() - : lock1(&lock5), - lock2(&lock1), - lock3(&lock2), - lock4(&lock3), - lock5(&lock4) {} - - SchedulerLock lock1; - SchedulerLock lock2; - SchedulerLock lock3; - SchedulerLock lock4; - SchedulerLock lock5; - }; - - EXPECT_DCHECK_DEATH({ LockCycle cycle; }); -} - -} // namespace -} // namespace internal -} // namespace base
diff --git a/base/task_scheduler/scheduler_single_thread_task_runner_manager_unittest.cc b/base/task_scheduler/scheduler_single_thread_task_runner_manager_unittest.cc deleted file mode 100644 index 52d99f6..0000000 --- a/base/task_scheduler/scheduler_single_thread_task_runner_manager_unittest.cc +++ /dev/null
@@ -1,676 +0,0 @@ -// 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/task_scheduler/scheduler_single_thread_task_runner_manager.h" - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/memory/ptr_util.h" -#include "base/synchronization/atomic_flag.h" -#include "base/synchronization/lock.h" -#include "base/synchronization/waitable_event.h" -#include "base/task_scheduler/delayed_task_manager.h" -#include "base/task_scheduler/post_task.h" -#include "base/task_scheduler/scheduler_worker_pool_params.h" -#include "base/task_scheduler/task_tracker.h" -#include "base/task_scheduler/task_traits.h" -#include "base/test/gtest_util.h" -#include "base/test/test_timeouts.h" -#include "base/threading/platform_thread.h" -#include "base/threading/simple_thread.h" -#include "base/threading/thread.h" -#include "base/threading/thread_restrictions.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(OS_WIN) -#include <windows.h> - -#include "base/win/com_init_util.h" -#include "base/win/current_module.h" -#endif // defined(OS_WIN) - -namespace base { -namespace internal { - -namespace { - -class TaskSchedulerSingleThreadTaskRunnerManagerTest : public testing::Test { - public: - TaskSchedulerSingleThreadTaskRunnerManagerTest() - : service_thread_("TaskSchedulerServiceThread") {} - - void SetUp() override { - service_thread_.Start(); - delayed_task_manager_.Start(service_thread_.task_runner()); - single_thread_task_runner_manager_ = - std::make_unique<SchedulerSingleThreadTaskRunnerManager>( - task_tracker_.GetTrackedRef(), &delayed_task_manager_); - StartSingleThreadTaskRunnerManagerFromSetUp(); - } - - void TearDown() override { - if (single_thread_task_runner_manager_) - TearDownSingleThreadTaskRunnerManager(); - service_thread_.Stop(); - } - - protected: - virtual void StartSingleThreadTaskRunnerManagerFromSetUp() { - single_thread_task_runner_manager_->Start(); - } - - virtual void TearDownSingleThreadTaskRunnerManager() { - single_thread_task_runner_manager_->JoinForTesting(); - single_thread_task_runner_manager_.reset(); - } - - Thread service_thread_; - TaskTracker task_tracker_ = {"Test"}; - DelayedTaskManager delayed_task_manager_; - std::unique_ptr<SchedulerSingleThreadTaskRunnerManager> - single_thread_task_runner_manager_; - - private: - DISALLOW_COPY_AND_ASSIGN(TaskSchedulerSingleThreadTaskRunnerManagerTest); -}; - -void CaptureThreadRef(PlatformThreadRef* thread_ref) { - ASSERT_TRUE(thread_ref); - *thread_ref = PlatformThread::CurrentRef(); -} - -void CaptureThreadPriority(ThreadPriority* thread_priority) { - ASSERT_TRUE(thread_priority); - *thread_priority = PlatformThread::GetCurrentThreadPriority(); -} - -void CaptureThreadName(std::string* thread_name) { - *thread_name = PlatformThread::GetName(); -} - -void ShouldNotRun() { - ADD_FAILURE() << "Ran a task that shouldn't run."; -} - -} // namespace - -TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerTest, DifferentThreadsUsed) { - scoped_refptr<SingleThreadTaskRunner> task_runner_1 = - single_thread_task_runner_manager_ - ->CreateSingleThreadTaskRunnerWithTraits( - {TaskShutdownBehavior::BLOCK_SHUTDOWN}, - SingleThreadTaskRunnerThreadMode::DEDICATED); - scoped_refptr<SingleThreadTaskRunner> task_runner_2 = - single_thread_task_runner_manager_ - ->CreateSingleThreadTaskRunnerWithTraits( - {TaskShutdownBehavior::BLOCK_SHUTDOWN}, - SingleThreadTaskRunnerThreadMode::DEDICATED); - - PlatformThreadRef thread_ref_1; - task_runner_1->PostTask(FROM_HERE, - BindOnce(&CaptureThreadRef, &thread_ref_1)); - PlatformThreadRef thread_ref_2; - task_runner_2->PostTask(FROM_HERE, - BindOnce(&CaptureThreadRef, &thread_ref_2)); - - task_tracker_.Shutdown(); - - ASSERT_FALSE(thread_ref_1.is_null()); - ASSERT_FALSE(thread_ref_2.is_null()); - EXPECT_NE(thread_ref_1, thread_ref_2); -} - -TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerTest, SameThreadUsed) { - scoped_refptr<SingleThreadTaskRunner> task_runner_1 = - single_thread_task_runner_manager_ - ->CreateSingleThreadTaskRunnerWithTraits( - {TaskShutdownBehavior::BLOCK_SHUTDOWN}, - SingleThreadTaskRunnerThreadMode::SHARED); - scoped_refptr<SingleThreadTaskRunner> task_runner_2 = - single_thread_task_runner_manager_ - ->CreateSingleThreadTaskRunnerWithTraits( - {TaskShutdownBehavior::BLOCK_SHUTDOWN}, - SingleThreadTaskRunnerThreadMode::SHARED); - - PlatformThreadRef thread_ref_1; - task_runner_1->PostTask(FROM_HERE, - BindOnce(&CaptureThreadRef, &thread_ref_1)); - PlatformThreadRef thread_ref_2; - task_runner_2->PostTask(FROM_HERE, - BindOnce(&CaptureThreadRef, &thread_ref_2)); - - task_tracker_.Shutdown(); - - ASSERT_FALSE(thread_ref_1.is_null()); - ASSERT_FALSE(thread_ref_2.is_null()); - EXPECT_EQ(thread_ref_1, thread_ref_2); -} - -TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerTest, - RunsTasksInCurrentSequence) { - scoped_refptr<SingleThreadTaskRunner> task_runner_1 = - single_thread_task_runner_manager_ - ->CreateSingleThreadTaskRunnerWithTraits( - {TaskShutdownBehavior::BLOCK_SHUTDOWN}, - SingleThreadTaskRunnerThreadMode::DEDICATED); - scoped_refptr<SingleThreadTaskRunner> task_runner_2 = - single_thread_task_runner_manager_ - ->CreateSingleThreadTaskRunnerWithTraits( - {TaskShutdownBehavior::BLOCK_SHUTDOWN}, - SingleThreadTaskRunnerThreadMode::DEDICATED); - - EXPECT_FALSE(task_runner_1->RunsTasksInCurrentSequence()); - EXPECT_FALSE(task_runner_2->RunsTasksInCurrentSequence()); - - task_runner_1->PostTask( - FROM_HERE, - BindOnce( - [](scoped_refptr<SingleThreadTaskRunner> task_runner_1, - scoped_refptr<SingleThreadTaskRunner> task_runner_2) { - EXPECT_TRUE(task_runner_1->RunsTasksInCurrentSequence()); - EXPECT_FALSE(task_runner_2->RunsTasksInCurrentSequence()); - }, - task_runner_1, task_runner_2)); - - task_runner_2->PostTask( - FROM_HERE, - BindOnce( - [](scoped_refptr<SingleThreadTaskRunner> task_runner_1, - scoped_refptr<SingleThreadTaskRunner> task_runner_2) { - EXPECT_FALSE(task_runner_1->RunsTasksInCurrentSequence()); - EXPECT_TRUE(task_runner_2->RunsTasksInCurrentSequence()); - }, - task_runner_1, task_runner_2)); - - task_tracker_.Shutdown(); -} - -TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerTest, - SharedWithBaseSyncPrimitivesDCHECKs) { - testing::GTEST_FLAG(death_test_style) = "threadsafe"; - EXPECT_DCHECK_DEATH({ - single_thread_task_runner_manager_->CreateSingleThreadTaskRunnerWithTraits( - {WithBaseSyncPrimitives()}, SingleThreadTaskRunnerThreadMode::SHARED); - }); -} - -// Regression test for https://crbug.com/829786 -TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerTest, - ContinueOnShutdownDoesNotBlockBlockShutdown) { - WaitableEvent task_has_started(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - WaitableEvent task_can_continue(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - - // Post a CONTINUE_ON_SHUTDOWN task that waits on - // |task_can_continue| to a shared SingleThreadTaskRunner. - single_thread_task_runner_manager_ - ->CreateSingleThreadTaskRunnerWithTraits( - {TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, - SingleThreadTaskRunnerThreadMode::SHARED) - ->PostTask(FROM_HERE, base::BindOnce( - [](WaitableEvent* task_has_started, - WaitableEvent* task_can_continue) { - task_has_started->Signal(); - ScopedAllowBaseSyncPrimitivesForTesting - allow_base_sync_primitives; - task_can_continue->Wait(); - }, - Unretained(&task_has_started), - Unretained(&task_can_continue))); - - task_has_started.Wait(); - - // Post a BLOCK_SHUTDOWN task to a shared SingleThreadTaskRunner. - single_thread_task_runner_manager_ - ->CreateSingleThreadTaskRunnerWithTraits( - {TaskShutdownBehavior::BLOCK_SHUTDOWN}, - SingleThreadTaskRunnerThreadMode::SHARED) - ->PostTask(FROM_HERE, DoNothing()); - - // Shutdown should not hang even though the first task hasn't finished. - task_tracker_.Shutdown(); - - // Let the first task finish. - task_can_continue.Signal(); - - // Tear down from the test body to prevent accesses to |task_can_continue| - // after it goes out of scope. - TearDownSingleThreadTaskRunnerManager(); -} - -namespace { - -class TaskSchedulerSingleThreadTaskRunnerManagerCommonTest - : public TaskSchedulerSingleThreadTaskRunnerManagerTest, - public ::testing::WithParamInterface<SingleThreadTaskRunnerThreadMode> { - public: - TaskSchedulerSingleThreadTaskRunnerManagerCommonTest() = default; - - private: - DISALLOW_COPY_AND_ASSIGN( - TaskSchedulerSingleThreadTaskRunnerManagerCommonTest); -}; - -} // namespace - -TEST_P(TaskSchedulerSingleThreadTaskRunnerManagerCommonTest, - PrioritySetCorrectly) { - // Why are events used here instead of the task tracker? - // Shutting down can cause priorities to get raised. This means we have to use - // events to determine when a task is run. - scoped_refptr<SingleThreadTaskRunner> task_runner_background = - single_thread_task_runner_manager_ - ->CreateSingleThreadTaskRunnerWithTraits({TaskPriority::BACKGROUND}, - GetParam()); - scoped_refptr<SingleThreadTaskRunner> task_runner_normal = - single_thread_task_runner_manager_ - ->CreateSingleThreadTaskRunnerWithTraits({TaskPriority::USER_VISIBLE}, - GetParam()); - - ThreadPriority thread_priority_background; - task_runner_background->PostTask( - FROM_HERE, BindOnce(&CaptureThreadPriority, &thread_priority_background)); - WaitableEvent waitable_event_background( - WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - task_runner_background->PostTask( - FROM_HERE, - BindOnce(&WaitableEvent::Signal, Unretained(&waitable_event_background))); - - ThreadPriority thread_priority_normal; - task_runner_normal->PostTask( - FROM_HERE, BindOnce(&CaptureThreadPriority, &thread_priority_normal)); - WaitableEvent waitable_event_normal( - WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - task_runner_normal->PostTask( - FROM_HERE, - BindOnce(&WaitableEvent::Signal, Unretained(&waitable_event_normal))); - - waitable_event_background.Wait(); - waitable_event_normal.Wait(); - - if (Lock::HandlesMultipleThreadPriorities() && - PlatformThread::CanIncreaseCurrentThreadPriority()) { - EXPECT_EQ(ThreadPriority::BACKGROUND, thread_priority_background); - } else { - EXPECT_EQ(ThreadPriority::NORMAL, thread_priority_background); - } - EXPECT_EQ(ThreadPriority::NORMAL, thread_priority_normal); -} - -TEST_P(TaskSchedulerSingleThreadTaskRunnerManagerCommonTest, ThreadNamesSet) { - constexpr TaskTraits foo_traits = {TaskPriority::BACKGROUND, - TaskShutdownBehavior::BLOCK_SHUTDOWN}; - scoped_refptr<SingleThreadTaskRunner> foo_task_runner = - single_thread_task_runner_manager_ - ->CreateSingleThreadTaskRunnerWithTraits(foo_traits, GetParam()); - std::string foo_captured_name; - foo_task_runner->PostTask(FROM_HERE, - BindOnce(&CaptureThreadName, &foo_captured_name)); - - constexpr TaskTraits user_blocking_traits = { - TaskPriority::USER_BLOCKING, MayBlock(), - TaskShutdownBehavior::BLOCK_SHUTDOWN}; - scoped_refptr<SingleThreadTaskRunner> user_blocking_task_runner = - single_thread_task_runner_manager_ - ->CreateSingleThreadTaskRunnerWithTraits(user_blocking_traits, - GetParam()); - - std::string user_blocking_captured_name; - user_blocking_task_runner->PostTask( - FROM_HERE, BindOnce(&CaptureThreadName, &user_blocking_captured_name)); - - task_tracker_.Shutdown(); - - EXPECT_NE(std::string::npos, - foo_captured_name.find( - kEnvironmentParams[GetEnvironmentIndexForTraits(foo_traits)] - .name_suffix)); - EXPECT_NE( - std::string::npos, - user_blocking_captured_name.find( - kEnvironmentParams[GetEnvironmentIndexForTraits(user_blocking_traits)] - .name_suffix)); - - if (GetParam() == SingleThreadTaskRunnerThreadMode::DEDICATED) { - EXPECT_EQ(std::string::npos, foo_captured_name.find("Shared")); - EXPECT_EQ(std::string::npos, user_blocking_captured_name.find("Shared")); - } else { - EXPECT_NE(std::string::npos, foo_captured_name.find("Shared")); - EXPECT_NE(std::string::npos, user_blocking_captured_name.find("Shared")); - } -} - -TEST_P(TaskSchedulerSingleThreadTaskRunnerManagerCommonTest, - PostTaskAfterShutdown) { - auto task_runner = - single_thread_task_runner_manager_ - ->CreateSingleThreadTaskRunnerWithTraits(TaskTraits(), GetParam()); - task_tracker_.Shutdown(); - EXPECT_FALSE(task_runner->PostTask(FROM_HERE, BindOnce(&ShouldNotRun))); -} - -// Verify that a Task runs shortly after its delay expires. -TEST_P(TaskSchedulerSingleThreadTaskRunnerManagerCommonTest, PostDelayedTask) { - TimeTicks start_time = TimeTicks::Now(); - - WaitableEvent task_ran(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - auto task_runner = - single_thread_task_runner_manager_ - ->CreateSingleThreadTaskRunnerWithTraits(TaskTraits(), GetParam()); - - // Wait until the task runner is up and running to make sure the test below is - // solely timing the delayed task, not bringing up a physical thread. - task_runner->PostTask( - FROM_HERE, BindOnce(&WaitableEvent::Signal, Unretained(&task_ran))); - task_ran.Wait(); - ASSERT_TRUE(!task_ran.IsSignaled()); - - // Post a task with a short delay. - EXPECT_TRUE(task_runner->PostDelayedTask( - FROM_HERE, BindOnce(&WaitableEvent::Signal, Unretained(&task_ran)), - TestTimeouts::tiny_timeout())); - - // Wait until the task runs. - task_ran.Wait(); - - // Expect the task to run after its delay expires, but no more than 250 ms - // after that. - const TimeDelta actual_delay = TimeTicks::Now() - start_time; - EXPECT_GE(actual_delay, TestTimeouts::tiny_timeout()); - EXPECT_LT(actual_delay, - TimeDelta::FromMilliseconds(250) + TestTimeouts::tiny_timeout()); -} - -// Verify that posting tasks after the single-thread manager is destroyed fails -// but doesn't crash. -TEST_P(TaskSchedulerSingleThreadTaskRunnerManagerCommonTest, - PostTaskAfterDestroy) { - auto task_runner = - single_thread_task_runner_manager_ - ->CreateSingleThreadTaskRunnerWithTraits(TaskTraits(), GetParam()); - EXPECT_TRUE(task_runner->PostTask(FROM_HERE, DoNothing())); - task_tracker_.Shutdown(); - TearDownSingleThreadTaskRunnerManager(); - EXPECT_FALSE(task_runner->PostTask(FROM_HERE, BindOnce(&ShouldNotRun))); -} - -INSTANTIATE_TEST_CASE_P( - AllModes, - TaskSchedulerSingleThreadTaskRunnerManagerCommonTest, - ::testing::Values(SingleThreadTaskRunnerThreadMode::SHARED, - SingleThreadTaskRunnerThreadMode::DEDICATED)); - -namespace { - -class CallJoinFromDifferentThread : public SimpleThread { - public: - CallJoinFromDifferentThread( - SchedulerSingleThreadTaskRunnerManager* manager_to_join) - : SimpleThread("SchedulerSingleThreadTaskRunnerManagerJoinThread"), - manager_to_join_(manager_to_join), - run_started_event_(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED) {} - - ~CallJoinFromDifferentThread() override = default; - - void Run() override { - run_started_event_.Signal(); - manager_to_join_->JoinForTesting(); - } - - void WaitForRunToStart() { run_started_event_.Wait(); } - - private: - SchedulerSingleThreadTaskRunnerManager* const manager_to_join_; - WaitableEvent run_started_event_; - - DISALLOW_COPY_AND_ASSIGN(CallJoinFromDifferentThread); -}; - -class TaskSchedulerSingleThreadTaskRunnerManagerJoinTest - : public TaskSchedulerSingleThreadTaskRunnerManagerTest { - public: - TaskSchedulerSingleThreadTaskRunnerManagerJoinTest() = default; - ~TaskSchedulerSingleThreadTaskRunnerManagerJoinTest() override = default; - - protected: - void TearDownSingleThreadTaskRunnerManager() override { - // The tests themselves are responsible for calling JoinForTesting(). - single_thread_task_runner_manager_.reset(); - } - - private: - DISALLOW_COPY_AND_ASSIGN(TaskSchedulerSingleThreadTaskRunnerManagerJoinTest); -}; - -} // namespace - -TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerJoinTest, ConcurrentJoin) { - // Exercises the codepath where the workers are unavailable for unregistration - // because of a Join call. - WaitableEvent task_running(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - WaitableEvent task_blocking(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - - { - auto task_runner = single_thread_task_runner_manager_ - ->CreateSingleThreadTaskRunnerWithTraits( - {WithBaseSyncPrimitives()}, - SingleThreadTaskRunnerThreadMode::DEDICATED); - EXPECT_TRUE(task_runner->PostTask( - FROM_HERE, - BindOnce(&WaitableEvent::Signal, Unretained(&task_running)))); - EXPECT_TRUE(task_runner->PostTask( - FROM_HERE, BindOnce(&WaitableEvent::Wait, Unretained(&task_blocking)))); - } - - task_running.Wait(); - CallJoinFromDifferentThread join_from_different_thread( - single_thread_task_runner_manager_.get()); - join_from_different_thread.Start(); - join_from_different_thread.WaitForRunToStart(); - task_blocking.Signal(); - join_from_different_thread.Join(); -} - -TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerJoinTest, - ConcurrentJoinExtraSkippedTask) { - // Tests to make sure that tasks are properly cleaned up at Join, allowing - // SingleThreadTaskRunners to unregister themselves. - WaitableEvent task_running(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - WaitableEvent task_blocking(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - - { - auto task_runner = single_thread_task_runner_manager_ - ->CreateSingleThreadTaskRunnerWithTraits( - {WithBaseSyncPrimitives()}, - SingleThreadTaskRunnerThreadMode::DEDICATED); - EXPECT_TRUE(task_runner->PostTask( - FROM_HERE, - BindOnce(&WaitableEvent::Signal, Unretained(&task_running)))); - EXPECT_TRUE(task_runner->PostTask( - FROM_HERE, BindOnce(&WaitableEvent::Wait, Unretained(&task_blocking)))); - EXPECT_TRUE(task_runner->PostTask(FROM_HERE, DoNothing())); - } - - task_running.Wait(); - CallJoinFromDifferentThread join_from_different_thread( - single_thread_task_runner_manager_.get()); - join_from_different_thread.Start(); - join_from_different_thread.WaitForRunToStart(); - task_blocking.Signal(); - join_from_different_thread.Join(); -} - -#if defined(OS_WIN) - -TEST_P(TaskSchedulerSingleThreadTaskRunnerManagerCommonTest, - COMSTAInitialized) { - scoped_refptr<SingleThreadTaskRunner> com_task_runner = - single_thread_task_runner_manager_->CreateCOMSTATaskRunnerWithTraits( - {TaskShutdownBehavior::BLOCK_SHUTDOWN}, GetParam()); - - com_task_runner->PostTask(FROM_HERE, BindOnce(&win::AssertComApartmentType, - win::ComApartmentType::STA)); - - task_tracker_.Shutdown(); -} - -TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerTest, COMSTASameThreadUsed) { - scoped_refptr<SingleThreadTaskRunner> task_runner_1 = - single_thread_task_runner_manager_->CreateCOMSTATaskRunnerWithTraits( - {TaskShutdownBehavior::BLOCK_SHUTDOWN}, - SingleThreadTaskRunnerThreadMode::SHARED); - scoped_refptr<SingleThreadTaskRunner> task_runner_2 = - single_thread_task_runner_manager_->CreateCOMSTATaskRunnerWithTraits( - {TaskShutdownBehavior::BLOCK_SHUTDOWN}, - SingleThreadTaskRunnerThreadMode::SHARED); - - PlatformThreadRef thread_ref_1; - task_runner_1->PostTask(FROM_HERE, - BindOnce(&CaptureThreadRef, &thread_ref_1)); - PlatformThreadRef thread_ref_2; - task_runner_2->PostTask(FROM_HERE, - BindOnce(&CaptureThreadRef, &thread_ref_2)); - - task_tracker_.Shutdown(); - - ASSERT_FALSE(thread_ref_1.is_null()); - ASSERT_FALSE(thread_ref_2.is_null()); - EXPECT_EQ(thread_ref_1, thread_ref_2); -} - -namespace { - -const wchar_t* const kTestWindowClassName = - L"TaskSchedulerSingleThreadTaskRunnerManagerTestWinMessageWindow"; - -class TaskSchedulerSingleThreadTaskRunnerManagerTestWin - : public TaskSchedulerSingleThreadTaskRunnerManagerTest { - public: - TaskSchedulerSingleThreadTaskRunnerManagerTestWin() = default; - - void SetUp() override { - TaskSchedulerSingleThreadTaskRunnerManagerTest::SetUp(); - register_class_succeeded_ = RegisterTestWindowClass(); - ASSERT_TRUE(register_class_succeeded_); - } - - void TearDown() override { - if (register_class_succeeded_) - ::UnregisterClass(kTestWindowClassName, CURRENT_MODULE()); - - TaskSchedulerSingleThreadTaskRunnerManagerTest::TearDown(); - } - - HWND CreateTestWindow() { - return CreateWindow(kTestWindowClassName, kTestWindowClassName, 0, 0, 0, 0, - 0, HWND_MESSAGE, nullptr, CURRENT_MODULE(), nullptr); - } - - private: - bool RegisterTestWindowClass() { - WNDCLASSEX window_class = {}; - window_class.cbSize = sizeof(window_class); - window_class.lpfnWndProc = &::DefWindowProc; - window_class.hInstance = CURRENT_MODULE(); - window_class.lpszClassName = kTestWindowClassName; - return !!::RegisterClassEx(&window_class); - } - - bool register_class_succeeded_ = false; - - DISALLOW_COPY_AND_ASSIGN(TaskSchedulerSingleThreadTaskRunnerManagerTestWin); -}; - -} // namespace - -TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerTestWin, PumpsMessages) { - scoped_refptr<SingleThreadTaskRunner> com_task_runner = - single_thread_task_runner_manager_->CreateCOMSTATaskRunnerWithTraits( - {TaskShutdownBehavior::BLOCK_SHUTDOWN}, - SingleThreadTaskRunnerThreadMode::DEDICATED); - HWND hwnd = nullptr; - // HWNDs process messages on the thread that created them, so we have to - // create them within the context of the task runner to properly simulate a - // COM callback. - com_task_runner->PostTask( - FROM_HERE, - BindOnce( - [](TaskSchedulerSingleThreadTaskRunnerManagerTestWin* test_harness, - HWND* hwnd) { *hwnd = test_harness->CreateTestWindow(); }, - Unretained(this), &hwnd)); - - task_tracker_.FlushForTesting(); - - ASSERT_NE(hwnd, nullptr); - // If the message pump isn't running, we will hang here. This simulates how - // COM would receive a callback with its own message HWND. - SendMessage(hwnd, WM_USER, 0, 0); - - com_task_runner->PostTask( - FROM_HERE, BindOnce([](HWND hwnd) { ::DestroyWindow(hwnd); }, hwnd)); - - task_tracker_.Shutdown(); -} - -#endif // defined(OS_WIN) - -namespace { - -class TaskSchedulerSingleThreadTaskRunnerManagerStartTest - : public TaskSchedulerSingleThreadTaskRunnerManagerTest { - public: - TaskSchedulerSingleThreadTaskRunnerManagerStartTest() = default; - - private: - void StartSingleThreadTaskRunnerManagerFromSetUp() override { - // Start() is called in the test body rather than in SetUp(). - } - - DISALLOW_COPY_AND_ASSIGN(TaskSchedulerSingleThreadTaskRunnerManagerStartTest); -}; - -} // namespace - -// Verify that a task posted before Start() doesn't run until Start() is called. -TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerStartTest, - PostTaskBeforeStart) { - AtomicFlag manager_started; - WaitableEvent task_finished(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - single_thread_task_runner_manager_ - ->CreateSingleThreadTaskRunnerWithTraits( - TaskTraits(), SingleThreadTaskRunnerThreadMode::DEDICATED) - ->PostTask( - FROM_HERE, - BindOnce( - [](WaitableEvent* task_finished, AtomicFlag* manager_started) { - // The task should not run before Start(). - EXPECT_TRUE(manager_started->IsSet()); - task_finished->Signal(); - }, - Unretained(&task_finished), Unretained(&manager_started))); - - // Wait a little bit to make sure that the task doesn't run before start. - // Note: This test won't catch a case where the task runs between setting - // |manager_started| and calling Start(). However, we expect the test to be - // flaky if the tested code allows that to happen. - PlatformThread::Sleep(TestTimeouts::tiny_timeout()); - manager_started.Set(); - single_thread_task_runner_manager_->Start(); - - // Wait for the task to complete to keep |manager_started| alive. - task_finished.Wait(); -} - -} // namespace internal -} // namespace base
diff --git a/base/task_scheduler/scheduler_worker_pool_impl_unittest.cc b/base/task_scheduler/scheduler_worker_pool_impl_unittest.cc deleted file mode 100644 index 21e77f4..0000000 --- a/base/task_scheduler/scheduler_worker_pool_impl_unittest.cc +++ /dev/null
@@ -1,1566 +0,0 @@ -// 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/task_scheduler/scheduler_worker_pool_impl.h" - -#include <stddef.h> - -#include <memory> -#include <unordered_set> -#include <vector> - -#include "base/atomicops.h" -#include "base/barrier_closure.h" -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/callback.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/memory/ref_counted.h" -#include "base/metrics/histogram.h" -#include "base/metrics/histogram_samples.h" -#include "base/metrics/statistics_recorder.h" -#include "base/synchronization/condition_variable.h" -#include "base/synchronization/lock.h" -#include "base/synchronization/waitable_event.h" -#include "base/task_runner.h" -#include "base/task_scheduler/delayed_task_manager.h" -#include "base/task_scheduler/scheduler_worker_pool_params.h" -#include "base/task_scheduler/sequence.h" -#include "base/task_scheduler/sequence_sort_key.h" -#include "base/task_scheduler/task_tracker.h" -#include "base/task_scheduler/test_task_factory.h" -#include "base/task_scheduler/test_utils.h" -#include "base/test/gtest_util.h" -#include "base/test/test_simple_task_runner.h" -#include "base/test/test_timeouts.h" -#include "base/threading/platform_thread.h" -#include "base/threading/scoped_blocking_call.h" -#include "base/threading/simple_thread.h" -#include "base/threading/thread.h" -#include "base/threading/thread_checker_impl.h" -#include "base/threading/thread_local_storage.h" -#include "base/threading/thread_restrictions.h" -#include "base/time/time.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(OS_WIN) -#include "base/win/com_init_util.h" -#endif // defined(OS_WIN) - -namespace base { -namespace internal { -namespace { - -constexpr size_t kNumWorkersInWorkerPool = 4; -constexpr size_t kNumThreadsPostingTasks = 4; -constexpr size_t kNumTasksPostedPerThread = 150; -// This can't be lower because Windows' WaitableEvent wakes up too early when a -// small timeout is used. This results in many spurious wake ups before a worker -// is allowed to cleanup. -constexpr TimeDelta kReclaimTimeForCleanupTests = - TimeDelta::FromMilliseconds(500); - -// Waits on |event| in a scope where the blocking observer is null, to avoid -// affecting the worker capacity. -void WaitWithoutBlockingObserver(WaitableEvent* event) { - internal::ScopedClearBlockingObserverForTesting clear_blocking_observer; - event->Wait(); -} - -class TaskSchedulerWorkerPoolImplTestBase { - protected: - TaskSchedulerWorkerPoolImplTestBase() - : service_thread_("TaskSchedulerServiceThread"){}; - - void CommonSetUp() { - CreateAndStartWorkerPool(TimeDelta::Max(), kNumWorkersInWorkerPool); - } - - void CommonTearDown() { - service_thread_.Stop(); - task_tracker_.FlushForTesting(); - worker_pool_->WaitForAllWorkersIdleForTesting(); - worker_pool_->JoinForTesting(); - } - - void CreateWorkerPool() { - ASSERT_FALSE(worker_pool_); - service_thread_.Start(); - delayed_task_manager_.Start(service_thread_.task_runner()); - worker_pool_ = std::make_unique<SchedulerWorkerPoolImpl>( - "TestWorkerPool", "A", ThreadPriority::NORMAL, - task_tracker_.GetTrackedRef(), &delayed_task_manager_); - ASSERT_TRUE(worker_pool_); - } - - virtual void StartWorkerPool(TimeDelta suggested_reclaim_time, - size_t num_workers) { - ASSERT_TRUE(worker_pool_); - worker_pool_->Start( - SchedulerWorkerPoolParams(num_workers, suggested_reclaim_time), - service_thread_.task_runner(), nullptr, - SchedulerWorkerPoolImpl::WorkerEnvironment::NONE); - } - - void CreateAndStartWorkerPool(TimeDelta suggested_reclaim_time, - size_t num_workers) { - CreateWorkerPool(); - StartWorkerPool(suggested_reclaim_time, num_workers); - } - - Thread service_thread_; - TaskTracker task_tracker_ = {"Test"}; - - std::unique_ptr<SchedulerWorkerPoolImpl> worker_pool_; - - private: - DelayedTaskManager delayed_task_manager_; - - DISALLOW_COPY_AND_ASSIGN(TaskSchedulerWorkerPoolImplTestBase); -}; - -class TaskSchedulerWorkerPoolImplTest - : public TaskSchedulerWorkerPoolImplTestBase, - public testing::Test { - protected: - TaskSchedulerWorkerPoolImplTest() = default; - - void SetUp() override { TaskSchedulerWorkerPoolImplTestBase::CommonSetUp(); } - - void TearDown() override { - TaskSchedulerWorkerPoolImplTestBase::CommonTearDown(); - } - - private: - DISALLOW_COPY_AND_ASSIGN(TaskSchedulerWorkerPoolImplTest); -}; - -class TaskSchedulerWorkerPoolImplTestParam - : public TaskSchedulerWorkerPoolImplTestBase, - public testing::TestWithParam<test::ExecutionMode> { - protected: - TaskSchedulerWorkerPoolImplTestParam() = default; - - void SetUp() override { TaskSchedulerWorkerPoolImplTestBase::CommonSetUp(); } - - void TearDown() override { - TaskSchedulerWorkerPoolImplTestBase::CommonTearDown(); - } - - private: - DISALLOW_COPY_AND_ASSIGN(TaskSchedulerWorkerPoolImplTestParam); -}; - -using PostNestedTask = test::TestTaskFactory::PostNestedTask; - -class ThreadPostingTasksWaitIdle : public SimpleThread { - public: - // Constructs a thread that posts tasks to |worker_pool| through an - // |execution_mode| task runner. The thread waits until all workers in - // |worker_pool| are idle before posting a new task. - ThreadPostingTasksWaitIdle(SchedulerWorkerPoolImpl* worker_pool, - test::ExecutionMode execution_mode) - : SimpleThread("ThreadPostingTasksWaitIdle"), - worker_pool_(worker_pool), - factory_(CreateTaskRunnerWithExecutionMode(worker_pool, execution_mode), - execution_mode) { - DCHECK(worker_pool_); - } - - const test::TestTaskFactory* factory() const { return &factory_; } - - private: - void Run() override { - EXPECT_FALSE(factory_.task_runner()->RunsTasksInCurrentSequence()); - - for (size_t i = 0; i < kNumTasksPostedPerThread; ++i) { - worker_pool_->WaitForAllWorkersIdleForTesting(); - EXPECT_TRUE(factory_.PostTask(PostNestedTask::NO, Closure())); - } - } - - SchedulerWorkerPoolImpl* const worker_pool_; - const scoped_refptr<TaskRunner> task_runner_; - test::TestTaskFactory factory_; - - DISALLOW_COPY_AND_ASSIGN(ThreadPostingTasksWaitIdle); -}; - -} // namespace - -TEST_P(TaskSchedulerWorkerPoolImplTestParam, PostTasksWaitAllWorkersIdle) { - // Create threads to post tasks. To verify that workers can sleep and be woken - // up when new tasks are posted, wait for all workers to become idle before - // posting a new task. - std::vector<std::unique_ptr<ThreadPostingTasksWaitIdle>> - threads_posting_tasks; - for (size_t i = 0; i < kNumThreadsPostingTasks; ++i) { - threads_posting_tasks.push_back( - std::make_unique<ThreadPostingTasksWaitIdle>(worker_pool_.get(), - GetParam())); - threads_posting_tasks.back()->Start(); - } - - // Wait for all tasks to run. - for (const auto& thread_posting_tasks : threads_posting_tasks) { - thread_posting_tasks->Join(); - thread_posting_tasks->factory()->WaitForAllTasksToRun(); - } - - // Wait until all workers are idle to be sure that no task accesses its - // TestTaskFactory after |thread_posting_tasks| is destroyed. - worker_pool_->WaitForAllWorkersIdleForTesting(); -} - -TEST_P(TaskSchedulerWorkerPoolImplTestParam, PostTasksWithOneAvailableWorker) { - // Post blocking tasks to keep all workers busy except one until |event| is - // signaled. Use different factories so that tasks are added to different - // sequences and can run simultaneously when the execution mode is SEQUENCED. - WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - std::vector<std::unique_ptr<test::TestTaskFactory>> blocked_task_factories; - for (size_t i = 0; i < (kNumWorkersInWorkerPool - 1); ++i) { - blocked_task_factories.push_back(std::make_unique<test::TestTaskFactory>( - CreateTaskRunnerWithExecutionMode(worker_pool_.get(), GetParam()), - GetParam())); - EXPECT_TRUE(blocked_task_factories.back()->PostTask( - PostNestedTask::NO, - BindOnce(&WaitWithoutBlockingObserver, Unretained(&event)))); - blocked_task_factories.back()->WaitForAllTasksToRun(); - } - - // Post |kNumTasksPostedPerThread| tasks that should all run despite the fact - // that only one worker in |worker_pool_| isn't busy. - test::TestTaskFactory short_task_factory( - CreateTaskRunnerWithExecutionMode(worker_pool_.get(), GetParam()), - GetParam()); - for (size_t i = 0; i < kNumTasksPostedPerThread; ++i) - EXPECT_TRUE(short_task_factory.PostTask(PostNestedTask::NO, Closure())); - short_task_factory.WaitForAllTasksToRun(); - - // Release tasks waiting on |event|. - event.Signal(); - - // Wait until all workers are idle to be sure that no task accesses - // its TestTaskFactory after it is destroyed. - worker_pool_->WaitForAllWorkersIdleForTesting(); -} - -TEST_P(TaskSchedulerWorkerPoolImplTestParam, Saturate) { - // Verify that it is possible to have |kNumWorkersInWorkerPool| - // tasks/sequences running simultaneously. Use different factories so that the - // blocking tasks are added to different sequences and can run simultaneously - // when the execution mode is SEQUENCED. - WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - std::vector<std::unique_ptr<test::TestTaskFactory>> factories; - for (size_t i = 0; i < kNumWorkersInWorkerPool; ++i) { - factories.push_back(std::make_unique<test::TestTaskFactory>( - CreateTaskRunnerWithExecutionMode(worker_pool_.get(), GetParam()), - GetParam())); - EXPECT_TRUE(factories.back()->PostTask( - PostNestedTask::NO, - BindOnce(&WaitWithoutBlockingObserver, Unretained(&event)))); - factories.back()->WaitForAllTasksToRun(); - } - - // Release tasks waiting on |event|. - event.Signal(); - - // Wait until all workers are idle to be sure that no task accesses - // its TestTaskFactory after it is destroyed. - worker_pool_->WaitForAllWorkersIdleForTesting(); -} - -#if defined(OS_WIN) -TEST_P(TaskSchedulerWorkerPoolImplTestParam, NoEnvironment) { - // Verify that COM is not initialized in a SchedulerWorkerPoolImpl initialized - // with SchedulerWorkerPoolImpl::WorkerEnvironment::NONE. - scoped_refptr<TaskRunner> task_runner = - CreateTaskRunnerWithExecutionMode(worker_pool_.get(), GetParam()); - - WaitableEvent task_running(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - task_runner->PostTask( - FROM_HERE, BindOnce( - [](WaitableEvent* task_running) { - win::AssertComApartmentType(win::ComApartmentType::NONE); - task_running->Signal(); - }, - &task_running)); - - task_running.Wait(); - - worker_pool_->WaitForAllWorkersIdleForTesting(); -} -#endif // defined(OS_WIN) - -INSTANTIATE_TEST_CASE_P(Parallel, - TaskSchedulerWorkerPoolImplTestParam, - ::testing::Values(test::ExecutionMode::PARALLEL)); -INSTANTIATE_TEST_CASE_P(Sequenced, - TaskSchedulerWorkerPoolImplTestParam, - ::testing::Values(test::ExecutionMode::SEQUENCED)); - -#if defined(OS_WIN) - -namespace { - -class TaskSchedulerWorkerPoolImplTestCOMMTAParam - : public TaskSchedulerWorkerPoolImplTestBase, - public testing::TestWithParam<test::ExecutionMode> { - protected: - TaskSchedulerWorkerPoolImplTestCOMMTAParam() = default; - - void SetUp() override { TaskSchedulerWorkerPoolImplTestBase::CommonSetUp(); } - - void TearDown() override { - TaskSchedulerWorkerPoolImplTestBase::CommonTearDown(); - } - - private: - void StartWorkerPool(TimeDelta suggested_reclaim_time, - size_t num_workers) override { - ASSERT_TRUE(worker_pool_); - worker_pool_->Start( - SchedulerWorkerPoolParams(num_workers, suggested_reclaim_time), - service_thread_.task_runner(), nullptr, - SchedulerWorkerPoolImpl::WorkerEnvironment::COM_MTA); - } - - DISALLOW_COPY_AND_ASSIGN(TaskSchedulerWorkerPoolImplTestCOMMTAParam); -}; - -} // namespace - -TEST_P(TaskSchedulerWorkerPoolImplTestCOMMTAParam, COMMTAInitialized) { - // Verify that SchedulerWorkerPoolImpl workers have a COM MTA available. - scoped_refptr<TaskRunner> task_runner = - CreateTaskRunnerWithExecutionMode(worker_pool_.get(), GetParam()); - - WaitableEvent task_running(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - task_runner->PostTask( - FROM_HERE, BindOnce( - [](WaitableEvent* task_running) { - win::AssertComApartmentType(win::ComApartmentType::MTA); - task_running->Signal(); - }, - &task_running)); - - task_running.Wait(); - - worker_pool_->WaitForAllWorkersIdleForTesting(); -} - -INSTANTIATE_TEST_CASE_P(Parallel, - TaskSchedulerWorkerPoolImplTestCOMMTAParam, - ::testing::Values(test::ExecutionMode::PARALLEL)); -INSTANTIATE_TEST_CASE_P(Sequenced, - TaskSchedulerWorkerPoolImplTestCOMMTAParam, - ::testing::Values(test::ExecutionMode::SEQUENCED)); - -#endif // defined(OS_WIN) - -namespace { - -class TaskSchedulerWorkerPoolImplPostTaskBeforeStartTest - : public TaskSchedulerWorkerPoolImplTest { - public: - void SetUp() override { - CreateWorkerPool(); - // Let the test start the worker pool. - } -}; - -void TaskPostedBeforeStart(PlatformThreadRef* platform_thread_ref, - WaitableEvent* task_running, - WaitableEvent* barrier) { - *platform_thread_ref = PlatformThread::CurrentRef(); - task_running->Signal(); - WaitWithoutBlockingObserver(barrier); -} - -} // namespace - -// Verify that 2 tasks posted before Start() to a SchedulerWorkerPoolImpl with -// more than 2 workers run on different workers when Start() is called. -TEST_F(TaskSchedulerWorkerPoolImplPostTaskBeforeStartTest, - PostTasksBeforeStart) { - PlatformThreadRef task_1_thread_ref; - PlatformThreadRef task_2_thread_ref; - WaitableEvent task_1_running(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - WaitableEvent task_2_running(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - - // This event is used to prevent a task from completing before the other task - // starts running. If that happened, both tasks could run on the same worker - // and this test couldn't verify that the correct number of workers were woken - // up. - WaitableEvent barrier(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - - worker_pool_->CreateTaskRunnerWithTraits({WithBaseSyncPrimitives()}) - ->PostTask( - FROM_HERE, - BindOnce(&TaskPostedBeforeStart, Unretained(&task_1_thread_ref), - Unretained(&task_1_running), Unretained(&barrier))); - worker_pool_->CreateTaskRunnerWithTraits({WithBaseSyncPrimitives()}) - ->PostTask( - FROM_HERE, - BindOnce(&TaskPostedBeforeStart, Unretained(&task_2_thread_ref), - Unretained(&task_2_running), Unretained(&barrier))); - - // Workers should not be created and tasks should not run before the pool is - // started. - EXPECT_EQ(0U, worker_pool_->NumberOfWorkersForTesting()); - EXPECT_FALSE(task_1_running.IsSignaled()); - EXPECT_FALSE(task_2_running.IsSignaled()); - - StartWorkerPool(TimeDelta::Max(), kNumWorkersInWorkerPool); - - // Tasks should run shortly after the pool is started. - task_1_running.Wait(); - task_2_running.Wait(); - - // Tasks should run on different threads. - EXPECT_NE(task_1_thread_ref, task_2_thread_ref); - - barrier.Signal(); - task_tracker_.FlushForTesting(); -} - -// Verify that posting many tasks before Start will cause the number of workers -// to grow to |worker_capacity_| during Start. -TEST_F(TaskSchedulerWorkerPoolImplPostTaskBeforeStartTest, PostManyTasks) { - scoped_refptr<TaskRunner> task_runner = - worker_pool_->CreateTaskRunnerWithTraits({WithBaseSyncPrimitives()}); - constexpr size_t kNumTasksPosted = 2 * kNumWorkersInWorkerPool; - for (size_t i = 0; i < kNumTasksPosted; ++i) - task_runner->PostTask(FROM_HERE, DoNothing()); - - EXPECT_EQ(0U, worker_pool_->NumberOfWorkersForTesting()); - - StartWorkerPool(TimeDelta::Max(), kNumWorkersInWorkerPool); - ASSERT_GT(kNumTasksPosted, worker_pool_->GetWorkerCapacityForTesting()); - EXPECT_EQ(kNumWorkersInWorkerPool, - worker_pool_->GetWorkerCapacityForTesting()); - - EXPECT_EQ(worker_pool_->NumberOfWorkersForTesting(), - worker_pool_->GetWorkerCapacityForTesting()); -} - -namespace { - -constexpr size_t kMagicTlsValue = 42; - -class TaskSchedulerWorkerPoolCheckTlsReuse - : public TaskSchedulerWorkerPoolImplTest { - public: - void SetTlsValueAndWait() { - slot_.Set(reinterpret_cast<void*>(kMagicTlsValue)); - WaitWithoutBlockingObserver(&waiter_); - } - - void CountZeroTlsValuesAndWait(WaitableEvent* count_waiter) { - if (!slot_.Get()) - subtle::NoBarrier_AtomicIncrement(&zero_tls_values_, 1); - - count_waiter->Signal(); - WaitWithoutBlockingObserver(&waiter_); - } - - protected: - TaskSchedulerWorkerPoolCheckTlsReuse() : - waiter_(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED) {} - - void SetUp() override { - CreateAndStartWorkerPool(kReclaimTimeForCleanupTests, - kNumWorkersInWorkerPool); - } - - subtle::Atomic32 zero_tls_values_ = 0; - - WaitableEvent waiter_; - - private: - ThreadLocalStorage::Slot slot_; - - DISALLOW_COPY_AND_ASSIGN(TaskSchedulerWorkerPoolCheckTlsReuse); -}; - -} // namespace - -// Checks that at least one worker has been cleaned up by checking the TLS. -TEST_F(TaskSchedulerWorkerPoolCheckTlsReuse, CheckCleanupWorkers) { - // Saturate the workers and mark each worker's thread with a magic TLS value. - std::vector<std::unique_ptr<test::TestTaskFactory>> factories; - for (size_t i = 0; i < kNumWorkersInWorkerPool; ++i) { - factories.push_back(std::make_unique<test::TestTaskFactory>( - worker_pool_->CreateTaskRunnerWithTraits({WithBaseSyncPrimitives()}), - test::ExecutionMode::PARALLEL)); - ASSERT_TRUE(factories.back()->PostTask( - PostNestedTask::NO, - Bind(&TaskSchedulerWorkerPoolCheckTlsReuse::SetTlsValueAndWait, - Unretained(this)))); - factories.back()->WaitForAllTasksToRun(); - } - - // Release tasks waiting on |waiter_|. - waiter_.Signal(); - worker_pool_->WaitForAllWorkersIdleForTesting(); - - // All workers should be done running by now, so reset for the next phase. - waiter_.Reset(); - - // Wait for the worker pool to clean up at least one worker. - worker_pool_->WaitForWorkersCleanedUpForTesting(1U); - - // Saturate and count the worker threads that do not have the magic TLS value. - // If the value is not there, that means we're at a new worker. - std::vector<std::unique_ptr<WaitableEvent>> count_waiters; - for (auto& factory : factories) { - count_waiters.push_back(WrapUnique(new WaitableEvent( - WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED))); - ASSERT_TRUE(factory->PostTask( - PostNestedTask::NO, - Bind(&TaskSchedulerWorkerPoolCheckTlsReuse::CountZeroTlsValuesAndWait, - Unretained(this), - count_waiters.back().get()))); - factory->WaitForAllTasksToRun(); - } - - // Wait for all counters to complete. - for (auto& count_waiter : count_waiters) - count_waiter->Wait(); - - EXPECT_GT(subtle::NoBarrier_Load(&zero_tls_values_), 0); - - // Release tasks waiting on |waiter_|. - waiter_.Signal(); -} - -namespace { - -class TaskSchedulerWorkerPoolHistogramTest - : public TaskSchedulerWorkerPoolImplTest { - public: - TaskSchedulerWorkerPoolHistogramTest() = default; - - protected: - // Override SetUp() to allow every test case to initialize a worker pool with - // its own arguments. - void SetUp() override {} - - // Floods |worker_pool_| with a single task each that blocks until - // |continue_event| is signaled. Every worker in the pool is blocked on - // |continue_event| when this method returns. Note: this helper can easily be - // generalized to be useful in other tests, but it's here for now because it's - // only used in a TaskSchedulerWorkerPoolHistogramTest at the moment. - void FloodPool(WaitableEvent* continue_event) { - ASSERT_FALSE(continue_event->IsSignaled()); - - auto task_runner = - worker_pool_->CreateTaskRunnerWithTraits({WithBaseSyncPrimitives()}); - - const auto pool_capacity = worker_pool_->GetWorkerCapacityForTesting(); - - WaitableEvent workers_flooded(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - RepeatingClosure all_workers_running_barrier = BarrierClosure( - pool_capacity, - BindOnce(&WaitableEvent::Signal, Unretained(&workers_flooded))); - for (size_t i = 0; i < pool_capacity; ++i) { - task_runner->PostTask( - FROM_HERE, - BindOnce( - [](OnceClosure on_running, WaitableEvent* continue_event) { - std::move(on_running).Run(); - WaitWithoutBlockingObserver(continue_event); - }, - all_workers_running_barrier, continue_event)); - } - workers_flooded.Wait(); - } - - private: - std::unique_ptr<StatisticsRecorder> statistics_recorder_ = - StatisticsRecorder::CreateTemporaryForTesting(); - - DISALLOW_COPY_AND_ASSIGN(TaskSchedulerWorkerPoolHistogramTest); -}; - -} // namespace - -TEST_F(TaskSchedulerWorkerPoolHistogramTest, NumTasksBetweenWaits) { - WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - CreateAndStartWorkerPool(TimeDelta::Max(), kNumWorkersInWorkerPool); - auto task_runner = worker_pool_->CreateSequencedTaskRunnerWithTraits( - {WithBaseSyncPrimitives()}); - - // Post a task. - task_runner->PostTask( - FROM_HERE, BindOnce(&WaitWithoutBlockingObserver, Unretained(&event))); - - // Post 2 more tasks while the first task hasn't completed its execution. It - // is guaranteed that these tasks will run immediately after the first task, - // without allowing the worker to sleep. - task_runner->PostTask(FROM_HERE, DoNothing()); - task_runner->PostTask(FROM_HERE, DoNothing()); - - // Allow tasks to run and wait until the SchedulerWorker is idle. - event.Signal(); - worker_pool_->WaitForAllWorkersIdleForTesting(); - - // Wake up the SchedulerWorker that just became idle by posting a task and - // wait until it becomes idle again. The SchedulerWorker should record the - // TaskScheduler.NumTasksBetweenWaits.* histogram on wake up. - task_runner->PostTask(FROM_HERE, DoNothing()); - worker_pool_->WaitForAllWorkersIdleForTesting(); - - // Verify that counts were recorded to the histogram as expected. - const auto* histogram = worker_pool_->num_tasks_between_waits_histogram(); - EXPECT_EQ(0, histogram->SnapshotSamples()->GetCount(0)); - EXPECT_EQ(1, histogram->SnapshotSamples()->GetCount(3)); - EXPECT_EQ(0, histogram->SnapshotSamples()->GetCount(10)); -} - -// Verifies that NumTasksBetweenWaits histogram is logged as expected across -// idle and cleanup periods. -TEST_F(TaskSchedulerWorkerPoolHistogramTest, - NumTasksBetweenWaitsWithIdlePeriodAndCleanup) { - WaitableEvent tasks_can_exit_event(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - CreateAndStartWorkerPool(kReclaimTimeForCleanupTests, - kNumWorkersInWorkerPool); - - WaitableEvent workers_continue(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - - FloodPool(&workers_continue); - - const auto* histogram = worker_pool_->num_tasks_between_waits_histogram(); - - // NumTasksBetweenWaits shouldn't be logged until idle. - EXPECT_EQ(0, histogram->SnapshotSamples()->GetCount(0)); - EXPECT_EQ(0, histogram->SnapshotSamples()->GetCount(1)); - EXPECT_EQ(0, histogram->SnapshotSamples()->GetCount(10)); - - // Make all workers go idle. - workers_continue.Signal(); - worker_pool_->WaitForAllWorkersIdleForTesting(); - - // All workers should have reported a single hit in the "1" bucket per the the - // histogram being reported when going idle and each worker having processed - // precisely 1 task per the controlled flooding logic above. - EXPECT_EQ(0, histogram->SnapshotSamples()->GetCount(0)); - EXPECT_EQ(static_cast<int>(kNumWorkersInWorkerPool), - histogram->SnapshotSamples()->GetCount(1)); - EXPECT_EQ(0, histogram->SnapshotSamples()->GetCount(10)); - - worker_pool_->WaitForWorkersCleanedUpForTesting(kNumWorkersInWorkerPool - 1); - - EXPECT_EQ(0, histogram->SnapshotSamples()->GetCount(0)); - EXPECT_EQ(static_cast<int>(kNumWorkersInWorkerPool), - histogram->SnapshotSamples()->GetCount(1)); - EXPECT_EQ(0, histogram->SnapshotSamples()->GetCount(10)); - - // Flooding the pool once again (without letting any workers go idle) - // shouldn't affect the counts either. - - workers_continue.Reset(); - FloodPool(&workers_continue); - - EXPECT_EQ(0, histogram->SnapshotSamples()->GetCount(0)); - EXPECT_EQ(static_cast<int>(kNumWorkersInWorkerPool), - histogram->SnapshotSamples()->GetCount(1)); - EXPECT_EQ(0, histogram->SnapshotSamples()->GetCount(10)); - - workers_continue.Signal(); - worker_pool_->WaitForAllWorkersIdleForTesting(); -} - -TEST_F(TaskSchedulerWorkerPoolHistogramTest, NumTasksBeforeCleanup) { - CreateWorkerPool(); - auto histogrammed_thread_task_runner = - worker_pool_->CreateSequencedTaskRunnerWithTraits( - {WithBaseSyncPrimitives()}); - - // Post 3 tasks and hold the thread for idle thread stack ordering. - // This test assumes |histogrammed_thread_task_runner| gets assigned the same - // thread for each of its tasks. - PlatformThreadRef thread_ref; - histogrammed_thread_task_runner->PostTask( - FROM_HERE, BindOnce( - [](PlatformThreadRef* thread_ref) { - ASSERT_TRUE(thread_ref); - *thread_ref = PlatformThread::CurrentRef(); - }, - Unretained(&thread_ref))); - histogrammed_thread_task_runner->PostTask( - FROM_HERE, BindOnce( - [](PlatformThreadRef* thread_ref) { - ASSERT_FALSE(thread_ref->is_null()); - EXPECT_EQ(*thread_ref, PlatformThread::CurrentRef()); - }, - Unretained(&thread_ref))); - - WaitableEvent cleanup_thread_running( - WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - WaitableEvent cleanup_thread_continue( - WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - histogrammed_thread_task_runner->PostTask( - FROM_HERE, - BindOnce( - [](PlatformThreadRef* thread_ref, - WaitableEvent* cleanup_thread_running, - WaitableEvent* cleanup_thread_continue) { - ASSERT_FALSE(thread_ref->is_null()); - EXPECT_EQ(*thread_ref, PlatformThread::CurrentRef()); - cleanup_thread_running->Signal(); - WaitWithoutBlockingObserver(cleanup_thread_continue); - }, - Unretained(&thread_ref), Unretained(&cleanup_thread_running), - Unretained(&cleanup_thread_continue))); - - // Start the worker pool with 2 workers, to avoid depending on the scheduler's - // logic to always keep one extra idle worker. - // - // The pool is started after the 3 initial tasks have been posted to ensure - // that they are scheduled on the same worker. If the tasks could run as they - // are posted, there would be a chance that: - // 1. Worker #1: Runs a tasks and empties the sequence, without adding - // itself to the idle stack yet. - // 2. Posting thread: Posts another task to the now empty sequence. Wakes - // up a new worker, since worker #1 isn't on the idle - // stack yet. - // 3: Worker #2: Runs the tasks, violating the expectation that the 3 - // initial tasks run on the same worker. - constexpr size_t kTwoWorkers = 2; - StartWorkerPool(kReclaimTimeForCleanupTests, kTwoWorkers); - - // Wait until the 3rd task is scheduled. - cleanup_thread_running.Wait(); - - // To allow the SchedulerWorker associated with - // |histogrammed_thread_task_runner| to cleanup, make sure it isn't on top of - // the idle stack by waking up another SchedulerWorker via - // |task_runner_for_top_idle|. |histogrammed_thread_task_runner| should - // release and go idle first and then |task_runner_for_top_idle| should - // release and go idle. This allows the SchedulerWorker associated with - // |histogrammed_thread_task_runner| to cleanup. - WaitableEvent top_idle_thread_running( - WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - WaitableEvent top_idle_thread_continue( - WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - auto task_runner_for_top_idle = - worker_pool_->CreateSequencedTaskRunnerWithTraits( - {WithBaseSyncPrimitives()}); - task_runner_for_top_idle->PostTask( - FROM_HERE, BindOnce( - [](PlatformThreadRef thread_ref, - WaitableEvent* top_idle_thread_running, - WaitableEvent* top_idle_thread_continue) { - ASSERT_FALSE(thread_ref.is_null()); - EXPECT_NE(thread_ref, PlatformThread::CurrentRef()) - << "Worker reused. Worker will not cleanup and the " - "histogram value will be wrong."; - top_idle_thread_running->Signal(); - WaitWithoutBlockingObserver(top_idle_thread_continue); - }, - thread_ref, Unretained(&top_idle_thread_running), - Unretained(&top_idle_thread_continue))); - top_idle_thread_running.Wait(); - EXPECT_EQ(0U, worker_pool_->NumberOfIdleWorkersForTesting()); - cleanup_thread_continue.Signal(); - // Wait for the cleanup thread to also become idle. - worker_pool_->WaitForWorkersIdleForTesting(1U); - top_idle_thread_continue.Signal(); - // Allow the thread processing the |histogrammed_thread_task_runner| work to - // cleanup. - worker_pool_->WaitForWorkersCleanedUpForTesting(1U); - - // Verify that counts were recorded to the histogram as expected. - const auto* histogram = worker_pool_->num_tasks_before_detach_histogram(); - EXPECT_EQ(0, histogram->SnapshotSamples()->GetCount(0)); - EXPECT_EQ(0, histogram->SnapshotSamples()->GetCount(1)); - EXPECT_EQ(0, histogram->SnapshotSamples()->GetCount(2)); - EXPECT_EQ(1, histogram->SnapshotSamples()->GetCount(3)); - EXPECT_EQ(0, histogram->SnapshotSamples()->GetCount(4)); - EXPECT_EQ(0, histogram->SnapshotSamples()->GetCount(5)); - EXPECT_EQ(0, histogram->SnapshotSamples()->GetCount(6)); - EXPECT_EQ(0, histogram->SnapshotSamples()->GetCount(10)); -} - -TEST(TaskSchedulerWorkerPoolStandbyPolicyTest, InitOne) { - TaskTracker task_tracker("Test"); - DelayedTaskManager delayed_task_manager; - scoped_refptr<TaskRunner> service_thread_task_runner = - MakeRefCounted<TestSimpleTaskRunner>(); - delayed_task_manager.Start(service_thread_task_runner); - auto worker_pool = std::make_unique<SchedulerWorkerPoolImpl>( - "OnePolicyWorkerPool", "A", ThreadPriority::NORMAL, - task_tracker.GetTrackedRef(), &delayed_task_manager); - worker_pool->Start(SchedulerWorkerPoolParams(8U, TimeDelta::Max()), - service_thread_task_runner, nullptr, - SchedulerWorkerPoolImpl::WorkerEnvironment::NONE); - ASSERT_TRUE(worker_pool); - EXPECT_EQ(1U, worker_pool->NumberOfWorkersForTesting()); - worker_pool->JoinForTesting(); -} - -// Verify the SchedulerWorkerPoolImpl keeps at least one idle standby thread, -// capacity permitting. -TEST(TaskSchedulerWorkerPoolStandbyPolicyTest, VerifyStandbyThread) { - constexpr size_t kWorkerCapacity = 3; - - TaskTracker task_tracker("Test"); - DelayedTaskManager delayed_task_manager; - scoped_refptr<TaskRunner> service_thread_task_runner = - MakeRefCounted<TestSimpleTaskRunner>(); - delayed_task_manager.Start(service_thread_task_runner); - auto worker_pool = std::make_unique<SchedulerWorkerPoolImpl>( - "StandbyThreadWorkerPool", "A", ThreadPriority::NORMAL, - task_tracker.GetTrackedRef(), &delayed_task_manager); - worker_pool->Start( - SchedulerWorkerPoolParams(kWorkerCapacity, kReclaimTimeForCleanupTests), - service_thread_task_runner, nullptr, - SchedulerWorkerPoolImpl::WorkerEnvironment::NONE); - ASSERT_TRUE(worker_pool); - EXPECT_EQ(1U, worker_pool->NumberOfWorkersForTesting()); - - auto task_runner = - worker_pool->CreateTaskRunnerWithTraits({WithBaseSyncPrimitives()}); - - WaitableEvent thread_running(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - WaitableEvent thread_continue(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - - RepeatingClosure closure = BindRepeating( - [](WaitableEvent* thread_running, WaitableEvent* thread_continue) { - thread_running->Signal(); - WaitWithoutBlockingObserver(thread_continue); - }, - Unretained(&thread_running), Unretained(&thread_continue)); - - // There should be one idle thread until we reach worker capacity - for (size_t i = 0; i < kWorkerCapacity; ++i) { - EXPECT_EQ(i + 1, worker_pool->NumberOfWorkersForTesting()); - task_runner->PostTask(FROM_HERE, closure); - thread_running.Wait(); - } - - // There should not be an extra idle thread if it means going above capacity - EXPECT_EQ(kWorkerCapacity, worker_pool->NumberOfWorkersForTesting()); - - thread_continue.Signal(); - // Wait long enough for all but one worker to clean up. - worker_pool->WaitForWorkersCleanedUpForTesting(kWorkerCapacity - 1); - EXPECT_EQ(1U, worker_pool->NumberOfWorkersForTesting()); - // Give extra time for a worker to cleanup : none should as the pool is - // expected to keep a worker ready regardless of how long it was idle for. - PlatformThread::Sleep(kReclaimTimeForCleanupTests); - EXPECT_EQ(1U, worker_pool->NumberOfWorkersForTesting()); - - worker_pool->JoinForTesting(); -} - -namespace { - -enum class OptionalBlockingType { - NO_BLOCK, - MAY_BLOCK, - WILL_BLOCK, -}; - -struct NestedBlockingType { - NestedBlockingType(BlockingType first_in, - OptionalBlockingType second_in, - BlockingType behaves_as_in) - : first(first_in), second(second_in), behaves_as(behaves_as_in) {} - - BlockingType first; - OptionalBlockingType second; - BlockingType behaves_as; -}; - -class NestedScopedBlockingCall { - public: - NestedScopedBlockingCall(const NestedBlockingType& nested_blocking_type) - : first_scoped_blocking_call_(nested_blocking_type.first), - second_scoped_blocking_call_( - nested_blocking_type.second == OptionalBlockingType::WILL_BLOCK - ? std::make_unique<ScopedBlockingCall>(BlockingType::WILL_BLOCK) - : (nested_blocking_type.second == - OptionalBlockingType::MAY_BLOCK - ? std::make_unique<ScopedBlockingCall>( - BlockingType::MAY_BLOCK) - : nullptr)) {} - - private: - ScopedBlockingCall first_scoped_blocking_call_; - std::unique_ptr<ScopedBlockingCall> second_scoped_blocking_call_; - - DISALLOW_COPY_AND_ASSIGN(NestedScopedBlockingCall); -}; - -} // namespace - -class TaskSchedulerWorkerPoolBlockingTest - : public TaskSchedulerWorkerPoolImplTestBase, - public testing::TestWithParam<NestedBlockingType> { - public: - TaskSchedulerWorkerPoolBlockingTest() - : blocking_thread_running_(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED), - blocking_thread_continue_(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED) {} - - static std::string ParamInfoToString( - ::testing::TestParamInfo<NestedBlockingType> param_info) { - std::string str = param_info.param.first == BlockingType::MAY_BLOCK - ? "MAY_BLOCK" - : "WILL_BLOCK"; - if (param_info.param.second == OptionalBlockingType::MAY_BLOCK) - str += "_MAY_BLOCK"; - else if (param_info.param.second == OptionalBlockingType::WILL_BLOCK) - str += "_WILL_BLOCK"; - return str; - } - - void SetUp() override { - TaskSchedulerWorkerPoolImplTestBase::CommonSetUp(); - task_runner_ = - worker_pool_->CreateTaskRunnerWithTraits({WithBaseSyncPrimitives()}); - } - - void TearDown() override { - TaskSchedulerWorkerPoolImplTestBase::CommonTearDown(); - } - - protected: - // Saturates the worker pool with a task that first blocks, waits to be - // unblocked, then exits. - void SaturateWithBlockingTasks( - const NestedBlockingType& nested_blocking_type) { - RepeatingClosure blocking_thread_running_closure = - BarrierClosure(kNumWorkersInWorkerPool, - BindOnce(&WaitableEvent::Signal, - Unretained(&blocking_thread_running_))); - - for (size_t i = 0; i < kNumWorkersInWorkerPool; ++i) { - task_runner_->PostTask( - FROM_HERE, - BindOnce( - [](Closure* blocking_thread_running_closure, - WaitableEvent* blocking_thread_continue_, - const NestedBlockingType& nested_blocking_type) { - NestedScopedBlockingCall nested_scoped_blocking_call( - nested_blocking_type); - blocking_thread_running_closure->Run(); - WaitWithoutBlockingObserver(blocking_thread_continue_); - }, - Unretained(&blocking_thread_running_closure), - Unretained(&blocking_thread_continue_), nested_blocking_type)); - } - blocking_thread_running_.Wait(); - } - - // Returns how long we can expect a change to |worker_capacity_| to occur - // after a task has become blocked. - TimeDelta GetWorkerCapacityChangeSleepTime() { - return std::max(SchedulerWorkerPoolImpl::kBlockedWorkersPollPeriod, - worker_pool_->MayBlockThreshold()) + - TestTimeouts::tiny_timeout(); - } - - // Waits indefinitely, until |worker_pool_|'s worker capacity increases to - // |expected_worker_capacity|. - void ExpectWorkerCapacityIncreasesTo(size_t expected_worker_capacity) { - size_t capacity = worker_pool_->GetWorkerCapacityForTesting(); - while (capacity != expected_worker_capacity) { - PlatformThread::Sleep(GetWorkerCapacityChangeSleepTime()); - size_t new_capacity = worker_pool_->GetWorkerCapacityForTesting(); - ASSERT_GE(new_capacity, capacity); - capacity = new_capacity; - } - } - - // Unblocks tasks posted by SaturateWithBlockingTasks(). - void UnblockTasks() { blocking_thread_continue_.Signal(); } - - scoped_refptr<TaskRunner> task_runner_; - - private: - WaitableEvent blocking_thread_running_; - WaitableEvent blocking_thread_continue_; - - DISALLOW_COPY_AND_ASSIGN(TaskSchedulerWorkerPoolBlockingTest); -}; - -// Verify that BlockingScopeEntered() causes worker capacity to increase and -// creates a worker if needed. Also verify that BlockingScopeExited() decreases -// worker capacity after an increase. -TEST_P(TaskSchedulerWorkerPoolBlockingTest, ThreadBlockedUnblocked) { - ASSERT_EQ(worker_pool_->GetWorkerCapacityForTesting(), - kNumWorkersInWorkerPool); - - SaturateWithBlockingTasks(GetParam()); - if (GetParam().behaves_as == BlockingType::MAY_BLOCK) - ExpectWorkerCapacityIncreasesTo(2 * kNumWorkersInWorkerPool); - // A range of possible number of workers is accepted because of - // crbug.com/757897. - EXPECT_GE(worker_pool_->NumberOfWorkersForTesting(), - kNumWorkersInWorkerPool + 1); - EXPECT_LE(worker_pool_->NumberOfWorkersForTesting(), - 2 * kNumWorkersInWorkerPool); - EXPECT_EQ(worker_pool_->GetWorkerCapacityForTesting(), - 2 * kNumWorkersInWorkerPool); - - UnblockTasks(); - task_tracker_.FlushForTesting(); - EXPECT_EQ(worker_pool_->GetWorkerCapacityForTesting(), - kNumWorkersInWorkerPool); -} - -// Verify that tasks posted in a saturated pool before a ScopedBlockingCall will -// execute after ScopedBlockingCall is instantiated. -TEST_P(TaskSchedulerWorkerPoolBlockingTest, PostBeforeBlocking) { - WaitableEvent thread_running(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - WaitableEvent thread_can_block(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - WaitableEvent thread_continue(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - - for (size_t i = 0; i < kNumWorkersInWorkerPool; ++i) { - task_runner_->PostTask( - FROM_HERE, - BindOnce( - [](const NestedBlockingType& nested_blocking_type, - WaitableEvent* thread_running, WaitableEvent* thread_can_block, - WaitableEvent* thread_continue) { - thread_running->Signal(); - WaitWithoutBlockingObserver(thread_can_block); - - NestedScopedBlockingCall nested_scoped_blocking_call( - nested_blocking_type); - WaitWithoutBlockingObserver(thread_continue); - }, - GetParam(), Unretained(&thread_running), - Unretained(&thread_can_block), Unretained(&thread_continue))); - thread_running.Wait(); - } - - // All workers should be occupied and the pool should be saturated. Workers - // have not entered ScopedBlockingCall yet. - EXPECT_EQ(worker_pool_->NumberOfWorkersForTesting(), kNumWorkersInWorkerPool); - EXPECT_EQ(worker_pool_->GetWorkerCapacityForTesting(), - kNumWorkersInWorkerPool); - - WaitableEvent extra_thread_running(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - WaitableEvent extra_threads_continue( - WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - RepeatingClosure extra_threads_running_barrier = BarrierClosure( - kNumWorkersInWorkerPool, - BindOnce(&WaitableEvent::Signal, Unretained(&extra_thread_running))); - for (size_t i = 0; i < kNumWorkersInWorkerPool; ++i) { - task_runner_->PostTask(FROM_HERE, - BindOnce( - [](Closure* extra_threads_running_barrier, - WaitableEvent* extra_threads_continue) { - extra_threads_running_barrier->Run(); - WaitWithoutBlockingObserver( - extra_threads_continue); - }, - Unretained(&extra_threads_running_barrier), - Unretained(&extra_threads_continue))); - } - - // Allow tasks to enter ScopedBlockingCall. Workers should be created for the - // tasks we just posted. - thread_can_block.Signal(); - if (GetParam().behaves_as == BlockingType::MAY_BLOCK) - ExpectWorkerCapacityIncreasesTo(2 * kNumWorkersInWorkerPool); - - // Should not block forever. - extra_thread_running.Wait(); - EXPECT_EQ(worker_pool_->NumberOfWorkersForTesting(), - 2 * kNumWorkersInWorkerPool); - extra_threads_continue.Signal(); - - thread_continue.Signal(); - task_tracker_.FlushForTesting(); -} -// Verify that workers become idle when the pool is over-capacity and that -// those workers do no work. -TEST_P(TaskSchedulerWorkerPoolBlockingTest, WorkersIdleWhenOverCapacity) { - ASSERT_EQ(worker_pool_->GetWorkerCapacityForTesting(), - kNumWorkersInWorkerPool); - - SaturateWithBlockingTasks(GetParam()); - if (GetParam().behaves_as == BlockingType::MAY_BLOCK) - ExpectWorkerCapacityIncreasesTo(2 * kNumWorkersInWorkerPool); - EXPECT_EQ(worker_pool_->GetWorkerCapacityForTesting(), - 2 * kNumWorkersInWorkerPool); - // A range of possible number of workers is accepted because of - // crbug.com/757897. - EXPECT_GE(worker_pool_->NumberOfWorkersForTesting(), - kNumWorkersInWorkerPool + 1); - EXPECT_LE(worker_pool_->NumberOfWorkersForTesting(), - 2 * kNumWorkersInWorkerPool); - - WaitableEvent thread_running(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - WaitableEvent thread_continue(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - - RepeatingClosure thread_running_barrier = BarrierClosure( - kNumWorkersInWorkerPool, - BindOnce(&WaitableEvent::Signal, Unretained(&thread_running))); - // Posting these tasks should cause new workers to be created. - for (size_t i = 0; i < kNumWorkersInWorkerPool; ++i) { - auto callback = BindOnce( - [](Closure* thread_running_barrier, WaitableEvent* thread_continue) { - thread_running_barrier->Run(); - WaitWithoutBlockingObserver(thread_continue); - }, - Unretained(&thread_running_barrier), Unretained(&thread_continue)); - task_runner_->PostTask(FROM_HERE, std::move(callback)); - } - thread_running.Wait(); - - ASSERT_EQ(worker_pool_->NumberOfIdleWorkersForTesting(), 0U); - EXPECT_EQ(worker_pool_->NumberOfWorkersForTesting(), - 2 * kNumWorkersInWorkerPool); - - AtomicFlag is_exiting; - // These tasks should not get executed until after other tasks become - // unblocked. - for (size_t i = 0; i < kNumWorkersInWorkerPool; ++i) { - task_runner_->PostTask(FROM_HERE, BindOnce( - [](AtomicFlag* is_exiting) { - EXPECT_TRUE(is_exiting->IsSet()); - }, - Unretained(&is_exiting))); - } - - // The original |kNumWorkersInWorkerPool| will finish their tasks after being - // unblocked. There will be work in the work queue, but the pool should now - // be over-capacity and workers will become idle. - UnblockTasks(); - worker_pool_->WaitForWorkersIdleForTesting(kNumWorkersInWorkerPool); - EXPECT_EQ(worker_pool_->NumberOfIdleWorkersForTesting(), - kNumWorkersInWorkerPool); - - // Posting more tasks should not cause workers idle from the pool being over - // capacity to begin doing work. - for (size_t i = 0; i < kNumWorkersInWorkerPool; ++i) { - task_runner_->PostTask(FROM_HERE, BindOnce( - [](AtomicFlag* is_exiting) { - EXPECT_TRUE(is_exiting->IsSet()); - }, - Unretained(&is_exiting))); - } - - // Give time for those idle workers to possibly do work (which should not - // happen). - PlatformThread::Sleep(TestTimeouts::tiny_timeout()); - - is_exiting.Set(); - // Unblocks the new workers. - thread_continue.Signal(); - task_tracker_.FlushForTesting(); -} - -INSTANTIATE_TEST_CASE_P( - , - TaskSchedulerWorkerPoolBlockingTest, - ::testing::Values(NestedBlockingType(BlockingType::MAY_BLOCK, - OptionalBlockingType::NO_BLOCK, - BlockingType::MAY_BLOCK), - NestedBlockingType(BlockingType::WILL_BLOCK, - OptionalBlockingType::NO_BLOCK, - BlockingType::WILL_BLOCK), - NestedBlockingType(BlockingType::MAY_BLOCK, - OptionalBlockingType::WILL_BLOCK, - BlockingType::WILL_BLOCK), - NestedBlockingType(BlockingType::WILL_BLOCK, - OptionalBlockingType::MAY_BLOCK, - BlockingType::WILL_BLOCK)), - TaskSchedulerWorkerPoolBlockingTest::ParamInfoToString); - -// Verify that if a thread enters the scope of a MAY_BLOCK ScopedBlockingCall, -// but exits the scope before the MayBlockThreshold() is reached, that the -// worker capacity does not increase. -TEST_F(TaskSchedulerWorkerPoolBlockingTest, ThreadBlockUnblockPremature) { - ASSERT_EQ(worker_pool_->GetWorkerCapacityForTesting(), - kNumWorkersInWorkerPool); - - TimeDelta worker_capacity_change_sleep = GetWorkerCapacityChangeSleepTime(); - worker_pool_->MaximizeMayBlockThresholdForTesting(); - - SaturateWithBlockingTasks(NestedBlockingType(BlockingType::MAY_BLOCK, - OptionalBlockingType::NO_BLOCK, - BlockingType::MAY_BLOCK)); - PlatformThread::Sleep(worker_capacity_change_sleep); - EXPECT_EQ(worker_pool_->NumberOfWorkersForTesting(), kNumWorkersInWorkerPool); - EXPECT_EQ(worker_pool_->GetWorkerCapacityForTesting(), - kNumWorkersInWorkerPool); - - UnblockTasks(); - task_tracker_.FlushForTesting(); - EXPECT_EQ(worker_pool_->GetWorkerCapacityForTesting(), - kNumWorkersInWorkerPool); -} - -// Verify that if worker capacity is incremented because of a MAY_BLOCK -// ScopedBlockingCall, it isn't incremented again when there is a nested -// WILL_BLOCK ScopedBlockingCall. -TEST_F(TaskSchedulerWorkerPoolBlockingTest, - MayBlockIncreaseCapacityNestedWillBlock) { - ASSERT_EQ(worker_pool_->GetWorkerCapacityForTesting(), - kNumWorkersInWorkerPool); - auto task_runner = - worker_pool_->CreateTaskRunnerWithTraits({WithBaseSyncPrimitives()}); - WaitableEvent can_return(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - - // Saturate the pool so that a MAY_BLOCK ScopedBlockingCall would increment - // the worker capacity. - for (size_t i = 0; i < kNumWorkersInWorkerPool - 1; ++i) { - task_runner->PostTask(FROM_HERE, BindOnce(&WaitWithoutBlockingObserver, - Unretained(&can_return))); - } - - WaitableEvent can_instantiate_will_block( - WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - WaitableEvent did_instantiate_will_block( - WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - - // Post a task that instantiates a MAY_BLOCK ScopedBlockingCall. - task_runner->PostTask( - FROM_HERE, - BindOnce( - [](WaitableEvent* can_instantiate_will_block, - WaitableEvent* did_instantiate_will_block, - WaitableEvent* can_return) { - ScopedBlockingCall may_block(BlockingType::MAY_BLOCK); - WaitWithoutBlockingObserver(can_instantiate_will_block); - ScopedBlockingCall will_block(BlockingType::WILL_BLOCK); - did_instantiate_will_block->Signal(); - WaitWithoutBlockingObserver(can_return); - }, - Unretained(&can_instantiate_will_block), - Unretained(&did_instantiate_will_block), Unretained(&can_return))); - - // After a short delay, worker capacity should be incremented. - ExpectWorkerCapacityIncreasesTo(kNumWorkersInWorkerPool + 1); - - // Wait until the task instantiates a WILL_BLOCK ScopedBlockingCall. - can_instantiate_will_block.Signal(); - did_instantiate_will_block.Wait(); - - // Worker capacity shouldn't be incremented again. - EXPECT_EQ(kNumWorkersInWorkerPool + 1, - worker_pool_->GetWorkerCapacityForTesting()); - - // Tear down. - can_return.Signal(); - task_tracker_.FlushForTesting(); - EXPECT_EQ(worker_pool_->GetWorkerCapacityForTesting(), - kNumWorkersInWorkerPool); -} - -// Verify that workers that become idle due to the pool being over capacity will -// eventually cleanup. -TEST(TaskSchedulerWorkerPoolOverWorkerCapacityTest, VerifyCleanup) { - constexpr size_t kWorkerCapacity = 3; - - TaskTracker task_tracker("Test"); - DelayedTaskManager delayed_task_manager; - scoped_refptr<TaskRunner> service_thread_task_runner = - MakeRefCounted<TestSimpleTaskRunner>(); - delayed_task_manager.Start(service_thread_task_runner); - SchedulerWorkerPoolImpl worker_pool( - "OverWorkerCapacityTestWorkerPool", "A", ThreadPriority::NORMAL, - task_tracker.GetTrackedRef(), &delayed_task_manager); - worker_pool.Start( - SchedulerWorkerPoolParams(kWorkerCapacity, kReclaimTimeForCleanupTests), - service_thread_task_runner, nullptr, - SchedulerWorkerPoolImpl::WorkerEnvironment::NONE); - - scoped_refptr<TaskRunner> task_runner = - worker_pool.CreateTaskRunnerWithTraits({WithBaseSyncPrimitives()}); - - WaitableEvent threads_running(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - WaitableEvent threads_continue(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - RepeatingClosure threads_running_barrier = BarrierClosure( - kWorkerCapacity, - BindOnce(&WaitableEvent::Signal, Unretained(&threads_running))); - - WaitableEvent blocked_call_continue( - WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - - RepeatingClosure closure = BindRepeating( - [](Closure* threads_running_barrier, WaitableEvent* threads_continue, - WaitableEvent* blocked_call_continue) { - threads_running_barrier->Run(); - { - ScopedBlockingCall scoped_blocking_call(BlockingType::WILL_BLOCK); - WaitWithoutBlockingObserver(blocked_call_continue); - } - WaitWithoutBlockingObserver(threads_continue); - }, - Unretained(&threads_running_barrier), Unretained(&threads_continue), - Unretained(&blocked_call_continue)); - - for (size_t i = 0; i < kWorkerCapacity; ++i) - task_runner->PostTask(FROM_HERE, closure); - - threads_running.Wait(); - - WaitableEvent extra_threads_running( - WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - WaitableEvent extra_threads_continue( - WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - - RepeatingClosure extra_threads_running_barrier = BarrierClosure( - kWorkerCapacity, - BindOnce(&WaitableEvent::Signal, Unretained(&extra_threads_running))); - // These tasks should run on the new threads from increasing worker capacity. - for (size_t i = 0; i < kWorkerCapacity; ++i) { - task_runner->PostTask(FROM_HERE, - BindOnce( - [](Closure* extra_threads_running_barrier, - WaitableEvent* extra_threads_continue) { - extra_threads_running_barrier->Run(); - WaitWithoutBlockingObserver( - extra_threads_continue); - }, - Unretained(&extra_threads_running_barrier), - Unretained(&extra_threads_continue))); - } - extra_threads_running.Wait(); - - ASSERT_EQ(kWorkerCapacity * 2, worker_pool.NumberOfWorkersForTesting()); - EXPECT_EQ(kWorkerCapacity * 2, worker_pool.GetWorkerCapacityForTesting()); - blocked_call_continue.Signal(); - extra_threads_continue.Signal(); - - // Periodically post tasks to ensure that posting tasks does not prevent - // workers that are idle due to the pool being over capacity from cleaning up. - for (int i = 0; i < 16; ++i) { - task_runner->PostDelayedTask(FROM_HERE, DoNothing(), - kReclaimTimeForCleanupTests * i * 0.5); - } - - // Note: one worker above capacity will not get cleaned up since it's on the - // top of the idle stack. - worker_pool.WaitForWorkersCleanedUpForTesting(kWorkerCapacity - 1); - EXPECT_EQ(kWorkerCapacity + 1, worker_pool.NumberOfWorkersForTesting()); - - threads_continue.Signal(); - - worker_pool.JoinForTesting(); -} - -// Verify that the maximum number of workers is 256 and that hitting the max -// leaves the pool in a valid state with regards to worker capacity. -TEST_F(TaskSchedulerWorkerPoolBlockingTest, MaximumWorkersTest) { - constexpr size_t kMaxNumberOfWorkers = 256; - constexpr size_t kNumExtraTasks = 10; - - WaitableEvent early_blocking_thread_running( - WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - RepeatingClosure early_threads_barrier_closure = - BarrierClosure(kMaxNumberOfWorkers, - BindOnce(&WaitableEvent::Signal, - Unretained(&early_blocking_thread_running))); - - WaitableEvent early_threads_finished( - WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - RepeatingClosure early_threads_finished_barrier = BarrierClosure( - kMaxNumberOfWorkers, - BindOnce(&WaitableEvent::Signal, Unretained(&early_threads_finished))); - - WaitableEvent early_release_thread_continue( - WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - - // Post ScopedBlockingCall tasks to hit the worker cap. - for (size_t i = 0; i < kMaxNumberOfWorkers; ++i) { - task_runner_->PostTask(FROM_HERE, - BindOnce( - [](Closure* early_threads_barrier_closure, - WaitableEvent* early_release_thread_continue, - Closure* early_threads_finished) { - { - ScopedBlockingCall scoped_blocking_call( - BlockingType::WILL_BLOCK); - early_threads_barrier_closure->Run(); - WaitWithoutBlockingObserver( - early_release_thread_continue); - } - early_threads_finished->Run(); - }, - Unretained(&early_threads_barrier_closure), - Unretained(&early_release_thread_continue), - Unretained(&early_threads_finished_barrier))); - } - - early_blocking_thread_running.Wait(); - EXPECT_EQ(worker_pool_->GetWorkerCapacityForTesting(), - kNumWorkersInWorkerPool + kMaxNumberOfWorkers); - - WaitableEvent late_release_thread_contine( - WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - - WaitableEvent late_blocking_thread_running( - WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - RepeatingClosure late_threads_barrier_closure = BarrierClosure( - kNumExtraTasks, BindOnce(&WaitableEvent::Signal, - Unretained(&late_blocking_thread_running))); - - // Posts additional tasks. Note: we should already have |kMaxNumberOfWorkers| - // tasks running. These tasks should not be able to get executed yet as - // the pool is already at its max worker cap. - for (size_t i = 0; i < kNumExtraTasks; ++i) { - task_runner_->PostTask( - FROM_HERE, - BindOnce( - [](Closure* late_threads_barrier_closure, - WaitableEvent* late_release_thread_contine) { - ScopedBlockingCall scoped_blocking_call(BlockingType::WILL_BLOCK); - late_threads_barrier_closure->Run(); - WaitWithoutBlockingObserver(late_release_thread_contine); - }, - Unretained(&late_threads_barrier_closure), - Unretained(&late_release_thread_contine))); - } - - // Give time to see if we exceed the max number of workers. - PlatformThread::Sleep(TestTimeouts::tiny_timeout()); - EXPECT_LE(worker_pool_->NumberOfWorkersForTesting(), kMaxNumberOfWorkers); - - early_release_thread_continue.Signal(); - early_threads_finished.Wait(); - late_blocking_thread_running.Wait(); - - WaitableEvent final_tasks_running(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - WaitableEvent final_tasks_continue(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - RepeatingClosure final_tasks_running_barrier = BarrierClosure( - kNumWorkersInWorkerPool, - BindOnce(&WaitableEvent::Signal, Unretained(&final_tasks_running))); - - // Verify that we are still able to saturate the pool. - for (size_t i = 0; i < kNumWorkersInWorkerPool; ++i) { - task_runner_->PostTask( - FROM_HERE, - BindOnce( - [](Closure* closure, WaitableEvent* final_tasks_continue) { - closure->Run(); - WaitWithoutBlockingObserver(final_tasks_continue); - }, - Unretained(&final_tasks_running_barrier), - Unretained(&final_tasks_continue))); - } - final_tasks_running.Wait(); - EXPECT_EQ(worker_pool_->GetWorkerCapacityForTesting(), - kNumWorkersInWorkerPool + kNumExtraTasks); - late_release_thread_contine.Signal(); - final_tasks_continue.Signal(); - task_tracker_.FlushForTesting(); -} - -// Verify that worker detachement doesn't race with worker cleanup, regression -// test for https://crbug.com/810464. -TEST(TaskSchedulerWorkerPoolTest, RacyCleanup) { -#if defined(OS_FUCHSIA) - // Fuchsia + QEMU doesn't deal well with *many* threads being - // created/destroyed at once: https://crbug.com/816575. - constexpr size_t kWorkerCapacity = 16; -#else // defined(OS_FUCHSIA) - constexpr size_t kWorkerCapacity = 256; -#endif // defined(OS_FUCHSIA) - constexpr TimeDelta kReclaimTimeForRacyCleanupTest = - TimeDelta::FromMilliseconds(10); - - TaskTracker task_tracker("Test"); - DelayedTaskManager delayed_task_manager; - scoped_refptr<TaskRunner> service_thread_task_runner = - MakeRefCounted<TestSimpleTaskRunner>(); - delayed_task_manager.Start(service_thread_task_runner); - SchedulerWorkerPoolImpl worker_pool( - "RacyCleanupTestWorkerPool", "A", ThreadPriority::NORMAL, - task_tracker.GetTrackedRef(), &delayed_task_manager); - worker_pool.Start(SchedulerWorkerPoolParams(kWorkerCapacity, - kReclaimTimeForRacyCleanupTest), - service_thread_task_runner, nullptr, - SchedulerWorkerPoolImpl::WorkerEnvironment::NONE); - - scoped_refptr<TaskRunner> task_runner = - worker_pool.CreateTaskRunnerWithTraits({WithBaseSyncPrimitives()}); - - WaitableEvent threads_running(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - WaitableEvent unblock_threads(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - RepeatingClosure threads_running_barrier = BarrierClosure( - kWorkerCapacity, - BindOnce(&WaitableEvent::Signal, Unretained(&threads_running))); - - for (size_t i = 0; i < kWorkerCapacity; ++i) { - task_runner->PostTask( - FROM_HERE, - BindOnce( - [](OnceClosure on_running, WaitableEvent* unblock_threads) { - std::move(on_running).Run(); - WaitWithoutBlockingObserver(unblock_threads); - }, - threads_running_barrier, Unretained(&unblock_threads))); - } - - // Wait for all workers to be ready and release them all at once. - threads_running.Wait(); - unblock_threads.Signal(); - - // Sleep to wakeup precisely when all workers are going to try to cleanup per - // being idle. - PlatformThread::Sleep(kReclaimTimeForRacyCleanupTest); - - worker_pool.JoinForTesting(); - - // Unwinding this test will be racy if worker cleanup can race with - // SchedulerWorkerPoolImpl destruction : https://crbug.com/810464. -} - -} // namespace internal -} // namespace base
diff --git a/base/task_scheduler/scheduler_worker_pool_unittest.cc b/base/task_scheduler/scheduler_worker_pool_unittest.cc deleted file mode 100644 index 20c1ad0..0000000 --- a/base/task_scheduler/scheduler_worker_pool_unittest.cc +++ /dev/null
@@ -1,345 +0,0 @@ -// 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/task_scheduler/scheduler_worker_pool.h" - -#include <memory> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/location.h" -#include "base/memory/ref_counted.h" -#include "base/task_runner.h" -#include "base/task_scheduler/delayed_task_manager.h" -#include "base/task_scheduler/scheduler_worker_pool_impl.h" -#include "base/task_scheduler/scheduler_worker_pool_params.h" -#include "base/task_scheduler/task_tracker.h" -#include "base/task_scheduler/task_traits.h" -#include "base/task_scheduler/test_task_factory.h" -#include "base/task_scheduler/test_utils.h" -#include "base/test/test_timeouts.h" -#include "base/threading/platform_thread.h" -#include "base/threading/simple_thread.h" -#include "base/threading/thread.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(OS_WIN) -#include "base/task_scheduler/platform_native_worker_pool_win.h" -#endif - -namespace base { -namespace internal { - -namespace { - -constexpr size_t kNumWorkersInWorkerPool = 4; -constexpr size_t kNumThreadsPostingTasks = 4; -constexpr size_t kNumTasksPostedPerThread = 150; - -enum class PoolType { - GENERIC, -#if defined(OS_WIN) - WINDOWS, -#endif -}; - -struct PoolExecutionType { - PoolType pool_type; - test::ExecutionMode execution_mode; -}; - -using PostNestedTask = test::TestTaskFactory::PostNestedTask; - -class ThreadPostingTasks : public SimpleThread { - public: - // Constructs a thread that posts |num_tasks_posted_per_thread| tasks to - // |worker_pool| through an |execution_mode| task runner. If - // |post_nested_task| is YES, each task posted by this thread posts another - // task when it runs. - ThreadPostingTasks(SchedulerWorkerPool* worker_pool, - test::ExecutionMode execution_mode, - PostNestedTask post_nested_task) - : SimpleThread("ThreadPostingTasks"), - worker_pool_(worker_pool), - post_nested_task_(post_nested_task), - factory_(test::CreateTaskRunnerWithExecutionMode(worker_pool, - execution_mode), - execution_mode) { - DCHECK(worker_pool_); - } - - const test::TestTaskFactory* factory() const { return &factory_; } - - private: - void Run() override { - EXPECT_FALSE(factory_.task_runner()->RunsTasksInCurrentSequence()); - - for (size_t i = 0; i < kNumTasksPostedPerThread; ++i) - EXPECT_TRUE(factory_.PostTask(post_nested_task_, Closure())); - } - - SchedulerWorkerPool* const worker_pool_; - const scoped_refptr<TaskRunner> task_runner_; - const PostNestedTask post_nested_task_; - test::TestTaskFactory factory_; - - DISALLOW_COPY_AND_ASSIGN(ThreadPostingTasks); -}; - -class TaskSchedulerWorkerPoolTest - : public testing::TestWithParam<PoolExecutionType> { - protected: - TaskSchedulerWorkerPoolTest() - : service_thread_("TaskSchedulerServiceThread") {} - - void SetUp() override { - service_thread_.Start(); - delayed_task_manager_.Start(service_thread_.task_runner()); - CreateWorkerPool(); - } - - void TearDown() override { - service_thread_.Stop(); - if (worker_pool_) - worker_pool_->JoinForTesting(); - } - - void CreateWorkerPool() { - ASSERT_FALSE(worker_pool_); - switch (GetParam().pool_type) { - case PoolType::GENERIC: - worker_pool_ = std::make_unique<SchedulerWorkerPoolImpl>( - "TestWorkerPool", "A", ThreadPriority::NORMAL, - task_tracker_.GetTrackedRef(), &delayed_task_manager_); - break; -#if defined(OS_WIN) - case PoolType::WINDOWS: - worker_pool_ = std::make_unique<PlatformNativeWorkerPoolWin>( - task_tracker_.GetTrackedRef(), &delayed_task_manager_); - break; -#endif - } - ASSERT_TRUE(worker_pool_); - } - - void StartWorkerPool() { - ASSERT_TRUE(worker_pool_); - switch (GetParam().pool_type) { - case PoolType::GENERIC: { - SchedulerWorkerPoolImpl* scheduler_worker_pool_impl = - static_cast<SchedulerWorkerPoolImpl*>(worker_pool_.get()); - scheduler_worker_pool_impl->Start( - SchedulerWorkerPoolParams(kNumWorkersInWorkerPool, - TimeDelta::Max()), - service_thread_.task_runner(), nullptr, - SchedulerWorkerPoolImpl::WorkerEnvironment::NONE); - break; - } -#if defined(OS_WIN) - case PoolType::WINDOWS: { - PlatformNativeWorkerPoolWin* scheduler_worker_pool_windows_impl = - static_cast<PlatformNativeWorkerPoolWin*>(worker_pool_.get()); - scheduler_worker_pool_windows_impl->Start(); - break; - } -#endif - } - } - - Thread service_thread_; - TaskTracker task_tracker_ = {"Test"}; - DelayedTaskManager delayed_task_manager_; - - std::unique_ptr<SchedulerWorkerPool> worker_pool_; - - private: - DISALLOW_COPY_AND_ASSIGN(TaskSchedulerWorkerPoolTest); -}; - -void ShouldNotRun() { - ADD_FAILURE() << "Ran a task that shouldn't run."; -} - -} // namespace - -TEST_P(TaskSchedulerWorkerPoolTest, PostTasks) { - StartWorkerPool(); - // Create threads to post tasks. - std::vector<std::unique_ptr<ThreadPostingTasks>> threads_posting_tasks; - for (size_t i = 0; i < kNumThreadsPostingTasks; ++i) { - threads_posting_tasks.push_back(std::make_unique<ThreadPostingTasks>( - worker_pool_.get(), GetParam().execution_mode, PostNestedTask::NO)); - threads_posting_tasks.back()->Start(); - } - - // Wait for all tasks to run. - for (const auto& thread_posting_tasks : threads_posting_tasks) { - thread_posting_tasks->Join(); - thread_posting_tasks->factory()->WaitForAllTasksToRun(); - } - - // Flush the task tracker to be sure that no task accesses its TestTaskFactory - // after |thread_posting_tasks| is destroyed. - task_tracker_.FlushForTesting(); -} - -TEST_P(TaskSchedulerWorkerPoolTest, NestedPostTasks) { - StartWorkerPool(); - // Create threads to post tasks. Each task posted by these threads will post - // another task when it runs. - std::vector<std::unique_ptr<ThreadPostingTasks>> threads_posting_tasks; - for (size_t i = 0; i < kNumThreadsPostingTasks; ++i) { - threads_posting_tasks.push_back(std::make_unique<ThreadPostingTasks>( - worker_pool_.get(), GetParam().execution_mode, PostNestedTask::YES)); - threads_posting_tasks.back()->Start(); - } - - // Wait for all tasks to run. - for (const auto& thread_posting_tasks : threads_posting_tasks) { - thread_posting_tasks->Join(); - thread_posting_tasks->factory()->WaitForAllTasksToRun(); - } - - // Flush the task tracker to be sure that no task accesses its TestTaskFactory - // after |thread_posting_tasks| is destroyed. - task_tracker_.FlushForTesting(); -} - -// Verify that a Task can't be posted after shutdown. -TEST_P(TaskSchedulerWorkerPoolTest, PostTaskAfterShutdown) { - StartWorkerPool(); - auto task_runner = test::CreateTaskRunnerWithExecutionMode( - worker_pool_.get(), GetParam().execution_mode); - task_tracker_.Shutdown(); - EXPECT_FALSE(task_runner->PostTask(FROM_HERE, BindOnce(&ShouldNotRun))); -} - -// Verify that posting tasks after the pool was destroyed fails but doesn't -// crash. -TEST_P(TaskSchedulerWorkerPoolTest, PostAfterDestroy) { - StartWorkerPool(); - auto task_runner = test::CreateTaskRunnerWithExecutionMode( - worker_pool_.get(), GetParam().execution_mode); - EXPECT_TRUE(task_runner->PostTask(FROM_HERE, DoNothing())); - task_tracker_.Shutdown(); - worker_pool_->JoinForTesting(); - worker_pool_.reset(); - EXPECT_FALSE(task_runner->PostTask(FROM_HERE, BindOnce(&ShouldNotRun))); -} - -// Verify that a Task runs shortly after its delay expires. -TEST_P(TaskSchedulerWorkerPoolTest, PostDelayedTask) { - StartWorkerPool(); - - WaitableEvent task_ran(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - - auto task_runner = test::CreateTaskRunnerWithExecutionMode( - worker_pool_.get(), GetParam().execution_mode); - - // Wait until the task runner is up and running to make sure the test below is - // solely timing the delayed task, not bringing up a physical thread. - task_runner->PostTask( - FROM_HERE, BindOnce(&WaitableEvent::Signal, Unretained(&task_ran))); - task_ran.Wait(); - ASSERT_TRUE(!task_ran.IsSignaled()); - - // Post a task with a short delay. - TimeTicks start_time = TimeTicks::Now(); - EXPECT_TRUE(task_runner->PostDelayedTask( - FROM_HERE, BindOnce(&WaitableEvent::Signal, Unretained(&task_ran)), - TestTimeouts::tiny_timeout())); - - // Wait until the task runs. - task_ran.Wait(); - - // Expect the task to run after its delay expires, but no more than 250 - // ms after that. - const TimeDelta actual_delay = TimeTicks::Now() - start_time; - EXPECT_GE(actual_delay, TestTimeouts::tiny_timeout()); - EXPECT_LT(actual_delay, - TimeDelta::FromMilliseconds(250) + TestTimeouts::tiny_timeout()); -} - -// Verify that the RunsTasksInCurrentSequence() method of a SEQUENCED TaskRunner -// returns false when called from a task that isn't part of the sequence. Note: -// Tests that use TestTaskFactory already verify that -// RunsTasksInCurrentSequence() returns true when appropriate so this method -// complements it to get full coverage of that method. -TEST_P(TaskSchedulerWorkerPoolTest, SequencedRunsTasksInCurrentSequence) { - StartWorkerPool(); - auto task_runner = test::CreateTaskRunnerWithExecutionMode( - worker_pool_.get(), GetParam().execution_mode); - auto sequenced_task_runner = - worker_pool_->CreateSequencedTaskRunnerWithTraits(TaskTraits()); - - WaitableEvent task_ran(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - task_runner->PostTask( - FROM_HERE, - BindOnce( - [](scoped_refptr<TaskRunner> sequenced_task_runner, - WaitableEvent* task_ran) { - EXPECT_FALSE(sequenced_task_runner->RunsTasksInCurrentSequence()); - task_ran->Signal(); - }, - sequenced_task_runner, Unretained(&task_ran))); - task_ran.Wait(); -} - -// Verify that tasks posted before Start run after Start. -TEST_P(TaskSchedulerWorkerPoolTest, PostBeforeStart) { - WaitableEvent task_1_running(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - WaitableEvent task_2_running(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - - scoped_refptr<TaskRunner> task_runner = - worker_pool_->CreateTaskRunnerWithTraits({WithBaseSyncPrimitives()}); - - task_runner->PostTask( - FROM_HERE, BindOnce(&WaitableEvent::Signal, Unretained(&task_1_running))); - task_runner->PostTask( - FROM_HERE, BindOnce(&WaitableEvent::Signal, Unretained(&task_2_running))); - - // Workers should not be created and tasks should not run before the pool is - // started. The sleep is to give time for the tasks to potentially run. - PlatformThread::Sleep(TestTimeouts::tiny_timeout()); - EXPECT_FALSE(task_1_running.IsSignaled()); - EXPECT_FALSE(task_2_running.IsSignaled()); - - StartWorkerPool(); - - // Tasks should run shortly after the pool is started. - task_1_running.Wait(); - task_2_running.Wait(); - - task_tracker_.FlushForTesting(); -} - -INSTANTIATE_TEST_CASE_P(GenericParallel, - TaskSchedulerWorkerPoolTest, - ::testing::Values(PoolExecutionType{ - PoolType::GENERIC, test::ExecutionMode::PARALLEL})); -INSTANTIATE_TEST_CASE_P(GenericSequenced, - TaskSchedulerWorkerPoolTest, - ::testing::Values(PoolExecutionType{ - PoolType::GENERIC, - test::ExecutionMode::SEQUENCED})); - -#if defined(OS_WIN) -INSTANTIATE_TEST_CASE_P(WinParallel, - TaskSchedulerWorkerPoolTest, - ::testing::Values(PoolExecutionType{ - PoolType::WINDOWS, test::ExecutionMode::PARALLEL})); -INSTANTIATE_TEST_CASE_P(WinSequenced, - TaskSchedulerWorkerPoolTest, - ::testing::Values(PoolExecutionType{ - PoolType::WINDOWS, - test::ExecutionMode::SEQUENCED})); -#endif - -} // namespace internal -} // namespace base
diff --git a/base/task_scheduler/scheduler_worker_stack_unittest.cc b/base/task_scheduler/scheduler_worker_stack_unittest.cc deleted file mode 100644 index 8707874..0000000 --- a/base/task_scheduler/scheduler_worker_stack_unittest.cc +++ /dev/null
@@ -1,253 +0,0 @@ -// 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/task_scheduler/scheduler_worker_stack.h" - -#include "base/logging.h" -#include "base/memory/ptr_util.h" -#include "base/memory/ref_counted.h" -#include "base/task_scheduler/scheduler_worker.h" -#include "base/task_scheduler/sequence.h" -#include "base/task_scheduler/task_tracker.h" -#include "base/test/gtest_util.h" -#include "base/threading/platform_thread.h" -#include "base/time/time.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace internal { - -namespace { - -class MockSchedulerWorkerDelegate : public SchedulerWorker::Delegate { - public: - void OnCanScheduleSequence(scoped_refptr<Sequence> sequence) override { - ADD_FAILURE() << "Unexpected call to OnCanScheduleSequence()."; - } - SchedulerWorker::ThreadLabel GetThreadLabel() const override { - return SchedulerWorker::ThreadLabel::DEDICATED; - } - void OnMainEntry(const SchedulerWorker* worker) override {} - scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override { - return nullptr; - } - void DidRunTask() override { - ADD_FAILURE() << "Unexpected call to DidRunTask()"; - } - void ReEnqueueSequence(scoped_refptr<Sequence> sequence) override { - ADD_FAILURE() << "Unexpected call to ReEnqueueSequence()"; - } - TimeDelta GetSleepTimeout() override { - return TimeDelta::Max(); - } -}; - -class TaskSchedulerWorkerStackTest : public testing::Test { - protected: - void SetUp() override { - worker_a_ = MakeRefCounted<SchedulerWorker>( - ThreadPriority::NORMAL, WrapUnique(new MockSchedulerWorkerDelegate), - task_tracker_.GetTrackedRef()); - ASSERT_TRUE(worker_a_); - worker_b_ = MakeRefCounted<SchedulerWorker>( - ThreadPriority::NORMAL, WrapUnique(new MockSchedulerWorkerDelegate), - task_tracker_.GetTrackedRef()); - ASSERT_TRUE(worker_b_); - worker_c_ = MakeRefCounted<SchedulerWorker>( - ThreadPriority::NORMAL, WrapUnique(new MockSchedulerWorkerDelegate), - task_tracker_.GetTrackedRef()); - ASSERT_TRUE(worker_c_); - } - - private: - TaskTracker task_tracker_ = {"Test"}; - - protected: - scoped_refptr<SchedulerWorker> worker_a_; - scoped_refptr<SchedulerWorker> worker_b_; - scoped_refptr<SchedulerWorker> worker_c_; -}; - -} // namespace - -// Verify that Push() and Pop() add/remove values in FIFO order. -TEST_F(TaskSchedulerWorkerStackTest, PushPop) { - SchedulerWorkerStack stack; - EXPECT_EQ(nullptr, stack.Pop()); - - EXPECT_TRUE(stack.IsEmpty()); - EXPECT_EQ(0U, stack.Size()); - - stack.Push(worker_a_.get()); - EXPECT_FALSE(stack.IsEmpty()); - EXPECT_EQ(1U, stack.Size()); - - stack.Push(worker_b_.get()); - EXPECT_FALSE(stack.IsEmpty()); - EXPECT_EQ(2U, stack.Size()); - - stack.Push(worker_c_.get()); - EXPECT_FALSE(stack.IsEmpty()); - EXPECT_EQ(3U, stack.Size()); - - EXPECT_EQ(worker_c_.get(), stack.Pop()); - EXPECT_FALSE(stack.IsEmpty()); - EXPECT_EQ(2U, stack.Size()); - - stack.Push(worker_c_.get()); - EXPECT_FALSE(stack.IsEmpty()); - EXPECT_EQ(3U, stack.Size()); - - EXPECT_EQ(worker_c_.get(), stack.Pop()); - EXPECT_FALSE(stack.IsEmpty()); - EXPECT_EQ(2U, stack.Size()); - - EXPECT_EQ(worker_b_.get(), stack.Pop()); - EXPECT_FALSE(stack.IsEmpty()); - EXPECT_EQ(1U, stack.Size()); - - EXPECT_EQ(worker_a_.get(), stack.Pop()); - EXPECT_TRUE(stack.IsEmpty()); - EXPECT_EQ(0U, stack.Size()); - - EXPECT_EQ(nullptr, stack.Pop()); -} - -// Verify that Peek() returns the correct values in FIFO order. -TEST_F(TaskSchedulerWorkerStackTest, PeekPop) { - SchedulerWorkerStack stack; - EXPECT_EQ(nullptr, stack.Peek()); - - EXPECT_TRUE(stack.IsEmpty()); - EXPECT_EQ(0U, stack.Size()); - - stack.Push(worker_a_.get()); - EXPECT_EQ(worker_a_.get(), stack.Peek()); - EXPECT_FALSE(stack.IsEmpty()); - EXPECT_EQ(1U, stack.Size()); - - stack.Push(worker_b_.get()); - EXPECT_EQ(worker_b_.get(), stack.Peek()); - EXPECT_FALSE(stack.IsEmpty()); - EXPECT_EQ(2U, stack.Size()); - - stack.Push(worker_c_.get()); - EXPECT_EQ(worker_c_.get(), stack.Peek()); - EXPECT_FALSE(stack.IsEmpty()); - EXPECT_EQ(3U, stack.Size()); - - EXPECT_EQ(worker_c_.get(), stack.Pop()); - EXPECT_EQ(worker_b_.get(), stack.Peek()); - EXPECT_FALSE(stack.IsEmpty()); - EXPECT_EQ(2U, stack.Size()); - - EXPECT_EQ(worker_b_.get(), stack.Pop()); - EXPECT_EQ(worker_a_.get(), stack.Peek()); - EXPECT_FALSE(stack.IsEmpty()); - EXPECT_EQ(1U, stack.Size()); - - EXPECT_EQ(worker_a_.get(), stack.Pop()); - EXPECT_TRUE(stack.IsEmpty()); - EXPECT_EQ(0U, stack.Size()); - - EXPECT_EQ(nullptr, stack.Peek()); -} - -// Verify that Contains() returns true for workers on the stack. -TEST_F(TaskSchedulerWorkerStackTest, Contains) { - SchedulerWorkerStack stack; - EXPECT_FALSE(stack.Contains(worker_a_.get())); - EXPECT_FALSE(stack.Contains(worker_b_.get())); - EXPECT_FALSE(stack.Contains(worker_c_.get())); - - stack.Push(worker_a_.get()); - EXPECT_TRUE(stack.Contains(worker_a_.get())); - EXPECT_FALSE(stack.Contains(worker_b_.get())); - EXPECT_FALSE(stack.Contains(worker_c_.get())); - - stack.Push(worker_b_.get()); - EXPECT_TRUE(stack.Contains(worker_a_.get())); - EXPECT_TRUE(stack.Contains(worker_b_.get())); - EXPECT_FALSE(stack.Contains(worker_c_.get())); - - stack.Push(worker_c_.get()); - EXPECT_TRUE(stack.Contains(worker_a_.get())); - EXPECT_TRUE(stack.Contains(worker_b_.get())); - EXPECT_TRUE(stack.Contains(worker_c_.get())); - - stack.Pop(); - EXPECT_TRUE(stack.Contains(worker_a_.get())); - EXPECT_TRUE(stack.Contains(worker_b_.get())); - EXPECT_FALSE(stack.Contains(worker_c_.get())); - - stack.Pop(); - EXPECT_TRUE(stack.Contains(worker_a_.get())); - EXPECT_FALSE(stack.Contains(worker_b_.get())); - EXPECT_FALSE(stack.Contains(worker_c_.get())); - - stack.Pop(); - EXPECT_FALSE(stack.Contains(worker_a_.get())); - EXPECT_FALSE(stack.Contains(worker_b_.get())); - EXPECT_FALSE(stack.Contains(worker_c_.get())); -} - -// Verify that a value can be removed by Remove(). -TEST_F(TaskSchedulerWorkerStackTest, Remove) { - SchedulerWorkerStack stack; - EXPECT_TRUE(stack.IsEmpty()); - EXPECT_EQ(0U, stack.Size()); - - stack.Push(worker_a_.get()); - EXPECT_FALSE(stack.IsEmpty()); - EXPECT_EQ(1U, stack.Size()); - - stack.Push(worker_b_.get()); - EXPECT_FALSE(stack.IsEmpty()); - EXPECT_EQ(2U, stack.Size()); - - stack.Push(worker_c_.get()); - EXPECT_FALSE(stack.IsEmpty()); - EXPECT_EQ(3U, stack.Size()); - - stack.Remove(worker_b_.get()); - EXPECT_FALSE(stack.IsEmpty()); - EXPECT_EQ(2U, stack.Size()); - - EXPECT_EQ(worker_c_.get(), stack.Pop()); - EXPECT_FALSE(stack.IsEmpty()); - EXPECT_EQ(1U, stack.Size()); - - EXPECT_EQ(worker_a_.get(), stack.Pop()); - EXPECT_TRUE(stack.IsEmpty()); - EXPECT_EQ(0U, stack.Size()); -} - -// Verify that a value can be pushed again after it has been removed. -TEST_F(TaskSchedulerWorkerStackTest, PushAfterRemove) { - SchedulerWorkerStack stack; - EXPECT_EQ(0U, stack.Size()); - EXPECT_TRUE(stack.IsEmpty()); - - stack.Push(worker_a_.get()); - EXPECT_EQ(1U, stack.Size()); - EXPECT_FALSE(stack.IsEmpty()); - - stack.Remove(worker_a_.get()); - EXPECT_EQ(0U, stack.Size()); - EXPECT_TRUE(stack.IsEmpty()); - - stack.Push(worker_a_.get()); - EXPECT_EQ(1U, stack.Size()); - EXPECT_FALSE(stack.IsEmpty()); -} - -// Verify that Push() DCHECKs when a value is inserted twice. -TEST_F(TaskSchedulerWorkerStackTest, PushTwice) { - SchedulerWorkerStack stack; - stack.Push(worker_a_.get()); - EXPECT_DCHECK_DEATH({ stack.Push(worker_a_.get()); }); -} - -} // namespace internal -} // namespace base
diff --git a/base/task_scheduler/scheduler_worker_unittest.cc b/base/task_scheduler/scheduler_worker_unittest.cc deleted file mode 100644 index b7a2eda..0000000 --- a/base/task_scheduler/scheduler_worker_unittest.cc +++ /dev/null
@@ -1,907 +0,0 @@ -// 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/task_scheduler/scheduler_worker.h" - -#include <stddef.h> - -#include <memory> -#include <vector> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/memory/ref_counted.h" -#include "base/synchronization/condition_variable.h" -#include "base/synchronization/waitable_event.h" -#include "base/task_scheduler/scheduler_lock.h" -#include "base/task_scheduler/scheduler_worker_observer.h" -#include "base/task_scheduler/sequence.h" -#include "base/task_scheduler/task.h" -#include "base/task_scheduler/task_tracker.h" -#include "base/task_scheduler/test_utils.h" -#include "base/test/test_timeouts.h" -#include "base/threading/platform_thread.h" -#include "base/threading/simple_thread.h" -#include "base/time/time.h" -#include "build_config.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(OS_WIN) -#include <objbase.h> - -#include "base/win/com_init_check_hook.h" -#endif - -using testing::_; -using testing::Mock; -using testing::Ne; -using testing::StrictMock; - -namespace base { -namespace internal { -namespace { - -const size_t kNumSequencesPerTest = 150; - -class SchedulerWorkerDefaultDelegate : public SchedulerWorker::Delegate { - public: - SchedulerWorkerDefaultDelegate() = default; - - // SchedulerWorker::Delegate: - void OnCanScheduleSequence(scoped_refptr<Sequence> sequence) override { - ADD_FAILURE() << "Unexpected call to OnCanScheduleSequence()."; - } - SchedulerWorker::ThreadLabel GetThreadLabel() const override { - return SchedulerWorker::ThreadLabel::DEDICATED; - } - void OnMainEntry(const SchedulerWorker* worker) override {} - scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override { - return nullptr; - } - void DidRunTask() override { - ADD_FAILURE() << "Unexpected call to DidRunTask()"; - } - void ReEnqueueSequence(scoped_refptr<Sequence> sequence) override { - ADD_FAILURE() << "Unexpected call to ReEnqueueSequence()"; - } - TimeDelta GetSleepTimeout() override { return TimeDelta::Max(); } - - private: - DISALLOW_COPY_AND_ASSIGN(SchedulerWorkerDefaultDelegate); -}; - -// The test parameter is the number of Tasks per Sequence returned by GetWork(). -class TaskSchedulerWorkerTest : public testing::TestWithParam<size_t> { - protected: - TaskSchedulerWorkerTest() - : main_entry_called_(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED), - num_get_work_cv_(lock_.CreateConditionVariable()), - worker_set_(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED) {} - - void SetUp() override { - worker_ = MakeRefCounted<SchedulerWorker>( - ThreadPriority::NORMAL, - std::make_unique<TestSchedulerWorkerDelegate>(this), - task_tracker_.GetTrackedRef()); - ASSERT_TRUE(worker_); - worker_->Start(); - worker_set_.Signal(); - main_entry_called_.Wait(); - } - - void TearDown() override { - // |worker_| needs to be released before ~TaskTracker() as it holds a - // TrackedRef to it. - worker_->JoinForTesting(); - worker_ = nullptr; - } - - size_t TasksPerSequence() const { return GetParam(); } - - // Wait until GetWork() has been called |num_get_work| times. - void WaitForNumGetWork(size_t num_get_work) { - AutoSchedulerLock auto_lock(lock_); - while (num_get_work_ < num_get_work) - num_get_work_cv_->Wait(); - } - - void SetMaxGetWork(size_t max_get_work) { - AutoSchedulerLock auto_lock(lock_); - max_get_work_ = max_get_work; - } - - void SetNumSequencesToCreate(size_t num_sequences_to_create) { - AutoSchedulerLock auto_lock(lock_); - EXPECT_EQ(0U, num_sequences_to_create_); - num_sequences_to_create_ = num_sequences_to_create; - } - - size_t NumRunTasks() { - AutoSchedulerLock auto_lock(lock_); - return num_run_tasks_; - } - - std::vector<scoped_refptr<Sequence>> CreatedSequences() { - AutoSchedulerLock auto_lock(lock_); - return created_sequences_; - } - - std::vector<scoped_refptr<Sequence>> EnqueuedSequences() { - AutoSchedulerLock auto_lock(lock_); - return re_enqueued_sequences_; - } - - scoped_refptr<SchedulerWorker> worker_; - - private: - class TestSchedulerWorkerDelegate : public SchedulerWorkerDefaultDelegate { - public: - TestSchedulerWorkerDelegate(TaskSchedulerWorkerTest* outer) - : outer_(outer) {} - - ~TestSchedulerWorkerDelegate() override { - EXPECT_FALSE(IsCallToDidRunTaskExpected()); - } - - // SchedulerWorker::Delegate: - void OnMainEntry(const SchedulerWorker* worker) override { - outer_->worker_set_.Wait(); - EXPECT_EQ(outer_->worker_.get(), worker); - EXPECT_FALSE(IsCallToDidRunTaskExpected()); - - // Without synchronization, OnMainEntry() could be called twice without - // generating an error. - AutoSchedulerLock auto_lock(outer_->lock_); - EXPECT_FALSE(outer_->main_entry_called_.IsSignaled()); - outer_->main_entry_called_.Signal(); - } - - scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override { - EXPECT_FALSE(IsCallToDidRunTaskExpected()); - EXPECT_EQ(outer_->worker_.get(), worker); - - { - AutoSchedulerLock auto_lock(outer_->lock_); - - // Increment the number of times that this method has been called. - ++outer_->num_get_work_; - outer_->num_get_work_cv_->Signal(); - - // Verify that this method isn't called more times than expected. - EXPECT_LE(outer_->num_get_work_, outer_->max_get_work_); - - // Check if a Sequence should be returned. - if (outer_->num_sequences_to_create_ == 0) - return nullptr; - --outer_->num_sequences_to_create_; - } - - // Create a Sequence with TasksPerSequence() Tasks. - scoped_refptr<Sequence> sequence(new Sequence); - for (size_t i = 0; i < outer_->TasksPerSequence(); ++i) { - Task task(FROM_HERE, - BindOnce(&TaskSchedulerWorkerTest::RunTaskCallback, - Unretained(outer_)), - TaskTraits(), TimeDelta()); - EXPECT_TRUE(outer_->task_tracker_.WillPostTask(task)); - sequence->PushTask(std::move(task)); - } - - ExpectCallToDidRunTask(); - - { - // Add the Sequence to the vector of created Sequences. - AutoSchedulerLock auto_lock(outer_->lock_); - outer_->created_sequences_.push_back(sequence); - } - - sequence = outer_->task_tracker_.WillScheduleSequence(std::move(sequence), - nullptr); - EXPECT_TRUE(sequence); - return sequence; - } - - void DidRunTask() override { - AutoSchedulerLock auto_lock(expect_did_run_task_lock_); - EXPECT_TRUE(expect_did_run_task_); - expect_did_run_task_ = false; - } - - // This override verifies that |sequence| contains the expected number of - // Tasks and adds it to |enqueued_sequences_|. Unlike a normal - // EnqueueSequence implementation, it doesn't reinsert |sequence| into a - // queue for further execution. - void ReEnqueueSequence(scoped_refptr<Sequence> sequence) override { - EXPECT_FALSE(IsCallToDidRunTaskExpected()); - EXPECT_GT(outer_->TasksPerSequence(), 1U); - - // Verify that |sequence| contains TasksPerSequence() - 1 Tasks. - for (size_t i = 0; i < outer_->TasksPerSequence() - 1; ++i) { - EXPECT_TRUE(sequence->TakeTask()); - EXPECT_EQ(i == outer_->TasksPerSequence() - 2, sequence->Pop()); - } - - // Add |sequence| to |re_enqueued_sequences_|. - AutoSchedulerLock auto_lock(outer_->lock_); - outer_->re_enqueued_sequences_.push_back(std::move(sequence)); - EXPECT_LE(outer_->re_enqueued_sequences_.size(), - outer_->created_sequences_.size()); - } - - private: - // Expect a call to DidRunTask() before the next call to any other method of - // this delegate. - void ExpectCallToDidRunTask() { - AutoSchedulerLock auto_lock(expect_did_run_task_lock_); - expect_did_run_task_ = true; - } - - bool IsCallToDidRunTaskExpected() const { - AutoSchedulerLock auto_lock(expect_did_run_task_lock_); - return expect_did_run_task_; - } - - TaskSchedulerWorkerTest* outer_; - - // Synchronizes access to |expect_did_run_task_|. - mutable SchedulerLock expect_did_run_task_lock_; - - // Whether the next method called on this delegate should be DidRunTask(). - bool expect_did_run_task_ = false; - - DISALLOW_COPY_AND_ASSIGN(TestSchedulerWorkerDelegate); - }; - - void RunTaskCallback() { - AutoSchedulerLock auto_lock(lock_); - ++num_run_tasks_; - EXPECT_LE(num_run_tasks_, created_sequences_.size()); - } - - TaskTracker task_tracker_ = {"Test"}; - - // Synchronizes access to all members below. - mutable SchedulerLock lock_; - - // Signaled once OnMainEntry() has been called. - WaitableEvent main_entry_called_; - - // Number of Sequences that should be created by GetWork(). When this - // is 0, GetWork() returns nullptr. - size_t num_sequences_to_create_ = 0; - - // Number of times that GetWork() has been called. - size_t num_get_work_ = 0; - - // Maximum number of times that GetWork() can be called. - size_t max_get_work_ = 0; - - // Condition variable signaled when |num_get_work_| is incremented. - std::unique_ptr<ConditionVariable> num_get_work_cv_; - - // Sequences created by GetWork(). - std::vector<scoped_refptr<Sequence>> created_sequences_; - - // Sequences passed to EnqueueSequence(). - std::vector<scoped_refptr<Sequence>> re_enqueued_sequences_; - - // Number of times that RunTaskCallback() has been called. - size_t num_run_tasks_ = 0; - - // Signaled after |worker_| is set. - WaitableEvent worker_set_; - - DISALLOW_COPY_AND_ASSIGN(TaskSchedulerWorkerTest); -}; - -} // namespace - -// Verify that when GetWork() continuously returns Sequences, all Tasks in these -// Sequences run successfully. The test wakes up the SchedulerWorker once. -TEST_P(TaskSchedulerWorkerTest, ContinuousWork) { - // Set GetWork() to return |kNumSequencesPerTest| Sequences before starting to - // return nullptr. - SetNumSequencesToCreate(kNumSequencesPerTest); - - // Expect |kNumSequencesPerTest| calls to GetWork() in which it returns a - // Sequence and one call in which its returns nullptr. - const size_t kExpectedNumGetWork = kNumSequencesPerTest + 1; - SetMaxGetWork(kExpectedNumGetWork); - - // Wake up |worker_| and wait until GetWork() has been invoked the - // expected amount of times. - worker_->WakeUp(); - WaitForNumGetWork(kExpectedNumGetWork); - - // All tasks should have run. - EXPECT_EQ(kNumSequencesPerTest, NumRunTasks()); - - // If Sequences returned by GetWork() contain more than one Task, they aren't - // empty after the worker pops Tasks from them and thus should be returned to - // EnqueueSequence(). - if (TasksPerSequence() > 1) - EXPECT_EQ(CreatedSequences(), EnqueuedSequences()); - else - EXPECT_TRUE(EnqueuedSequences().empty()); -} - -// Verify that when GetWork() alternates between returning a Sequence and -// returning nullptr, all Tasks in the returned Sequences run successfully. The -// test wakes up the SchedulerWorker once for each Sequence. -TEST_P(TaskSchedulerWorkerTest, IntermittentWork) { - for (size_t i = 0; i < kNumSequencesPerTest; ++i) { - // Set GetWork() to return 1 Sequence before starting to return - // nullptr. - SetNumSequencesToCreate(1); - - // Expect |i + 1| calls to GetWork() in which it returns a Sequence and - // |i + 1| calls in which it returns nullptr. - const size_t expected_num_get_work = 2 * (i + 1); - SetMaxGetWork(expected_num_get_work); - - // Wake up |worker_| and wait until GetWork() has been invoked - // the expected amount of times. - worker_->WakeUp(); - WaitForNumGetWork(expected_num_get_work); - - // The Task should have run - EXPECT_EQ(i + 1, NumRunTasks()); - - // If Sequences returned by GetWork() contain more than one Task, they - // aren't empty after the worker pops Tasks from them and thus should be - // returned to EnqueueSequence(). - if (TasksPerSequence() > 1) - EXPECT_EQ(CreatedSequences(), EnqueuedSequences()); - else - EXPECT_TRUE(EnqueuedSequences().empty()); - } -} - -INSTANTIATE_TEST_CASE_P(OneTaskPerSequence, - TaskSchedulerWorkerTest, - ::testing::Values(1)); -INSTANTIATE_TEST_CASE_P(TwoTasksPerSequence, - TaskSchedulerWorkerTest, - ::testing::Values(2)); - -namespace { - -class ControllableCleanupDelegate : public SchedulerWorkerDefaultDelegate { - public: - class Controls : public RefCountedThreadSafe<Controls> { - public: - Controls() - : work_running_(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::SIGNALED), - work_processed_(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED), - cleanup_requested_(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED), - destroyed_(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED), - exited_(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED) {} - - void HaveWorkBlock() { work_running_.Reset(); } - - void UnblockWork() { work_running_.Signal(); } - - void WaitForWorkToRun() { work_processed_.Wait(); } - - void WaitForCleanupRequest() { cleanup_requested_.Wait(); } - - void WaitForDelegateDestroy() { destroyed_.Wait(); } - - void WaitForMainExit() { exited_.Wait(); } - - void set_expect_get_work(bool expect_get_work) { - expect_get_work_ = expect_get_work; - } - - void ResetState() { - work_running_.Signal(); - work_processed_.Reset(); - cleanup_requested_.Reset(); - exited_.Reset(); - work_requested_ = false; - } - - void set_can_cleanup(bool can_cleanup) { can_cleanup_ = can_cleanup; } - - private: - friend class ControllableCleanupDelegate; - friend class RefCountedThreadSafe<Controls>; - ~Controls() = default; - - WaitableEvent work_running_; - WaitableEvent work_processed_; - WaitableEvent cleanup_requested_; - WaitableEvent destroyed_; - WaitableEvent exited_; - - bool expect_get_work_ = true; - bool can_cleanup_ = false; - bool work_requested_ = false; - - DISALLOW_COPY_AND_ASSIGN(Controls); - }; - - ControllableCleanupDelegate(TaskTracker* task_tracker) - : task_tracker_(task_tracker), controls_(new Controls()) {} - - ~ControllableCleanupDelegate() override { controls_->destroyed_.Signal(); } - - scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) - override { - EXPECT_TRUE(controls_->expect_get_work_); - - // Sends one item of work to signal |work_processed_|. On subsequent calls, - // sends nullptr to indicate there's no more work to be done. - if (controls_->work_requested_) { - if (CanCleanup(worker)) { - OnCleanup(); - worker->Cleanup(); - controls_->set_expect_get_work(false); - } - return nullptr; - } - - controls_->work_requested_ = true; - scoped_refptr<Sequence> sequence(new Sequence); - Task task( - FROM_HERE, - BindOnce( - [](WaitableEvent* work_processed, WaitableEvent* work_running) { - work_processed->Signal(); - work_running->Wait(); - }, - Unretained(&controls_->work_processed_), - Unretained(&controls_->work_running_)), - {WithBaseSyncPrimitives(), TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, - TimeDelta()); - EXPECT_TRUE(task_tracker_->WillPostTask(task)); - sequence->PushTask(std::move(task)); - sequence = - task_tracker_->WillScheduleSequence(std::move(sequence), nullptr); - EXPECT_TRUE(sequence); - return sequence; - } - - void DidRunTask() override {} - - void OnMainExit(SchedulerWorker* worker) override { - controls_->exited_.Signal(); - } - - bool CanCleanup(SchedulerWorker* worker) { - // Saving |can_cleanup_| now so that callers waiting on |cleanup_requested_| - // have the thread go to sleep and then allow timing out. - bool can_cleanup = controls_->can_cleanup_; - controls_->cleanup_requested_.Signal(); - return can_cleanup; - } - - void OnCleanup() { - EXPECT_TRUE(controls_->can_cleanup_); - EXPECT_TRUE(controls_->cleanup_requested_.IsSignaled()); - } - - // ControllableCleanupDelegate: - scoped_refptr<Controls> controls() { return controls_; } - - private: - scoped_refptr<Sequence> work_sequence_; - TaskTracker* const task_tracker_; - scoped_refptr<Controls> controls_; - - DISALLOW_COPY_AND_ASSIGN(ControllableCleanupDelegate); -}; - -class MockedControllableCleanupDelegate : public ControllableCleanupDelegate { - public: - MockedControllableCleanupDelegate(TaskTracker* task_tracker) - : ControllableCleanupDelegate(task_tracker){}; - ~MockedControllableCleanupDelegate() override = default; - - // SchedulerWorker::Delegate: - MOCK_METHOD1(OnMainEntry, void(const SchedulerWorker* worker)); - - private: - DISALLOW_COPY_AND_ASSIGN(MockedControllableCleanupDelegate); -}; - -} // namespace - -// Verify that calling SchedulerWorker::Cleanup() from GetWork() causes -// the SchedulerWorker's thread to exit. -TEST(TaskSchedulerWorkerTest, WorkerCleanupFromGetWork) { - TaskTracker task_tracker("Test"); - // Will be owned by SchedulerWorker. - MockedControllableCleanupDelegate* delegate = - new StrictMock<MockedControllableCleanupDelegate>(&task_tracker); - scoped_refptr<ControllableCleanupDelegate::Controls> controls = - delegate->controls(); - controls->set_can_cleanup(true); - EXPECT_CALL(*delegate, OnMainEntry(_)); - auto worker = MakeRefCounted<SchedulerWorker>(ThreadPriority::NORMAL, - WrapUnique(delegate), - task_tracker.GetTrackedRef()); - worker->Start(); - worker->WakeUp(); - controls->WaitForWorkToRun(); - Mock::VerifyAndClear(delegate); - controls->WaitForMainExit(); -} - -TEST(TaskSchedulerWorkerTest, WorkerCleanupDuringWork) { - TaskTracker task_tracker("Test"); - // Will be owned by SchedulerWorker. - // No mock here as that's reasonably covered by other tests and the delegate - // may destroy on a different thread. Mocks aren't designed with that in mind. - std::unique_ptr<ControllableCleanupDelegate> delegate = - std::make_unique<ControllableCleanupDelegate>(&task_tracker); - scoped_refptr<ControllableCleanupDelegate::Controls> controls = - delegate->controls(); - - controls->HaveWorkBlock(); - - auto worker = MakeRefCounted<SchedulerWorker>(ThreadPriority::NORMAL, - std::move(delegate), - task_tracker.GetTrackedRef()); - worker->Start(); - worker->WakeUp(); - - controls->WaitForWorkToRun(); - worker->Cleanup(); - worker = nullptr; - controls->UnblockWork(); - controls->WaitForDelegateDestroy(); -} - -TEST(TaskSchedulerWorkerTest, WorkerCleanupDuringWait) { - TaskTracker task_tracker("Test"); - // Will be owned by SchedulerWorker. - // No mock here as that's reasonably covered by other tests and the delegate - // may destroy on a different thread. Mocks aren't designed with that in mind. - std::unique_ptr<ControllableCleanupDelegate> delegate = - std::make_unique<ControllableCleanupDelegate>(&task_tracker); - scoped_refptr<ControllableCleanupDelegate::Controls> controls = - delegate->controls(); - - auto worker = MakeRefCounted<SchedulerWorker>(ThreadPriority::NORMAL, - std::move(delegate), - task_tracker.GetTrackedRef()); - worker->Start(); - worker->WakeUp(); - - controls->WaitForCleanupRequest(); - worker->Cleanup(); - worker = nullptr; - controls->WaitForDelegateDestroy(); -} - -TEST(TaskSchedulerWorkerTest, WorkerCleanupDuringShutdown) { - TaskTracker task_tracker("Test"); - // Will be owned by SchedulerWorker. - // No mock here as that's reasonably covered by other tests and the delegate - // may destroy on a different thread. Mocks aren't designed with that in mind. - std::unique_ptr<ControllableCleanupDelegate> delegate = - std::make_unique<ControllableCleanupDelegate>(&task_tracker); - scoped_refptr<ControllableCleanupDelegate::Controls> controls = - delegate->controls(); - - controls->HaveWorkBlock(); - - auto worker = MakeRefCounted<SchedulerWorker>(ThreadPriority::NORMAL, - std::move(delegate), - task_tracker.GetTrackedRef()); - worker->Start(); - worker->WakeUp(); - - controls->WaitForWorkToRun(); - task_tracker.Shutdown(); - worker->Cleanup(); - worker = nullptr; - controls->UnblockWork(); - controls->WaitForDelegateDestroy(); -} - -// Verify that Start() is a no-op after Cleanup(). -TEST(TaskSchedulerWorkerTest, CleanupBeforeStart) { - TaskTracker task_tracker("Test"); - // Will be owned by SchedulerWorker. - // No mock here as that's reasonably covered by other tests and the delegate - // may destroy on a different thread. Mocks aren't designed with that in mind. - std::unique_ptr<ControllableCleanupDelegate> delegate = - std::make_unique<ControllableCleanupDelegate>(&task_tracker); - scoped_refptr<ControllableCleanupDelegate::Controls> controls = - delegate->controls(); - controls->set_expect_get_work(false); - - auto worker = MakeRefCounted<SchedulerWorker>(ThreadPriority::NORMAL, - std::move(delegate), - task_tracker.GetTrackedRef()); - - worker->Cleanup(); - worker->Start(); - - EXPECT_FALSE(worker->ThreadAliveForTesting()); -} - -namespace { - -class CallJoinFromDifferentThread : public SimpleThread { - public: - CallJoinFromDifferentThread(SchedulerWorker* worker_to_join) - : SimpleThread("SchedulerWorkerJoinThread"), - worker_to_join_(worker_to_join), - run_started_event_(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED) {} - - ~CallJoinFromDifferentThread() override = default; - - void Run() override { - run_started_event_.Signal(); - worker_to_join_->JoinForTesting(); - } - - void WaitForRunToStart() { run_started_event_.Wait(); } - - private: - SchedulerWorker* const worker_to_join_; - WaitableEvent run_started_event_; - DISALLOW_COPY_AND_ASSIGN(CallJoinFromDifferentThread); -}; - -} // namespace - -TEST(TaskSchedulerWorkerTest, WorkerCleanupDuringJoin) { - TaskTracker task_tracker("Test"); - // Will be owned by SchedulerWorker. - // No mock here as that's reasonably covered by other tests and the - // delegate may destroy on a different thread. Mocks aren't designed with that - // in mind. - std::unique_ptr<ControllableCleanupDelegate> delegate = - std::make_unique<ControllableCleanupDelegate>(&task_tracker); - scoped_refptr<ControllableCleanupDelegate::Controls> controls = - delegate->controls(); - - controls->HaveWorkBlock(); - - auto worker = MakeRefCounted<SchedulerWorker>(ThreadPriority::NORMAL, - std::move(delegate), - task_tracker.GetTrackedRef()); - worker->Start(); - worker->WakeUp(); - - controls->WaitForWorkToRun(); - CallJoinFromDifferentThread join_from_different_thread(worker.get()); - join_from_different_thread.Start(); - join_from_different_thread.WaitForRunToStart(); - // Sleep here to give the other thread a chance to call JoinForTesting(). - // Receiving a signal that Run() was called doesn't mean JoinForTesting() was - // necessarily called, and we can't signal after JoinForTesting() as - // JoinForTesting() blocks until we call UnblockWork(). - PlatformThread::Sleep(TestTimeouts::tiny_timeout()); - worker->Cleanup(); - worker = nullptr; - controls->UnblockWork(); - controls->WaitForDelegateDestroy(); - join_from_different_thread.Join(); -} - -namespace { - -class ExpectThreadPriorityDelegate : public SchedulerWorkerDefaultDelegate { - public: - ExpectThreadPriorityDelegate() - : priority_verified_in_get_work_event_( - WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED), - expected_thread_priority_(ThreadPriority::BACKGROUND) {} - - void SetExpectedThreadPriority(ThreadPriority expected_thread_priority) { - expected_thread_priority_ = expected_thread_priority; - } - - void WaitForPriorityVerifiedInGetWork() { - priority_verified_in_get_work_event_.Wait(); - } - - // SchedulerWorker::Delegate: - void OnMainEntry(const SchedulerWorker* worker) override { - VerifyThreadPriority(); - } - scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override { - VerifyThreadPriority(); - priority_verified_in_get_work_event_.Signal(); - return nullptr; - } - - private: - void VerifyThreadPriority() { - AutoSchedulerLock auto_lock(expected_thread_priority_lock_); - EXPECT_EQ(expected_thread_priority_, - PlatformThread::GetCurrentThreadPriority()); - } - - // Signaled after GetWork() has verified the priority of the worker thread. - WaitableEvent priority_verified_in_get_work_event_; - - // Synchronizes access to |expected_thread_priority_|. - SchedulerLock expected_thread_priority_lock_; - - // Expected thread priority for the next call to OnMainEntry() or GetWork(). - ThreadPriority expected_thread_priority_; - - DISALLOW_COPY_AND_ASSIGN(ExpectThreadPriorityDelegate); -}; - -} // namespace - -TEST(TaskSchedulerWorkerTest, BumpPriorityOfAliveThreadDuringShutdown) { - TaskTracker task_tracker("Test"); - - std::unique_ptr<ExpectThreadPriorityDelegate> delegate( - new ExpectThreadPriorityDelegate); - ExpectThreadPriorityDelegate* delegate_raw = delegate.get(); - delegate_raw->SetExpectedThreadPriority( - PlatformThread::CanIncreaseCurrentThreadPriority() - ? ThreadPriority::BACKGROUND - : ThreadPriority::NORMAL); - - auto worker = MakeRefCounted<SchedulerWorker>(ThreadPriority::BACKGROUND, - std::move(delegate), - task_tracker.GetTrackedRef()); - worker->Start(); - - // Verify that the initial thread priority is BACKGROUND (or NORMAL if thread - // priority can't be increased). - worker->WakeUp(); - delegate_raw->WaitForPriorityVerifiedInGetWork(); - - // Verify that the thread priority is bumped to NORMAL during shutdown. - delegate_raw->SetExpectedThreadPriority(ThreadPriority::NORMAL); - task_tracker.SetHasShutdownStartedForTesting(); - worker->WakeUp(); - delegate_raw->WaitForPriorityVerifiedInGetWork(); - - worker->JoinForTesting(); -} - -namespace { - -class VerifyCallsToObserverDelegate : public SchedulerWorkerDefaultDelegate { - public: - VerifyCallsToObserverDelegate(test::MockSchedulerWorkerObserver* observer) - : observer_(observer) {} - - // SchedulerWorker::Delegate: - void OnMainEntry(const SchedulerWorker* worker) override { - Mock::VerifyAndClear(observer_); - } - - void OnMainExit(SchedulerWorker* worker) override { - EXPECT_CALL(*observer_, OnSchedulerWorkerMainExit()); - } - - private: - test::MockSchedulerWorkerObserver* const observer_; - - DISALLOW_COPY_AND_ASSIGN(VerifyCallsToObserverDelegate); -}; - -} // namespace - -// Verify that the SchedulerWorkerObserver is notified when the worker enters -// and exits its main function. -TEST(TaskSchedulerWorkerTest, SchedulerWorkerObserver) { - StrictMock<test::MockSchedulerWorkerObserver> observer; - { - TaskTracker task_tracker("Test"); - auto delegate = std::make_unique<VerifyCallsToObserverDelegate>(&observer); - auto worker = MakeRefCounted<SchedulerWorker>(ThreadPriority::NORMAL, - std::move(delegate), - task_tracker.GetTrackedRef()); - - EXPECT_CALL(observer, OnSchedulerWorkerMainEntry()); - worker->Start(&observer); - worker->Cleanup(); - worker = nullptr; - } - Mock::VerifyAndClear(&observer); -} - -#if defined(OS_WIN) - -namespace { - -class CoInitializeDelegate : public SchedulerWorkerDefaultDelegate { - public: - CoInitializeDelegate() - : get_work_returned_(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED) {} - - scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override { - EXPECT_FALSE(get_work_returned_.IsSignaled()); - EXPECT_EQ(E_UNEXPECTED, coinitialize_hresult_); - - coinitialize_hresult_ = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); - if (SUCCEEDED(coinitialize_hresult_)) - CoUninitialize(); - - get_work_returned_.Signal(); - return nullptr; - } - - void WaitUntilGetWorkReturned() { get_work_returned_.Wait(); } - - HRESULT coinitialize_hresult() const { return coinitialize_hresult_; } - - private: - WaitableEvent get_work_returned_; - HRESULT coinitialize_hresult_ = E_UNEXPECTED; - - DISALLOW_COPY_AND_ASSIGN(CoInitializeDelegate); -}; - -} // namespace - -TEST(TaskSchedulerWorkerTest, BackwardCompatibilityEnabled) { - TaskTracker task_tracker("Test"); - auto delegate = std::make_unique<CoInitializeDelegate>(); - CoInitializeDelegate* const delegate_raw = delegate.get(); - - // Create a worker with backward compatibility ENABLED. Wake it up and wait - // until GetWork() returns. - auto worker = MakeRefCounted<SchedulerWorker>( - ThreadPriority::NORMAL, std::move(delegate), task_tracker.GetTrackedRef(), - nullptr, SchedulerBackwardCompatibility::INIT_COM_STA); - worker->Start(); - worker->WakeUp(); - delegate_raw->WaitUntilGetWorkReturned(); - - // The call to CoInitializeEx() should have returned S_FALSE to indicate that - // the COM library was already initialized on the thread. - // See SchedulerWorker::Thread::ThreadMain for why we expect two different - // results here. -#if defined(COM_INIT_CHECK_HOOK_ENABLED) - EXPECT_EQ(S_OK, delegate_raw->coinitialize_hresult()); -#else - EXPECT_EQ(S_FALSE, delegate_raw->coinitialize_hresult()); -#endif - - worker->JoinForTesting(); -} - -TEST(TaskSchedulerWorkerTest, BackwardCompatibilityDisabled) { - TaskTracker task_tracker("Test"); - auto delegate = std::make_unique<CoInitializeDelegate>(); - CoInitializeDelegate* const delegate_raw = delegate.get(); - - // Create a worker with backward compatibility DISABLED. Wake it up and wait - // until GetWork() returns. - auto worker = MakeRefCounted<SchedulerWorker>( - ThreadPriority::NORMAL, std::move(delegate), task_tracker.GetTrackedRef(), - nullptr, SchedulerBackwardCompatibility::DISABLED); - worker->Start(); - worker->WakeUp(); - delegate_raw->WaitUntilGetWorkReturned(); - - // The call to CoInitializeEx() should have returned S_OK to indicate that the - // COM library wasn't already initialized on the thread. - EXPECT_EQ(S_OK, delegate_raw->coinitialize_hresult()); - - worker->JoinForTesting(); -} - -#endif // defined(OS_WIN) - -} // namespace internal -} // namespace base
diff --git a/base/task_scheduler/scoped_set_task_priority_for_current_thread_unittest.cc b/base/task_scheduler/scoped_set_task_priority_for_current_thread_unittest.cc deleted file mode 100644 index c497af6..0000000 --- a/base/task_scheduler/scoped_set_task_priority_for_current_thread_unittest.cc +++ /dev/null
@@ -1,26 +0,0 @@ -// 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/task_scheduler/scoped_set_task_priority_for_current_thread.h" - -#include "base/task_scheduler/task_traits.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace internal { - -TEST(TaskSchedulerScopedSetTaskPriorityForCurrentThreadTest, - ScopedSetTaskPriorityForCurrentThread) { - EXPECT_EQ(TaskPriority::USER_VISIBLE, GetTaskPriorityForCurrentThread()); - { - ScopedSetTaskPriorityForCurrentThread - scoped_set_task_priority_for_current_thread( - TaskPriority::USER_BLOCKING); - EXPECT_EQ(TaskPriority::USER_BLOCKING, GetTaskPriorityForCurrentThread()); - } - EXPECT_EQ(TaskPriority::USER_VISIBLE, GetTaskPriorityForCurrentThread()); -} - -} // namespace internal -} // namespace base
diff --git a/base/task_scheduler/sequence_sort_key_unittest.cc b/base/task_scheduler/sequence_sort_key_unittest.cc deleted file mode 100644 index 2c1d80d..0000000 --- a/base/task_scheduler/sequence_sort_key_unittest.cc +++ /dev/null
@@ -1,243 +0,0 @@ -// 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/task_scheduler/sequence_sort_key.h" - -#include "base/task_scheduler/task_traits.h" -#include "base/time/time.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace internal { - -TEST(TaskSchedulerSequenceSortKeyTest, OperatorLessThan) { - SequenceSortKey key_a(TaskPriority::USER_BLOCKING, - TimeTicks::FromInternalValue(1000)); - SequenceSortKey key_b(TaskPriority::USER_BLOCKING, - TimeTicks::FromInternalValue(2000)); - SequenceSortKey key_c(TaskPriority::USER_VISIBLE, - TimeTicks::FromInternalValue(1000)); - SequenceSortKey key_d(TaskPriority::USER_VISIBLE, - TimeTicks::FromInternalValue(2000)); - SequenceSortKey key_e(TaskPriority::BACKGROUND, - TimeTicks::FromInternalValue(1000)); - SequenceSortKey key_f(TaskPriority::BACKGROUND, - TimeTicks::FromInternalValue(2000)); - - EXPECT_FALSE(key_a < key_a); - EXPECT_LT(key_b, key_a); - EXPECT_LT(key_c, key_a); - EXPECT_LT(key_d, key_a); - EXPECT_LT(key_e, key_a); - EXPECT_LT(key_f, key_a); - - EXPECT_FALSE(key_a < key_b); - EXPECT_FALSE(key_b < key_b); - EXPECT_LT(key_c, key_b); - EXPECT_LT(key_d, key_b); - EXPECT_LT(key_e, key_b); - EXPECT_LT(key_f, key_b); - - EXPECT_FALSE(key_a < key_c); - EXPECT_FALSE(key_b < key_c); - EXPECT_FALSE(key_c < key_c); - EXPECT_LT(key_d, key_c); - EXPECT_LT(key_e, key_c); - EXPECT_LT(key_f, key_c); - - EXPECT_FALSE(key_a < key_d); - EXPECT_FALSE(key_b < key_d); - EXPECT_FALSE(key_c < key_d); - EXPECT_FALSE(key_d < key_d); - EXPECT_LT(key_e, key_d); - EXPECT_LT(key_f, key_d); - - EXPECT_FALSE(key_a < key_e); - EXPECT_FALSE(key_b < key_e); - EXPECT_FALSE(key_c < key_e); - EXPECT_FALSE(key_d < key_e); - EXPECT_FALSE(key_e < key_e); - EXPECT_LT(key_f, key_e); - - EXPECT_FALSE(key_a < key_f); - EXPECT_FALSE(key_b < key_f); - EXPECT_FALSE(key_c < key_f); - EXPECT_FALSE(key_d < key_f); - EXPECT_FALSE(key_e < key_f); - EXPECT_FALSE(key_f < key_f); -} - -TEST(TaskSchedulerSequenceSortKeyTest, OperatorGreaterThan) { - SequenceSortKey key_a(TaskPriority::USER_BLOCKING, - TimeTicks::FromInternalValue(1000)); - SequenceSortKey key_b(TaskPriority::USER_BLOCKING, - TimeTicks::FromInternalValue(2000)); - SequenceSortKey key_c(TaskPriority::USER_VISIBLE, - TimeTicks::FromInternalValue(1000)); - SequenceSortKey key_d(TaskPriority::USER_VISIBLE, - TimeTicks::FromInternalValue(2000)); - SequenceSortKey key_e(TaskPriority::BACKGROUND, - TimeTicks::FromInternalValue(1000)); - SequenceSortKey key_f(TaskPriority::BACKGROUND, - TimeTicks::FromInternalValue(2000)); - - EXPECT_FALSE(key_a > key_a); - EXPECT_FALSE(key_b > key_a); - EXPECT_FALSE(key_c > key_a); - EXPECT_FALSE(key_d > key_a); - EXPECT_FALSE(key_e > key_a); - EXPECT_FALSE(key_f > key_a); - - EXPECT_GT(key_a, key_b); - EXPECT_FALSE(key_b > key_b); - EXPECT_FALSE(key_c > key_b); - EXPECT_FALSE(key_d > key_b); - EXPECT_FALSE(key_e > key_b); - EXPECT_FALSE(key_f > key_b); - - EXPECT_GT(key_a, key_c); - EXPECT_GT(key_b, key_c); - EXPECT_FALSE(key_c > key_c); - EXPECT_FALSE(key_d > key_c); - EXPECT_FALSE(key_e > key_c); - EXPECT_FALSE(key_f > key_c); - - EXPECT_GT(key_a, key_d); - EXPECT_GT(key_b, key_d); - EXPECT_GT(key_c, key_d); - EXPECT_FALSE(key_d > key_d); - EXPECT_FALSE(key_e > key_d); - EXPECT_FALSE(key_f > key_d); - - EXPECT_GT(key_a, key_e); - EXPECT_GT(key_b, key_e); - EXPECT_GT(key_c, key_e); - EXPECT_GT(key_d, key_e); - EXPECT_FALSE(key_e > key_e); - EXPECT_FALSE(key_f > key_e); - - EXPECT_GT(key_a, key_f); - EXPECT_GT(key_b, key_f); - EXPECT_GT(key_c, key_f); - EXPECT_GT(key_d, key_f); - EXPECT_GT(key_e, key_f); - EXPECT_FALSE(key_f > key_f); -} - -TEST(TaskSchedulerSequenceSortKeyTest, OperatorEqual) { - SequenceSortKey key_a(TaskPriority::USER_BLOCKING, - TimeTicks::FromInternalValue(1000)); - SequenceSortKey key_b(TaskPriority::USER_BLOCKING, - TimeTicks::FromInternalValue(2000)); - SequenceSortKey key_c(TaskPriority::USER_VISIBLE, - TimeTicks::FromInternalValue(1000)); - SequenceSortKey key_d(TaskPriority::USER_VISIBLE, - TimeTicks::FromInternalValue(2000)); - SequenceSortKey key_e(TaskPriority::BACKGROUND, - TimeTicks::FromInternalValue(1000)); - SequenceSortKey key_f(TaskPriority::BACKGROUND, - TimeTicks::FromInternalValue(2000)); - - EXPECT_EQ(key_a, key_a); - EXPECT_FALSE(key_b == key_a); - EXPECT_FALSE(key_c == key_a); - EXPECT_FALSE(key_d == key_a); - EXPECT_FALSE(key_e == key_a); - EXPECT_FALSE(key_f == key_a); - - EXPECT_FALSE(key_a == key_b); - EXPECT_EQ(key_b, key_b); - EXPECT_FALSE(key_c == key_b); - EXPECT_FALSE(key_d == key_b); - EXPECT_FALSE(key_e == key_b); - EXPECT_FALSE(key_f == key_b); - - EXPECT_FALSE(key_a == key_c); - EXPECT_FALSE(key_b == key_c); - EXPECT_EQ(key_c, key_c); - EXPECT_FALSE(key_d == key_c); - EXPECT_FALSE(key_e == key_c); - EXPECT_FALSE(key_f == key_c); - - EXPECT_FALSE(key_a == key_d); - EXPECT_FALSE(key_b == key_d); - EXPECT_FALSE(key_c == key_d); - EXPECT_EQ(key_d, key_d); - EXPECT_FALSE(key_e == key_d); - EXPECT_FALSE(key_f == key_d); - - EXPECT_FALSE(key_a == key_e); - EXPECT_FALSE(key_b == key_e); - EXPECT_FALSE(key_c == key_e); - EXPECT_FALSE(key_d == key_e); - EXPECT_EQ(key_e, key_e); - EXPECT_FALSE(key_f == key_e); - - EXPECT_FALSE(key_a == key_f); - EXPECT_FALSE(key_b == key_f); - EXPECT_FALSE(key_c == key_f); - EXPECT_FALSE(key_d == key_f); - EXPECT_FALSE(key_e == key_f); - EXPECT_EQ(key_f, key_f); -} - -TEST(TaskSchedulerSequenceSortKeyTest, OperatorNotEqual) { - SequenceSortKey key_a(TaskPriority::USER_BLOCKING, - TimeTicks::FromInternalValue(1000)); - SequenceSortKey key_b(TaskPriority::USER_BLOCKING, - TimeTicks::FromInternalValue(2000)); - SequenceSortKey key_c(TaskPriority::USER_VISIBLE, - TimeTicks::FromInternalValue(1000)); - SequenceSortKey key_d(TaskPriority::USER_VISIBLE, - TimeTicks::FromInternalValue(2000)); - SequenceSortKey key_e(TaskPriority::BACKGROUND, - TimeTicks::FromInternalValue(1000)); - SequenceSortKey key_f(TaskPriority::BACKGROUND, - TimeTicks::FromInternalValue(2000)); - - EXPECT_FALSE(key_a != key_a); - EXPECT_NE(key_b, key_a); - EXPECT_NE(key_c, key_a); - EXPECT_NE(key_d, key_a); - EXPECT_NE(key_e, key_a); - EXPECT_NE(key_f, key_a); - - EXPECT_NE(key_a, key_b); - EXPECT_FALSE(key_b != key_b); - EXPECT_NE(key_c, key_b); - EXPECT_NE(key_d, key_b); - EXPECT_NE(key_e, key_b); - EXPECT_NE(key_f, key_b); - - EXPECT_NE(key_a, key_c); - EXPECT_NE(key_b, key_c); - EXPECT_FALSE(key_c != key_c); - EXPECT_NE(key_d, key_c); - EXPECT_NE(key_e, key_c); - EXPECT_NE(key_f, key_c); - - EXPECT_NE(key_a, key_d); - EXPECT_NE(key_b, key_d); - EXPECT_NE(key_c, key_d); - EXPECT_FALSE(key_d != key_d); - EXPECT_NE(key_e, key_d); - EXPECT_NE(key_f, key_d); - - EXPECT_NE(key_a, key_e); - EXPECT_NE(key_b, key_e); - EXPECT_NE(key_c, key_e); - EXPECT_NE(key_d, key_e); - EXPECT_FALSE(key_e != key_e); - EXPECT_NE(key_f, key_e); - - EXPECT_NE(key_a, key_f); - EXPECT_NE(key_b, key_f); - EXPECT_NE(key_c, key_f); - EXPECT_NE(key_d, key_f); - EXPECT_NE(key_e, key_f); - EXPECT_FALSE(key_f != key_f); -} - -} // namespace internal -} // namespace base
diff --git a/base/task_scheduler/sequence_unittest.cc b/base/task_scheduler/sequence_unittest.cc deleted file mode 100644 index 86d1547..0000000 --- a/base/task_scheduler/sequence_unittest.cc +++ /dev/null
@@ -1,172 +0,0 @@ -// 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/task_scheduler/sequence.h" - -#include <utility> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/memory/ptr_util.h" -#include "base/test/gtest_util.h" -#include "base/time/time.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace internal { - -namespace { - -class MockTask { - public: - MOCK_METHOD0(Run, void()); -}; - -Task CreateTask(MockTask* mock_task) { - return Task(FROM_HERE, BindOnce(&MockTask::Run, Unretained(mock_task)), - {TaskPriority::BACKGROUND}, TimeDelta()); -} - -void ExpectMockTask(MockTask* mock_task, Task* task) { - EXPECT_CALL(*mock_task, Run()); - std::move(task->task).Run(); - testing::Mock::VerifyAndClear(mock_task); -} - -} // namespace - -TEST(TaskSchedulerSequenceTest, PushTakeRemove) { - testing::StrictMock<MockTask> mock_task_a; - testing::StrictMock<MockTask> mock_task_b; - testing::StrictMock<MockTask> mock_task_c; - testing::StrictMock<MockTask> mock_task_d; - testing::StrictMock<MockTask> mock_task_e; - - scoped_refptr<Sequence> sequence = MakeRefCounted<Sequence>(); - - // Push task A in the sequence. PushTask() should return true since it's the - // first task-> - EXPECT_TRUE(sequence->PushTask(CreateTask(&mock_task_a))); - - // Push task B, C and D in the sequence. PushTask() should return false since - // there is already a task in a sequence. - EXPECT_FALSE(sequence->PushTask(CreateTask(&mock_task_b))); - EXPECT_FALSE(sequence->PushTask(CreateTask(&mock_task_c))); - EXPECT_FALSE(sequence->PushTask(CreateTask(&mock_task_d))); - - // Take the task in front of the sequence. It should be task A. - Optional<Task> task = sequence->TakeTask(); - ExpectMockTask(&mock_task_a, &task.value()); - EXPECT_FALSE(task->sequenced_time.is_null()); - - // Remove the empty slot. Task B should now be in front. - EXPECT_FALSE(sequence->Pop()); - task = sequence->TakeTask(); - ExpectMockTask(&mock_task_b, &task.value()); - EXPECT_FALSE(task->sequenced_time.is_null()); - - // Remove the empty slot. Task C should now be in front. - EXPECT_FALSE(sequence->Pop()); - task = sequence->TakeTask(); - ExpectMockTask(&mock_task_c, &task.value()); - EXPECT_FALSE(task->sequenced_time.is_null()); - - // Remove the empty slot. - EXPECT_FALSE(sequence->Pop()); - - // Push task E in the sequence. - EXPECT_FALSE(sequence->PushTask(CreateTask(&mock_task_e))); - - // Task D should be in front. - task = sequence->TakeTask(); - ExpectMockTask(&mock_task_d, &task.value()); - EXPECT_FALSE(task->sequenced_time.is_null()); - - // Remove the empty slot. Task E should now be in front. - EXPECT_FALSE(sequence->Pop()); - task = sequence->TakeTask(); - ExpectMockTask(&mock_task_e, &task.value()); - EXPECT_FALSE(task->sequenced_time.is_null()); - - // Remove the empty slot. The sequence should now be empty. - EXPECT_TRUE(sequence->Pop()); -} - -// Verifies the sort key of a sequence that contains one BACKGROUND task. -TEST(TaskSchedulerSequenceTest, GetSortKeyBackground) { - // Create a sequence with a BACKGROUND task. - Task background_task(FROM_HERE, DoNothing(), {TaskPriority::BACKGROUND}, - TimeDelta()); - scoped_refptr<Sequence> background_sequence = MakeRefCounted<Sequence>(); - background_sequence->PushTask(std::move(background_task)); - - // Get the sort key. - const SequenceSortKey background_sort_key = background_sequence->GetSortKey(); - - // Take the task from the sequence, so that its sequenced time is available - // for the check below. - auto take_background_task = background_sequence->TakeTask(); - - // Verify the sort key. - EXPECT_EQ(TaskPriority::BACKGROUND, background_sort_key.priority()); - EXPECT_EQ(take_background_task->sequenced_time, - background_sort_key.next_task_sequenced_time()); - - // Pop for correctness. - background_sequence->Pop(); -} - -// Same as TaskSchedulerSequenceTest.GetSortKeyBackground, but with a -// USER_VISIBLE task. -TEST(TaskSchedulerSequenceTest, GetSortKeyForeground) { - // Create a sequence with a USER_VISIBLE task. - Task foreground_task(FROM_HERE, DoNothing(), {TaskPriority::USER_VISIBLE}, - TimeDelta()); - scoped_refptr<Sequence> foreground_sequence = MakeRefCounted<Sequence>(); - foreground_sequence->PushTask(std::move(foreground_task)); - - // Get the sort key. - const SequenceSortKey foreground_sort_key = foreground_sequence->GetSortKey(); - - // Take the task from the sequence, so that its sequenced time is available - // for the check below. - auto take_foreground_task = foreground_sequence->TakeTask(); - - // Verify the sort key. - EXPECT_EQ(TaskPriority::USER_VISIBLE, foreground_sort_key.priority()); - EXPECT_EQ(take_foreground_task->sequenced_time, - foreground_sort_key.next_task_sequenced_time()); - - // Pop for correctness. - foreground_sequence->Pop(); -} - -// Verify that a DCHECK fires if Pop() is called on a sequence whose front slot -// isn't empty. -TEST(TaskSchedulerSequenceTest, PopNonEmptyFrontSlot) { - scoped_refptr<Sequence> sequence = MakeRefCounted<Sequence>(); - sequence->PushTask(Task(FROM_HERE, DoNothing(), TaskTraits(), TimeDelta())); - - EXPECT_DCHECK_DEATH({ sequence->Pop(); }); -} - -// Verify that a DCHECK fires if TakeTask() is called on a sequence whose front -// slot is empty. -TEST(TaskSchedulerSequenceTest, TakeEmptyFrontSlot) { - scoped_refptr<Sequence> sequence = MakeRefCounted<Sequence>(); - sequence->PushTask(Task(FROM_HERE, DoNothing(), TaskTraits(), TimeDelta())); - - EXPECT_TRUE(sequence->TakeTask()); - EXPECT_DCHECK_DEATH({ sequence->TakeTask(); }); -} - -// Verify that a DCHECK fires if TakeTask() is called on an empty sequence. -TEST(TaskSchedulerSequenceTest, TakeEmptySequence) { - scoped_refptr<Sequence> sequence = MakeRefCounted<Sequence>(); - EXPECT_DCHECK_DEATH({ sequence->TakeTask(); }); -} - -} // namespace internal -} // namespace base
diff --git a/base/task_scheduler/service_thread_unittest.cc b/base/task_scheduler/service_thread_unittest.cc deleted file mode 100644 index df4d8d6..0000000 --- a/base/task_scheduler/service_thread_unittest.cc +++ /dev/null
@@ -1,96 +0,0 @@ -// 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/task_scheduler/service_thread.h" - -#include <string> - -#include "base/bind.h" -#include "base/debug/stack_trace.h" -#include "base/task_scheduler/task_scheduler.h" -#include "base/task_scheduler/task_scheduler_impl.h" -#include "base/test/histogram_tester.h" -#include "base/threading/platform_thread.h" -#include "base/time/time.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace internal { - -namespace { - -// Verifies that |query| is found on the current stack. Ignores failures if this -// configuration doesn't have symbols. -void VerifyHasStringOnStack(const std::string& query) { - const std::string stack = debug::StackTrace().ToString(); - SCOPED_TRACE(stack); - const bool found_on_stack = stack.find(query) != std::string::npos; - const bool stack_has_symbols = - stack.find("SchedulerWorker") != std::string::npos; - EXPECT_TRUE(found_on_stack || !stack_has_symbols) << query; -} - -} // namespace - -#if defined(OS_POSIX) -// Many POSIX bots flakily crash on |debug::StackTrace().ToString()|, -// https://crbug.com/840429. -#define MAYBE_StackHasIdentifyingFrame DISABLED_StackHasIdentifyingFrame -#else -#define MAYBE_StackHasIdentifyingFrame StackHasIdentifyingFrame -#endif - -TEST(TaskSchedulerServiceThreadTest, MAYBE_StackHasIdentifyingFrame) { - ServiceThread service_thread(nullptr); - service_thread.Start(); - - service_thread.task_runner()->PostTask( - FROM_HERE, BindOnce(&VerifyHasStringOnStack, "ServiceThread")); - - service_thread.FlushForTesting(); -} - -// Integration test verifying that a service thread running in a fully -// integrated TaskScheduler environment results in reporting -// HeartbeatLatencyMicroseconds metrics. -TEST(TaskSchedulerServiceThreadIntegrationTest, HeartbeatLatencyReport) { - TaskScheduler::SetInstance( - std::make_unique<internal::TaskSchedulerImpl>("Test")); - TaskScheduler::GetInstance()->StartWithDefaultParams(); - - static constexpr const char* kExpectedMetrics[] = { - "TaskScheduler.HeartbeatLatencyMicroseconds.Test." - "UserBlockingTaskPriority", - "TaskScheduler.HeartbeatLatencyMicroseconds.Test." - "UserBlockingTaskPriority_MayBlock", - "TaskScheduler.HeartbeatLatencyMicroseconds.Test." - "UserVisibleTaskPriority", - "TaskScheduler.HeartbeatLatencyMicroseconds.Test." - "UserVisibleTaskPriority_MayBlock", - "TaskScheduler.HeartbeatLatencyMicroseconds.Test." - "BackgroundTaskPriority", - "TaskScheduler.HeartbeatLatencyMicroseconds.Test." - "BackgroundTaskPriority_MayBlock"}; - - constexpr TimeDelta kReasonableTimeout = TimeDelta::FromSeconds(6); - constexpr TimeDelta kBusyWaitTime = TimeDelta::FromMilliseconds(100); - - const TimeTicks start_time = TimeTicks::Now(); - - HistogramTester tester; - for (const char* expected_metric : kExpectedMetrics) { - for (int i = 0; tester.GetAllSamples(expected_metric).empty(); ++i) { - if (TimeTicks::Now() - start_time > kReasonableTimeout) - LOG(WARNING) << "Waiting a while for " << expected_metric; - PlatformThread::Sleep(kBusyWaitTime); - } - } - - TaskScheduler::GetInstance()->JoinForTesting(); - TaskScheduler::SetInstance(nullptr); -} - -} // namespace internal -} // namespace base
diff --git a/base/task_scheduler/task_scheduler_impl_unittest.cc b/base/task_scheduler/task_scheduler_impl_unittest.cc deleted file mode 100644 index 6eee033..0000000 --- a/base/task_scheduler/task_scheduler_impl_unittest.cc +++ /dev/null
@@ -1,823 +0,0 @@ -// 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/task_scheduler/task_scheduler_impl.h" - -#include <stddef.h> - -#include <string> -#include <utility> -#include <vector> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/callback.h" -#include "base/debug/stack_trace.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/metrics/field_trial.h" -#include "base/metrics/field_trial_params.h" -#include "base/synchronization/lock.h" -#include "base/synchronization/waitable_event.h" -#include "base/task_scheduler/scheduler_worker_observer.h" -#include "base/task_scheduler/scheduler_worker_pool_params.h" -#include "base/task_scheduler/task_traits.h" -#include "base/task_scheduler/test_task_factory.h" -#include "base/task_scheduler/test_utils.h" -#include "base/test/test_timeouts.h" -#include "base/threading/platform_thread.h" -#include "base/threading/sequence_local_storage_slot.h" -#include "base/threading/simple_thread.h" -#include "base/threading/thread.h" -#include "base/threading/thread_restrictions.h" -#include "base/time/time.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(OS_POSIX) -#include <unistd.h> - -#include "base/debug/leak_annotations.h" -#include "base/files/file_descriptor_watcher_posix.h" -#include "base/files/file_util.h" -#include "base/posix/eintr_wrapper.h" -#endif // defined(OS_POSIX) - -#if defined(OS_WIN) -#include "base/win/com_init_util.h" -#endif // defined(OS_WIN) - -namespace base { -namespace internal { - -namespace { - -struct TraitsExecutionModePair { - TraitsExecutionModePair(const TaskTraits& traits, - test::ExecutionMode execution_mode) - : traits(traits), execution_mode(execution_mode) {} - - TaskTraits traits; - test::ExecutionMode execution_mode; -}; - -#if DCHECK_IS_ON() -// Returns whether I/O calls are allowed on the current thread. -bool GetIOAllowed() { - const bool previous_value = ThreadRestrictions::SetIOAllowed(true); - ThreadRestrictions::SetIOAllowed(previous_value); - return previous_value; -} -#endif - -// Verify that the current thread priority and I/O restrictions are appropriate -// to run a Task with |traits|. -// Note: ExecutionMode is verified inside TestTaskFactory. -void VerifyTaskEnvironment(const TaskTraits& traits) { - const bool supports_background_priority = - Lock::HandlesMultipleThreadPriorities() && - PlatformThread::CanIncreaseCurrentThreadPriority(); - - EXPECT_EQ(supports_background_priority && - traits.priority() == TaskPriority::BACKGROUND - ? ThreadPriority::BACKGROUND - : ThreadPriority::NORMAL, - PlatformThread::GetCurrentThreadPriority()); - -#if DCHECK_IS_ON() - // The #if above is required because GetIOAllowed() always returns true when - // !DCHECK_IS_ON(), even when |traits| don't allow file I/O. - EXPECT_EQ(traits.may_block(), GetIOAllowed()); -#endif - - // Verify that the thread the task is running on is named as expected. - const std::string current_thread_name(PlatformThread::GetName()); - EXPECT_NE(std::string::npos, current_thread_name.find("TaskScheduler")); - EXPECT_NE(std::string::npos, - current_thread_name.find( - traits.priority() == TaskPriority::BACKGROUND ? "Background" - : "Foreground")); - EXPECT_EQ(traits.may_block(), - current_thread_name.find("Blocking") != std::string::npos); -} - -void VerifyTaskEnvironmentAndSignalEvent(const TaskTraits& traits, - WaitableEvent* event) { - DCHECK(event); - VerifyTaskEnvironment(traits); - event->Signal(); -} - -void VerifyTimeAndTaskEnvironmentAndSignalEvent(const TaskTraits& traits, - TimeTicks expected_time, - WaitableEvent* event) { - DCHECK(event); - EXPECT_LE(expected_time, TimeTicks::Now()); - VerifyTaskEnvironment(traits); - event->Signal(); -} - -scoped_refptr<TaskRunner> CreateTaskRunnerWithTraitsAndExecutionMode( - TaskScheduler* scheduler, - const TaskTraits& traits, - test::ExecutionMode execution_mode, - SingleThreadTaskRunnerThreadMode default_single_thread_task_runner_mode = - SingleThreadTaskRunnerThreadMode::SHARED) { - switch (execution_mode) { - case test::ExecutionMode::PARALLEL: - return scheduler->CreateTaskRunnerWithTraits(traits); - case test::ExecutionMode::SEQUENCED: - return scheduler->CreateSequencedTaskRunnerWithTraits(traits); - case test::ExecutionMode::SINGLE_THREADED: { - return scheduler->CreateSingleThreadTaskRunnerWithTraits( - traits, default_single_thread_task_runner_mode); - } - } - ADD_FAILURE() << "Unknown ExecutionMode"; - return nullptr; -} - -class ThreadPostingTasks : public SimpleThread { - public: - // Creates a thread that posts Tasks to |scheduler| with |traits| and - // |execution_mode|. - ThreadPostingTasks(TaskSchedulerImpl* scheduler, - const TaskTraits& traits, - test::ExecutionMode execution_mode) - : SimpleThread("ThreadPostingTasks"), - traits_(traits), - factory_(CreateTaskRunnerWithTraitsAndExecutionMode(scheduler, - traits, - execution_mode), - execution_mode) {} - - void WaitForAllTasksToRun() { factory_.WaitForAllTasksToRun(); } - - private: - void Run() override { - EXPECT_FALSE(factory_.task_runner()->RunsTasksInCurrentSequence()); - - const size_t kNumTasksPerThread = 150; - for (size_t i = 0; i < kNumTasksPerThread; ++i) { - factory_.PostTask(test::TestTaskFactory::PostNestedTask::NO, - Bind(&VerifyTaskEnvironment, traits_)); - } - } - - const TaskTraits traits_; - test::TestTaskFactory factory_; - - DISALLOW_COPY_AND_ASSIGN(ThreadPostingTasks); -}; - -// Returns a vector with a TraitsExecutionModePair for each valid -// combination of {ExecutionMode, TaskPriority, MayBlock()}. -std::vector<TraitsExecutionModePair> GetTraitsExecutionModePairs() { - std::vector<TraitsExecutionModePair> params; - - const test::ExecutionMode execution_modes[] = { - test::ExecutionMode::PARALLEL, test::ExecutionMode::SEQUENCED, - test::ExecutionMode::SINGLE_THREADED}; - - for (test::ExecutionMode execution_mode : execution_modes) { - for (size_t priority_index = static_cast<size_t>(TaskPriority::LOWEST); - priority_index <= static_cast<size_t>(TaskPriority::HIGHEST); - ++priority_index) { - const TaskPriority priority = static_cast<TaskPriority>(priority_index); - params.push_back(TraitsExecutionModePair({priority}, execution_mode)); - params.push_back(TraitsExecutionModePair({MayBlock()}, execution_mode)); - } - } - - return params; -} - -class TaskSchedulerImplTest - : public testing::TestWithParam<TraitsExecutionModePair> { - protected: - TaskSchedulerImplTest() : scheduler_("Test"), field_trial_list_(nullptr) {} - - void EnableAllTasksUserBlocking() { - constexpr char kFieldTrialName[] = "BrowserScheduler"; - constexpr char kFieldTrialTestGroup[] = "DummyGroup"; - std::map<std::string, std::string> variation_params; - variation_params["AllTasksUserBlocking"] = "true"; - base::AssociateFieldTrialParams(kFieldTrialName, kFieldTrialTestGroup, - variation_params); - base::FieldTrialList::CreateFieldTrial(kFieldTrialName, - kFieldTrialTestGroup); - } - - void set_scheduler_worker_observer( - SchedulerWorkerObserver* scheduler_worker_observer) { - scheduler_worker_observer_ = scheduler_worker_observer; - } - - void StartTaskScheduler() { - constexpr TimeDelta kSuggestedReclaimTime = TimeDelta::FromSeconds(30); - constexpr int kMaxNumBackgroundThreads = 1; - constexpr int kMaxNumBackgroundBlockingThreads = 3; - constexpr int kMaxNumForegroundThreads = 4; - constexpr int kMaxNumForegroundBlockingThreads = 12; - - scheduler_.Start( - {{kMaxNumBackgroundThreads, kSuggestedReclaimTime}, - {kMaxNumBackgroundBlockingThreads, kSuggestedReclaimTime}, - {kMaxNumForegroundThreads, kSuggestedReclaimTime}, - {kMaxNumForegroundBlockingThreads, kSuggestedReclaimTime}}, - scheduler_worker_observer_); - } - - void TearDown() override { - if (did_tear_down_) - return; - - scheduler_.FlushForTesting(); - scheduler_.JoinForTesting(); - did_tear_down_ = true; - } - - TaskSchedulerImpl scheduler_; - - private: - base::FieldTrialList field_trial_list_; - SchedulerWorkerObserver* scheduler_worker_observer_ = nullptr; - bool did_tear_down_ = false; - - DISALLOW_COPY_AND_ASSIGN(TaskSchedulerImplTest); -}; - -} // namespace - -// Verifies that a Task posted via PostDelayedTaskWithTraits with parameterized -// TaskTraits and no delay runs on a thread with the expected priority and I/O -// restrictions. The ExecutionMode parameter is ignored by this test. -TEST_P(TaskSchedulerImplTest, PostDelayedTaskWithTraitsNoDelay) { - StartTaskScheduler(); - WaitableEvent task_ran(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - scheduler_.PostDelayedTaskWithTraits( - FROM_HERE, GetParam().traits, - BindOnce(&VerifyTaskEnvironmentAndSignalEvent, GetParam().traits, - Unretained(&task_ran)), - TimeDelta()); - task_ran.Wait(); -} - -// Verifies that a Task posted via PostDelayedTaskWithTraits with parameterized -// TaskTraits and a non-zero delay runs on a thread with the expected priority -// and I/O restrictions after the delay expires. The ExecutionMode parameter is -// ignored by this test. -TEST_P(TaskSchedulerImplTest, PostDelayedTaskWithTraitsWithDelay) { - StartTaskScheduler(); - WaitableEvent task_ran(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - scheduler_.PostDelayedTaskWithTraits( - FROM_HERE, GetParam().traits, - BindOnce(&VerifyTimeAndTaskEnvironmentAndSignalEvent, GetParam().traits, - TimeTicks::Now() + TestTimeouts::tiny_timeout(), - Unretained(&task_ran)), - TestTimeouts::tiny_timeout()); - task_ran.Wait(); -} - -// Verifies that Tasks posted via a TaskRunner with parameterized TaskTraits and -// ExecutionMode run on a thread with the expected priority and I/O restrictions -// and respect the characteristics of their ExecutionMode. -TEST_P(TaskSchedulerImplTest, PostTasksViaTaskRunner) { - StartTaskScheduler(); - test::TestTaskFactory factory( - CreateTaskRunnerWithTraitsAndExecutionMode(&scheduler_, GetParam().traits, - GetParam().execution_mode), - GetParam().execution_mode); - EXPECT_FALSE(factory.task_runner()->RunsTasksInCurrentSequence()); - - const size_t kNumTasksPerTest = 150; - for (size_t i = 0; i < kNumTasksPerTest; ++i) { - factory.PostTask(test::TestTaskFactory::PostNestedTask::NO, - Bind(&VerifyTaskEnvironment, GetParam().traits)); - } - - factory.WaitForAllTasksToRun(); -} - -// Verifies that a task posted via PostDelayedTaskWithTraits without a delay -// doesn't run before Start() is called. -TEST_P(TaskSchedulerImplTest, PostDelayedTaskWithTraitsNoDelayBeforeStart) { - WaitableEvent task_running(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - scheduler_.PostDelayedTaskWithTraits( - FROM_HERE, GetParam().traits, - BindOnce(&VerifyTaskEnvironmentAndSignalEvent, GetParam().traits, - Unretained(&task_running)), - TimeDelta()); - - // Wait a little bit to make sure that the task doesn't run before Start(). - // Note: This test won't catch a case where the task runs just after the check - // and before Start(). However, we expect the test to be flaky if the tested - // code allows that to happen. - PlatformThread::Sleep(TestTimeouts::tiny_timeout()); - EXPECT_FALSE(task_running.IsSignaled()); - - StartTaskScheduler(); - task_running.Wait(); -} - -// Verifies that a task posted via PostDelayedTaskWithTraits with a delay -// doesn't run before Start() is called. -TEST_P(TaskSchedulerImplTest, PostDelayedTaskWithTraitsWithDelayBeforeStart) { - WaitableEvent task_running(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - scheduler_.PostDelayedTaskWithTraits( - FROM_HERE, GetParam().traits, - BindOnce(&VerifyTimeAndTaskEnvironmentAndSignalEvent, GetParam().traits, - TimeTicks::Now() + TestTimeouts::tiny_timeout(), - Unretained(&task_running)), - TestTimeouts::tiny_timeout()); - - // Wait a little bit to make sure that the task doesn't run before Start(). - // Note: This test won't catch a case where the task runs just after the check - // and before Start(). However, we expect the test to be flaky if the tested - // code allows that to happen. - PlatformThread::Sleep(TestTimeouts::tiny_timeout()); - EXPECT_FALSE(task_running.IsSignaled()); - - StartTaskScheduler(); - task_running.Wait(); -} - -// Verifies that a task posted via a TaskRunner doesn't run before Start() is -// called. -TEST_P(TaskSchedulerImplTest, PostTaskViaTaskRunnerBeforeStart) { - WaitableEvent task_running(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - CreateTaskRunnerWithTraitsAndExecutionMode(&scheduler_, GetParam().traits, - GetParam().execution_mode) - ->PostTask(FROM_HERE, - BindOnce(&VerifyTaskEnvironmentAndSignalEvent, - GetParam().traits, Unretained(&task_running))); - - // Wait a little bit to make sure that the task doesn't run before Start(). - // Note: This test won't catch a case where the task runs just after the check - // and before Start(). However, we expect the test to be flaky if the tested - // code allows that to happen. - PlatformThread::Sleep(TestTimeouts::tiny_timeout()); - EXPECT_FALSE(task_running.IsSignaled()); - - StartTaskScheduler(); - - // This should not hang if the task runs after Start(). - task_running.Wait(); -} - -// Verify that all tasks posted to a TaskRunner after Start() run in a -// USER_BLOCKING environment when the AllTasksUserBlocking variation param of -// the BrowserScheduler experiment is true. -TEST_P(TaskSchedulerImplTest, AllTasksAreUserBlockingTaskRunner) { - EnableAllTasksUserBlocking(); - StartTaskScheduler(); - - WaitableEvent task_running(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - CreateTaskRunnerWithTraitsAndExecutionMode(&scheduler_, GetParam().traits, - GetParam().execution_mode) - ->PostTask(FROM_HERE, - BindOnce(&VerifyTaskEnvironmentAndSignalEvent, - TaskTraits::Override(GetParam().traits, - {TaskPriority::USER_BLOCKING}), - Unretained(&task_running))); - task_running.Wait(); -} - -// Verify that all tasks posted via PostDelayedTaskWithTraits() after Start() -// run in a USER_BLOCKING environment when the AllTasksUserBlocking variation -// param of the BrowserScheduler experiment is true. -TEST_P(TaskSchedulerImplTest, AllTasksAreUserBlocking) { - EnableAllTasksUserBlocking(); - StartTaskScheduler(); - - WaitableEvent task_running(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - // Ignore |params.execution_mode| in this test. - scheduler_.PostDelayedTaskWithTraits( - FROM_HERE, GetParam().traits, - BindOnce(&VerifyTaskEnvironmentAndSignalEvent, - TaskTraits::Override(GetParam().traits, - {TaskPriority::USER_BLOCKING}), - Unretained(&task_running)), - TimeDelta()); - task_running.Wait(); -} - -// Verifies that FlushAsyncForTesting() calls back correctly for all trait and -// execution mode pairs. -TEST_P(TaskSchedulerImplTest, FlushAsyncForTestingSimple) { - StartTaskScheduler(); - - WaitableEvent unblock_task(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - CreateTaskRunnerWithTraitsAndExecutionMode( - &scheduler_, - TaskTraits::Override(GetParam().traits, {WithBaseSyncPrimitives()}), - GetParam().execution_mode, SingleThreadTaskRunnerThreadMode::DEDICATED) - ->PostTask(FROM_HERE, - BindOnce(&WaitableEvent::Wait, Unretained(&unblock_task))); - - WaitableEvent flush_event(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - scheduler_.FlushAsyncForTesting( - BindOnce(&WaitableEvent::Signal, Unretained(&flush_event))); - PlatformThread::Sleep(TestTimeouts::tiny_timeout()); - EXPECT_FALSE(flush_event.IsSignaled()); - - unblock_task.Signal(); - - flush_event.Wait(); -} - -INSTANTIATE_TEST_CASE_P(OneTraitsExecutionModePair, - TaskSchedulerImplTest, - ::testing::ValuesIn(GetTraitsExecutionModePairs())); - -// Spawns threads that simultaneously post Tasks to TaskRunners with various -// TaskTraits and ExecutionModes. Verifies that each Task runs on a thread with -// the expected priority and I/O restrictions and respects the characteristics -// of its ExecutionMode. -TEST_F(TaskSchedulerImplTest, MultipleTraitsExecutionModePairs) { - StartTaskScheduler(); - std::vector<std::unique_ptr<ThreadPostingTasks>> threads_posting_tasks; - for (const auto& traits_execution_mode_pair : GetTraitsExecutionModePairs()) { - threads_posting_tasks.push_back(WrapUnique( - new ThreadPostingTasks(&scheduler_, traits_execution_mode_pair.traits, - traits_execution_mode_pair.execution_mode))); - threads_posting_tasks.back()->Start(); - } - - for (const auto& thread : threads_posting_tasks) { - thread->WaitForAllTasksToRun(); - thread->Join(); - } -} - -TEST_F(TaskSchedulerImplTest, - GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated) { - StartTaskScheduler(); - EXPECT_EQ(1, scheduler_.GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated( - {TaskPriority::BACKGROUND})); - EXPECT_EQ(3, scheduler_.GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated( - {MayBlock(), TaskPriority::BACKGROUND})); - EXPECT_EQ(4, scheduler_.GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated( - {TaskPriority::USER_VISIBLE})); - EXPECT_EQ(12, scheduler_.GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated( - {MayBlock(), TaskPriority::USER_VISIBLE})); - EXPECT_EQ(4, scheduler_.GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated( - {TaskPriority::USER_BLOCKING})); - EXPECT_EQ(12, scheduler_.GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated( - {MayBlock(), TaskPriority::USER_BLOCKING})); -} - -// Verify that the RunsTasksInCurrentSequence() method of a SequencedTaskRunner -// returns false when called from a task that isn't part of the sequence. -TEST_F(TaskSchedulerImplTest, SequencedRunsTasksInCurrentSequence) { - StartTaskScheduler(); - auto single_thread_task_runner = - scheduler_.CreateSingleThreadTaskRunnerWithTraits( - TaskTraits(), SingleThreadTaskRunnerThreadMode::SHARED); - auto sequenced_task_runner = - scheduler_.CreateSequencedTaskRunnerWithTraits(TaskTraits()); - - WaitableEvent task_ran(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - single_thread_task_runner->PostTask( - FROM_HERE, - BindOnce( - [](scoped_refptr<TaskRunner> sequenced_task_runner, - WaitableEvent* task_ran) { - EXPECT_FALSE(sequenced_task_runner->RunsTasksInCurrentSequence()); - task_ran->Signal(); - }, - sequenced_task_runner, Unretained(&task_ran))); - task_ran.Wait(); -} - -// Verify that the RunsTasksInCurrentSequence() method of a -// SingleThreadTaskRunner returns false when called from a task that isn't part -// of the sequence. -TEST_F(TaskSchedulerImplTest, SingleThreadRunsTasksInCurrentSequence) { - StartTaskScheduler(); - auto sequenced_task_runner = - scheduler_.CreateSequencedTaskRunnerWithTraits(TaskTraits()); - auto single_thread_task_runner = - scheduler_.CreateSingleThreadTaskRunnerWithTraits( - TaskTraits(), SingleThreadTaskRunnerThreadMode::SHARED); - - WaitableEvent task_ran(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - sequenced_task_runner->PostTask( - FROM_HERE, - BindOnce( - [](scoped_refptr<TaskRunner> single_thread_task_runner, - WaitableEvent* task_ran) { - EXPECT_FALSE( - single_thread_task_runner->RunsTasksInCurrentSequence()); - task_ran->Signal(); - }, - single_thread_task_runner, Unretained(&task_ran))); - task_ran.Wait(); -} - -#if defined(OS_WIN) -TEST_F(TaskSchedulerImplTest, COMSTATaskRunnersRunWithCOMSTA) { - StartTaskScheduler(); - auto com_sta_task_runner = scheduler_.CreateCOMSTATaskRunnerWithTraits( - TaskTraits(), SingleThreadTaskRunnerThreadMode::SHARED); - - WaitableEvent task_ran(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - com_sta_task_runner->PostTask( - FROM_HERE, Bind( - [](WaitableEvent* task_ran) { - win::AssertComApartmentType(win::ComApartmentType::STA); - task_ran->Signal(); - }, - Unretained(&task_ran))); - task_ran.Wait(); -} -#endif // defined(OS_WIN) - -TEST_F(TaskSchedulerImplTest, DelayedTasksNotRunAfterShutdown) { - StartTaskScheduler(); - // As with delayed tasks in general, this is racy. If the task does happen to - // run after Shutdown within the timeout, it will fail this test. - // - // The timeout should be set sufficiently long enough to ensure that the - // delayed task did not run. 2x is generally good enough. - // - // A non-racy way to do this would be to post two sequenced tasks: - // 1) Regular Post Task: A WaitableEvent.Wait - // 2) Delayed Task: ADD_FAILURE() - // and signalling the WaitableEvent after Shutdown() on a different thread - // since Shutdown() will block. However, the cost of managing this extra - // thread was deemed to be too great for the unlikely race. - scheduler_.PostDelayedTaskWithTraits(FROM_HERE, TaskTraits(), - BindOnce([]() { ADD_FAILURE(); }), - TestTimeouts::tiny_timeout()); - scheduler_.Shutdown(); - PlatformThread::Sleep(TestTimeouts::tiny_timeout() * 2); -} - -#if defined(OS_POSIX) - -TEST_F(TaskSchedulerImplTest, FileDescriptorWatcherNoOpsAfterShutdown) { - StartTaskScheduler(); - - int pipes[2]; - ASSERT_EQ(0, pipe(pipes)); - - scoped_refptr<TaskRunner> blocking_task_runner = - scheduler_.CreateSequencedTaskRunnerWithTraits( - {TaskShutdownBehavior::BLOCK_SHUTDOWN}); - blocking_task_runner->PostTask( - FROM_HERE, - BindOnce( - [](int read_fd) { - std::unique_ptr<FileDescriptorWatcher::Controller> controller = - FileDescriptorWatcher::WatchReadable( - read_fd, BindRepeating([]() { NOTREACHED(); })); - - // This test is for components that intentionally leak their - // watchers at shutdown. We can't clean |controller| up because its - // destructor will assert that it's being called from the correct - // sequence. After the task scheduler is shutdown, it is not - // possible to run tasks on this sequence. - // - // Note: Do not inline the controller.release() call into the - // ANNOTATE_LEAKING_OBJECT_PTR as the annotation is removed - // by the preprocessor in non-LEAK_SANITIZER builds, - // effectively breaking this test. - ANNOTATE_LEAKING_OBJECT_PTR(controller.get()); - controller.release(); - }, - pipes[0])); - - scheduler_.Shutdown(); - - constexpr char kByte = '!'; - ASSERT_TRUE(WriteFileDescriptor(pipes[1], &kByte, sizeof(kByte))); - - // Give a chance for the file watcher to fire before closing the handles. - PlatformThread::Sleep(TestTimeouts::tiny_timeout()); - - EXPECT_EQ(0, IGNORE_EINTR(close(pipes[0]))); - EXPECT_EQ(0, IGNORE_EINTR(close(pipes[1]))); -} -#endif // defined(OS_POSIX) - -// Verify that tasks posted on the same sequence access the same values on -// SequenceLocalStorage, and tasks on different sequences see different values. -TEST_F(TaskSchedulerImplTest, SequenceLocalStorage) { - StartTaskScheduler(); - - SequenceLocalStorageSlot<int> slot; - auto sequenced_task_runner1 = - scheduler_.CreateSequencedTaskRunnerWithTraits(TaskTraits()); - auto sequenced_task_runner2 = - scheduler_.CreateSequencedTaskRunnerWithTraits(TaskTraits()); - - sequenced_task_runner1->PostTask( - FROM_HERE, - BindOnce([](SequenceLocalStorageSlot<int>* slot) { slot->Set(11); }, - &slot)); - - sequenced_task_runner1->PostTask(FROM_HERE, - BindOnce( - [](SequenceLocalStorageSlot<int>* slot) { - EXPECT_EQ(slot->Get(), 11); - }, - &slot)); - - sequenced_task_runner2->PostTask(FROM_HERE, - BindOnce( - [](SequenceLocalStorageSlot<int>* slot) { - EXPECT_NE(slot->Get(), 11); - }, - &slot)); - - scheduler_.FlushForTesting(); -} - -TEST_F(TaskSchedulerImplTest, FlushAsyncNoTasks) { - StartTaskScheduler(); - bool called_back = false; - scheduler_.FlushAsyncForTesting( - BindOnce([](bool* called_back) { *called_back = true; }, - Unretained(&called_back))); - EXPECT_TRUE(called_back); -} - -namespace { - -// Verifies that |query| is found on the current stack. Ignores failures if this -// configuration doesn't have symbols. -void VerifyHasStringOnStack(const std::string& query) { - const std::string stack = debug::StackTrace().ToString(); - SCOPED_TRACE(stack); - const bool found_on_stack = stack.find(query) != std::string::npos; - const bool stack_has_symbols = - stack.find("SchedulerWorker") != std::string::npos; - EXPECT_TRUE(found_on_stack || !stack_has_symbols) << query; -} - -} // namespace - -#if defined(OS_POSIX) -// Many POSIX bots flakily crash on |debug::StackTrace().ToString()|, -// https://crbug.com/840429. -#define MAYBE_IdentifiableStacks DISABLED_IdentifiableStacks -#else -#define MAYBE_IdentifiableStacks IdentifiableStacks -#endif - -// Integration test that verifies that workers have a frame on their stacks -// which easily identifies the type of worker (useful to diagnose issues from -// logs without memory dumps). -TEST_F(TaskSchedulerImplTest, MAYBE_IdentifiableStacks) { - StartTaskScheduler(); - - scheduler_.CreateSequencedTaskRunnerWithTraits({})->PostTask( - FROM_HERE, BindOnce(&VerifyHasStringOnStack, "RunPooledWorker")); - scheduler_.CreateSequencedTaskRunnerWithTraits({TaskPriority::BACKGROUND}) - ->PostTask(FROM_HERE, BindOnce(&VerifyHasStringOnStack, - "RunBackgroundPooledWorker")); - - scheduler_ - .CreateSingleThreadTaskRunnerWithTraits( - {}, SingleThreadTaskRunnerThreadMode::SHARED) - ->PostTask(FROM_HERE, - BindOnce(&VerifyHasStringOnStack, "RunSharedWorker")); - scheduler_ - .CreateSingleThreadTaskRunnerWithTraits( - {TaskPriority::BACKGROUND}, SingleThreadTaskRunnerThreadMode::SHARED) - ->PostTask(FROM_HERE, BindOnce(&VerifyHasStringOnStack, - "RunBackgroundSharedWorker")); - - scheduler_ - .CreateSingleThreadTaskRunnerWithTraits( - {}, SingleThreadTaskRunnerThreadMode::DEDICATED) - ->PostTask(FROM_HERE, - BindOnce(&VerifyHasStringOnStack, "RunDedicatedWorker")); - scheduler_ - .CreateSingleThreadTaskRunnerWithTraits( - {TaskPriority::BACKGROUND}, - SingleThreadTaskRunnerThreadMode::DEDICATED) - ->PostTask(FROM_HERE, BindOnce(&VerifyHasStringOnStack, - "RunBackgroundDedicatedWorker")); - -#if defined(OS_WIN) - scheduler_ - .CreateCOMSTATaskRunnerWithTraits( - {}, SingleThreadTaskRunnerThreadMode::SHARED) - ->PostTask(FROM_HERE, - BindOnce(&VerifyHasStringOnStack, "RunSharedCOMWorker")); - scheduler_ - .CreateCOMSTATaskRunnerWithTraits( - {TaskPriority::BACKGROUND}, SingleThreadTaskRunnerThreadMode::SHARED) - ->PostTask(FROM_HERE, BindOnce(&VerifyHasStringOnStack, - "RunBackgroundSharedCOMWorker")); - - scheduler_ - .CreateCOMSTATaskRunnerWithTraits( - {}, SingleThreadTaskRunnerThreadMode::DEDICATED) - ->PostTask(FROM_HERE, - BindOnce(&VerifyHasStringOnStack, "RunDedicatedCOMWorker")); - scheduler_ - .CreateCOMSTATaskRunnerWithTraits( - {TaskPriority::BACKGROUND}, - SingleThreadTaskRunnerThreadMode::DEDICATED) - ->PostTask(FROM_HERE, BindOnce(&VerifyHasStringOnStack, - "RunBackgroundDedicatedCOMWorker")); -#endif // defined(OS_WIN) - - scheduler_.FlushForTesting(); -} - -TEST_F(TaskSchedulerImplTest, SchedulerWorkerObserver) { - testing::StrictMock<test::MockSchedulerWorkerObserver> observer; - set_scheduler_worker_observer(&observer); - -// 4 workers should be created for the 4 pools. After that, 8 threads should -// be created for single-threaded work (16 on Windows). -#if defined(OS_WIN) - constexpr int kExpectedNumWorkers = 20; -#else - constexpr int kExpectedNumWorkers = 12; -#endif - EXPECT_CALL(observer, OnSchedulerWorkerMainEntry()) - .Times(kExpectedNumWorkers); - - StartTaskScheduler(); - - std::vector<scoped_refptr<SingleThreadTaskRunner>> task_runners; - - task_runners.push_back(scheduler_.CreateSingleThreadTaskRunnerWithTraits( - {TaskPriority::BACKGROUND}, SingleThreadTaskRunnerThreadMode::SHARED)); - task_runners.push_back(scheduler_.CreateSingleThreadTaskRunnerWithTraits( - {TaskPriority::BACKGROUND, MayBlock()}, - SingleThreadTaskRunnerThreadMode::SHARED)); - task_runners.push_back(scheduler_.CreateSingleThreadTaskRunnerWithTraits( - {TaskPriority::USER_BLOCKING}, SingleThreadTaskRunnerThreadMode::SHARED)); - task_runners.push_back(scheduler_.CreateSingleThreadTaskRunnerWithTraits( - {TaskPriority::USER_BLOCKING, MayBlock()}, - SingleThreadTaskRunnerThreadMode::SHARED)); - - task_runners.push_back(scheduler_.CreateSingleThreadTaskRunnerWithTraits( - {TaskPriority::BACKGROUND}, SingleThreadTaskRunnerThreadMode::DEDICATED)); - task_runners.push_back(scheduler_.CreateSingleThreadTaskRunnerWithTraits( - {TaskPriority::BACKGROUND, MayBlock()}, - SingleThreadTaskRunnerThreadMode::DEDICATED)); - task_runners.push_back(scheduler_.CreateSingleThreadTaskRunnerWithTraits( - {TaskPriority::USER_BLOCKING}, - SingleThreadTaskRunnerThreadMode::DEDICATED)); - task_runners.push_back(scheduler_.CreateSingleThreadTaskRunnerWithTraits( - {TaskPriority::USER_BLOCKING, MayBlock()}, - SingleThreadTaskRunnerThreadMode::DEDICATED)); - -#if defined(OS_WIN) - task_runners.push_back(scheduler_.CreateCOMSTATaskRunnerWithTraits( - {TaskPriority::BACKGROUND}, SingleThreadTaskRunnerThreadMode::SHARED)); - task_runners.push_back(scheduler_.CreateCOMSTATaskRunnerWithTraits( - {TaskPriority::BACKGROUND, MayBlock()}, - SingleThreadTaskRunnerThreadMode::SHARED)); - task_runners.push_back(scheduler_.CreateCOMSTATaskRunnerWithTraits( - {TaskPriority::USER_BLOCKING}, SingleThreadTaskRunnerThreadMode::SHARED)); - task_runners.push_back(scheduler_.CreateCOMSTATaskRunnerWithTraits( - {TaskPriority::USER_BLOCKING, MayBlock()}, - SingleThreadTaskRunnerThreadMode::SHARED)); - - task_runners.push_back(scheduler_.CreateCOMSTATaskRunnerWithTraits( - {TaskPriority::BACKGROUND}, SingleThreadTaskRunnerThreadMode::DEDICATED)); - task_runners.push_back(scheduler_.CreateCOMSTATaskRunnerWithTraits( - {TaskPriority::BACKGROUND, MayBlock()}, - SingleThreadTaskRunnerThreadMode::DEDICATED)); - task_runners.push_back(scheduler_.CreateCOMSTATaskRunnerWithTraits( - {TaskPriority::USER_BLOCKING}, - SingleThreadTaskRunnerThreadMode::DEDICATED)); - task_runners.push_back(scheduler_.CreateCOMSTATaskRunnerWithTraits( - {TaskPriority::USER_BLOCKING, MayBlock()}, - SingleThreadTaskRunnerThreadMode::DEDICATED)); -#endif - - for (auto& task_runner : task_runners) - task_runner->PostTask(FROM_HERE, DoNothing()); - - EXPECT_CALL(observer, OnSchedulerWorkerMainExit()).Times(kExpectedNumWorkers); - - // Allow single-threaded workers to be released. - task_runners.clear(); - - TearDown(); -} - -} // namespace internal -} // namespace base
diff --git a/base/task_scheduler/task_tracker_posix_unittest.cc b/base/task_scheduler/task_tracker_posix_unittest.cc deleted file mode 100644 index d8849de..0000000 --- a/base/task_scheduler/task_tracker_posix_unittest.cc +++ /dev/null
@@ -1,101 +0,0 @@ -// 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/task_scheduler/task_tracker_posix.h" - -#include <unistd.h> - -#include <utility> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/files/file_descriptor_watcher_posix.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/memory/ref_counted.h" -#include "base/message_loop/message_loop.h" -#include "base/posix/eintr_wrapper.h" -#include "base/run_loop.h" -#include "base/sequence_token.h" -#include "base/task_scheduler/task.h" -#include "base/task_scheduler/task_traits.h" -#include "base/task_scheduler/test_utils.h" -#include "base/test/null_task_runner.h" -#include "base/threading/thread.h" -#include "base/time/time.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace internal { - -namespace { - -class TaskSchedulerTaskTrackerPosixTest : public testing::Test { - public: - TaskSchedulerTaskTrackerPosixTest() : service_thread_("ServiceThread") { - Thread::Options service_thread_options; - service_thread_options.message_loop_type = MessageLoop::TYPE_IO; - service_thread_.StartWithOptions(service_thread_options); - tracker_.set_watch_file_descriptor_message_loop( - static_cast<MessageLoopForIO*>(service_thread_.message_loop())); - } - - protected: - Thread service_thread_; - TaskTrackerPosix tracker_ = {"Test"}; - - private: - DISALLOW_COPY_AND_ASSIGN(TaskSchedulerTaskTrackerPosixTest); -}; - -} // namespace - -// Verify that TaskTrackerPosix runs a Task it receives. -TEST_F(TaskSchedulerTaskTrackerPosixTest, RunTask) { - bool did_run = false; - Task task(FROM_HERE, - Bind([](bool* did_run) { *did_run = true; }, Unretained(&did_run)), - TaskTraits(), TimeDelta()); - - EXPECT_TRUE(tracker_.WillPostTask(task)); - - auto sequence = test::CreateSequenceWithTask(std::move(task)); - EXPECT_EQ(sequence, tracker_.WillScheduleSequence(sequence, nullptr)); - // Expect RunAndPopNextTask to return nullptr since |sequence| is empty after - // popping a task from it. - EXPECT_FALSE(tracker_.RunAndPopNextTask(sequence, nullptr)); - - EXPECT_TRUE(did_run); -} - -// Verify that FileDescriptorWatcher::WatchReadable() can be called from a task -// running in TaskTrackerPosix without a crash. -TEST_F(TaskSchedulerTaskTrackerPosixTest, FileDescriptorWatcher) { - int fds[2]; - ASSERT_EQ(0, pipe(fds)); - Task task(FROM_HERE, - Bind(IgnoreResult(&FileDescriptorWatcher::WatchReadable), fds[0], - DoNothing()), - TaskTraits(), TimeDelta()); - // FileDescriptorWatcher::WatchReadable needs a SequencedTaskRunnerHandle. - task.sequenced_task_runner_ref = MakeRefCounted<NullTaskRunner>(); - - EXPECT_TRUE(tracker_.WillPostTask(task)); - - auto sequence = test::CreateSequenceWithTask(std::move(task)); - EXPECT_EQ(sequence, tracker_.WillScheduleSequence(sequence, nullptr)); - // Expect RunAndPopNextTask to return nullptr since |sequence| is empty after - // popping a task from it. - EXPECT_FALSE(tracker_.RunAndPopNextTask(sequence, nullptr)); - - // Join the service thread to make sure that the read watch is registered and - // unregistered before file descriptors are closed. - service_thread_.Stop(); - - EXPECT_EQ(0, IGNORE_EINTR(close(fds[0]))); - EXPECT_EQ(0, IGNORE_EINTR(close(fds[1]))); -} - -} // namespace internal -} // namespace base
diff --git a/base/task_scheduler/task_tracker_unittest.cc b/base/task_scheduler/task_tracker_unittest.cc deleted file mode 100644 index ea8a3c1..0000000 --- a/base/task_scheduler/task_tracker_unittest.cc +++ /dev/null
@@ -1,1368 +0,0 @@ -// 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/task_scheduler/task_tracker.h" - -#include <stdint.h> - -#include <memory> -#include <utility> -#include <vector> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/callback.h" -#include "base/logging.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/memory/ref_counted.h" -#include "base/metrics/histogram_base.h" -#include "base/metrics/histogram_samples.h" -#include "base/metrics/statistics_recorder.h" -#include "base/sequence_token.h" -#include "base/sequenced_task_runner.h" -#include "base/single_thread_task_runner.h" -#include "base/synchronization/atomic_flag.h" -#include "base/synchronization/waitable_event.h" -#include "base/task_scheduler/scheduler_lock.h" -#include "base/task_scheduler/task.h" -#include "base/task_scheduler/task_traits.h" -#include "base/task_scheduler/test_utils.h" -#include "base/test/gtest_util.h" -#include "base/test/histogram_tester.h" -#include "base/test/test_simple_task_runner.h" -#include "base/test/test_timeouts.h" -#include "base/threading/platform_thread.h" -#include "base/threading/sequenced_task_runner_handle.h" -#include "base/threading/simple_thread.h" -#include "base/threading/thread_restrictions.h" -#include "base/threading/thread_task_runner_handle.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace internal { - -namespace { - -constexpr size_t kLoadTestNumIterations = 75; - -class MockCanScheduleSequenceObserver : public CanScheduleSequenceObserver { - public: - void OnCanScheduleSequence(scoped_refptr<Sequence> sequence) override { - MockOnCanScheduleSequence(sequence.get()); - } - - MOCK_METHOD1(MockOnCanScheduleSequence, void(Sequence*)); -}; - -// Invokes a closure asynchronously. -class CallbackThread : public SimpleThread { - public: - explicit CallbackThread(const Closure& closure) - : SimpleThread("CallbackThread"), closure_(closure) {} - - // Returns true once the callback returns. - bool has_returned() { return has_returned_.IsSet(); } - - private: - void Run() override { - closure_.Run(); - has_returned_.Set(); - } - - const Closure closure_; - AtomicFlag has_returned_; - - DISALLOW_COPY_AND_ASSIGN(CallbackThread); -}; - -class ThreadPostingAndRunningTask : public SimpleThread { - public: - enum class Action { - WILL_POST, - RUN, - WILL_POST_AND_RUN, - }; - - ThreadPostingAndRunningTask(TaskTracker* tracker, - Task* task, - Action action, - bool expect_post_succeeds) - : SimpleThread("ThreadPostingAndRunningTask"), - tracker_(tracker), - owned_task_(FROM_HERE, OnceClosure(), TaskTraits(), TimeDelta()), - task_(task), - action_(action), - expect_post_succeeds_(expect_post_succeeds) { - EXPECT_TRUE(task_); - - // Ownership of the Task is required to run it. - EXPECT_NE(Action::RUN, action_); - EXPECT_NE(Action::WILL_POST_AND_RUN, action_); - } - - ThreadPostingAndRunningTask(TaskTracker* tracker, - Task task, - Action action, - bool expect_post_succeeds) - : SimpleThread("ThreadPostingAndRunningTask"), - tracker_(tracker), - owned_task_(std::move(task)), - task_(&owned_task_), - action_(action), - expect_post_succeeds_(expect_post_succeeds) { - EXPECT_TRUE(owned_task_.task); - } - - private: - void Run() override { - bool post_succeeded = true; - if (action_ == Action::WILL_POST || action_ == Action::WILL_POST_AND_RUN) { - post_succeeded = tracker_->WillPostTask(*task_); - EXPECT_EQ(expect_post_succeeds_, post_succeeded); - } - if (post_succeeded && - (action_ == Action::RUN || action_ == Action::WILL_POST_AND_RUN)) { - EXPECT_TRUE(owned_task_.task); - - testing::StrictMock<MockCanScheduleSequenceObserver> - never_notified_observer; - auto sequence = tracker_->WillScheduleSequence( - test::CreateSequenceWithTask(std::move(owned_task_)), - &never_notified_observer); - ASSERT_TRUE(sequence); - // Expect RunAndPopNextTask to return nullptr since |sequence| is empty - // after popping a task from it. - EXPECT_FALSE(tracker_->RunAndPopNextTask(std::move(sequence), - &never_notified_observer)); - } - } - - TaskTracker* const tracker_; - Task owned_task_; - Task* task_; - const Action action_; - const bool expect_post_succeeds_; - - DISALLOW_COPY_AND_ASSIGN(ThreadPostingAndRunningTask); -}; - -class ScopedSetSingletonAllowed { - public: - ScopedSetSingletonAllowed(bool singleton_allowed) - : previous_value_( - ThreadRestrictions::SetSingletonAllowed(singleton_allowed)) {} - ~ScopedSetSingletonAllowed() { - ThreadRestrictions::SetSingletonAllowed(previous_value_); - } - - private: - const bool previous_value_; -}; - -class TaskSchedulerTaskTrackerTest - : public testing::TestWithParam<TaskShutdownBehavior> { - protected: - TaskSchedulerTaskTrackerTest() = default; - - // Creates a task with |shutdown_behavior|. - Task CreateTask(TaskShutdownBehavior shutdown_behavior) { - return Task( - FROM_HERE, - Bind(&TaskSchedulerTaskTrackerTest::RunTaskCallback, Unretained(this)), - TaskTraits(shutdown_behavior), TimeDelta()); - } - - void DispatchAndRunTaskWithTracker(Task task) { - auto sequence = tracker_.WillScheduleSequence( - test::CreateSequenceWithTask(std::move(task)), - &never_notified_observer_); - ASSERT_TRUE(sequence); - tracker_.RunAndPopNextTask(std::move(sequence), &never_notified_observer_); - } - - // Calls tracker_->Shutdown() on a new thread. When this returns, Shutdown() - // method has been entered on the new thread, but it hasn't necessarily - // returned. - void CallShutdownAsync() { - ASSERT_FALSE(thread_calling_shutdown_); - thread_calling_shutdown_.reset(new CallbackThread( - Bind(&TaskTracker::Shutdown, Unretained(&tracker_)))); - thread_calling_shutdown_->Start(); - while (!tracker_.HasShutdownStarted()) - PlatformThread::YieldCurrentThread(); - } - - void WaitForAsyncIsShutdownComplete() { - ASSERT_TRUE(thread_calling_shutdown_); - thread_calling_shutdown_->Join(); - EXPECT_TRUE(thread_calling_shutdown_->has_returned()); - EXPECT_TRUE(tracker_.IsShutdownComplete()); - } - - void VerifyAsyncShutdownInProgress() { - ASSERT_TRUE(thread_calling_shutdown_); - EXPECT_FALSE(thread_calling_shutdown_->has_returned()); - EXPECT_TRUE(tracker_.HasShutdownStarted()); - EXPECT_FALSE(tracker_.IsShutdownComplete()); - } - - // Calls tracker_->FlushForTesting() on a new thread. - void CallFlushFromAnotherThread() { - ASSERT_FALSE(thread_calling_flush_); - thread_calling_flush_.reset(new CallbackThread( - Bind(&TaskTracker::FlushForTesting, Unretained(&tracker_)))); - thread_calling_flush_->Start(); - } - - void WaitForAsyncFlushReturned() { - ASSERT_TRUE(thread_calling_flush_); - thread_calling_flush_->Join(); - EXPECT_TRUE(thread_calling_flush_->has_returned()); - } - - void VerifyAsyncFlushInProgress() { - ASSERT_TRUE(thread_calling_flush_); - EXPECT_FALSE(thread_calling_flush_->has_returned()); - } - - size_t NumTasksExecuted() { - AutoSchedulerLock auto_lock(lock_); - return num_tasks_executed_; - } - - TaskTracker tracker_ = {"Test"}; - testing::StrictMock<MockCanScheduleSequenceObserver> never_notified_observer_; - - private: - void RunTaskCallback() { - AutoSchedulerLock auto_lock(lock_); - ++num_tasks_executed_; - } - - std::unique_ptr<CallbackThread> thread_calling_shutdown_; - std::unique_ptr<CallbackThread> thread_calling_flush_; - - // Synchronizes accesses to |num_tasks_executed_|. - SchedulerLock lock_; - - size_t num_tasks_executed_ = 0; - - DISALLOW_COPY_AND_ASSIGN(TaskSchedulerTaskTrackerTest); -}; - -#define WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED() \ - do { \ - SCOPED_TRACE(""); \ - WaitForAsyncIsShutdownComplete(); \ - } while (false) - -#define VERIFY_ASYNC_SHUTDOWN_IN_PROGRESS() \ - do { \ - SCOPED_TRACE(""); \ - VerifyAsyncShutdownInProgress(); \ - } while (false) - -#define WAIT_FOR_ASYNC_FLUSH_RETURNED() \ - do { \ - SCOPED_TRACE(""); \ - WaitForAsyncFlushReturned(); \ - } while (false) - -#define VERIFY_ASYNC_FLUSH_IN_PROGRESS() \ - do { \ - SCOPED_TRACE(""); \ - VerifyAsyncFlushInProgress(); \ - } while (false) - -} // namespace - -TEST_P(TaskSchedulerTaskTrackerTest, WillPostAndRunBeforeShutdown) { - Task task(CreateTask(GetParam())); - - // Inform |task_tracker_| that |task| will be posted. - EXPECT_TRUE(tracker_.WillPostTask(task)); - - // Run the task. - EXPECT_EQ(0U, NumTasksExecuted()); - - DispatchAndRunTaskWithTracker(std::move(task)); - EXPECT_EQ(1U, NumTasksExecuted()); - - // Shutdown() shouldn't block. - tracker_.Shutdown(); -} - -TEST_P(TaskSchedulerTaskTrackerTest, WillPostAndRunLongTaskBeforeShutdown) { - // Create a task that signals |task_running| and blocks until |task_barrier| - // is signaled. - WaitableEvent task_running(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - WaitableEvent task_barrier(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - Task blocked_task( - FROM_HERE, - Bind( - [](WaitableEvent* task_running, WaitableEvent* task_barrier) { - task_running->Signal(); - task_barrier->Wait(); - }, - Unretained(&task_running), Unretained(&task_barrier)), - TaskTraits(WithBaseSyncPrimitives(), GetParam()), TimeDelta()); - - // Inform |task_tracker_| that |blocked_task| will be posted. - EXPECT_TRUE(tracker_.WillPostTask(blocked_task)); - - // Create a thread to run the task. Wait until the task starts running. - ThreadPostingAndRunningTask thread_running_task( - &tracker_, std::move(blocked_task), - ThreadPostingAndRunningTask::Action::RUN, false); - thread_running_task.Start(); - task_running.Wait(); - - // Initiate shutdown after the task has started to run. - CallShutdownAsync(); - - if (GetParam() == TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN) { - // Shutdown should complete even with a CONTINUE_ON_SHUTDOWN in progress. - WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED(); - } else { - // Shutdown should block with any non CONTINUE_ON_SHUTDOWN task in progress. - VERIFY_ASYNC_SHUTDOWN_IN_PROGRESS(); - } - - // Unblock the task. - task_barrier.Signal(); - thread_running_task.Join(); - - // Shutdown should now complete for a non CONTINUE_ON_SHUTDOWN task. - if (GetParam() != TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN) - WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED(); -} - -TEST_P(TaskSchedulerTaskTrackerTest, WillPostBeforeShutdownRunDuringShutdown) { - // Inform |task_tracker_| that a task will be posted. - Task task(CreateTask(GetParam())); - EXPECT_TRUE(tracker_.WillPostTask(task)); - - // Inform |task_tracker_| that a BLOCK_SHUTDOWN task will be posted just to - // block shutdown. - Task block_shutdown_task(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN)); - EXPECT_TRUE(tracker_.WillPostTask(block_shutdown_task)); - - // Call Shutdown() asynchronously. - CallShutdownAsync(); - VERIFY_ASYNC_SHUTDOWN_IN_PROGRESS(); - - // Try to run |task|. It should only run it it's BLOCK_SHUTDOWN. Otherwise it - // should be discarded. - EXPECT_EQ(0U, NumTasksExecuted()); - const bool should_run = GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN; - - DispatchAndRunTaskWithTracker(std::move(task)); - EXPECT_EQ(should_run ? 1U : 0U, NumTasksExecuted()); - VERIFY_ASYNC_SHUTDOWN_IN_PROGRESS(); - - // Unblock shutdown by running the remaining BLOCK_SHUTDOWN task. - DispatchAndRunTaskWithTracker(std::move(block_shutdown_task)); - EXPECT_EQ(should_run ? 2U : 1U, NumTasksExecuted()); - WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED(); -} - -TEST_P(TaskSchedulerTaskTrackerTest, WillPostBeforeShutdownRunAfterShutdown) { - // Inform |task_tracker_| that a task will be posted. - Task task(CreateTask(GetParam())); - EXPECT_TRUE(tracker_.WillPostTask(task)); - - // Call Shutdown() asynchronously. - CallShutdownAsync(); - EXPECT_EQ(0U, NumTasksExecuted()); - - if (GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN) { - VERIFY_ASYNC_SHUTDOWN_IN_PROGRESS(); - - // Run the task to unblock shutdown. - DispatchAndRunTaskWithTracker(std::move(task)); - EXPECT_EQ(1U, NumTasksExecuted()); - WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED(); - - // It is not possible to test running a BLOCK_SHUTDOWN task posted before - // shutdown after shutdown because Shutdown() won't return if there are - // pending BLOCK_SHUTDOWN tasks. - } else { - WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED(); - - // The task shouldn't be allowed to run after shutdown. - DispatchAndRunTaskWithTracker(std::move(task)); - EXPECT_EQ(0U, NumTasksExecuted()); - } -} - -TEST_P(TaskSchedulerTaskTrackerTest, WillPostAndRunDuringShutdown) { - // Inform |task_tracker_| that a BLOCK_SHUTDOWN task will be posted just to - // block shutdown. - Task block_shutdown_task(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN)); - EXPECT_TRUE(tracker_.WillPostTask(block_shutdown_task)); - - // Call Shutdown() asynchronously. - CallShutdownAsync(); - VERIFY_ASYNC_SHUTDOWN_IN_PROGRESS(); - - if (GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN) { - // Inform |task_tracker_| that a BLOCK_SHUTDOWN task will be posted. - Task task(CreateTask(GetParam())); - EXPECT_TRUE(tracker_.WillPostTask(task)); - - // Run the BLOCK_SHUTDOWN task. - EXPECT_EQ(0U, NumTasksExecuted()); - DispatchAndRunTaskWithTracker(std::move(task)); - EXPECT_EQ(1U, NumTasksExecuted()); - } else { - // It shouldn't be allowed to post a non BLOCK_SHUTDOWN task. - Task task(CreateTask(GetParam())); - EXPECT_FALSE(tracker_.WillPostTask(task)); - - // Don't try to run the task, because it wasn't allowed to be posted. - } - - // Unblock shutdown by running |block_shutdown_task|. - VERIFY_ASYNC_SHUTDOWN_IN_PROGRESS(); - DispatchAndRunTaskWithTracker(std::move(block_shutdown_task)); - EXPECT_EQ(GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN ? 2U : 1U, - NumTasksExecuted()); - WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED(); -} - -TEST_P(TaskSchedulerTaskTrackerTest, WillPostAfterShutdown) { - tracker_.Shutdown(); - - Task task(CreateTask(GetParam())); - - // |task_tracker_| shouldn't allow a task to be posted after shutdown. - EXPECT_FALSE(tracker_.WillPostTask(task)); -} - -// Verify that BLOCK_SHUTDOWN and SKIP_ON_SHUTDOWN tasks can -// AssertSingletonAllowed() but CONTINUE_ON_SHUTDOWN tasks can't. -TEST_P(TaskSchedulerTaskTrackerTest, SingletonAllowed) { - const bool can_use_singletons = - (GetParam() != TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN); - - Task task(FROM_HERE, BindOnce(&ThreadRestrictions::AssertSingletonAllowed), - TaskTraits(GetParam()), TimeDelta()); - EXPECT_TRUE(tracker_.WillPostTask(task)); - - // Set the singleton allowed bit to the opposite of what it is expected to be - // when |tracker| runs |task| to verify that |tracker| actually sets the - // correct value. - ScopedSetSingletonAllowed scoped_singleton_allowed(!can_use_singletons); - - // Running the task should fail iff the task isn't allowed to use singletons. - if (can_use_singletons) { - DispatchAndRunTaskWithTracker(std::move(task)); - } else { - EXPECT_DCHECK_DEATH({ DispatchAndRunTaskWithTracker(std::move(task)); }); - } -} - -// Verify that AssertIOAllowed() succeeds only for a MayBlock() task. -TEST_P(TaskSchedulerTaskTrackerTest, IOAllowed) { - // Unset the IO allowed bit. Expect TaskTracker to set it before running a - // task with the MayBlock() trait. - ThreadRestrictions::SetIOAllowed(false); - Task task_with_may_block(FROM_HERE, Bind([]() { - // Shouldn't fail. - AssertBlockingAllowed(); - }), - TaskTraits(MayBlock(), GetParam()), TimeDelta()); - EXPECT_TRUE(tracker_.WillPostTask(task_with_may_block)); - DispatchAndRunTaskWithTracker(std::move(task_with_may_block)); - - // Set the IO allowed bit. Expect TaskTracker to unset it before running a - // task without the MayBlock() trait. - ThreadRestrictions::SetIOAllowed(true); - Task task_without_may_block( - FROM_HERE, - Bind([]() { EXPECT_DCHECK_DEATH({ AssertBlockingAllowed(); }); }), - TaskTraits(GetParam()), TimeDelta()); - EXPECT_TRUE(tracker_.WillPostTask(task_without_may_block)); - DispatchAndRunTaskWithTracker(std::move(task_without_may_block)); -} - -static void RunTaskRunnerHandleVerificationTask(TaskTracker* tracker, - Task verify_task) { - // Pretend |verify_task| is posted to respect TaskTracker's contract. - EXPECT_TRUE(tracker->WillPostTask(verify_task)); - - // Confirm that the test conditions are right (no TaskRunnerHandles set - // already). - EXPECT_FALSE(ThreadTaskRunnerHandle::IsSet()); - EXPECT_FALSE(SequencedTaskRunnerHandle::IsSet()); - - testing::StrictMock<MockCanScheduleSequenceObserver> never_notified_observer; - auto sequence = tracker->WillScheduleSequence( - test::CreateSequenceWithTask(std::move(verify_task)), - &never_notified_observer); - ASSERT_TRUE(sequence); - tracker->RunAndPopNextTask(std::move(sequence), &never_notified_observer); - - // TaskRunnerHandle state is reset outside of task's scope. - EXPECT_FALSE(ThreadTaskRunnerHandle::IsSet()); - EXPECT_FALSE(SequencedTaskRunnerHandle::IsSet()); -} - -static void VerifyNoTaskRunnerHandle() { - EXPECT_FALSE(ThreadTaskRunnerHandle::IsSet()); - EXPECT_FALSE(SequencedTaskRunnerHandle::IsSet()); -} - -TEST_P(TaskSchedulerTaskTrackerTest, TaskRunnerHandleIsNotSetOnParallel) { - // Create a task that will verify that TaskRunnerHandles are not set in its - // scope per no TaskRunner ref being set to it. - Task verify_task(FROM_HERE, BindOnce(&VerifyNoTaskRunnerHandle), - TaskTraits(GetParam()), TimeDelta()); - - RunTaskRunnerHandleVerificationTask(&tracker_, std::move(verify_task)); -} - -static void VerifySequencedTaskRunnerHandle( - const SequencedTaskRunner* expected_task_runner) { - EXPECT_FALSE(ThreadTaskRunnerHandle::IsSet()); - EXPECT_TRUE(SequencedTaskRunnerHandle::IsSet()); - EXPECT_EQ(expected_task_runner, SequencedTaskRunnerHandle::Get()); -} - -TEST_P(TaskSchedulerTaskTrackerTest, - SequencedTaskRunnerHandleIsSetOnSequenced) { - scoped_refptr<SequencedTaskRunner> test_task_runner(new TestSimpleTaskRunner); - - // Create a task that will verify that SequencedTaskRunnerHandle is properly - // set to |test_task_runner| in its scope per |sequenced_task_runner_ref| - // being set to it. - Task verify_task(FROM_HERE, - BindOnce(&VerifySequencedTaskRunnerHandle, - Unretained(test_task_runner.get())), - TaskTraits(GetParam()), TimeDelta()); - verify_task.sequenced_task_runner_ref = test_task_runner; - - RunTaskRunnerHandleVerificationTask(&tracker_, std::move(verify_task)); -} - -static void VerifyThreadTaskRunnerHandle( - const SingleThreadTaskRunner* expected_task_runner) { - EXPECT_TRUE(ThreadTaskRunnerHandle::IsSet()); - // SequencedTaskRunnerHandle inherits ThreadTaskRunnerHandle for thread. - EXPECT_TRUE(SequencedTaskRunnerHandle::IsSet()); - EXPECT_EQ(expected_task_runner, ThreadTaskRunnerHandle::Get()); -} - -TEST_P(TaskSchedulerTaskTrackerTest, - ThreadTaskRunnerHandleIsSetOnSingleThreaded) { - scoped_refptr<SingleThreadTaskRunner> test_task_runner( - new TestSimpleTaskRunner); - - // Create a task that will verify that ThreadTaskRunnerHandle is properly set - // to |test_task_runner| in its scope per |single_thread_task_runner_ref| - // being set on it. - Task verify_task(FROM_HERE, - BindOnce(&VerifyThreadTaskRunnerHandle, - Unretained(test_task_runner.get())), - TaskTraits(GetParam()), TimeDelta()); - verify_task.single_thread_task_runner_ref = test_task_runner; - - RunTaskRunnerHandleVerificationTask(&tracker_, std::move(verify_task)); -} - -TEST_P(TaskSchedulerTaskTrackerTest, FlushPendingDelayedTask) { - const Task delayed_task(FROM_HERE, DoNothing(), TaskTraits(GetParam()), - TimeDelta::FromDays(1)); - tracker_.WillPostTask(delayed_task); - // FlushForTesting() should return even if the delayed task didn't run. - tracker_.FlushForTesting(); -} - -TEST_P(TaskSchedulerTaskTrackerTest, FlushAsyncForTestingPendingDelayedTask) { - const Task delayed_task(FROM_HERE, DoNothing(), TaskTraits(GetParam()), - TimeDelta::FromDays(1)); - tracker_.WillPostTask(delayed_task); - // FlushAsyncForTesting() should callback even if the delayed task didn't run. - bool called_back = false; - tracker_.FlushAsyncForTesting( - BindOnce([](bool* called_back) { *called_back = true; }, - Unretained(&called_back))); - EXPECT_TRUE(called_back); -} - -TEST_P(TaskSchedulerTaskTrackerTest, FlushPendingUndelayedTask) { - Task undelayed_task(FROM_HERE, DoNothing(), TaskTraits(GetParam()), - TimeDelta()); - tracker_.WillPostTask(undelayed_task); - - // FlushForTesting() shouldn't return before the undelayed task runs. - CallFlushFromAnotherThread(); - PlatformThread::Sleep(TestTimeouts::tiny_timeout()); - VERIFY_ASYNC_FLUSH_IN_PROGRESS(); - - // FlushForTesting() should return after the undelayed task runs. - DispatchAndRunTaskWithTracker(std::move(undelayed_task)); - WAIT_FOR_ASYNC_FLUSH_RETURNED(); -} - -TEST_P(TaskSchedulerTaskTrackerTest, FlushAsyncForTestingPendingUndelayedTask) { - Task undelayed_task(FROM_HERE, DoNothing(), TaskTraits(GetParam()), - TimeDelta()); - tracker_.WillPostTask(undelayed_task); - - // FlushAsyncForTesting() shouldn't callback before the undelayed task runs. - WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - tracker_.FlushAsyncForTesting( - BindOnce(&WaitableEvent::Signal, Unretained(&event))); - PlatformThread::Sleep(TestTimeouts::tiny_timeout()); - EXPECT_FALSE(event.IsSignaled()); - - // FlushAsyncForTesting() should callback after the undelayed task runs. - DispatchAndRunTaskWithTracker(std::move(undelayed_task)); - event.Wait(); -} - -TEST_P(TaskSchedulerTaskTrackerTest, PostTaskDuringFlush) { - Task undelayed_task(FROM_HERE, DoNothing(), TaskTraits(GetParam()), - TimeDelta()); - tracker_.WillPostTask(undelayed_task); - - // FlushForTesting() shouldn't return before the undelayed task runs. - CallFlushFromAnotherThread(); - PlatformThread::Sleep(TestTimeouts::tiny_timeout()); - VERIFY_ASYNC_FLUSH_IN_PROGRESS(); - - // Simulate posting another undelayed task. - Task other_undelayed_task(FROM_HERE, DoNothing(), TaskTraits(GetParam()), - TimeDelta()); - tracker_.WillPostTask(other_undelayed_task); - - // Run the first undelayed task. - DispatchAndRunTaskWithTracker(std::move(undelayed_task)); - - // FlushForTesting() shouldn't return before the second undelayed task runs. - PlatformThread::Sleep(TestTimeouts::tiny_timeout()); - VERIFY_ASYNC_FLUSH_IN_PROGRESS(); - - // FlushForTesting() should return after the second undelayed task runs. - DispatchAndRunTaskWithTracker(std::move(other_undelayed_task)); - WAIT_FOR_ASYNC_FLUSH_RETURNED(); -} - -TEST_P(TaskSchedulerTaskTrackerTest, PostTaskDuringFlushAsyncForTesting) { - Task undelayed_task(FROM_HERE, DoNothing(), TaskTraits(GetParam()), - TimeDelta()); - tracker_.WillPostTask(undelayed_task); - - // FlushAsyncForTesting() shouldn't callback before the undelayed task runs. - WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - tracker_.FlushAsyncForTesting( - BindOnce(&WaitableEvent::Signal, Unretained(&event))); - PlatformThread::Sleep(TestTimeouts::tiny_timeout()); - EXPECT_FALSE(event.IsSignaled()); - - // Simulate posting another undelayed task. - Task other_undelayed_task(FROM_HERE, DoNothing(), TaskTraits(GetParam()), - TimeDelta()); - tracker_.WillPostTask(other_undelayed_task); - - // Run the first undelayed task. - DispatchAndRunTaskWithTracker(std::move(undelayed_task)); - - // FlushAsyncForTesting() shouldn't callback before the second undelayed task - // runs. - PlatformThread::Sleep(TestTimeouts::tiny_timeout()); - EXPECT_FALSE(event.IsSignaled()); - - // FlushAsyncForTesting() should callback after the second undelayed task - // runs. - DispatchAndRunTaskWithTracker(std::move(other_undelayed_task)); - event.Wait(); -} - -TEST_P(TaskSchedulerTaskTrackerTest, RunDelayedTaskDuringFlush) { - // Simulate posting a delayed and an undelayed task. - Task delayed_task(FROM_HERE, DoNothing(), TaskTraits(GetParam()), - TimeDelta::FromDays(1)); - tracker_.WillPostTask(delayed_task); - Task undelayed_task(FROM_HERE, DoNothing(), TaskTraits(GetParam()), - TimeDelta()); - tracker_.WillPostTask(undelayed_task); - - // FlushForTesting() shouldn't return before the undelayed task runs. - CallFlushFromAnotherThread(); - PlatformThread::Sleep(TestTimeouts::tiny_timeout()); - VERIFY_ASYNC_FLUSH_IN_PROGRESS(); - - // Run the delayed task. - DispatchAndRunTaskWithTracker(std::move(delayed_task)); - - // FlushForTesting() shouldn't return since there is still a pending undelayed - // task. - PlatformThread::Sleep(TestTimeouts::tiny_timeout()); - VERIFY_ASYNC_FLUSH_IN_PROGRESS(); - - // Run the undelayed task. - DispatchAndRunTaskWithTracker(std::move(undelayed_task)); - - // FlushForTesting() should now return. - WAIT_FOR_ASYNC_FLUSH_RETURNED(); -} - -TEST_P(TaskSchedulerTaskTrackerTest, RunDelayedTaskDuringFlushAsyncForTesting) { - // Simulate posting a delayed and an undelayed task. - Task delayed_task(FROM_HERE, DoNothing(), TaskTraits(GetParam()), - TimeDelta::FromDays(1)); - tracker_.WillPostTask(delayed_task); - Task undelayed_task(FROM_HERE, DoNothing(), TaskTraits(GetParam()), - TimeDelta()); - tracker_.WillPostTask(undelayed_task); - - // FlushAsyncForTesting() shouldn't callback before the undelayed task runs. - WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - tracker_.FlushAsyncForTesting( - BindOnce(&WaitableEvent::Signal, Unretained(&event))); - PlatformThread::Sleep(TestTimeouts::tiny_timeout()); - EXPECT_FALSE(event.IsSignaled()); - - // Run the delayed task. - DispatchAndRunTaskWithTracker(std::move(delayed_task)); - - // FlushAsyncForTesting() shouldn't callback since there is still a pending - // undelayed task. - PlatformThread::Sleep(TestTimeouts::tiny_timeout()); - EXPECT_FALSE(event.IsSignaled()); - - // Run the undelayed task. - DispatchAndRunTaskWithTracker(std::move(undelayed_task)); - - // FlushAsyncForTesting() should now callback. - event.Wait(); -} - -TEST_P(TaskSchedulerTaskTrackerTest, FlushAfterShutdown) { - if (GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN) - return; - - // Simulate posting a task. - Task undelayed_task(FROM_HERE, DoNothing(), TaskTraits(GetParam()), - TimeDelta()); - tracker_.WillPostTask(undelayed_task); - - // Shutdown() should return immediately since there are no pending - // BLOCK_SHUTDOWN tasks. - tracker_.Shutdown(); - - // FlushForTesting() should return immediately after shutdown, even if an - // undelayed task hasn't run. - tracker_.FlushForTesting(); -} - -TEST_P(TaskSchedulerTaskTrackerTest, FlushAfterShutdownAsync) { - if (GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN) - return; - - // Simulate posting a task. - Task undelayed_task(FROM_HERE, DoNothing(), TaskTraits(GetParam()), - TimeDelta()); - tracker_.WillPostTask(undelayed_task); - - // Shutdown() should return immediately since there are no pending - // BLOCK_SHUTDOWN tasks. - tracker_.Shutdown(); - - // FlushForTesting() should callback immediately after shutdown, even if an - // undelayed task hasn't run. - bool called_back = false; - tracker_.FlushAsyncForTesting( - BindOnce([](bool* called_back) { *called_back = true; }, - Unretained(&called_back))); - EXPECT_TRUE(called_back); -} - -TEST_P(TaskSchedulerTaskTrackerTest, ShutdownDuringFlush) { - if (GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN) - return; - - // Simulate posting a task. - Task undelayed_task(FROM_HERE, DoNothing(), TaskTraits(GetParam()), - TimeDelta()); - tracker_.WillPostTask(undelayed_task); - - // FlushForTesting() shouldn't return before the undelayed task runs or - // shutdown completes. - CallFlushFromAnotherThread(); - PlatformThread::Sleep(TestTimeouts::tiny_timeout()); - VERIFY_ASYNC_FLUSH_IN_PROGRESS(); - - // Shutdown() should return immediately since there are no pending - // BLOCK_SHUTDOWN tasks. - tracker_.Shutdown(); - - // FlushForTesting() should now return, even if an undelayed task hasn't run. - WAIT_FOR_ASYNC_FLUSH_RETURNED(); -} - -TEST_P(TaskSchedulerTaskTrackerTest, ShutdownDuringFlushAsyncForTesting) { - if (GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN) - return; - - // Simulate posting a task. - Task undelayed_task(FROM_HERE, DoNothing(), TaskTraits(GetParam()), - TimeDelta()); - tracker_.WillPostTask(undelayed_task); - - // FlushAsyncForTesting() shouldn't callback before the undelayed task runs or - // shutdown completes. - WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - tracker_.FlushAsyncForTesting( - BindOnce(&WaitableEvent::Signal, Unretained(&event))); - PlatformThread::Sleep(TestTimeouts::tiny_timeout()); - EXPECT_FALSE(event.IsSignaled()); - - // Shutdown() should return immediately since there are no pending - // BLOCK_SHUTDOWN tasks. - tracker_.Shutdown(); - - // FlushAsyncForTesting() should now callback, even if an undelayed task - // hasn't run. - event.Wait(); -} - -TEST_P(TaskSchedulerTaskTrackerTest, DoublePendingFlushAsyncForTestingFails) { - Task undelayed_task(FROM_HERE, DoNothing(), TaskTraits(GetParam()), - TimeDelta()); - tracker_.WillPostTask(undelayed_task); - - // FlushAsyncForTesting() shouldn't callback before the undelayed task runs. - bool called_back = false; - tracker_.FlushAsyncForTesting( - BindOnce([](bool* called_back) { *called_back = true; }, - Unretained(&called_back))); - EXPECT_FALSE(called_back); - EXPECT_DCHECK_DEATH({ tracker_.FlushAsyncForTesting(BindOnce([]() {})); }); -} - -INSTANTIATE_TEST_CASE_P( - ContinueOnShutdown, - TaskSchedulerTaskTrackerTest, - ::testing::Values(TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN)); -INSTANTIATE_TEST_CASE_P( - SkipOnShutdown, - TaskSchedulerTaskTrackerTest, - ::testing::Values(TaskShutdownBehavior::SKIP_ON_SHUTDOWN)); -INSTANTIATE_TEST_CASE_P( - BlockShutdown, - TaskSchedulerTaskTrackerTest, - ::testing::Values(TaskShutdownBehavior::BLOCK_SHUTDOWN)); - -namespace { - -void ExpectSequenceToken(SequenceToken sequence_token) { - EXPECT_EQ(sequence_token, SequenceToken::GetForCurrentThread()); -} - -} // namespace - -// Verify that SequenceToken::GetForCurrentThread() returns the Sequence's token -// when a Task runs. -TEST_F(TaskSchedulerTaskTrackerTest, CurrentSequenceToken) { - scoped_refptr<Sequence> sequence = MakeRefCounted<Sequence>(); - - const SequenceToken sequence_token = sequence->token(); - Task task(FROM_HERE, Bind(&ExpectSequenceToken, sequence_token), TaskTraits(), - TimeDelta()); - tracker_.WillPostTask(task); - - sequence->PushTask(std::move(task)); - - EXPECT_FALSE(SequenceToken::GetForCurrentThread().IsValid()); - sequence = tracker_.WillScheduleSequence(std::move(sequence), - &never_notified_observer_); - ASSERT_TRUE(sequence); - tracker_.RunAndPopNextTask(std::move(sequence), &never_notified_observer_); - EXPECT_FALSE(SequenceToken::GetForCurrentThread().IsValid()); -} - -TEST_F(TaskSchedulerTaskTrackerTest, LoadWillPostAndRunBeforeShutdown) { - // Post and run tasks asynchronously. - std::vector<std::unique_ptr<ThreadPostingAndRunningTask>> threads; - - for (size_t i = 0; i < kLoadTestNumIterations; ++i) { - threads.push_back(std::make_unique<ThreadPostingAndRunningTask>( - &tracker_, CreateTask(TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN), - ThreadPostingAndRunningTask::Action::WILL_POST_AND_RUN, true)); - threads.back()->Start(); - - threads.push_back(std::make_unique<ThreadPostingAndRunningTask>( - &tracker_, CreateTask(TaskShutdownBehavior::SKIP_ON_SHUTDOWN), - ThreadPostingAndRunningTask::Action::WILL_POST_AND_RUN, true)); - threads.back()->Start(); - - threads.push_back(std::make_unique<ThreadPostingAndRunningTask>( - &tracker_, CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN), - ThreadPostingAndRunningTask::Action::WILL_POST_AND_RUN, true)); - threads.back()->Start(); - } - - for (const auto& thread : threads) - thread->Join(); - - // Expect all tasks to be executed. - EXPECT_EQ(kLoadTestNumIterations * 3, NumTasksExecuted()); - - // Should return immediately because no tasks are blocking shutdown. - tracker_.Shutdown(); -} - -TEST_F(TaskSchedulerTaskTrackerTest, - LoadWillPostBeforeShutdownAndRunDuringShutdown) { - // Post tasks asynchronously. - std::vector<Task> tasks_continue_on_shutdown; - std::vector<Task> tasks_skip_on_shutdown; - std::vector<Task> tasks_block_shutdown; - for (size_t i = 0; i < kLoadTestNumIterations; ++i) { - tasks_continue_on_shutdown.push_back( - CreateTask(TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN)); - tasks_skip_on_shutdown.push_back( - CreateTask(TaskShutdownBehavior::SKIP_ON_SHUTDOWN)); - tasks_block_shutdown.push_back( - CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN)); - } - - std::vector<std::unique_ptr<ThreadPostingAndRunningTask>> post_threads; - for (size_t i = 0; i < kLoadTestNumIterations; ++i) { - post_threads.push_back(std::make_unique<ThreadPostingAndRunningTask>( - &tracker_, &tasks_continue_on_shutdown[i], - ThreadPostingAndRunningTask::Action::WILL_POST, true)); - post_threads.back()->Start(); - - post_threads.push_back(std::make_unique<ThreadPostingAndRunningTask>( - &tracker_, &tasks_skip_on_shutdown[i], - ThreadPostingAndRunningTask::Action::WILL_POST, true)); - post_threads.back()->Start(); - - post_threads.push_back(std::make_unique<ThreadPostingAndRunningTask>( - &tracker_, &tasks_block_shutdown[i], - ThreadPostingAndRunningTask::Action::WILL_POST, true)); - post_threads.back()->Start(); - } - - for (const auto& thread : post_threads) - thread->Join(); - - // Call Shutdown() asynchronously. - CallShutdownAsync(); - - // Run tasks asynchronously. - std::vector<std::unique_ptr<ThreadPostingAndRunningTask>> run_threads; - for (size_t i = 0; i < kLoadTestNumIterations; ++i) { - run_threads.push_back(std::make_unique<ThreadPostingAndRunningTask>( - &tracker_, std::move(tasks_continue_on_shutdown[i]), - ThreadPostingAndRunningTask::Action::RUN, false)); - run_threads.back()->Start(); - - run_threads.push_back(std::make_unique<ThreadPostingAndRunningTask>( - &tracker_, std::move(tasks_skip_on_shutdown[i]), - ThreadPostingAndRunningTask::Action::RUN, false)); - run_threads.back()->Start(); - - run_threads.push_back(std::make_unique<ThreadPostingAndRunningTask>( - &tracker_, std::move(tasks_block_shutdown[i]), - ThreadPostingAndRunningTask::Action::RUN, false)); - run_threads.back()->Start(); - } - - for (const auto& thread : run_threads) - thread->Join(); - - WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED(); - - // Expect BLOCK_SHUTDOWN tasks to have been executed. - EXPECT_EQ(kLoadTestNumIterations, NumTasksExecuted()); -} - -TEST_F(TaskSchedulerTaskTrackerTest, LoadWillPostAndRunDuringShutdown) { - // Inform |task_tracker_| that a BLOCK_SHUTDOWN task will be posted just to - // block shutdown. - Task block_shutdown_task(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN)); - EXPECT_TRUE(tracker_.WillPostTask(block_shutdown_task)); - - // Call Shutdown() asynchronously. - CallShutdownAsync(); - - // Post and run tasks asynchronously. - std::vector<std::unique_ptr<ThreadPostingAndRunningTask>> threads; - - for (size_t i = 0; i < kLoadTestNumIterations; ++i) { - threads.push_back(std::make_unique<ThreadPostingAndRunningTask>( - &tracker_, CreateTask(TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN), - ThreadPostingAndRunningTask::Action::WILL_POST_AND_RUN, false)); - threads.back()->Start(); - - threads.push_back(std::make_unique<ThreadPostingAndRunningTask>( - &tracker_, CreateTask(TaskShutdownBehavior::SKIP_ON_SHUTDOWN), - ThreadPostingAndRunningTask::Action::WILL_POST_AND_RUN, false)); - threads.back()->Start(); - - threads.push_back(std::make_unique<ThreadPostingAndRunningTask>( - &tracker_, CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN), - ThreadPostingAndRunningTask::Action::WILL_POST_AND_RUN, true)); - threads.back()->Start(); - } - - for (const auto& thread : threads) - thread->Join(); - - // Expect BLOCK_SHUTDOWN tasks to have been executed. - EXPECT_EQ(kLoadTestNumIterations, NumTasksExecuted()); - - // Shutdown() shouldn't return before |block_shutdown_task| is executed. - VERIFY_ASYNC_SHUTDOWN_IN_PROGRESS(); - - // Unblock shutdown by running |block_shutdown_task|. - DispatchAndRunTaskWithTracker(std::move(block_shutdown_task)); - EXPECT_EQ(kLoadTestNumIterations + 1, NumTasksExecuted()); - WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED(); -} - -// Verify that RunAndPopNextTask() returns the sequence from which it ran a task -// when it can be rescheduled. -TEST_F(TaskSchedulerTaskTrackerTest, - RunAndPopNextTaskReturnsSequenceToReschedule) { - Task task_1(FROM_HERE, DoNothing(), TaskTraits(), TimeDelta()); - EXPECT_TRUE(tracker_.WillPostTask(task_1)); - Task task_2(FROM_HERE, DoNothing(), TaskTraits(), TimeDelta()); - EXPECT_TRUE(tracker_.WillPostTask(task_2)); - - scoped_refptr<Sequence> sequence = - test::CreateSequenceWithTask(std::move(task_1)); - sequence->PushTask(std::move(task_2)); - EXPECT_EQ(sequence, tracker_.WillScheduleSequence(sequence, nullptr)); - - EXPECT_EQ(sequence, tracker_.RunAndPopNextTask(sequence, nullptr)); -} - -// Verify that WillScheduleSequence() returns nullptr when it receives a -// background sequence and the maximum number of background sequences that can -// be scheduled concurrently is reached. Verify that an observer is notified -// when a background sequence can be scheduled (i.e. when one of the previously -// scheduled background sequences has run). -TEST_F(TaskSchedulerTaskTrackerTest, - WillScheduleBackgroundSequenceWithMaxBackgroundSequences) { - constexpr int kMaxNumScheduledBackgroundSequences = 2; - TaskTracker tracker("Test", kMaxNumScheduledBackgroundSequences); - - // Simulate posting |kMaxNumScheduledBackgroundSequences| background tasks - // and scheduling the associated sequences. This should succeed. - std::vector<scoped_refptr<Sequence>> scheduled_sequences; - testing::StrictMock<MockCanScheduleSequenceObserver> never_notified_observer; - for (int i = 0; i < kMaxNumScheduledBackgroundSequences; ++i) { - Task task(FROM_HERE, DoNothing(), TaskTraits(TaskPriority::BACKGROUND), - TimeDelta()); - EXPECT_TRUE(tracker.WillPostTask(task)); - scoped_refptr<Sequence> sequence = - test::CreateSequenceWithTask(std::move(task)); - EXPECT_EQ(sequence, - tracker.WillScheduleSequence(sequence, &never_notified_observer)); - scheduled_sequences.push_back(std::move(sequence)); - } - - // Simulate posting extra background tasks and scheduling the associated - // sequences. This should fail because the maximum number of background - // sequences that can be scheduled concurrently is already reached. - std::vector<std::unique_ptr<bool>> extra_tasks_did_run; - std::vector< - std::unique_ptr<testing::StrictMock<MockCanScheduleSequenceObserver>>> - extra_observers; - std::vector<scoped_refptr<Sequence>> extra_sequences; - for (int i = 0; i < kMaxNumScheduledBackgroundSequences; ++i) { - extra_tasks_did_run.push_back(std::make_unique<bool>()); - Task extra_task( - FROM_HERE, - BindOnce([](bool* extra_task_did_run) { *extra_task_did_run = true; }, - Unretained(extra_tasks_did_run.back().get())), - TaskTraits(TaskPriority::BACKGROUND), TimeDelta()); - EXPECT_TRUE(tracker.WillPostTask(extra_task)); - extra_sequences.push_back( - test::CreateSequenceWithTask(std::move(extra_task))); - extra_observers.push_back( - std::make_unique< - testing::StrictMock<MockCanScheduleSequenceObserver>>()); - EXPECT_EQ(nullptr, - tracker.WillScheduleSequence(extra_sequences.back(), - extra_observers.back().get())); - } - - // Run the sequences scheduled at the beginning of the test. Expect an - // observer from |extra_observer| to be notified every time a task finishes to - // run. - for (int i = 0; i < kMaxNumScheduledBackgroundSequences; ++i) { - EXPECT_CALL(*extra_observers[i].get(), - MockOnCanScheduleSequence(extra_sequences[i].get())); - EXPECT_FALSE(tracker.RunAndPopNextTask(scheduled_sequences[i], - &never_notified_observer)); - testing::Mock::VerifyAndClear(extra_observers[i].get()); - } - - // Run the extra sequences. - for (int i = 0; i < kMaxNumScheduledBackgroundSequences; ++i) { - EXPECT_FALSE(*extra_tasks_did_run[i]); - EXPECT_FALSE(tracker.RunAndPopNextTask(extra_sequences[i], - &never_notified_observer)); - EXPECT_TRUE(*extra_tasks_did_run[i]); - } -} - -namespace { - -void SetBool(bool* arg) { - ASSERT_TRUE(arg); - EXPECT_FALSE(*arg); - *arg = true; -} - -} // namespace - -// Verify that RunAndPopNextTask() doesn't reschedule the background sequence it -// was assigned if there is a preempted background sequence with an earlier -// sequence time (compared to the next task in the sequence assigned to -// RunAndPopNextTask()). -TEST_F(TaskSchedulerTaskTrackerTest, - RunNextBackgroundTaskWithEarlierPendingBackgroundTask) { - constexpr int kMaxNumScheduledBackgroundSequences = 1; - TaskTracker tracker("Test", kMaxNumScheduledBackgroundSequences); - testing::StrictMock<MockCanScheduleSequenceObserver> never_notified_observer; - - // Simulate posting a background task and scheduling the associated sequence. - // This should succeed. - bool task_a_1_did_run = false; - Task task_a_1(FROM_HERE, BindOnce(&SetBool, Unretained(&task_a_1_did_run)), - TaskTraits(TaskPriority::BACKGROUND), TimeDelta()); - EXPECT_TRUE(tracker.WillPostTask(task_a_1)); - scoped_refptr<Sequence> sequence_a = - test::CreateSequenceWithTask(std::move(task_a_1)); - EXPECT_EQ(sequence_a, - tracker.WillScheduleSequence(sequence_a, &never_notified_observer)); - - // Simulate posting an extra background task and scheduling the associated - // sequence. This should fail because the maximum number of background - // sequences that can be scheduled concurrently is already reached. - bool task_b_1_did_run = false; - Task task_b_1(FROM_HERE, BindOnce(&SetBool, Unretained(&task_b_1_did_run)), - TaskTraits(TaskPriority::BACKGROUND), TimeDelta()); - EXPECT_TRUE(tracker.WillPostTask(task_b_1)); - scoped_refptr<Sequence> sequence_b = - test::CreateSequenceWithTask(std::move(task_b_1)); - testing::StrictMock<MockCanScheduleSequenceObserver> task_b_1_observer; - EXPECT_FALSE(tracker.WillScheduleSequence(sequence_b, &task_b_1_observer)); - - // Wait to be sure that the sequence time of |task_a_2| is after the sequenced - // time of |task_b_1|. - PlatformThread::Sleep(TestTimeouts::tiny_timeout()); - - // Post an extra background task in |sequence_a|. - bool task_a_2_did_run = false; - Task task_a_2(FROM_HERE, BindOnce(&SetBool, Unretained(&task_a_2_did_run)), - TaskTraits(TaskPriority::BACKGROUND), TimeDelta()); - EXPECT_TRUE(tracker.WillPostTask(task_a_2)); - sequence_a->PushTask(std::move(task_a_2)); - - // Run the first task in |sequence_a|. RunAndPopNextTask() should return - // nullptr since |sequence_a| can't be rescheduled immediately. - // |task_b_1_observer| should be notified that |sequence_b| can be scheduled. - testing::StrictMock<MockCanScheduleSequenceObserver> task_a_2_observer; - EXPECT_CALL(task_b_1_observer, MockOnCanScheduleSequence(sequence_b.get())); - EXPECT_FALSE(tracker.RunAndPopNextTask(sequence_a, &task_a_2_observer)); - testing::Mock::VerifyAndClear(&task_b_1_observer); - EXPECT_TRUE(task_a_1_did_run); - - // Run the first task in |sequence_b|. RunAndPopNextTask() should return - // nullptr since |sequence_b| is empty after popping a task from it. - // |task_a_2_observer| should be notified that |sequence_a| can be - // scheduled. - EXPECT_CALL(task_a_2_observer, MockOnCanScheduleSequence(sequence_a.get())); - EXPECT_FALSE(tracker.RunAndPopNextTask(sequence_b, &never_notified_observer)); - testing::Mock::VerifyAndClear(&task_a_2_observer); - EXPECT_TRUE(task_b_1_did_run); - - // Run the first task in |sequence_a|. RunAndPopNextTask() should return - // nullptr since |sequence_b| is empty after popping a task from it. No - // observer should be notified. - EXPECT_FALSE(tracker.RunAndPopNextTask(sequence_a, &never_notified_observer)); - EXPECT_TRUE(task_a_2_did_run); -} - -// Verify that preempted background sequences are scheduled when shutdown -// starts. -TEST_F(TaskSchedulerTaskTrackerTest, - SchedulePreemptedBackgroundSequencesOnShutdown) { - constexpr int kMaxNumScheduledBackgroundSequences = 0; - TaskTracker tracker("Test", kMaxNumScheduledBackgroundSequences); - testing::StrictMock<MockCanScheduleSequenceObserver> observer; - - // Simulate scheduling sequences. TaskTracker should prevent this. - std::vector<scoped_refptr<Sequence>> preempted_sequences; - for (int i = 0; i < 3; ++i) { - Task task(FROM_HERE, DoNothing(), - TaskTraits(TaskPriority::BACKGROUND, - TaskShutdownBehavior::BLOCK_SHUTDOWN), - TimeDelta()); - EXPECT_TRUE(tracker.WillPostTask(task)); - scoped_refptr<Sequence> sequence = - test::CreateSequenceWithTask(std::move(task)); - EXPECT_FALSE(tracker.WillScheduleSequence(sequence, &observer)); - preempted_sequences.push_back(std::move(sequence)); - - // Wait to be sure that tasks have different |sequenced_time|. - PlatformThread::Sleep(TestTimeouts::tiny_timeout()); - } - - // Perform shutdown. Expect |preempted_sequences| to be scheduled in posting - // order. - { - testing::InSequence in_sequence; - for (auto& preempted_sequence : preempted_sequences) { - EXPECT_CALL(observer, MockOnCanScheduleSequence(preempted_sequence.get())) - .WillOnce(testing::Invoke([&tracker](Sequence* sequence) { - // Run the task to unblock shutdown. - tracker.RunAndPopNextTask(sequence, nullptr); - })); - } - tracker.Shutdown(); - } -} - -namespace { - -class WaitAllowedTestThread : public SimpleThread { - public: - WaitAllowedTestThread() : SimpleThread("WaitAllowedTestThread") {} - - private: - void Run() override { - auto task_tracker = std::make_unique<TaskTracker>("Test"); - - // Waiting is allowed by default. Expect TaskTracker to disallow it before - // running a task without the WithBaseSyncPrimitives() trait. - internal::AssertBaseSyncPrimitivesAllowed(); - Task task_without_sync_primitives( - FROM_HERE, Bind([]() { - EXPECT_DCHECK_DEATH({ internal::AssertBaseSyncPrimitivesAllowed(); }); - }), - TaskTraits(), TimeDelta()); - EXPECT_TRUE(task_tracker->WillPostTask(task_without_sync_primitives)); - testing::StrictMock<MockCanScheduleSequenceObserver> - never_notified_observer; - auto sequence_without_sync_primitives = task_tracker->WillScheduleSequence( - test::CreateSequenceWithTask(std::move(task_without_sync_primitives)), - &never_notified_observer); - ASSERT_TRUE(sequence_without_sync_primitives); - task_tracker->RunAndPopNextTask(std::move(sequence_without_sync_primitives), - &never_notified_observer); - - // Disallow waiting. Expect TaskTracker to allow it before running a task - // with the WithBaseSyncPrimitives() trait. - ThreadRestrictions::DisallowWaiting(); - Task task_with_sync_primitives( - FROM_HERE, Bind([]() { - // Shouldn't fail. - internal::AssertBaseSyncPrimitivesAllowed(); - }), - TaskTraits(WithBaseSyncPrimitives()), TimeDelta()); - EXPECT_TRUE(task_tracker->WillPostTask(task_with_sync_primitives)); - auto sequence_with_sync_primitives = task_tracker->WillScheduleSequence( - test::CreateSequenceWithTask(std::move(task_with_sync_primitives)), - &never_notified_observer); - ASSERT_TRUE(sequence_with_sync_primitives); - task_tracker->RunAndPopNextTask(std::move(sequence_with_sync_primitives), - &never_notified_observer); - - ScopedAllowBaseSyncPrimitivesForTesting - allow_wait_in_task_tracker_destructor; - task_tracker.reset(); - } - - DISALLOW_COPY_AND_ASSIGN(WaitAllowedTestThread); -}; - -} // namespace - -// Verify that AssertIOAllowed() succeeds only for a WithBaseSyncPrimitives() -// task. -TEST(TaskSchedulerTaskTrackerWaitAllowedTest, WaitAllowed) { - // Run the test on the separate thread since it is not possible to reset the - // "wait allowed" bit of a thread without being a friend of - // ThreadRestrictions. - testing::GTEST_FLAG(death_test_style) = "threadsafe"; - WaitAllowedTestThread wait_allowed_test_thread; - wait_allowed_test_thread.Start(); - wait_allowed_test_thread.Join(); -} - -// Verify that TaskScheduler.TaskLatency.* histograms are correctly recorded -// when a task runs. -TEST(TaskSchedulerTaskTrackerHistogramTest, TaskLatency) { - auto statistics_recorder = StatisticsRecorder::CreateTemporaryForTesting(); - - TaskTracker tracker("Test"); - testing::StrictMock<MockCanScheduleSequenceObserver> never_notified_observer; - - struct { - const TaskTraits traits; - const char* const expected_histogram; - } static constexpr kTests[] = { - {{TaskPriority::BACKGROUND}, - "TaskScheduler.TaskLatencyMicroseconds.Test." - "BackgroundTaskPriority"}, - {{MayBlock(), TaskPriority::BACKGROUND}, - "TaskScheduler.TaskLatencyMicroseconds.Test." - "BackgroundTaskPriority_MayBlock"}, - {{WithBaseSyncPrimitives(), TaskPriority::BACKGROUND}, - "TaskScheduler.TaskLatencyMicroseconds.Test." - "BackgroundTaskPriority_MayBlock"}, - {{TaskPriority::USER_VISIBLE}, - "TaskScheduler.TaskLatencyMicroseconds.Test." - "UserVisibleTaskPriority"}, - {{MayBlock(), TaskPriority::USER_VISIBLE}, - "TaskScheduler.TaskLatencyMicroseconds.Test." - "UserVisibleTaskPriority_MayBlock"}, - {{WithBaseSyncPrimitives(), TaskPriority::USER_VISIBLE}, - "TaskScheduler.TaskLatencyMicroseconds.Test." - "UserVisibleTaskPriority_MayBlock"}, - {{TaskPriority::USER_BLOCKING}, - "TaskScheduler.TaskLatencyMicroseconds.Test." - "UserBlockingTaskPriority"}, - {{MayBlock(), TaskPriority::USER_BLOCKING}, - "TaskScheduler.TaskLatencyMicroseconds.Test." - "UserBlockingTaskPriority_MayBlock"}, - {{WithBaseSyncPrimitives(), TaskPriority::USER_BLOCKING}, - "TaskScheduler.TaskLatencyMicroseconds.Test." - "UserBlockingTaskPriority_MayBlock"}}; - - for (const auto& test : kTests) { - Task task(FROM_HERE, DoNothing(), test.traits, TimeDelta()); - ASSERT_TRUE(tracker.WillPostTask(task)); - - HistogramTester tester; - - auto sequence = tracker.WillScheduleSequence( - test::CreateSequenceWithTask(std::move(task)), - &never_notified_observer); - ASSERT_TRUE(sequence); - tracker.RunAndPopNextTask(std::move(sequence), &never_notified_observer); - tester.ExpectTotalCount(test.expected_histogram, 1); - } -} - -} // namespace internal -} // namespace base
diff --git a/base/task_scheduler/task_traits_unittest.cc b/base/task_scheduler/task_traits_unittest.cc deleted file mode 100644 index 2a35048..0000000 --- a/base/task_scheduler/task_traits_unittest.cc +++ /dev/null
@@ -1,175 +0,0 @@ -// 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/task_scheduler/task_traits.h" - -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(TaskSchedulerTaskTraitsTest, Default) { - constexpr TaskTraits traits = {}; - EXPECT_FALSE(traits.priority_set_explicitly()); - EXPECT_EQ(TaskPriority::USER_VISIBLE, traits.priority()); - EXPECT_EQ(TaskShutdownBehavior::SKIP_ON_SHUTDOWN, traits.shutdown_behavior()); - EXPECT_FALSE(traits.may_block()); - EXPECT_FALSE(traits.with_base_sync_primitives()); -} - -TEST(TaskSchedulerTaskTraitsTest, TaskPriority) { - constexpr TaskTraits traits = {TaskPriority::BACKGROUND}; - EXPECT_TRUE(traits.priority_set_explicitly()); - EXPECT_EQ(TaskPriority::BACKGROUND, traits.priority()); - EXPECT_EQ(TaskShutdownBehavior::SKIP_ON_SHUTDOWN, traits.shutdown_behavior()); - EXPECT_FALSE(traits.may_block()); - EXPECT_FALSE(traits.with_base_sync_primitives()); -} - -TEST(TaskSchedulerTaskTraitsTest, TaskShutdownBehavior) { - constexpr TaskTraits traits = {TaskShutdownBehavior::BLOCK_SHUTDOWN}; - EXPECT_FALSE(traits.priority_set_explicitly()); - EXPECT_EQ(TaskPriority::USER_VISIBLE, traits.priority()); - EXPECT_EQ(TaskShutdownBehavior::BLOCK_SHUTDOWN, traits.shutdown_behavior()); - EXPECT_FALSE(traits.may_block()); - EXPECT_FALSE(traits.with_base_sync_primitives()); -} - -TEST(TaskSchedulerTaskTraitsTest, MayBlock) { - constexpr TaskTraits traits = {MayBlock()}; - EXPECT_FALSE(traits.priority_set_explicitly()); - EXPECT_EQ(TaskPriority::USER_VISIBLE, traits.priority()); - EXPECT_EQ(TaskShutdownBehavior::SKIP_ON_SHUTDOWN, traits.shutdown_behavior()); - EXPECT_TRUE(traits.may_block()); - EXPECT_FALSE(traits.with_base_sync_primitives()); -} - -TEST(TaskSchedulerTaskTraitsTest, WithBaseSyncPrimitives) { - constexpr TaskTraits traits = {WithBaseSyncPrimitives()}; - EXPECT_FALSE(traits.priority_set_explicitly()); - EXPECT_EQ(TaskPriority::USER_VISIBLE, traits.priority()); - EXPECT_EQ(TaskShutdownBehavior::SKIP_ON_SHUTDOWN, traits.shutdown_behavior()); - EXPECT_FALSE(traits.may_block()); - EXPECT_TRUE(traits.with_base_sync_primitives()); -} - -TEST(TaskSchedulerTaskTraitsTest, MultipleTraits) { - constexpr TaskTraits traits = {TaskPriority::BACKGROUND, - TaskShutdownBehavior::BLOCK_SHUTDOWN, - MayBlock(), WithBaseSyncPrimitives()}; - EXPECT_TRUE(traits.priority_set_explicitly()); - EXPECT_EQ(TaskPriority::BACKGROUND, traits.priority()); - EXPECT_EQ(TaskShutdownBehavior::BLOCK_SHUTDOWN, traits.shutdown_behavior()); - EXPECT_TRUE(traits.may_block()); - EXPECT_TRUE(traits.with_base_sync_primitives()); -} - -TEST(TaskSchedulerTaskTraitsTest, Copy) { - constexpr TaskTraits traits = {TaskPriority::BACKGROUND, - TaskShutdownBehavior::BLOCK_SHUTDOWN, - MayBlock(), WithBaseSyncPrimitives()}; - constexpr TaskTraits traits_copy(traits); - EXPECT_EQ(traits.priority_set_explicitly(), - traits_copy.priority_set_explicitly()); - EXPECT_EQ(traits.priority(), traits_copy.priority()); - EXPECT_EQ(traits.shutdown_behavior(), traits_copy.shutdown_behavior()); - EXPECT_EQ(traits.may_block(), traits_copy.may_block()); - EXPECT_EQ(traits.with_base_sync_primitives(), - traits_copy.with_base_sync_primitives()); -} - -TEST(TaskSchedulerTaskTraitsTest, OverridePriority) { - constexpr TaskTraits left = {TaskPriority::BACKGROUND}; - constexpr TaskTraits right = {TaskPriority::USER_BLOCKING}; - constexpr TaskTraits overridden = TaskTraits::Override(left, right); - EXPECT_TRUE(overridden.priority_set_explicitly()); - EXPECT_EQ(TaskPriority::USER_BLOCKING, overridden.priority()); - EXPECT_FALSE(overridden.shutdown_behavior_set_explicitly()); - EXPECT_EQ(TaskShutdownBehavior::SKIP_ON_SHUTDOWN, - overridden.shutdown_behavior()); - EXPECT_FALSE(overridden.may_block()); - EXPECT_FALSE(overridden.with_base_sync_primitives()); -} - -TEST(TaskSchedulerTaskTraitsTest, OverrideShutdownBehavior) { - constexpr TaskTraits left = {TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}; - constexpr TaskTraits right = {TaskShutdownBehavior::BLOCK_SHUTDOWN}; - constexpr TaskTraits overridden = TaskTraits::Override(left, right); - EXPECT_FALSE(overridden.priority_set_explicitly()); - EXPECT_EQ(TaskPriority::USER_VISIBLE, overridden.priority()); - EXPECT_TRUE(overridden.shutdown_behavior_set_explicitly()); - EXPECT_EQ(TaskShutdownBehavior::BLOCK_SHUTDOWN, - overridden.shutdown_behavior()); - EXPECT_FALSE(overridden.may_block()); - EXPECT_FALSE(overridden.with_base_sync_primitives()); -} - -TEST(TaskSchedulerTaskTraitsTest, OverrideMayBlock) { - { - constexpr TaskTraits left = {MayBlock()}; - constexpr TaskTraits right = {}; - constexpr TaskTraits overridden = TaskTraits::Override(left, right); - EXPECT_FALSE(overridden.priority_set_explicitly()); - EXPECT_EQ(TaskPriority::USER_VISIBLE, overridden.priority()); - EXPECT_FALSE(overridden.shutdown_behavior_set_explicitly()); - EXPECT_EQ(TaskShutdownBehavior::SKIP_ON_SHUTDOWN, - overridden.shutdown_behavior()); - EXPECT_TRUE(overridden.may_block()); - EXPECT_FALSE(overridden.with_base_sync_primitives()); - } - { - constexpr TaskTraits left = {}; - constexpr TaskTraits right = {MayBlock()}; - constexpr TaskTraits overridden = TaskTraits::Override(left, right); - EXPECT_FALSE(overridden.priority_set_explicitly()); - EXPECT_EQ(TaskPriority::USER_VISIBLE, overridden.priority()); - EXPECT_FALSE(overridden.shutdown_behavior_set_explicitly()); - EXPECT_EQ(TaskShutdownBehavior::SKIP_ON_SHUTDOWN, - overridden.shutdown_behavior()); - EXPECT_TRUE(overridden.may_block()); - EXPECT_FALSE(overridden.with_base_sync_primitives()); - } -} - -TEST(TaskSchedulerTaskTraitsTest, OverrideWithBaseSyncPrimitives) { - { - constexpr TaskTraits left = {WithBaseSyncPrimitives()}; - constexpr TaskTraits right = {}; - constexpr TaskTraits overridden = TaskTraits::Override(left, right); - EXPECT_FALSE(overridden.priority_set_explicitly()); - EXPECT_EQ(TaskPriority::USER_VISIBLE, overridden.priority()); - EXPECT_FALSE(overridden.shutdown_behavior_set_explicitly()); - EXPECT_EQ(TaskShutdownBehavior::SKIP_ON_SHUTDOWN, - overridden.shutdown_behavior()); - EXPECT_FALSE(overridden.may_block()); - EXPECT_TRUE(overridden.with_base_sync_primitives()); - } - { - constexpr TaskTraits left = {}; - constexpr TaskTraits right = {WithBaseSyncPrimitives()}; - constexpr TaskTraits overridden = TaskTraits::Override(left, right); - EXPECT_FALSE(overridden.priority_set_explicitly()); - EXPECT_EQ(TaskPriority::USER_VISIBLE, overridden.priority()); - EXPECT_FALSE(overridden.shutdown_behavior_set_explicitly()); - EXPECT_EQ(TaskShutdownBehavior::SKIP_ON_SHUTDOWN, - overridden.shutdown_behavior()); - EXPECT_FALSE(overridden.may_block()); - EXPECT_TRUE(overridden.with_base_sync_primitives()); - } -} - -TEST(TaskSchedulerTaskTraitsTest, OverrideMultipleTraits) { - constexpr TaskTraits left = {MayBlock(), TaskPriority::BACKGROUND, - TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}; - constexpr TaskTraits right = {WithBaseSyncPrimitives(), - TaskPriority::USER_BLOCKING}; - constexpr TaskTraits overridden = TaskTraits::Override(left, right); - EXPECT_TRUE(overridden.priority_set_explicitly()); - EXPECT_EQ(right.priority(), overridden.priority()); - EXPECT_TRUE(overridden.shutdown_behavior_set_explicitly()); - EXPECT_EQ(left.shutdown_behavior(), overridden.shutdown_behavior()); - EXPECT_TRUE(overridden.may_block()); - EXPECT_TRUE(overridden.with_base_sync_primitives()); -} - -} // namespace base
diff --git a/base/task_scheduler/task_traits_unittest.nc b/base/task_scheduler/task_traits_unittest.nc deleted file mode 100644 index 97f9c4b..0000000 --- a/base/task_scheduler/task_traits_unittest.nc +++ /dev/null
@@ -1,31 +0,0 @@ -// 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. - -// This is a "No Compile Test" suite. -// http://dev.chromium.org/developers/testing/no-compile-tests - -#include "base/task_scheduler/task_traits.h" - -namespace base { - -#if defined(NCTEST_TASK_TRAITS_MULTIPLE_MAY_BLOCK) // [r"Multiple arguments of the same type were provided to the constructor of TaskTraits."] -constexpr TaskTraits traits = {MayBlock(), MayBlock()}; -#elif defined(NCTEST_TASK_TRAITS_MULTIPLE_WITH_BASE_SYNC_PRIMITIVES) // [r"Multiple arguments of the same type were provided to the constructor of TaskTraits."] -constexpr TaskTraits traits = {WithBaseSyncPrimitives(), - WithBaseSyncPrimitives()}; -#elif defined(NCTEST_TASK_TRAITS_MULTIPLE_TASK_PRIORITY) // [r"Multiple arguments of the same type were provided to the constructor of TaskTraits."] -constexpr TaskTraits traits = {TaskPriority::BACKGROUND, - TaskPriority::USER_BLOCKING}; -#elif defined(NCTEST_TASK_TRAITS_MULTIPLE_SHUTDOWN_BEHAVIOR) // [r"Multiple arguments of the same type were provided to the constructor of TaskTraits."] -constexpr TaskTraits traits = {TaskShutdownBehavior::BLOCK_SHUTDOWN, - TaskShutdownBehavior::BLOCK_SHUTDOWN}; -#elif defined(NCTEST_TASK_TRAITS_MULTIPLE_SAME_TYPE_MIX) // [r"Multiple arguments of the same type were provided to the constructor of TaskTraits."] -constexpr TaskTraits traits = {TaskShutdownBehavior::BLOCK_SHUTDOWN, - MayBlock(), - TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}; -#elif defined(NCTEST_TASK_TRAITS_INVALID_TYPE) // [r"no matching constructor for initialization of 'const base::TaskTraits'"] -constexpr TaskTraits traits = {TaskShutdownBehavior::BLOCK_SHUTDOWN, true}; -#endif - -} // namespace base
diff --git a/base/task_scheduler/task_unittest.cc b/base/task_scheduler/task_unittest.cc deleted file mode 100644 index 31a59de..0000000 --- a/base/task_scheduler/task_unittest.cc +++ /dev/null
@@ -1,60 +0,0 @@ -// 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/task_scheduler/task.h" - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/location.h" -#include "base/task_scheduler/task_traits.h" -#include "base/time/time.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace internal { - -// Verify that the shutdown behavior of a BLOCK_SHUTDOWN delayed task is -// adjusted to SKIP_ON_SHUTDOWN. The shutown behavior of other delayed tasks -// should not change. -TEST(TaskSchedulerTaskTest, ShutdownBehaviorChangeWithDelay) { - Task continue_on_shutdown(FROM_HERE, DoNothing(), - {TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, - TimeDelta::FromSeconds(1)); - EXPECT_EQ(TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN, - continue_on_shutdown.traits.shutdown_behavior()); - - Task skip_on_shutdown(FROM_HERE, DoNothing(), - {TaskShutdownBehavior::SKIP_ON_SHUTDOWN}, - TimeDelta::FromSeconds(1)); - EXPECT_EQ(TaskShutdownBehavior::SKIP_ON_SHUTDOWN, - skip_on_shutdown.traits.shutdown_behavior()); - - Task block_shutdown(FROM_HERE, DoNothing(), - {TaskShutdownBehavior::BLOCK_SHUTDOWN}, - TimeDelta::FromSeconds(1)); - EXPECT_EQ(TaskShutdownBehavior::SKIP_ON_SHUTDOWN, - block_shutdown.traits.shutdown_behavior()); -} - -// Verify that the shutdown behavior of undelayed tasks is not adjusted. -TEST(TaskSchedulerTaskTest, NoShutdownBehaviorChangeNoDelay) { - Task continue_on_shutdown(FROM_HERE, DoNothing(), - {TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, - TimeDelta()); - EXPECT_EQ(TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN, - continue_on_shutdown.traits.shutdown_behavior()); - - Task skip_on_shutdown(FROM_HERE, DoNothing(), - {TaskShutdownBehavior::SKIP_ON_SHUTDOWN}, TimeDelta()); - EXPECT_EQ(TaskShutdownBehavior::SKIP_ON_SHUTDOWN, - skip_on_shutdown.traits.shutdown_behavior()); - - Task block_shutdown(FROM_HERE, DoNothing(), - {TaskShutdownBehavior::BLOCK_SHUTDOWN}, TimeDelta()); - EXPECT_EQ(TaskShutdownBehavior::BLOCK_SHUTDOWN, - block_shutdown.traits.shutdown_behavior()); -} - -} // namespace internal -} // namespace base
diff --git a/base/task_scheduler/tracked_ref_unittest.cc b/base/task_scheduler/tracked_ref_unittest.cc deleted file mode 100644 index b793c07..0000000 --- a/base/task_scheduler/tracked_ref_unittest.cc +++ /dev/null
@@ -1,150 +0,0 @@ -// 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/task_scheduler/tracked_ref.h" - -#include <memory> - -#include "base/bind.h" -#include "base/macros.h" -#include "base/synchronization/atomic_flag.h" -#include "base/test/test_timeouts.h" -#include "base/threading/thread.h" -#include "base/time/time.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace internal { - -namespace { - -class ObjectWithTrackedRefs { - public: - ObjectWithTrackedRefs() : tracked_ref_factory_(this) {} - ~ObjectWithTrackedRefs() { under_destruction_.Set(); } - - TrackedRef<ObjectWithTrackedRefs> GetTrackedRef() { - return tracked_ref_factory_.GetTrackedRef(); - } - - bool under_destruction() const { return under_destruction_.IsSet(); } - - private: - // True once ~ObjectWithTrackedRefs() has been initiated. - AtomicFlag under_destruction_; - - TrackedRefFactory<ObjectWithTrackedRefs> tracked_ref_factory_; - - DISALLOW_COPY_AND_ASSIGN(ObjectWithTrackedRefs); -}; - -} // namespace - -// Test that an object with a TrackedRefFactory can be destroyed by a single -// owner but that its destruction will be blocked on the TrackedRefs being -// released. -TEST(TrackedRefTest, TrackedRefObjectDeletion) { - Thread thread("TrackedRefTestThread"); - thread.Start(); - - std::unique_ptr<ObjectWithTrackedRefs> obj = - std::make_unique<ObjectWithTrackedRefs>(); - - TimeTicks begin = TimeTicks::Now(); - - thread.task_runner()->PostDelayedTask( - FROM_HERE, - BindOnce( - [](TrackedRef<ObjectWithTrackedRefs> obj) { - // By the time this kicks in, the object should already be under - // destruction, but blocked on this TrackedRef being released. This - // is technically racy (main thread has to run |obj.reset()| and - // this thread has to observe the side-effects before this delayed - // task fires). If this ever flakes this expectation could be turned - // into a while(!obj->under_destruction()); but until that's proven - // flaky in practice, this expectation is more readable and - // diagnosable then a hang. - EXPECT_TRUE(obj->under_destruction()); - }, - obj->GetTrackedRef()), - TestTimeouts::tiny_timeout()); - - // This should kick off destruction but block until the above task resolves - // and releases the TrackedRef. - obj.reset(); - EXPECT_GE(TimeTicks::Now() - begin, TestTimeouts::tiny_timeout()); -} - -TEST(TrackedRefTest, ManyThreadsRacing) { - constexpr int kNumThreads = 16; - std::vector<std::unique_ptr<Thread>> threads; - for (int i = 0; i < kNumThreads; ++i) { - threads.push_back(std::make_unique<Thread>("TrackedRefTestThread")); - threads.back()->StartAndWaitForTesting(); - } - - std::unique_ptr<ObjectWithTrackedRefs> obj = - std::make_unique<ObjectWithTrackedRefs>(); - - // Send a TrackedRef to each thread. - for (auto& thread : threads) { - thread->task_runner()->PostTask( - FROM_HERE, BindOnce( - [](TrackedRef<ObjectWithTrackedRefs> obj) { - // Confirm it's still safe to - // dereference |obj| (and, bonus, that - // playing with TrackedRefs some more - // isn't problematic). - EXPECT_TRUE(obj->GetTrackedRef()); - }, - obj->GetTrackedRef())); - } - - // Initiate destruction racily with the above tasks' execution (they will - // crash if TrackedRefs aren't WAI). - obj.reset(); -} - -// Test that instantiating and deleting a TrackedRefFactory without ever taking -// a TrackedRef on it is fine. -TEST(TrackedRefTest, NoTrackedRefs) { - ObjectWithTrackedRefs obj; -} - -namespace { -void ConsumesTrackedRef(TrackedRef<ObjectWithTrackedRefs> obj) {} -} // namespace - -// Test that destroying a TrackedRefFactory which had TrackedRefs in the past -// that are already gone is WAI. -TEST(TrackedRefTest, NoPendingTrackedRefs) { - ObjectWithTrackedRefs obj; - ConsumesTrackedRef(obj.GetTrackedRef()); -} - -TEST(TrackedRefTest, CopyAndMoveSemantics) { - struct Foo { - Foo() : factory(this) {} - TrackedRefFactory<Foo> factory; - }; - Foo foo; - - EXPECT_EQ(1, foo.factory.live_tracked_refs_.SubtleRefCountForDebug()); - - { - TrackedRef<Foo> plain = foo.factory.GetTrackedRef(); - EXPECT_EQ(2, foo.factory.live_tracked_refs_.SubtleRefCountForDebug()); - - TrackedRef<Foo> copy_constructed(plain); - EXPECT_EQ(3, foo.factory.live_tracked_refs_.SubtleRefCountForDebug()); - - TrackedRef<Foo> moved_constructed(std::move(copy_constructed)); - EXPECT_EQ(3, foo.factory.live_tracked_refs_.SubtleRefCountForDebug()); - } - - EXPECT_EQ(1, foo.factory.live_tracked_refs_.SubtleRefCountForDebug()); -} - -} // namespace internal -} // namespace base
diff --git a/base/template_util_unittest.cc b/base/template_util_unittest.cc deleted file mode 100644 index 2c42445..0000000 --- a/base/template_util_unittest.cc +++ /dev/null
@@ -1,106 +0,0 @@ -// 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/template_util.h" - -#include <string> - -#include "base/containers/flat_tree.h" -#include "base/test/move_only_int.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -enum SimpleEnum { SIMPLE_ENUM }; -enum EnumWithExplicitType : uint64_t { ENUM_WITH_EXPLICIT_TYPE }; -enum class ScopedEnum { SCOPED_ENUM }; -enum class ScopedEnumWithOperator { SCOPED_ENUM_WITH_OPERATOR }; -std::ostream& operator<<(std::ostream& os, ScopedEnumWithOperator v) { - return os; -} -struct SimpleStruct {}; -struct StructWithOperator {}; -std::ostream& operator<<(std::ostream& os, const StructWithOperator& v) { - return os; -} - -// is_non_const_reference<Type> -static_assert(!is_non_const_reference<int>::value, "IsNonConstReference"); -static_assert(!is_non_const_reference<const int&>::value, - "IsNonConstReference"); -static_assert(is_non_const_reference<int&>::value, "IsNonConstReference"); - -// A few standard types that definitely support printing. -static_assert(internal::SupportsOstreamOperator<int>::value, - "ints should be printable"); -static_assert(internal::SupportsOstreamOperator<const char*>::value, - "C strings should be printable"); -static_assert(internal::SupportsOstreamOperator<std::string>::value, - "std::string should be printable"); - -// Various kinds of enums operator<< support. -static_assert(internal::SupportsOstreamOperator<SimpleEnum>::value, - "simple enum should be printable by value"); -static_assert(internal::SupportsOstreamOperator<const SimpleEnum&>::value, - "simple enum should be printable by const ref"); -static_assert(internal::SupportsOstreamOperator<EnumWithExplicitType>::value, - "enum with explicit type should be printable by value"); -static_assert( - internal::SupportsOstreamOperator<const EnumWithExplicitType&>::value, - "enum with explicit type should be printable by const ref"); -static_assert(!internal::SupportsOstreamOperator<ScopedEnum>::value, - "scoped enum should not be printable by value"); -static_assert(!internal::SupportsOstreamOperator<const ScopedEnum&>::value, - "simple enum should not be printable by const ref"); -static_assert(internal::SupportsOstreamOperator<ScopedEnumWithOperator>::value, - "scoped enum with operator<< should be printable by value"); -static_assert( - internal::SupportsOstreamOperator<const ScopedEnumWithOperator&>::value, - "scoped enum with operator<< should be printable by const ref"); - -// operator<< support on structs. -static_assert(!internal::SupportsOstreamOperator<SimpleStruct>::value, - "simple struct should not be printable by value"); -static_assert(!internal::SupportsOstreamOperator<const SimpleStruct&>::value, - "simple struct should not be printable by const ref"); -static_assert(internal::SupportsOstreamOperator<StructWithOperator>::value, - "struct with operator<< should be printable by value"); -static_assert( - internal::SupportsOstreamOperator<const StructWithOperator&>::value, - "struct with operator<< should be printable by const ref"); - -// base::is_trivially_copyable -class TrivialCopy { - public: - TrivialCopy(int d) : data_(d) {} - - protected: - int data_; -}; - -class TrivialCopyButWithDestructor : public TrivialCopy { - public: - TrivialCopyButWithDestructor(int d) : TrivialCopy(d) {} - ~TrivialCopyButWithDestructor() { data_ = 0; } -}; - -static_assert(base::is_trivially_copyable<TrivialCopy>::value, - "TrivialCopy should be detected as trivially copyable"); -static_assert(!base::is_trivially_copyable<TrivialCopyButWithDestructor>::value, - "TrivialCopyButWithDestructor should not be detected as " - "trivially copyable"); - -class NoCopy { - public: - NoCopy(const NoCopy&) = delete; -}; - -static_assert( - !base::is_trivially_copy_constructible<std::vector<NoCopy>>::value, - "is_trivially_copy_constructible<std::vector<T>> must be compiled."); - -} // namespace - -} // namespace base
diff --git a/base/test/BUILD.gn b/base/test/BUILD.gn deleted file mode 100644 index 576729c..0000000 --- a/base/test/BUILD.gn +++ /dev/null
@@ -1,443 +0,0 @@ -# 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. - -import("//build/compiled_action.gni") -import("//build/config/ui.gni") -import("//build/config/nacl/config.gni") - -if (is_android) { - import("//build/config/android/rules.gni") -} - -static_library("test_config") { - testonly = true - sources = [ - "test_switches.cc", - "test_switches.h", - "test_timeouts.cc", - "test_timeouts.h", - ] - deps = [ - "//base", - ] -} - -static_library("test_support") { - testonly = true - sources = [ - "../trace_event/trace_config_memory_test_util.h", - "android/java_handler_thread_helpers.cc", - "android/java_handler_thread_helpers.h", - "android/url_utils.cc", - "android/url_utils.h", - "bind_test_util.h", - "copy_only_int.h", - "fuzzed_data_provider.cc", - "fuzzed_data_provider.h", - "gtest_util.cc", - "gtest_util.h", - "gtest_xml_unittest_result_printer.cc", - "gtest_xml_unittest_result_printer.h", - "gtest_xml_util.cc", - "gtest_xml_util.h", - "histogram_tester.cc", - "histogram_tester.h", - "icu_test_util.cc", - "icu_test_util.h", - "ios/wait_util.h", - "ios/wait_util.mm", - "launcher/test_result.cc", - "launcher/test_result.h", - "launcher/test_results_tracker.h", - "launcher/unit_test_launcher.h", - "mock_callback.h", - "mock_chrome_application_mac.h", - "mock_chrome_application_mac.mm", - "mock_devices_changed_observer.cc", - "mock_devices_changed_observer.h", - "mock_entropy_provider.cc", - "mock_entropy_provider.h", - "mock_log.cc", - "mock_log.h", - "move_only_int.h", - "multiprocess_test.h", - "multiprocess_test_android.cc", - "null_task_runner.cc", - "null_task_runner.h", - "perf_log.cc", - "perf_log.h", - "perf_test_suite.cc", - "perf_test_suite.h", - "perf_time_logger.cc", - "perf_time_logger.h", - "power_monitor_test_base.cc", - "power_monitor_test_base.h", - "scoped_command_line.cc", - "scoped_command_line.h", - "scoped_environment_variable_override.cc", - "scoped_environment_variable_override.h", - "scoped_feature_list.cc", - "scoped_feature_list.h", - "scoped_mock_time_message_loop_task_runner.cc", - "scoped_mock_time_message_loop_task_runner.h", - "scoped_path_override.cc", - "scoped_path_override.h", - "scoped_task_environment.cc", - "scoped_task_environment.h", - "sequenced_task_runner_test_template.cc", - "sequenced_task_runner_test_template.h", - "simple_test_clock.cc", - "simple_test_clock.h", - "simple_test_tick_clock.cc", - "simple_test_tick_clock.h", - "task_runner_test_template.cc", - "task_runner_test_template.h", - "test_discardable_memory_allocator.cc", - "test_discardable_memory_allocator.h", - "test_file_util.cc", - "test_file_util.h", - "test_file_util_android.cc", - "test_file_util_linux.cc", - "test_file_util_mac.cc", - "test_file_util_win.cc", - "test_io_thread.cc", - "test_io_thread.h", - "test_listener_ios.h", - "test_listener_ios.mm", - "test_message_loop.cc", - "test_message_loop.h", - "test_mock_time_task_runner.cc", - "test_mock_time_task_runner.h", - "test_pending_task.cc", - "test_pending_task.h", - "test_reg_util_win.cc", - "test_reg_util_win.h", - "test_shared_memory_util.cc", - "test_shared_memory_util.h", - "test_shortcut_win.cc", - "test_shortcut_win.h", - "test_simple_task_runner.cc", - "test_simple_task_runner.h", - "test_suite.cc", - "test_suite.h", - "test_support_android.cc", - "test_support_android.h", - "test_support_ios.h", - "test_support_ios.mm", - "test_ui_thread_android.cc", - "test_ui_thread_android.h", - "thread_test_helper.cc", - "thread_test_helper.h", - "trace_event_analyzer.cc", - "trace_event_analyzer.h", - "trace_to_file.cc", - "trace_to_file.h", - "user_action_tester.cc", - "user_action_tester.h", - "values_test_util.cc", - "values_test_util.h", - ] - - if (is_ios) { - sources += [ "launcher/unit_test_launcher_ios.cc" ] - } else if (!is_nacl_nonsfi) { - sources += [ - "launcher/test_launcher.cc", - "launcher/test_launcher.h", - "launcher/test_launcher_tracer.cc", - "launcher/test_launcher_tracer.h", - "launcher/test_results_tracker.cc", - "launcher/unit_test_launcher.cc", - "multiprocess_test.cc", - ] - } - - configs += [ "//build/config:precompiled_headers" ] - - data = [ - # The isolate needs this script for setting up the test. It's not actually - # needed to run this target locally. - "//testing/test_env.py", - ] - - public_deps = [ - ":test_config", - "//base", - "//base:base_static", - "//base:i18n", - ] - deps = [ - "//base/third_party/dynamic_annotations", - "//testing/gmock", - "//testing/gtest", - "//third_party/icu:icuuc", - "//third_party/libxml", - ] - - if (is_posix || is_fuchsia) { - sources += [ - "scoped_locale.cc", - "scoped_locale.h", - "test_file_util_posix.cc", - ] - } - - if (is_linux) { - public_deps += [ ":fontconfig_util_linux" ] - data_deps = [ - "//third_party/test_fonts", - ] - if (current_toolchain == host_toolchain) { - data_deps += [ ":do_generate_fontconfig_caches" ] - data += [ "$root_out_dir/fontconfig_caches/" ] - } - } - - if (is_ios) { - set_sources_assignment_filter([]) - sources += [ "test_file_util_mac.cc" ] - set_sources_assignment_filter(sources_assignment_filter) - } - - if (is_mac) { - libs = [ "AppKit.framework" ] - } - - if (is_android) { - set_sources_assignment_filter([]) - sources += [ "test_file_util_linux.cc" ] - set_sources_assignment_filter(sources_assignment_filter) - deps += [ - ":base_unittests_jni_headers", - ":test_support_jni_headers", - ] - public_deps += [ ":test_support_java" ] - } - - if (is_nacl_nonsfi) { - sources += [ - "launcher/test_launcher.h", - "launcher/test_result.h", - "launcher/unit_test_launcher.h", - "launcher/unit_test_launcher_nacl_nonsfi.cc", - ] - sources -= [ - "gtest_xml_util.cc", - "gtest_xml_util.h", - "icu_test_util.cc", - "icu_test_util.h", - "perf_test_suite.cc", - "perf_test_suite.h", - "scoped_path_override.cc", - "scoped_path_override.h", - "test_discardable_memory_allocator.cc", - "test_discardable_memory_allocator.h", - "test_file_util.cc", - "test_file_util.h", - "test_file_util_posix.cc", - "test_suite.cc", - "test_suite.h", - "trace_to_file.cc", - "trace_to_file.h", - ] - public_deps -= [ "//base:i18n" ] - deps -= [ - "//third_party/icu:icuuc", - "//third_party/libxml", - ] - } -} - -config("perf_test_config") { - defines = [ "PERF_TEST" ] -} - -# This is a source set instead of a static library because it seems like some -# linkers get confused when "main" is in a static library, and if you link to -# this, you always want the object file anyway. -source_set("test_support_perf") { - testonly = true - sources = [ - "run_all_perftests.cc", - ] - deps = [ - ":test_support", - "//base", - "//testing/gtest", - ] - - public_configs = [ ":perf_test_config" ] -} - -static_library("test_launcher_nacl_nonsfi") { - testonly = true - sources = [ - "launcher/test_launcher_nacl_nonsfi.cc", - "launcher/test_launcher_nacl_nonsfi.h", - ] - deps = [ - ":test_support", - ] -} - -static_library("run_all_unittests") { - testonly = true - sources = [ - "run_all_unittests.cc", - ] - deps = [ - ":test_support", - ] -} - -# These sources are linked into both the base_unittests binary and the test -# shared library target below. -source_set("native_library_test_utils") { - testonly = true - sources = [ - "native_library_test_utils.cc", - "native_library_test_utils.h", - ] -} - -# This shared library is dynamically loaded by NativeLibrary unittests. -shared_library("test_shared_library") { - testonly = true - sources = [ - "test_shared_library.cc", - ] - - deps = [ - ":native_library_test_utils", - ] -} - -static_library("run_all_base_unittests") { - # Only targets in base should depend on this, targets outside base - # should depend on run_all_unittests above. - visibility = [ "//base/*" ] - testonly = true - sources = [ - "run_all_base_unittests.cc", - ] - deps = [ - ":test_support", - ] -} - -if (is_linux) { - source_set("fontconfig_util_linux") { - sources = [ - "fontconfig_util_linux.cc", - "fontconfig_util_linux.h", - ] - deps = [ - "//base", - "//third_party/fontconfig", - ] - } - - if (current_toolchain == host_toolchain) { - executable("generate_fontconfig_caches") { - testonly = true - sources = [ - "generate_fontconfig_caches.cc", - ] - deps = [ - ":fontconfig_util_linux", - "//base", - "//build/config:exe_and_shlib_deps", - ] - } - - compiled_action("do_generate_fontconfig_caches") { - testonly = true - tool = ":generate_fontconfig_caches" - data_deps = [ - "//third_party/test_fonts", - ] - args = [] - outputs = [ - "$root_out_dir/fontconfig_caches/STAMP", - ] - } - } - - shared_library("malloc_wrapper") { - testonly = true - sources = [ - "malloc_wrapper.cc", - ] - deps = [ - "//base", - "//build/config:exe_and_shlib_deps", - ] - } -} - -if (is_android) { - generate_jni("base_unittests_jni_headers") { - sources = [ - "android/java/src/org/chromium/base/ContentUriTestUtils.java", - "android/java/src/org/chromium/base/JavaHandlerThreadHelpers.java", - "android/java/src/org/chromium/base/TestUiThread.java", - ] - jni_package = "base" - } - - generate_jni("test_support_jni_headers") { - sources = [ - "android/java/src/org/chromium/base/MainReturnCodeResult.java", - "android/java/src/org/chromium/base/MultiprocessTestClientLauncher.java", - "android/javatests/src/org/chromium/base/test/util/UrlUtils.java", - ] - jni_package = "base" - } - - android_library("test_support_java") { - testonly = true - deps = [ - "//base:base_java", - "//testing/android/native_test:native_main_runner_java", - "//third_party/android_tools:android_support_annotations_java", - "//third_party/jsr-305:jsr_305_javalib", - ] - srcjar_deps = [ ":test_support_java_aidl" ] - java_files = [ - "android/java/src/org/chromium/base/MainReturnCodeResult.java", - "android/java/src/org/chromium/base/MultiprocessTestClientLauncher.java", - "android/java/src/org/chromium/base/MultiprocessTestClientService.java", - "android/java/src/org/chromium/base/MultiprocessTestClientService0.java", - "android/java/src/org/chromium/base/MultiprocessTestClientService1.java", - "android/java/src/org/chromium/base/MultiprocessTestClientService2.java", - "android/java/src/org/chromium/base/MultiprocessTestClientService3.java", - "android/java/src/org/chromium/base/MultiprocessTestClientService4.java", - "android/java/src/org/chromium/base/MultiprocessTestClientServiceDelegate.java", - ] - } - - android_aidl("test_support_java_aidl") { - testonly = true - import_include = [ - "android/java/src", - "//base/android/java/src", - ] - sources = [ - "android/java/src/org/chromium/base/ITestCallback.aidl", - "android/java/src/org/chromium/base/ITestController.aidl", - ] - } -} - -# Trivial executable which outputs space-delimited argv to stdout, -# used for testing. -executable("test_child_process") { - testonly = true - sources = [ - "test_child_process.cc", - ] - deps = [ - "//build/config:exe_and_shlib_deps", - ] -}
diff --git a/base/test/histogram_tester_unittest.cc b/base/test/histogram_tester_unittest.cc deleted file mode 100644 index e49ed97..0000000 --- a/base/test/histogram_tester_unittest.cc +++ /dev/null
@@ -1,130 +0,0 @@ -// 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/histogram_tester.h" - -#include <memory> - -#include "base/metrics/histogram_macros.h" -#include "base/metrics/histogram_samples.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using ::testing::ElementsAre; -using ::testing::IsEmpty; - -namespace { - -const char kHistogram1[] = "Test1"; -const char kHistogram2[] = "Test2"; -const char kHistogram3[] = "Test3"; -const char kHistogram4[] = "Test4"; -const char kHistogram5[] = "Test5"; - -} // namespace - -namespace base { - -typedef testing::Test HistogramTesterTest; - -TEST_F(HistogramTesterTest, Scope) { - // Record a histogram before the creation of the recorder. - UMA_HISTOGRAM_BOOLEAN(kHistogram1, true); - - HistogramTester tester; - - // Verify that no histogram is recorded. - tester.ExpectTotalCount(kHistogram1, 0); - - // Record a histogram after the creation of the recorder. - UMA_HISTOGRAM_BOOLEAN(kHistogram1, true); - - // Verify that one histogram is recorded. - std::unique_ptr<HistogramSamples> samples( - tester.GetHistogramSamplesSinceCreation(kHistogram1)); - EXPECT_TRUE(samples); - EXPECT_EQ(1, samples->TotalCount()); -} - -TEST_F(HistogramTesterTest, GetHistogramSamplesSinceCreationNotNull) { - // Chose the histogram name uniquely, to ensure nothing was recorded for it so - // far. - static const char kHistogram[] = - "GetHistogramSamplesSinceCreationNotNullHistogram"; - HistogramTester tester; - - // Verify that the returned samples are empty but not null. - std::unique_ptr<HistogramSamples> samples( - tester.GetHistogramSamplesSinceCreation(kHistogram1)); - EXPECT_TRUE(samples); - tester.ExpectTotalCount(kHistogram, 0); -} - -TEST_F(HistogramTesterTest, TestUniqueSample) { - HistogramTester tester; - - // Record into a sample thrice - UMA_HISTOGRAM_COUNTS_100(kHistogram2, 2); - UMA_HISTOGRAM_COUNTS_100(kHistogram2, 2); - UMA_HISTOGRAM_COUNTS_100(kHistogram2, 2); - - tester.ExpectUniqueSample(kHistogram2, 2, 3); -} - -TEST_F(HistogramTesterTest, TestBucketsSample) { - HistogramTester tester; - - // Record into a sample twice - UMA_HISTOGRAM_COUNTS_100(kHistogram3, 2); - UMA_HISTOGRAM_COUNTS_100(kHistogram3, 2); - UMA_HISTOGRAM_COUNTS_100(kHistogram3, 2); - UMA_HISTOGRAM_COUNTS_100(kHistogram3, 2); - UMA_HISTOGRAM_COUNTS_100(kHistogram3, 3); - - tester.ExpectBucketCount(kHistogram3, 2, 4); - tester.ExpectBucketCount(kHistogram3, 3, 1); - - tester.ExpectTotalCount(kHistogram3, 5); -} - -TEST_F(HistogramTesterTest, TestBucketsSampleWithScope) { - // Record into a sample twice, once before the tester creation and once after. - UMA_HISTOGRAM_COUNTS_100(kHistogram4, 2); - - HistogramTester tester; - UMA_HISTOGRAM_COUNTS_100(kHistogram4, 3); - - tester.ExpectBucketCount(kHistogram4, 2, 0); - tester.ExpectBucketCount(kHistogram4, 3, 1); - - tester.ExpectTotalCount(kHistogram4, 1); -} - -TEST_F(HistogramTesterTest, TestGetAllSamples) { - HistogramTester tester; - UMA_HISTOGRAM_ENUMERATION(kHistogram5, 2, 5); - UMA_HISTOGRAM_ENUMERATION(kHistogram5, 3, 5); - UMA_HISTOGRAM_ENUMERATION(kHistogram5, 3, 5); - UMA_HISTOGRAM_ENUMERATION(kHistogram5, 5, 5); - - EXPECT_THAT(tester.GetAllSamples(kHistogram5), - ElementsAre(Bucket(2, 1), Bucket(3, 2), Bucket(5, 1))); -} - -TEST_F(HistogramTesterTest, TestGetAllSamples_NoSamples) { - HistogramTester tester; - EXPECT_THAT(tester.GetAllSamples(kHistogram5), IsEmpty()); -} - -TEST_F(HistogramTesterTest, TestGetTotalCountsForPrefix) { - HistogramTester tester; - UMA_HISTOGRAM_ENUMERATION("Test1.Test2.Test3", 2, 5); - - // Regression check for bug https://crbug.com/659977. - EXPECT_TRUE(tester.GetTotalCountsForPrefix("Test2.").empty()); - - EXPECT_EQ(1u, tester.GetTotalCountsForPrefix("Test1.").size()); -} - -} // namespace base
diff --git a/base/test/mock_callback_unittest.cc b/base/test/mock_callback_unittest.cc deleted file mode 100644 index c5f109f..0000000 --- a/base/test/mock_callback_unittest.cc +++ /dev/null
@@ -1,59 +0,0 @@ -// 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<Closure> mock_closure; - EXPECT_CALL(mock_closure, Run()); - mock_closure.Get().Run(); - - MockCallback<Callback<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<Callback<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)); - Callback<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)); -} - -} // namespace -} // namespace base
diff --git a/base/test/scoped_feature_list_unittest.cc b/base/test/scoped_feature_list_unittest.cc deleted file mode 100644 index 03d9897..0000000 --- a/base/test/scoped_feature_list_unittest.cc +++ /dev/null
@@ -1,297 +0,0 @@ -// 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) { - FieldTrialList field_trial_list(nullptr); - 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(), FeatureList::GetFieldTrial(kTestFeature1)); - 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, 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); - FieldTrialList field_trial_list(nullptr); - 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); - FieldTrialList field_trial_list(nullptr); - 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"); - } -} - -} // namespace test -} // namespace base
diff --git a/base/test/scoped_mock_time_message_loop_task_runner_unittest.cc b/base/test/scoped_mock_time_message_loop_task_runner_unittest.cc deleted file mode 100644 index b08323d..0000000 --- a/base/test/scoped_mock_time_message_loop_task_runner_unittest.cc +++ /dev/null
@@ -1,120 +0,0 @@ -// 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.h" -#include "base/message_loop/message_loop_current.h" -#include "base/test/test_mock_time_task_runner.h" -#include "base/test/test_pending_task.h" -#include "base/time/time.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -TaskRunner* GetCurrentTaskRunner() { - return MessageLoopCurrent::Get()->task_runner().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_; - - MessageLoop message_loop_; - - 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; - - Closure task_1 = DoNothing(); - Closure task_2 = DoNothing(); - Closure task_10 = Bind(&AssignTrue, &task_10_has_run); - Closure task_11 = Bind(&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, task_1, task_1_delay); - GetCurrentTaskRunner()->PostDelayedTask(FROM_HERE, task_2, task_2_delay); - GetCurrentTaskRunner()->PostDelayedTask(FROM_HERE, task_10, task_10_delay); - GetCurrentTaskRunner()->PostDelayedTask(FROM_HERE, 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/base/test/scoped_task_environment_unittest.cc b/base/test/scoped_task_environment_unittest.cc deleted file mode 100644 index 1c10d69..0000000 --- a/base/test/scoped_task_environment_unittest.cc +++ /dev/null
@@ -1,324 +0,0 @@ -// 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_task_environment.h" - -#include <memory> - -#include "base/atomicops.h" -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/synchronization/atomic_flag.h" -#include "base/synchronization/waitable_event.h" -#include "base/task_scheduler/post_task.h" -#include "base/test/test_timeouts.h" -#include "base/threading/platform_thread.h" -#include "base/threading/sequence_local_storage_slot.h" -#include "base/threading/thread_task_runner_handle.h" -#include "base/time/tick_clock.h" -#include "build_config.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) - -namespace base { -namespace test { - -namespace { - -class ScopedTaskEnvironmentTest - : public testing::TestWithParam<ScopedTaskEnvironment::MainThreadType> {}; - -void VerifyRunUntilIdleDidNotReturnAndSetFlag( - AtomicFlag* run_until_idle_returned, - AtomicFlag* task_ran) { - EXPECT_FALSE(run_until_idle_returned->IsSet()); - task_ran->Set(); -} - -void RunUntilIdleTest( - ScopedTaskEnvironment::MainThreadType main_thread_type, - ScopedTaskEnvironment::ExecutionMode execution_control_mode) { - AtomicFlag run_until_idle_returned; - ScopedTaskEnvironment scoped_task_environment(main_thread_type, - execution_control_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_task_scheduler_task_ran; - PostTask(FROM_HERE, BindOnce(&VerifyRunUntilIdleDidNotReturnAndSetFlag, - Unretained(&run_until_idle_returned), - Unretained(&first_task_scheduler_task_ran))); - - AtomicFlag second_task_scheduler_task_ran; - AtomicFlag second_main_thread_task_ran; - PostTaskAndReply(FROM_HERE, - BindOnce(&VerifyRunUntilIdleDidNotReturnAndSetFlag, - Unretained(&run_until_idle_returned), - Unretained(&second_task_scheduler_task_ran)), - BindOnce(&VerifyRunUntilIdleDidNotReturnAndSetFlag, - Unretained(&run_until_idle_returned), - Unretained(&second_main_thread_task_ran))); - - scoped_task_environment.RunUntilIdle(); - run_until_idle_returned.Set(); - - EXPECT_TRUE(first_main_thread_task_ran.IsSet()); - EXPECT_TRUE(first_task_scheduler_task_ran.IsSet()); - EXPECT_TRUE(second_task_scheduler_task_ran.IsSet()); - EXPECT_TRUE(second_main_thread_task_ran.IsSet()); -} - -} // namespace - -TEST_P(ScopedTaskEnvironmentTest, QueuedRunUntilIdle) { - RunUntilIdleTest(GetParam(), ScopedTaskEnvironment::ExecutionMode::QUEUED); -} - -TEST_P(ScopedTaskEnvironmentTest, AsyncRunUntilIdle) { - RunUntilIdleTest(GetParam(), ScopedTaskEnvironment::ExecutionMode::ASYNC); -} - -// Verify that tasks posted to an ExecutionMode::QUEUED ScopedTaskEnvironment do -// not run outside of RunUntilIdle(). -TEST_P(ScopedTaskEnvironmentTest, QueuedTasksDoNotRunOutsideOfRunUntilIdle) { - ScopedTaskEnvironment scoped_task_environment( - GetParam(), ScopedTaskEnvironment::ExecutionMode::QUEUED); - - AtomicFlag run_until_idle_called; - 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(); - scoped_task_environment.RunUntilIdle(); - - AtomicFlag other_run_until_idle_called; - 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(); - scoped_task_environment.RunUntilIdle(); -} - -// Verify that a task posted to an ExecutionMode::ASYNC ScopedTaskEnvironment -// can run without a call to RunUntilIdle(). -TEST_P(ScopedTaskEnvironmentTest, AsyncTasksRunAsTheyArePosted) { - ScopedTaskEnvironment scoped_task_environment( - GetParam(), ScopedTaskEnvironment::ExecutionMode::ASYNC); - - WaitableEvent task_ran(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - PostTask(FROM_HERE, - BindOnce([](WaitableEvent* task_ran) { task_ran->Signal(); }, - Unretained(&task_ran))); - task_ran.Wait(); -} - -// Verify that a task posted to an ExecutionMode::ASYNC ScopedTaskEnvironment -// after a call to RunUntilIdle() can run without another call to -// RunUntilIdle(). -TEST_P(ScopedTaskEnvironmentTest, - AsyncTasksRunAsTheyArePostedAfterRunUntilIdle) { - ScopedTaskEnvironment scoped_task_environment( - GetParam(), ScopedTaskEnvironment::ExecutionMode::ASYNC); - - scoped_task_environment.RunUntilIdle(); - - WaitableEvent task_ran(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - PostTask(FROM_HERE, - BindOnce([](WaitableEvent* task_ran) { task_ran->Signal(); }, - Unretained(&task_ran))); - task_ran.Wait(); -} - -TEST_P(ScopedTaskEnvironmentTest, DelayedTasks) { - // Use a QUEUED execution-mode environment, so that no tasks are actually - // executed until RunUntilIdle()/FastForwardBy() are invoked. - ScopedTaskEnvironment scoped_task_environment( - GetParam(), ScopedTaskEnvironment::ExecutionMode::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, - Bind( - [](subtle::Atomic32* counter) { - subtle::NoBarrier_AtomicIncrement(counter, 4); - }, - Unretained(&counter)), - kShortTaskDelay); - // TODO(gab): This currently doesn't run because the TaskScheduler's clock - // isn't mocked but it should be. - PostDelayedTask(FROM_HERE, - Bind( - [](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, - Bind( - [](subtle::Atomic32* counter) { - subtle::NoBarrier_AtomicIncrement(counter, 8); - }, - Unretained(&counter)), - TimeDelta::FromDays(5)); - ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, - Bind( - [](subtle::Atomic32* counter) { - subtle::NoBarrier_AtomicIncrement(counter, 16); - }, - Unretained(&counter)), - kLongTaskDelay); - - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, Bind( - [](subtle::Atomic32* counter) { - subtle::NoBarrier_AtomicIncrement(counter, 1); - }, - Unretained(&counter))); - PostTask(FROM_HERE, Bind( - [](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. - scoped_task_environment.RunUntilIdle(); - expected_value += 1; - expected_value += 2; - EXPECT_EQ(expected_value, counter); - - if (GetParam() == ScopedTaskEnvironment::MainThreadType::MOCK_TIME) { - // 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."); - scoped_task_environment.FastForwardBy(kInferiorTaskDelay); - EXPECT_EQ(expected_value, counter); - - scoped_task_environment.FastForwardBy(kShortTaskDelay - kInferiorTaskDelay); - expected_value += 4; - EXPECT_EQ(expected_value, counter); - - scoped_task_environment.FastForwardUntilNoTasksRemain(); - expected_value += 8; - expected_value += 16; - EXPECT_EQ(expected_value, counter); - } -} - -// Regression test for https://crbug.com/824770. -TEST_P(ScopedTaskEnvironmentTest, SupportsSequenceLocalStorageOnMainThread) { - ScopedTaskEnvironment scoped_task_environment( - GetParam(), ScopedTaskEnvironment::ExecutionMode::ASYNC); - - SequenceLocalStorageSlot<int> sls_slot; - sls_slot.Set(5); - EXPECT_EQ(5, sls_slot.Get()); -} - -#if defined(OS_POSIX) -TEST_F(ScopedTaskEnvironmentTest, SupportsFileDescriptorWatcherOnIOMainThread) { - ScopedTaskEnvironment scoped_task_environment( - ScopedTaskEnvironment::MainThreadType::IO, - ScopedTaskEnvironment::ExecutionMode::ASYNC); - - 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(); -} -#endif // defined(OS_POSIX) - -// Verify that the TickClock returned by -// |ScopedTaskEnvironment::GetMockTickClock| gets updated when the -// FastForward(By|UntilNoTasksRemain) functions are called. -TEST_F(ScopedTaskEnvironmentTest, FastForwardAdvanceTickClock) { - // Use a QUEUED execution-mode environment, so that no tasks are actually - // executed until RunUntilIdle()/FastForwardBy() are invoked. - ScopedTaskEnvironment scoped_task_environment( - ScopedTaskEnvironment::MainThreadType::MOCK_TIME, - ScopedTaskEnvironment::ExecutionMode::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 = - scoped_task_environment.GetMockTickClock(); - base::TimeTicks tick_clock_ref = tick_clock->NowTicks(); - - // Make sure that |FastForwardBy| advances the clock. - scoped_task_environment.FastForwardBy(kShortTaskDelay); - EXPECT_EQ(kShortTaskDelay, tick_clock->NowTicks() - tick_clock_ref); - - // Make sure that |FastForwardUntilNoTasksRemain| advances the clock. - scoped_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. - scoped_task_environment.FastForwardBy(kLongTaskDelay); - EXPECT_EQ(kLongTaskDelay * 2, tick_clock->NowTicks() - tick_clock_ref); -} - -INSTANTIATE_TEST_CASE_P( - MainThreadDefault, - ScopedTaskEnvironmentTest, - ::testing::Values(ScopedTaskEnvironment::MainThreadType::DEFAULT)); -INSTANTIATE_TEST_CASE_P( - MainThreadMockTime, - ScopedTaskEnvironmentTest, - ::testing::Values(ScopedTaskEnvironment::MainThreadType::MOCK_TIME)); -INSTANTIATE_TEST_CASE_P( - MainThreadUI, - ScopedTaskEnvironmentTest, - ::testing::Values(ScopedTaskEnvironment::MainThreadType::UI)); -INSTANTIATE_TEST_CASE_P( - MainThreadIO, - ScopedTaskEnvironmentTest, - ::testing::Values(ScopedTaskEnvironment::MainThreadType::IO)); - -} // namespace test -} // namespace base
diff --git a/base/test/test_mock_time_task_runner_unittest.cc b/base/test/test_mock_time_task_runner_unittest.cc deleted file mode 100644 index 04be466..0000000 --- a/base/test/test_mock_time_task_runner_unittest.cc +++ /dev/null
@@ -1,262 +0,0 @@ -// 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/cancelable_callback.h" -#include "base/memory/ref_counted.h" -#include "base/run_loop.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::Bind([](int* counter) { *counter += 1; }, Unretained(&counter))); - mock_time_task_runner->PostTask( - FROM_HERE, - base::Bind([](int* counter) { *counter += 32; }, Unretained(&counter))); - mock_time_task_runner->PostDelayedTask( - FROM_HERE, - base::Bind([](int* counter) { *counter += 256; }, Unretained(&counter)), - TimeDelta::FromSeconds(3)); - mock_time_task_runner->PostDelayedTask( - FROM_HERE, - base::Bind([](int* counter) { *counter += 64; }, Unretained(&counter)), - TimeDelta::FromSeconds(1)); - mock_time_task_runner->PostDelayedTask( - FROM_HERE, - base::Bind([](int* counter) { *counter += 1024; }, - Unretained(&counter)), - TimeDelta::FromMinutes(20)); - mock_time_task_runner->PostDelayedTask( - FROM_HERE, - base::Bind([](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::Bind([](int* counter) { *counter += 1; }, Unretained(&counter))); - ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::Bind([](int* counter) { *counter += 32; }, Unretained(&counter))); - ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, - base::Bind([](int* counter) { *counter += 256; }, Unretained(&counter)), - TimeDelta::FromSeconds(3)); - ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, - base::Bind([](int* counter) { *counter += 64; }, Unretained(&counter)), - TimeDelta::FromSeconds(1)); - ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, - base::Bind([](int* counter) { *counter += 1024; }, Unretained(&counter)), - TimeDelta::FromMinutes(20)); - ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, - base::Bind([](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::Bind([](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::Bind([](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); -} - -// 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, Bind([]() {})); - 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>(); - CancelableClosure task1(Bind([]() {})); - 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()); - - CancelableClosure task2(Bind([]() {})); - task_runner->PostDelayedTask(FROM_HERE, task2.callback(), - TimeDelta::FromSeconds(1)); - task2.Cancel(); - EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); - - CancelableClosure task3(Bind([]() {})); - task_runner->PostDelayedTask(FROM_HERE, task3.callback(), - TimeDelta::FromSeconds(1)); - task3.Cancel(); - EXPECT_EQ(TimeDelta::Max(), task_runner->NextPendingTaskDelay()); - - CancelableClosure task4(Bind([]() {})); - 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(); - CancelableClosure task(Bind([]() {})); - 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/base/test/test_pending_task_unittest.cc b/base/test/test_pending_task_unittest.cc deleted file mode 100644 index 6e01c8c..0000000 --- a/base/test/test_pending_task_unittest.cc +++ /dev/null
@@ -1,57 +0,0 @@ -// 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_pending_task.h" - -#include "base/bind.h" -#include "base/trace_event/trace_event.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest-spi.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(TestPendingTaskTest, TraceSupport) { - base::TestPendingTask task; - - // Check that TestPendingTask can be sent to the trace subsystem. - TRACE_EVENT1("test", "TestPendingTask::TraceSupport", "task", task.AsValue()); - - // Just a basic check that the trace output has *something* in it. - std::unique_ptr<base::trace_event::ConvertableToTraceFormat> task_value( - task.AsValue()); - EXPECT_THAT(task_value->ToString(), ::testing::HasSubstr("post_time")); -} - -TEST(TestPendingTaskTest, ToString) { - base::TestPendingTask task; - - // Just a basic check that ToString has *something* in it. - EXPECT_THAT(task.ToString(), ::testing::StartsWith("TestPendingTask(")); -} - -TEST(TestPendingTaskTest, GTestPrettyPrint) { - base::TestPendingTask task; - - // Check that gtest is calling the TestPendingTask's PrintTo method. - EXPECT_THAT(::testing::PrintToString(task), - ::testing::StartsWith("TestPendingTask(")); - - // Check that pretty printing works with the gtest iostreams operator. - EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(false) << task, "TestPendingTask("); -} - -TEST(TestPendingTaskTest, ShouldRunBefore) { - base::TestPendingTask task_first; - task_first.delay = base::TimeDelta::FromMilliseconds(1); - base::TestPendingTask task_after; - task_after.delay = base::TimeDelta::FromMilliseconds(2); - - EXPECT_FALSE(task_after.ShouldRunBefore(task_first)) - << task_after << ".ShouldRunBefore(" << task_first << ")\n"; - EXPECT_TRUE(task_first.ShouldRunBefore(task_after)) - << task_first << ".ShouldRunBefore(" << task_after << ")\n"; -} - -} // namespace base
diff --git a/base/test/test_reg_util_win_unittest.cc b/base/test/test_reg_util_win_unittest.cc deleted file mode 100644 index ca3bc99..0000000 --- a/base/test/test_reg_util_win_unittest.cc +++ /dev/null
@@ -1,133 +0,0 @@ -// 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/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 base::string16& 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 base::string16& 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 base::string16& key_path) { - base::win::RegKey key; - ASSERT_EQ(ERROR_SUCCESS, - key.Create(HKEY_CURRENT_USER, key_path.c_str(), KEY_ALL_ACCESS)); - } - - base::string16 FakeOverrideManagerPath(const base::Time& time) { - return fake_test_key_root_ + L"\\" + - base::Int64ToString16(time.ToInternalValue()); - } - - void CreateManager(const base::Time& timestamp) { - manager_.reset(new RegistryOverrideManager(timestamp, fake_test_key_root_)); - manager_->OverrideRegistry(HKEY_CURRENT_USER); - } - - base::string16 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)); - - base::string16 path_garbage = fake_test_key_root_ + L"\\Blah"; - base::string16 path_very_stale = - FakeOverrideManagerPath(kTestTime - base::TimeDelta::FromDays(100)); - base::string16 path_stale = - FakeOverrideManagerPath(kTestTime - base::TimeDelta::FromDays(5)); - base::string16 path_current = - FakeOverrideManagerPath(kTestTime - base::TimeDelta::FromMinutes(1)); - base::string16 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/base/test/trace_event_analyzer_unittest.cc b/base/test/trace_event_analyzer_unittest.cc deleted file mode 100644 index 6461b0f..0000000 --- a/base/test/trace_event_analyzer_unittest.cc +++ /dev/null
@@ -1,961 +0,0 @@ -// 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/ptr_util.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/trace_event_argument.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::Bind(&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"] = WrapUnique(new 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 (size_t i = 0; i < events.size(); ++i) - event_ptrs.push_back(&events[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 (size_t i = 0; i < events.size(); ++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"); - - 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/base/test/user_action_tester_unittest.cc b/base/test/user_action_tester_unittest.cc deleted file mode 100644 index a51849f..0000000 --- a/base/test/user_action_tester_unittest.cc +++ /dev/null
@@ -1,86 +0,0 @@ -// 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/user_action_tester.h" - -#include "base/metrics/user_metrics.h" -#include "base/metrics/user_metrics_action.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -const char kUserAction1[] = "user.action.1"; -const char kUserAction2[] = "user.action.2"; -const char kUserAction3[] = "user.action.3"; - -// Record an action and cause all ActionCallback observers to be notified. -void RecordAction(const char user_action[]) { - base::RecordAction(base::UserMetricsAction(user_action)); -} - -} // namespace - -// Verify user action counts are zero initially. -TEST(UserActionTesterTest, GetActionCountWhenNoActionsHaveBeenRecorded) { - UserActionTester user_action_tester; - EXPECT_EQ(0, user_action_tester.GetActionCount(kUserAction1)); -} - -// Verify user action counts are tracked properly. -TEST(UserActionTesterTest, GetActionCountWhenActionsHaveBeenRecorded) { - UserActionTester user_action_tester; - - RecordAction(kUserAction1); - RecordAction(kUserAction2); - RecordAction(kUserAction2); - - EXPECT_EQ(1, user_action_tester.GetActionCount(kUserAction1)); - EXPECT_EQ(2, user_action_tester.GetActionCount(kUserAction2)); - EXPECT_EQ(0, user_action_tester.GetActionCount(kUserAction3)); -} - -// Verify no seg faults occur when resetting action counts when none have been -// recorded. -TEST(UserActionTesterTest, ResetCountsWhenNoActionsHaveBeenRecorded) { - UserActionTester user_action_tester; - user_action_tester.ResetCounts(); -} - -// Verify user action counts are set to zero on a ResetCounts. -TEST(UserActionTesterTest, ResetCountsWhenActionsHaveBeenRecorded) { - UserActionTester user_action_tester; - - RecordAction(kUserAction1); - RecordAction(kUserAction1); - RecordAction(kUserAction2); - user_action_tester.ResetCounts(); - - EXPECT_EQ(0, user_action_tester.GetActionCount(kUserAction1)); - EXPECT_EQ(0, user_action_tester.GetActionCount(kUserAction2)); - EXPECT_EQ(0, user_action_tester.GetActionCount(kUserAction3)); -} - -// Verify the UserActionsTester is notified when base::RecordAction is called. -TEST(UserActionTesterTest, VerifyUserActionTesterListensForUserActions) { - UserActionTester user_action_tester; - - base::RecordAction(base::UserMetricsAction(kUserAction1)); - - EXPECT_EQ(1, user_action_tester.GetActionCount(kUserAction1)); -} - -// Verify the UserActionsTester is notified when base::RecordComputedAction is -// called. -TEST(UserActionTesterTest, - VerifyUserActionTesterListensForComputedUserActions) { - UserActionTester user_action_tester; - - base::RecordComputedAction(kUserAction1); - - EXPECT_EQ(1, user_action_tester.GetActionCount(kUserAction1)); -} - -} // namespace base
diff --git a/base/third_party/dynamic_annotations/BUILD.gn b/base/third_party/dynamic_annotations/BUILD.gn deleted file mode 100644 index 0fc4bf7..0000000 --- a/base/third_party/dynamic_annotations/BUILD.gn +++ /dev/null
@@ -1,27 +0,0 @@ -# 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. - -if (is_nacl) { - # Native client doesn't need dynamic annotations, so we provide a - # dummy target in order for clients to not have to special-case the - # dependency. - source_set("dynamic_annotations") { - sources = [ - "dynamic_annotations.h", - ] - } -} else { - # Should be static library, see documentation on //base:base for discussion. - static_library("dynamic_annotations") { - sources = [ - "../valgrind/valgrind.h", - "dynamic_annotations.c", - "dynamic_annotations.h", - ] - if (is_android && !is_debug) { - configs -= [ "//build/config/compiler:default_optimization" ] - configs += [ "//build/config/compiler:optimize_max" ] - } - } -}
diff --git a/base/third_party/libevent/BUILD.gn b/base/third_party/libevent/BUILD.gn deleted file mode 100644 index e934454..0000000 --- a/base/third_party/libevent/BUILD.gn +++ /dev/null
@@ -1,80 +0,0 @@ -# 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. - -import("//build/config/nacl/config.gni") - -static_library("libevent") { - sources = [ - "buffer.c", - "evbuffer.c", - "evdns.c", - "evdns.h", - "event-config.h", - "event-internal.h", - "event.c", - "event.h", - "event_tagging.c", - "evhttp.h", - "evrpc-internal.h", - "evrpc.c", - "evrpc.h", - "evsignal.h", - "evutil.c", - "evutil.h", - "http-internal.h", - "http.c", - "log.c", - "log.h", - "min_heap.h", - "poll.c", - "select.c", - "signal.c", - "strlcpy-internal.h", - "strlcpy.c", - ] - - defines = [ "HAVE_CONFIG_H" ] - - if (is_mac || is_ios) { - sources += [ - "kqueue.c", - "mac/config.h", - "mac/event-config.h", - ] - include_dirs = [ "mac" ] - } else if (is_linux) { - sources += [ - "epoll.c", - "linux/config.h", - "linux/event-config.h", - ] - include_dirs = [ "linux" ] - } else if (is_android) { - sources += [ - "android/config.h", - "android/event-config.h", - "epoll.c", - ] - include_dirs = [ "android" ] - } else if (is_nacl_nonsfi) { - sources -= [ - "evdns.c", - "event_tagging.c", - "evrpc.c", - "http.c", - "select.c", - "signal.c", - ] - sources += [ - "nacl_nonsfi/config.h", - "nacl_nonsfi/event-config.h", - "nacl_nonsfi/random.c", - "nacl_nonsfi/signal_stub.c", - ] - include_dirs = [ "nacl_nonsfi" ] - } - - configs -= [ "//build/config/compiler:chromium_code" ] - configs += [ "//build/config/compiler:no_chromium_code" ] -}
diff --git a/base/third_party/symbolize/BUILD.gn b/base/third_party/symbolize/BUILD.gn deleted file mode 100644 index 0dc7c2f..0000000 --- a/base/third_party/symbolize/BUILD.gn +++ /dev/null
@@ -1,36 +0,0 @@ -# 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. - -import("//build/config/compiler/compiler.gni") - -declare_args() { - # Stack traces will not include function names. Instead they will contain - # file and offset information that can be used with - # tools/valgrind/asan/asan_symbolize.py. By piping stderr through this script, - # and also enabling symbol_level = 2, you can get much more detailed stack - # traces with file names and line numbers, even in non-ASAN builds. - print_unsymbolized_stack_traces = is_asan || is_lsan || is_msan || is_tsan -} - -static_library("symbolize") { - visibility = [ "//base/*" ] - sources = [ - "config.h", - "demangle.cc", - "demangle.h", - "glog/logging.h", - "glog/raw_logging.h", - "symbolize.cc", - "symbolize.h", - "utilities.h", - ] - - defines = [] - if (print_unsymbolized_stack_traces) { - defines += [ "PRINT_UNSYMBOLIZED_STACK_TRACES" ] - } - - configs -= [ "//build/config/compiler:chromium_code" ] - configs += [ "//build/config/compiler:no_chromium_code" ] -}
diff --git a/base/third_party/xdg_mime/BUILD.gn b/base/third_party/xdg_mime/BUILD.gn deleted file mode 100644 index ac9e2c9..0000000 --- a/base/third_party/xdg_mime/BUILD.gn +++ /dev/null
@@ -1,28 +0,0 @@ -# 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. - -static_library("xdg_mime") { - visibility = [ "//base/*" ] - sources = [ - "xdgmime.c", - "xdgmime.h", - "xdgmimealias.c", - "xdgmimealias.h", - "xdgmimecache.c", - "xdgmimecache.h", - "xdgmimeglob.c", - "xdgmimeglob.h", - "xdgmimeicon.c", - "xdgmimeicon.h", - "xdgmimeint.c", - "xdgmimeint.h", - "xdgmimemagic.c", - "xdgmimemagic.h", - "xdgmimeparent.c", - "xdgmimeparent.h", - ] - - configs -= [ "//build/config/compiler:chromium_code" ] - configs += [ "//build/config/compiler:no_chromium_code" ] -}
diff --git a/base/third_party/xdg_user_dirs/BUILD.gn b/base/third_party/xdg_user_dirs/BUILD.gn deleted file mode 100644 index a5626e9..0000000 --- a/base/third_party/xdg_user_dirs/BUILD.gn +++ /dev/null
@@ -1,11 +0,0 @@ -# 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. - -static_library("xdg_user_dirs") { - visibility = [ "//base/*" ] - sources = [ - "xdg_user_dir_lookup.cc", - "xdg_user_dir_lookup.h", - ] -}
diff --git a/base/thread_annotations_unittest.cc b/base/thread_annotations_unittest.cc deleted file mode 100644 index b4aafef..0000000 --- a/base/thread_annotations_unittest.cc +++ /dev/null
@@ -1,58 +0,0 @@ -// 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 "thread_annotations.h" - -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -class LOCKABLE Lock { - public: - void Acquire() EXCLUSIVE_LOCK_FUNCTION() {} - void Release() UNLOCK_FUNCTION() {} -}; - -class SCOPED_LOCKABLE AutoLock { - public: - AutoLock(Lock& lock) EXCLUSIVE_LOCK_FUNCTION(lock) : lock_(lock) { - lock.Acquire(); - } - ~AutoLock() UNLOCK_FUNCTION() { lock_.Release(); } - - private: - Lock& lock_; -}; - -class ThreadSafe { - public: - void ExplicitIncrement(); - void ImplicitIncrement(); - - private: - Lock lock_; - int counter_ GUARDED_BY(lock_); -}; - -void ThreadSafe::ExplicitIncrement() { - lock_.Acquire(); - ++counter_; - lock_.Release(); -} - -void ThreadSafe::ImplicitIncrement() { - AutoLock auto_lock(lock_); - counter_++; -} - -TEST(ThreadAnnotationsTest, ExplicitIncrement) { - ThreadSafe thread_safe; - thread_safe.ExplicitIncrement(); -} -TEST(ThreadAnnotationsTest, ImplicitIncrement) { - ThreadSafe thread_safe; - thread_safe.ImplicitIncrement(); -} - -} // anonymous namespace
diff --git a/base/thread_annotations_unittest.nc b/base/thread_annotations_unittest.nc deleted file mode 100644 index ea64a7e..0000000 --- a/base/thread_annotations_unittest.nc +++ /dev/null
@@ -1,71 +0,0 @@ -// 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. - -// This is a "No Compile Test" suite. -// https://dev.chromium.org/developers/testing/no-compile-tests - -#include "base/thread_annotations.h" - -namespace { - -class LOCKABLE Lock { - public: - void Acquire() EXCLUSIVE_LOCK_FUNCTION() {} - void Release() UNLOCK_FUNCTION() {} -}; - -class SCOPED_LOCKABLE AutoLock { - public: - AutoLock(Lock& lock) EXCLUSIVE_LOCK_FUNCTION(lock) : lock_(lock) { - lock.Acquire(); - } - ~AutoLock() UNLOCK_FUNCTION() { lock_.Release(); } - - private: - Lock& lock_; -}; -class ThreadSafe { - public: - void BuggyIncrement(); - private: - Lock lock_; - int counter_ GUARDED_BY(lock_); -}; - -#if defined(NCTEST_LOCK_WITHOUT_UNLOCK) // [r"fatal error: mutex 'lock_' is still held at the end of function"] - -void ThreadSafe::BuggyIncrement() { - lock_.Acquire(); - ++counter_; - // Forgot to release the lock. -} - -#elif defined(NCTEST_ACCESS_WITHOUT_LOCK) // [r"fatal error: writing variable 'counter_' requires holding mutex 'lock_' exclusively"] - -void ThreadSafe::BuggyIncrement() { - // Member access without holding the lock guarding it. - ++counter_; -} - -#elif defined(NCTEST_ACCESS_WITHOUT_SCOPED_LOCK) // [r"fatal error: writing variable 'counter_' requires holding mutex 'lock_' exclusively"] - -void ThreadSafe::BuggyIncrement() { - { - AutoLock auto_lock(lock_); - // The AutoLock will go out of scope before the guarded member access. - } - ++counter_; -} - -#elif defined(NCTEST_GUARDED_BY_WRONG_TYPE) // [r"fatal error: 'guarded_by' attribute requires arguments whose type is annotated"] - -int not_lockable; -int global_counter GUARDED_BY(not_lockable); - -// Defined to avoid link error. -void ThreadSafe::BuggyIncrement() { } - -#endif - -} // anonymous namespace
diff --git a/base/threading/platform_thread_unittest.cc b/base/threading/platform_thread_unittest.cc deleted file mode 100644 index 968f0e0..0000000 --- a/base/threading/platform_thread_unittest.cc +++ /dev/null
@@ -1,367 +0,0 @@ -// 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 <stddef.h> - -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "base/synchronization/waitable_event.h" -#include "base/threading/platform_thread.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(OS_POSIX) -#include "base/threading/platform_thread_internal_posix.h" -#elif defined(OS_WIN) -#include <windows.h> -#endif - -namespace base { - -// Trivial tests that thread runs and doesn't crash on create, join, or detach - - -namespace { - -class TrivialThread : public PlatformThread::Delegate { - public: - TrivialThread() : run_event_(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED) {} - - void ThreadMain() override { run_event_.Signal(); } - - WaitableEvent& run_event() { return run_event_; } - - private: - WaitableEvent run_event_; - - DISALLOW_COPY_AND_ASSIGN(TrivialThread); -}; - -} // namespace - -TEST(PlatformThreadTest, TrivialJoin) { - TrivialThread thread; - PlatformThreadHandle handle; - - ASSERT_FALSE(thread.run_event().IsSignaled()); - ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); - PlatformThread::Join(handle); - ASSERT_TRUE(thread.run_event().IsSignaled()); -} - -TEST(PlatformThreadTest, TrivialJoinTimesTen) { - TrivialThread thread[10]; - PlatformThreadHandle handle[arraysize(thread)]; - - for (size_t n = 0; n < arraysize(thread); n++) - ASSERT_FALSE(thread[n].run_event().IsSignaled()); - for (size_t n = 0; n < arraysize(thread); n++) - ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n])); - for (size_t n = 0; n < arraysize(thread); n++) - PlatformThread::Join(handle[n]); - for (size_t n = 0; n < arraysize(thread); n++) - ASSERT_TRUE(thread[n].run_event().IsSignaled()); -} - -// The following detach tests are by nature racy. The run_event approximates the -// end and termination of the thread, but threads could persist shortly after -// the test completes. -TEST(PlatformThreadTest, TrivialDetach) { - TrivialThread thread; - PlatformThreadHandle handle; - - ASSERT_FALSE(thread.run_event().IsSignaled()); - ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); - PlatformThread::Detach(handle); - thread.run_event().Wait(); -} - -TEST(PlatformThreadTest, TrivialDetachTimesTen) { - TrivialThread thread[10]; - PlatformThreadHandle handle[arraysize(thread)]; - - for (size_t n = 0; n < arraysize(thread); n++) - ASSERT_FALSE(thread[n].run_event().IsSignaled()); - for (size_t n = 0; n < arraysize(thread); n++) { - ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n])); - PlatformThread::Detach(handle[n]); - } - for (size_t n = 0; n < arraysize(thread); n++) - thread[n].run_event().Wait(); -} - -// Tests of basic thread functions --------------------------------------------- - -namespace { - -class FunctionTestThread : public PlatformThread::Delegate { - public: - FunctionTestThread() - : thread_id_(kInvalidThreadId), - termination_ready_(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED), - terminate_thread_(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED), - done_(false) {} - ~FunctionTestThread() override { - EXPECT_TRUE(terminate_thread_.IsSignaled()) - << "Need to mark thread for termination and join the underlying thread " - << "before destroying a FunctionTestThread as it owns the " - << "WaitableEvent blocking the underlying thread's main."; - } - - // Grabs |thread_id_|, runs an optional test on that thread, signals - // |termination_ready_|, and then waits for |terminate_thread_| to be - // signaled before exiting. - void ThreadMain() override { - thread_id_ = PlatformThread::CurrentId(); - EXPECT_NE(thread_id_, kInvalidThreadId); - - // Make sure that the thread ID is the same across calls. - EXPECT_EQ(thread_id_, PlatformThread::CurrentId()); - - // Run extra tests. - RunTest(); - - termination_ready_.Signal(); - terminate_thread_.Wait(); - - done_ = true; - } - - PlatformThreadId thread_id() const { - EXPECT_TRUE(termination_ready_.IsSignaled()) << "Thread ID still unknown"; - return thread_id_; - } - - bool IsRunning() const { - return termination_ready_.IsSignaled() && !done_; - } - - // Blocks until this thread is started and ready to be terminated. - void WaitForTerminationReady() { termination_ready_.Wait(); } - - // Marks this thread for termination (callers must then join this thread to be - // guaranteed of termination). - void MarkForTermination() { terminate_thread_.Signal(); } - - private: - // Runs an optional test on the newly created thread. - virtual void RunTest() {} - - PlatformThreadId thread_id_; - - mutable WaitableEvent termination_ready_; - WaitableEvent terminate_thread_; - bool done_; - - DISALLOW_COPY_AND_ASSIGN(FunctionTestThread); -}; - -} // namespace - -TEST(PlatformThreadTest, Function) { - PlatformThreadId main_thread_id = PlatformThread::CurrentId(); - - FunctionTestThread thread; - PlatformThreadHandle handle; - - ASSERT_FALSE(thread.IsRunning()); - ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); - thread.WaitForTerminationReady(); - ASSERT_TRUE(thread.IsRunning()); - EXPECT_NE(thread.thread_id(), main_thread_id); - - thread.MarkForTermination(); - PlatformThread::Join(handle); - ASSERT_FALSE(thread.IsRunning()); - - // Make sure that the thread ID is the same across calls. - EXPECT_EQ(main_thread_id, PlatformThread::CurrentId()); -} - -TEST(PlatformThreadTest, FunctionTimesTen) { - PlatformThreadId main_thread_id = PlatformThread::CurrentId(); - - FunctionTestThread thread[10]; - PlatformThreadHandle handle[arraysize(thread)]; - - for (size_t n = 0; n < arraysize(thread); n++) - ASSERT_FALSE(thread[n].IsRunning()); - - for (size_t n = 0; n < arraysize(thread); n++) - ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n])); - for (size_t n = 0; n < arraysize(thread); n++) - thread[n].WaitForTerminationReady(); - - for (size_t n = 0; n < arraysize(thread); n++) { - ASSERT_TRUE(thread[n].IsRunning()); - EXPECT_NE(thread[n].thread_id(), main_thread_id); - - // Make sure no two threads get the same ID. - for (size_t i = 0; i < n; ++i) { - EXPECT_NE(thread[i].thread_id(), thread[n].thread_id()); - } - } - - for (size_t n = 0; n < arraysize(thread); n++) - thread[n].MarkForTermination(); - for (size_t n = 0; n < arraysize(thread); n++) - PlatformThread::Join(handle[n]); - for (size_t n = 0; n < arraysize(thread); n++) - ASSERT_FALSE(thread[n].IsRunning()); - - // Make sure that the thread ID is the same across calls. - EXPECT_EQ(main_thread_id, PlatformThread::CurrentId()); -} - -namespace { - -const ThreadPriority kThreadPriorityTestValues[] = { -// The order should be higher to lower to cover as much cases as possible on -// Linux trybots running without CAP_SYS_NICE permission. -#if !defined(OS_ANDROID) - // PlatformThread::GetCurrentThreadPriority() on Android does not support - // REALTIME_AUDIO case. See http://crbug.com/505474. - ThreadPriority::REALTIME_AUDIO, -#endif - ThreadPriority::DISPLAY, - // This redundant BACKGROUND priority is to test backgrounding from other - // priorities, and unbackgrounding. - ThreadPriority::BACKGROUND, - ThreadPriority::NORMAL, - ThreadPriority::BACKGROUND}; - -class ThreadPriorityTestThread : public FunctionTestThread { - public: - explicit ThreadPriorityTestThread(ThreadPriority priority) - : priority_(priority) {} - ~ThreadPriorityTestThread() override = default; - - private: - void RunTest() override { - // Confirm that the current thread's priority is as expected. - EXPECT_EQ(ThreadPriority::NORMAL, - PlatformThread::GetCurrentThreadPriority()); - - // Alter and verify the current thread's priority. - PlatformThread::SetCurrentThreadPriority(priority_); - EXPECT_EQ(priority_, PlatformThread::GetCurrentThreadPriority()); - } - - const ThreadPriority priority_; - - DISALLOW_COPY_AND_ASSIGN(ThreadPriorityTestThread); -}; - -} // namespace - -// Test changing a created thread's priority (which has different semantics on -// some platforms). -TEST(PlatformThreadTest, ThreadPriorityCurrentThread) { - const bool increase_priority_allowed = - PlatformThread::CanIncreaseCurrentThreadPriority(); - -// Bump the priority in order to verify that new threads are started with normal -// priority. Skip this on Mac since this platform doesn't allow changing the -// priority of the main thread. Also skip this on platforms that don't allow -// increasing the priority of a thread. -#if !defined(OS_MACOSX) - if (increase_priority_allowed) - PlatformThread::SetCurrentThreadPriority(ThreadPriority::DISPLAY); -#endif - - // Toggle each supported priority on the thread and confirm it affects it. - for (size_t i = 0; i < arraysize(kThreadPriorityTestValues); ++i) { - if (!increase_priority_allowed && - kThreadPriorityTestValues[i] > - PlatformThread::GetCurrentThreadPriority()) { - continue; - } - - ThreadPriorityTestThread thread(kThreadPriorityTestValues[i]); - PlatformThreadHandle handle; - - ASSERT_FALSE(thread.IsRunning()); - ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); - thread.WaitForTerminationReady(); - ASSERT_TRUE(thread.IsRunning()); - - thread.MarkForTermination(); - PlatformThread::Join(handle); - ASSERT_FALSE(thread.IsRunning()); - } -} - -// This tests internal PlatformThread APIs used under some POSIX platforms, -// with the exception of Mac OS X, iOS and Fuchsia. -#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_IOS) && \ - !defined(OS_FUCHSIA) -TEST(PlatformThreadTest, GetNiceValueToThreadPriority) { - using internal::NiceValueToThreadPriority; - using internal::kThreadPriorityToNiceValueMap; - - EXPECT_EQ(ThreadPriority::BACKGROUND, - kThreadPriorityToNiceValueMap[0].priority); - EXPECT_EQ(ThreadPriority::NORMAL, - kThreadPriorityToNiceValueMap[1].priority); - EXPECT_EQ(ThreadPriority::DISPLAY, - kThreadPriorityToNiceValueMap[2].priority); - EXPECT_EQ(ThreadPriority::REALTIME_AUDIO, - kThreadPriorityToNiceValueMap[3].priority); - - static const int kBackgroundNiceValue = - kThreadPriorityToNiceValueMap[0].nice_value; - static const int kNormalNiceValue = - kThreadPriorityToNiceValueMap[1].nice_value; - static const int kDisplayNiceValue = - kThreadPriorityToNiceValueMap[2].nice_value; - static const int kRealtimeAudioNiceValue = - kThreadPriorityToNiceValueMap[3].nice_value; - - // The tests below assume the nice values specified in the map are within - // the range below (both ends exclusive). - static const int kHighestNiceValue = 19; - static const int kLowestNiceValue = -20; - - EXPECT_GT(kHighestNiceValue, kBackgroundNiceValue); - EXPECT_GT(kBackgroundNiceValue, kNormalNiceValue); - EXPECT_GT(kNormalNiceValue, kDisplayNiceValue); - EXPECT_GT(kDisplayNiceValue, kRealtimeAudioNiceValue); - EXPECT_GT(kRealtimeAudioNiceValue, kLowestNiceValue); - - EXPECT_EQ(ThreadPriority::BACKGROUND, - NiceValueToThreadPriority(kHighestNiceValue)); - EXPECT_EQ(ThreadPriority::BACKGROUND, - NiceValueToThreadPriority(kBackgroundNiceValue + 1)); - EXPECT_EQ(ThreadPriority::BACKGROUND, - NiceValueToThreadPriority(kBackgroundNiceValue)); - EXPECT_EQ(ThreadPriority::BACKGROUND, - NiceValueToThreadPriority(kNormalNiceValue + 1)); - EXPECT_EQ(ThreadPriority::NORMAL, - NiceValueToThreadPriority(kNormalNiceValue)); - EXPECT_EQ(ThreadPriority::NORMAL, - NiceValueToThreadPriority(kDisplayNiceValue + 1)); - EXPECT_EQ(ThreadPriority::DISPLAY, - NiceValueToThreadPriority(kDisplayNiceValue)); - EXPECT_EQ(ThreadPriority::DISPLAY, - NiceValueToThreadPriority(kRealtimeAudioNiceValue + 1)); - EXPECT_EQ(ThreadPriority::REALTIME_AUDIO, - NiceValueToThreadPriority(kRealtimeAudioNiceValue)); - EXPECT_EQ(ThreadPriority::REALTIME_AUDIO, - NiceValueToThreadPriority(kLowestNiceValue)); -} -#endif // defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_IOS) && - // !defined(OS_FUCHSIA) - -TEST(PlatformThreadTest, SetHugeThreadName) { - // Construct an excessively long thread name. - std::string long_name(1024, 'a'); - - // SetName has no return code, so just verify that implementations - // don't [D]CHECK(). - PlatformThread::SetName(long_name); -} - -} // namespace base
diff --git a/base/threading/post_task_and_reply_impl_unittest.cc b/base/threading/post_task_and_reply_impl_unittest.cc deleted file mode 100644 index 319327d..0000000 --- a/base/threading/post_task_and_reply_impl_unittest.cc +++ /dev/null
@@ -1,198 +0,0 @@ -// 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/threading/post_task_and_reply_impl.h" - -#include <utility> - -#include "base/auto_reset.h" -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/test/test_mock_time_task_runner.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using ::testing::_; - -namespace base { -namespace internal { - -namespace { - -class PostTaskAndReplyTaskRunner : public internal::PostTaskAndReplyImpl { - public: - explicit PostTaskAndReplyTaskRunner(TaskRunner* destination) - : destination_(destination) {} - - private: - bool PostTask(const Location& from_here, OnceClosure task) override { - return destination_->PostTask(from_here, std::move(task)); - } - - // Non-owning. - TaskRunner* const destination_; -}; - -class ObjectToDelete : public RefCounted<ObjectToDelete> { - public: - // |delete_flag| is set to true when this object is deleted - ObjectToDelete(bool* delete_flag) : delete_flag_(delete_flag) { - EXPECT_FALSE(*delete_flag_); - } - - private: - friend class RefCounted<ObjectToDelete>; - ~ObjectToDelete() { *delete_flag_ = true; } - - bool* const delete_flag_; - - DISALLOW_COPY_AND_ASSIGN(ObjectToDelete); -}; - -class MockObject { - public: - MockObject() = default; - - MOCK_METHOD1(Task, void(scoped_refptr<ObjectToDelete>)); - MOCK_METHOD1(Reply, void(scoped_refptr<ObjectToDelete>)); - - private: - DISALLOW_COPY_AND_ASSIGN(MockObject); -}; - -class MockRunsTasksInCurrentSequenceTaskRunner : public TestMockTimeTaskRunner { - public: - MockRunsTasksInCurrentSequenceTaskRunner( - TestMockTimeTaskRunner::Type type = - TestMockTimeTaskRunner::Type::kStandalone) - : TestMockTimeTaskRunner(type) {} - - void RunUntilIdleWithRunsTasksInCurrentSequence() { - AutoReset<bool> reset(&runs_tasks_in_current_sequence_, true); - RunUntilIdle(); - } - - void ClearPendingTasksWithRunsTasksInCurrentSequence() { - AutoReset<bool> reset(&runs_tasks_in_current_sequence_, true); - ClearPendingTasks(); - } - - // TestMockTimeTaskRunner: - bool RunsTasksInCurrentSequence() const override { - return runs_tasks_in_current_sequence_; - } - - private: - ~MockRunsTasksInCurrentSequenceTaskRunner() override = default; - - bool runs_tasks_in_current_sequence_ = false; - - DISALLOW_COPY_AND_ASSIGN(MockRunsTasksInCurrentSequenceTaskRunner); -}; - -class PostTaskAndReplyImplTest : public testing::Test { - protected: - PostTaskAndReplyImplTest() = default; - - void PostTaskAndReplyToMockObject() { - // Expect the post to succeed. - EXPECT_TRUE( - PostTaskAndReplyTaskRunner(post_runner_.get()) - .PostTaskAndReply( - FROM_HERE, - BindOnce(&MockObject::Task, Unretained(&mock_object_), - MakeRefCounted<ObjectToDelete>(&delete_task_flag_)), - BindOnce(&MockObject::Reply, Unretained(&mock_object_), - MakeRefCounted<ObjectToDelete>(&delete_reply_flag_)))); - - // Expect the first task to be posted to |post_runner_|. - EXPECT_TRUE(post_runner_->HasPendingTask()); - EXPECT_FALSE(reply_runner_->HasPendingTask()); - EXPECT_FALSE(delete_task_flag_); - EXPECT_FALSE(delete_reply_flag_); - } - - scoped_refptr<MockRunsTasksInCurrentSequenceTaskRunner> post_runner_ = - MakeRefCounted<MockRunsTasksInCurrentSequenceTaskRunner>(); - scoped_refptr<MockRunsTasksInCurrentSequenceTaskRunner> reply_runner_ = - MakeRefCounted<MockRunsTasksInCurrentSequenceTaskRunner>( - TestMockTimeTaskRunner::Type::kBoundToThread); - testing::StrictMock<MockObject> mock_object_; - bool delete_task_flag_ = false; - bool delete_reply_flag_ = false; - - private: - DISALLOW_COPY_AND_ASSIGN(PostTaskAndReplyImplTest); -}; - -} // namespace - -TEST_F(PostTaskAndReplyImplTest, PostTaskAndReply) { - PostTaskAndReplyToMockObject(); - - EXPECT_CALL(mock_object_, Task(_)); - post_runner_->RunUntilIdleWithRunsTasksInCurrentSequence(); - testing::Mock::VerifyAndClear(&mock_object_); - // The task should have been deleted right after being run. - EXPECT_TRUE(delete_task_flag_); - EXPECT_FALSE(delete_reply_flag_); - - // Expect the reply to be posted to |reply_runner_|. - EXPECT_FALSE(post_runner_->HasPendingTask()); - EXPECT_TRUE(reply_runner_->HasPendingTask()); - - EXPECT_CALL(mock_object_, Reply(_)); - reply_runner_->RunUntilIdleWithRunsTasksInCurrentSequence(); - testing::Mock::VerifyAndClear(&mock_object_); - EXPECT_TRUE(delete_task_flag_); - // The reply should have been deleted right after being run. - EXPECT_TRUE(delete_reply_flag_); - - // Expect no pending task in |post_runner_| and |reply_runner_|. - EXPECT_FALSE(post_runner_->HasPendingTask()); - EXPECT_FALSE(reply_runner_->HasPendingTask()); -} - -TEST_F(PostTaskAndReplyImplTest, TaskDoesNotRun) { - PostTaskAndReplyToMockObject(); - - // Clear the |post_runner_|. Both callbacks should be scheduled for deletion - // on the |reply_runner_|. - post_runner_->ClearPendingTasksWithRunsTasksInCurrentSequence(); - EXPECT_FALSE(post_runner_->HasPendingTask()); - EXPECT_TRUE(reply_runner_->HasPendingTask()); - EXPECT_FALSE(delete_task_flag_); - EXPECT_FALSE(delete_reply_flag_); - - // Run the |reply_runner_|. Both callbacks should be deleted. - reply_runner_->RunUntilIdleWithRunsTasksInCurrentSequence(); - EXPECT_TRUE(delete_task_flag_); - EXPECT_TRUE(delete_reply_flag_); -} - -TEST_F(PostTaskAndReplyImplTest, ReplyDoesNotRun) { - PostTaskAndReplyToMockObject(); - - EXPECT_CALL(mock_object_, Task(_)); - post_runner_->RunUntilIdleWithRunsTasksInCurrentSequence(); - testing::Mock::VerifyAndClear(&mock_object_); - // The task should have been deleted right after being run. - EXPECT_TRUE(delete_task_flag_); - EXPECT_FALSE(delete_reply_flag_); - - // Expect the reply to be posted to |reply_runner_|. - EXPECT_FALSE(post_runner_->HasPendingTask()); - EXPECT_TRUE(reply_runner_->HasPendingTask()); - - // Clear the |reply_runner_| queue without running tasks. The reply callback - // should be deleted. - reply_runner_->ClearPendingTasksWithRunsTasksInCurrentSequence(); - EXPECT_TRUE(delete_task_flag_); - EXPECT_TRUE(delete_reply_flag_); -} - -} // namespace internal -} // namespace base
diff --git a/base/threading/scoped_blocking_call_unittest.cc b/base/threading/scoped_blocking_call_unittest.cc deleted file mode 100644 index 5e030f3..0000000 --- a/base/threading/scoped_blocking_call_unittest.cc +++ /dev/null
@@ -1,134 +0,0 @@ -// 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/threading/scoped_blocking_call.h" - -#include <memory> - -#include "base/macros.h" -#include "base/test/gtest_util.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -class MockBlockingObserver : public internal::BlockingObserver { - public: - MockBlockingObserver() = default; - - MOCK_METHOD1(BlockingStarted, void(BlockingType)); - MOCK_METHOD0(BlockingTypeUpgraded, void()); - MOCK_METHOD0(BlockingEnded, void()); - - private: - DISALLOW_COPY_AND_ASSIGN(MockBlockingObserver); -}; - -class ScopedBlockingCallTest : public testing::Test { - protected: - ScopedBlockingCallTest() { - internal::SetBlockingObserverForCurrentThread(&observer_); - } - - ~ScopedBlockingCallTest() override { - internal::ClearBlockingObserverForTesting(); - } - - testing::StrictMock<MockBlockingObserver> observer_; - - private: - DISALLOW_COPY_AND_ASSIGN(ScopedBlockingCallTest); -}; - -} // namespace - -TEST_F(ScopedBlockingCallTest, MayBlock) { - EXPECT_CALL(observer_, BlockingStarted(BlockingType::MAY_BLOCK)); - ScopedBlockingCall scoped_blocking_call(BlockingType::MAY_BLOCK); - testing::Mock::VerifyAndClear(&observer_); - EXPECT_CALL(observer_, BlockingEnded()); -} - -TEST_F(ScopedBlockingCallTest, WillBlock) { - EXPECT_CALL(observer_, BlockingStarted(BlockingType::WILL_BLOCK)); - ScopedBlockingCall scoped_blocking_call(BlockingType::WILL_BLOCK); - testing::Mock::VerifyAndClear(&observer_); - EXPECT_CALL(observer_, BlockingEnded()); -} - -TEST_F(ScopedBlockingCallTest, MayBlockWillBlock) { - EXPECT_CALL(observer_, BlockingStarted(BlockingType::MAY_BLOCK)); - ScopedBlockingCall scoped_blocking_call_a(BlockingType::MAY_BLOCK); - testing::Mock::VerifyAndClear(&observer_); - - { - EXPECT_CALL(observer_, BlockingTypeUpgraded()); - ScopedBlockingCall scoped_blocking_call_b(BlockingType::WILL_BLOCK); - testing::Mock::VerifyAndClear(&observer_); - } - - EXPECT_CALL(observer_, BlockingEnded()); -} - -TEST_F(ScopedBlockingCallTest, WillBlockMayBlock) { - EXPECT_CALL(observer_, BlockingStarted(BlockingType::WILL_BLOCK)); - ScopedBlockingCall scoped_blocking_call_a(BlockingType::WILL_BLOCK); - testing::Mock::VerifyAndClear(&observer_); - - { ScopedBlockingCall scoped_blocking_call_b(BlockingType::MAY_BLOCK); } - - EXPECT_CALL(observer_, BlockingEnded()); -} - -TEST_F(ScopedBlockingCallTest, MayBlockMayBlock) { - EXPECT_CALL(observer_, BlockingStarted(BlockingType::MAY_BLOCK)); - ScopedBlockingCall scoped_blocking_call_a(BlockingType::MAY_BLOCK); - testing::Mock::VerifyAndClear(&observer_); - - { ScopedBlockingCall scoped_blocking_call_b(BlockingType::MAY_BLOCK); } - - EXPECT_CALL(observer_, BlockingEnded()); -} - -TEST_F(ScopedBlockingCallTest, WillBlockWillBlock) { - EXPECT_CALL(observer_, BlockingStarted(BlockingType::WILL_BLOCK)); - ScopedBlockingCall scoped_blocking_call_a(BlockingType::WILL_BLOCK); - testing::Mock::VerifyAndClear(&observer_); - - { ScopedBlockingCall scoped_blocking_call_b(BlockingType::WILL_BLOCK); } - - EXPECT_CALL(observer_, BlockingEnded()); -} - -TEST_F(ScopedBlockingCallTest, MayBlockWillBlockTwice) { - EXPECT_CALL(observer_, BlockingStarted(BlockingType::MAY_BLOCK)); - ScopedBlockingCall scoped_blocking_call_a(BlockingType::MAY_BLOCK); - testing::Mock::VerifyAndClear(&observer_); - - { - EXPECT_CALL(observer_, BlockingTypeUpgraded()); - ScopedBlockingCall scoped_blocking_call_b(BlockingType::WILL_BLOCK); - testing::Mock::VerifyAndClear(&observer_); - - { - ScopedBlockingCall scoped_blocking_call_c(BlockingType::MAY_BLOCK); - ScopedBlockingCall scoped_blocking_call_d(BlockingType::WILL_BLOCK); - } - } - - EXPECT_CALL(observer_, BlockingEnded()); -} - -TEST(ScopedBlockingCallDestructionOrderTest, InvalidDestructionOrder) { - auto scoped_blocking_call_a = - std::make_unique<ScopedBlockingCall>(BlockingType::WILL_BLOCK); - auto scoped_blocking_call_b = - std::make_unique<ScopedBlockingCall>(BlockingType::WILL_BLOCK); - - EXPECT_DCHECK_DEATH({ scoped_blocking_call_a.reset(); }); -} - -} // namespace base
diff --git a/base/threading/sequence_local_storage_map_unittest.cc b/base/threading/sequence_local_storage_map_unittest.cc deleted file mode 100644 index a45bbc3..0000000 --- a/base/threading/sequence_local_storage_map_unittest.cc +++ /dev/null
@@ -1,117 +0,0 @@ -// 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/threading/sequence_local_storage_map.h" - -#include <memory> -#include <utility> - -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace internal { - -namespace { - -constexpr int kSlotId = 1; - -class SetOnDestroy { - public: - SetOnDestroy(bool* was_destroyed_ptr) - : was_destroyed_ptr_(was_destroyed_ptr) { - DCHECK(was_destroyed_ptr_); - DCHECK(!(*was_destroyed_ptr_)); - } - ~SetOnDestroy() { - DCHECK(!(*was_destroyed_ptr_)); - *was_destroyed_ptr_ = true; - } - - private: - bool* const was_destroyed_ptr_; - - DISALLOW_COPY_AND_ASSIGN(SetOnDestroy); -}; - -template <typename T, typename... Args> -SequenceLocalStorageMap::ValueDestructorPair CreateValueDestructorPair( - Args... args) { - T* value = new T(args...); - SequenceLocalStorageMap::ValueDestructorPair::DestructorFunc* destructor = - [](void* ptr) { std::default_delete<T>()(static_cast<T*>(ptr)); }; - - SequenceLocalStorageMap::ValueDestructorPair value_destructor_pair{ - value, destructor}; - - return value_destructor_pair; -} - -} // namespace - -// Verify that setting a value in the SequenceLocalStorageMap, then getting -// it will yield the same value. -TEST(SequenceLocalStorageMapTest, SetGet) { - SequenceLocalStorageMap sequence_local_storage_map; - ScopedSetSequenceLocalStorageMapForCurrentThread - scoped_sequence_local_storage_map(&sequence_local_storage_map); - - SequenceLocalStorageMap::ValueDestructorPair value_destructor_pair = - CreateValueDestructorPair<int>(5); - - sequence_local_storage_map.Set(kSlotId, std::move(value_destructor_pair)); - - EXPECT_EQ(*static_cast<int*>(sequence_local_storage_map.Get(kSlotId)), 5); -} - -// Verify that the destructor is called on a value stored in the -// SequenceLocalStorageMap when SequenceLocalStorageMap is destroyed. -TEST(SequenceLocalStorageMapTest, Destructor) { - bool set_on_destruction = false; - - { - SequenceLocalStorageMap sequence_local_storage_map; - ScopedSetSequenceLocalStorageMapForCurrentThread - scoped_sequence_local_storage_map(&sequence_local_storage_map); - - SequenceLocalStorageMap::ValueDestructorPair value_destructor_pair = - CreateValueDestructorPair<SetOnDestroy>(&set_on_destruction); - - sequence_local_storage_map.Set(kSlotId, std::move(value_destructor_pair)); - } - - EXPECT_TRUE(set_on_destruction); -} - -// Verify that overwriting a value already in the SequenceLocalStorageMap -// calls value's destructor. -TEST(SequenceLocalStorageMapTest, DestructorCalledOnSetOverwrite) { - bool set_on_destruction = false; - bool set_on_destruction2 = false; - { - SequenceLocalStorageMap sequence_local_storage_map; - ScopedSetSequenceLocalStorageMapForCurrentThread - scoped_sequence_local_storage_map(&sequence_local_storage_map); - - SequenceLocalStorageMap::ValueDestructorPair value_destructor_pair = - CreateValueDestructorPair<SetOnDestroy>(&set_on_destruction); - SequenceLocalStorageMap::ValueDestructorPair value_destructor_pair2 = - CreateValueDestructorPair<SetOnDestroy>(&set_on_destruction2); - - sequence_local_storage_map.Set(kSlotId, std::move(value_destructor_pair)); - - ASSERT_FALSE(set_on_destruction); - - // Overwrites the old value in the slot. - sequence_local_storage_map.Set(kSlotId, std::move(value_destructor_pair2)); - - // Destructor should've been called for the old value in the slot, and not - // yet called for the new value. - EXPECT_TRUE(set_on_destruction); - EXPECT_FALSE(set_on_destruction2); - } - EXPECT_TRUE(set_on_destruction2); -} - -} // namespace internal -} // namespace base
diff --git a/base/threading/sequence_local_storage_slot_unittest.cc b/base/threading/sequence_local_storage_slot_unittest.cc deleted file mode 100644 index 4a9f6a9..0000000 --- a/base/threading/sequence_local_storage_slot_unittest.cc +++ /dev/null
@@ -1,143 +0,0 @@ -// 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/threading/sequence_local_storage_slot.h" - -#include <utility> - -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/threading/sequence_local_storage_map.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -class SequenceLocalStorageSlotTest : public testing::Test { - protected: - SequenceLocalStorageSlotTest() - : scoped_sequence_local_storage_(&sequence_local_storage_) {} - - internal::SequenceLocalStorageMap sequence_local_storage_; - internal::ScopedSetSequenceLocalStorageMapForCurrentThread - scoped_sequence_local_storage_; - - private: - DISALLOW_COPY_AND_ASSIGN(SequenceLocalStorageSlotTest); -}; - -} // namespace - -// Verify that a value stored with Set() can be retrieved with Get(). -TEST_F(SequenceLocalStorageSlotTest, GetSet) { - SequenceLocalStorageSlot<int> slot; - slot.Set(5); - EXPECT_EQ(slot.Get(), 5); -} - -// Verify that setting an object in a SequenceLocalStorageSlot creates a copy -// of that object independent of the original one. -TEST_F(SequenceLocalStorageSlotTest, SetObjectIsIndependent) { - bool should_be_false = false; - - SequenceLocalStorageSlot<bool> slot; - - slot.Set(should_be_false); - - EXPECT_FALSE(slot.Get()); - slot.Get() = true; - EXPECT_TRUE(slot.Get()); - - EXPECT_NE(should_be_false, slot.Get()); -} - -// Verify that multiple slots work and that calling Get after overwriting -// a value in a slot yields the new value. -TEST_F(SequenceLocalStorageSlotTest, GetSetMultipleSlots) { - SequenceLocalStorageSlot<int> slot1; - SequenceLocalStorageSlot<int> slot2; - SequenceLocalStorageSlot<int> slot3; - - slot1.Set(1); - slot2.Set(2); - slot3.Set(3); - - EXPECT_EQ(slot1.Get(), 1); - EXPECT_EQ(slot2.Get(), 2); - EXPECT_EQ(slot3.Get(), 3); - - slot3.Set(4); - slot2.Set(5); - slot1.Set(6); - - EXPECT_EQ(slot3.Get(), 4); - EXPECT_EQ(slot2.Get(), 5); - EXPECT_EQ(slot1.Get(), 6); -} - -// Verify that changing the the value returned by Get() changes the value -// in sequence local storage. -TEST_F(SequenceLocalStorageSlotTest, GetReferenceModifiable) { - SequenceLocalStorageSlot<bool> slot; - slot.Set(false); - slot.Get() = true; - EXPECT_TRUE(slot.Get()); -} - -// Verify that a move-only type can be stored in sequence local storage. -TEST_F(SequenceLocalStorageSlotTest, SetGetWithMoveOnlyType) { - std::unique_ptr<int> int_unique_ptr = std::make_unique<int>(5); - - SequenceLocalStorageSlot<std::unique_ptr<int>> slot; - slot.Set(std::move(int_unique_ptr)); - - EXPECT_EQ(*slot.Get(), 5); -} - -// Verify that a Get() without a previous Set() on a slot returns a -// default-constructed value. -TEST_F(SequenceLocalStorageSlotTest, GetWithoutSetDefaultConstructs) { - struct DefaultConstructable { - int x = 0x12345678; - }; - - SequenceLocalStorageSlot<DefaultConstructable> slot; - - EXPECT_EQ(slot.Get().x, 0x12345678); -} - -// Verify that a Get() without a previous Set() on a slot with a POD-type -// returns a default-constructed value. -// Note: this test could be flaky and give a false pass. If it's flaky, the test -// might've "passed" because the memory for the slot happened to be zeroed. -TEST_F(SequenceLocalStorageSlotTest, GetWithoutSetDefaultConstructsPOD) { - SequenceLocalStorageSlot<void*> slot; - - EXPECT_EQ(slot.Get(), nullptr); -} - -// Verify that the value of a slot is specific to a SequenceLocalStorageMap -TEST(SequenceLocalStorageSlotMultipleMapTest, SetGetMultipleMapsOneSlot) { - SequenceLocalStorageSlot<unsigned int> slot; - internal::SequenceLocalStorageMap sequence_local_storage_maps[5]; - - // Set the value of the slot to be the index of the current - // SequenceLocalStorageMaps in the vector - for (unsigned int i = 0; i < arraysize(sequence_local_storage_maps); ++i) { - internal::ScopedSetSequenceLocalStorageMapForCurrentThread - scoped_sequence_local_storage(&sequence_local_storage_maps[i]); - - slot.Set(i); - } - - for (unsigned int i = 0; i < arraysize(sequence_local_storage_maps); ++i) { - internal::ScopedSetSequenceLocalStorageMapForCurrentThread - scoped_sequence_local_storage(&sequence_local_storage_maps[i]); - - EXPECT_EQ(slot.Get(), i); - } -} - -} // namespace base
diff --git a/base/threading/sequenced_task_runner_handle_unittest.cc b/base/threading/sequenced_task_runner_handle_unittest.cc deleted file mode 100644 index 48394da..0000000 --- a/base/threading/sequenced_task_runner_handle_unittest.cc +++ /dev/null
@@ -1,90 +0,0 @@ -// 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/threading/sequenced_task_runner_handle.h" - -#include <memory> -#include <utility> - -#include "base/bind.h" -#include "base/callback.h" -#include "base/location.h" -#include "base/memory/ref_counted.h" -#include "base/run_loop.h" -#include "base/sequence_checker_impl.h" -#include "base/sequenced_task_runner.h" -#include "base/synchronization/waitable_event.h" -#include "base/task_scheduler/post_task.h" -#include "base/test/scoped_task_environment.h" -#include "base/test/test_simple_task_runner.h" -#include "base/threading/thread_task_runner_handle.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -class SequencedTaskRunnerHandleTest : public ::testing::Test { - protected: - // Verifies that the context it runs on has a SequencedTaskRunnerHandle - // and that posting to it results in the posted task running in that same - // context (sequence). - static void VerifyCurrentSequencedTaskRunner() { - ASSERT_TRUE(SequencedTaskRunnerHandle::IsSet()); - scoped_refptr<SequencedTaskRunner> task_runner = - SequencedTaskRunnerHandle::Get(); - ASSERT_TRUE(task_runner); - - // Use SequenceCheckerImpl to make sure it's not a no-op in Release builds. - std::unique_ptr<SequenceCheckerImpl> sequence_checker( - new SequenceCheckerImpl); - task_runner->PostTask( - FROM_HERE, - base::BindOnce(&SequencedTaskRunnerHandleTest::CheckValidSequence, - std::move(sequence_checker))); - } - - static void CheckValidSequence( - std::unique_ptr<SequenceCheckerImpl> sequence_checker) { - EXPECT_TRUE(sequence_checker->CalledOnValidSequence()); - } - - base::test::ScopedTaskEnvironment scoped_task_environment_; -}; - -TEST_F(SequencedTaskRunnerHandleTest, FromMessageLoop) { - VerifyCurrentSequencedTaskRunner(); - RunLoop().RunUntilIdle(); -} - -TEST_F(SequencedTaskRunnerHandleTest, FromTaskSchedulerSequencedTask) { - base::CreateSequencedTaskRunnerWithTraits({})->PostTask( - FROM_HERE, - base::BindOnce( - &SequencedTaskRunnerHandleTest::VerifyCurrentSequencedTaskRunner)); - scoped_task_environment_.RunUntilIdle(); -} - -TEST_F(SequencedTaskRunnerHandleTest, NoHandleFromUnsequencedTask) { - base::PostTask(FROM_HERE, base::BindOnce([]() { - EXPECT_FALSE(SequencedTaskRunnerHandle::IsSet()); - })); - scoped_task_environment_.RunUntilIdle(); -} - -TEST(SequencedTaskRunnerHandleTestWithoutMessageLoop, FromHandleInScope) { - scoped_refptr<SequencedTaskRunner> test_task_runner(new TestSimpleTaskRunner); - EXPECT_FALSE(SequencedTaskRunnerHandle::IsSet()); - EXPECT_FALSE(ThreadTaskRunnerHandle::IsSet()); - { - SequencedTaskRunnerHandle handle(test_task_runner); - EXPECT_TRUE(SequencedTaskRunnerHandle::IsSet()); - EXPECT_FALSE(ThreadTaskRunnerHandle::IsSet()); - EXPECT_EQ(test_task_runner, SequencedTaskRunnerHandle::Get()); - } - EXPECT_FALSE(SequencedTaskRunnerHandle::IsSet()); - EXPECT_FALSE(ThreadTaskRunnerHandle::IsSet()); -} - -} // namespace -} // namespace base
diff --git a/base/threading/simple_thread_unittest.cc b/base/threading/simple_thread_unittest.cc deleted file mode 100644 index 4e618f9..0000000 --- a/base/threading/simple_thread_unittest.cc +++ /dev/null
@@ -1,234 +0,0 @@ -// 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 <memory> - -#include "base/atomic_sequence_num.h" -#include "base/memory/ptr_util.h" -#include "base/strings/string_number_conversions.h" -#include "base/synchronization/waitable_event.h" -#include "base/test/gtest_util.h" -#include "base/threading/simple_thread.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -class SetIntRunner : public DelegateSimpleThread::Delegate { - public: - SetIntRunner(int* ptr, int val) : ptr_(ptr), val_(val) { } - ~SetIntRunner() override = default; - - private: - void Run() override { *ptr_ = val_; } - - int* ptr_; - int val_; - - DISALLOW_COPY_AND_ASSIGN(SetIntRunner); -}; - -// Signals |started_| when Run() is invoked and waits until |released_| is -// signaled to return, signaling |done_| before doing so. Useful for tests that -// care to control Run()'s flow. -class ControlledRunner : public DelegateSimpleThread::Delegate { - public: - ControlledRunner() - : started_(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED), - released_(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED), - done_(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED) {} - - ~ControlledRunner() override { ReleaseAndWaitUntilDone(); } - - void WaitUntilStarted() { started_.Wait(); } - - void ReleaseAndWaitUntilDone() { - released_.Signal(); - done_.Wait(); - } - - private: - void Run() override { - started_.Signal(); - released_.Wait(); - done_.Signal(); - } - - WaitableEvent started_; - WaitableEvent released_; - WaitableEvent done_; - - DISALLOW_COPY_AND_ASSIGN(ControlledRunner); -}; - -class WaitEventRunner : public DelegateSimpleThread::Delegate { - public: - explicit WaitEventRunner(WaitableEvent* event) : event_(event) { } - ~WaitEventRunner() override = default; - - private: - void Run() override { - EXPECT_FALSE(event_->IsSignaled()); - event_->Signal(); - EXPECT_TRUE(event_->IsSignaled()); - } - - WaitableEvent* event_; - - DISALLOW_COPY_AND_ASSIGN(WaitEventRunner); -}; - -class SeqRunner : public DelegateSimpleThread::Delegate { - public: - explicit SeqRunner(AtomicSequenceNumber* seq) : seq_(seq) { } - - private: - void Run() override { seq_->GetNext(); } - - AtomicSequenceNumber* seq_; - - DISALLOW_COPY_AND_ASSIGN(SeqRunner); -}; - -// We count up on a sequence number, firing on the event when we've hit our -// expected amount, otherwise we wait on the event. This will ensure that we -// have all threads outstanding until we hit our expected thread pool size. -class VerifyPoolRunner : public DelegateSimpleThread::Delegate { - public: - VerifyPoolRunner(AtomicSequenceNumber* seq, - int total, WaitableEvent* event) - : seq_(seq), total_(total), event_(event) { } - - private: - void Run() override { - if (seq_->GetNext() == total_) { - event_->Signal(); - } else { - event_->Wait(); - } - } - - AtomicSequenceNumber* seq_; - int total_; - WaitableEvent* event_; - - DISALLOW_COPY_AND_ASSIGN(VerifyPoolRunner); -}; - -} // namespace - -TEST(SimpleThreadTest, CreateAndJoin) { - int stack_int = 0; - - SetIntRunner runner(&stack_int, 7); - EXPECT_EQ(0, stack_int); - - DelegateSimpleThread thread(&runner, "int_setter"); - EXPECT_FALSE(thread.HasBeenStarted()); - EXPECT_FALSE(thread.HasBeenJoined()); - EXPECT_EQ(0, stack_int); - - thread.Start(); - EXPECT_TRUE(thread.HasBeenStarted()); - EXPECT_FALSE(thread.HasBeenJoined()); - - thread.Join(); - EXPECT_TRUE(thread.HasBeenStarted()); - EXPECT_TRUE(thread.HasBeenJoined()); - EXPECT_EQ(7, stack_int); -} - -TEST(SimpleThreadTest, WaitForEvent) { - // Create a thread, and wait for it to signal us. - WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - - WaitEventRunner runner(&event); - DelegateSimpleThread thread(&runner, "event_waiter"); - - EXPECT_FALSE(event.IsSignaled()); - thread.Start(); - event.Wait(); - EXPECT_TRUE(event.IsSignaled()); - thread.Join(); -} - -TEST(SimpleThreadTest, NonJoinableStartAndDieOnJoin) { - ControlledRunner runner; - - SimpleThread::Options options; - options.joinable = false; - DelegateSimpleThread thread(&runner, "non_joinable", options); - - EXPECT_FALSE(thread.HasBeenStarted()); - thread.Start(); - EXPECT_TRUE(thread.HasBeenStarted()); - - // Note: this is not quite the same as |thread.HasBeenStarted()| which - // represents ThreadMain() getting ready to invoke Run() whereas - // |runner.WaitUntilStarted()| ensures Run() was actually invoked. - runner.WaitUntilStarted(); - - EXPECT_FALSE(thread.HasBeenJoined()); - EXPECT_DCHECK_DEATH({ thread.Join(); }); -} - -TEST(SimpleThreadTest, NonJoinableInactiveDelegateDestructionIsOkay) { - std::unique_ptr<ControlledRunner> runner(new ControlledRunner); - - SimpleThread::Options options; - options.joinable = false; - std::unique_ptr<DelegateSimpleThread> thread( - new DelegateSimpleThread(runner.get(), "non_joinable", options)); - - thread->Start(); - runner->WaitUntilStarted(); - - // Deleting a non-joinable SimpleThread after Run() was invoked is okay. - thread.reset(); - - runner->WaitUntilStarted(); - runner->ReleaseAndWaitUntilDone(); - // It should be safe to destroy a Delegate after its Run() method completed. - runner.reset(); -} - -TEST(SimpleThreadTest, ThreadPool) { - AtomicSequenceNumber seq; - SeqRunner runner(&seq); - DelegateSimpleThreadPool pool("seq_runner", 10); - - // Add work before we're running. - pool.AddWork(&runner, 300); - - EXPECT_EQ(seq.GetNext(), 0); - pool.Start(); - - // Add work while we're running. - pool.AddWork(&runner, 300); - - pool.JoinAll(); - - EXPECT_EQ(seq.GetNext(), 601); - - // We can reuse our pool. Verify that all 10 threads can actually run in - // parallel, so this test will only pass if there are actually 10 threads. - AtomicSequenceNumber seq2; - WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - // Changing 9 to 10, for example, would cause us JoinAll() to never return. - VerifyPoolRunner verifier(&seq2, 9, &event); - pool.Start(); - - pool.AddWork(&verifier, 10); - - pool.JoinAll(); - EXPECT_EQ(seq2.GetNext(), 10); -} - -} // namespace base
diff --git a/base/threading/thread_checker_unittest.cc b/base/threading/thread_checker_unittest.cc deleted file mode 100644 index 5fbbc52..0000000 --- a/base/threading/thread_checker_unittest.cc +++ /dev/null
@@ -1,245 +0,0 @@ -// 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/threading/thread_checker.h" - -#include <memory> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/sequence_token.h" -#include "base/test/gtest_util.h" -#include "base/test/test_simple_task_runner.h" -#include "base/threading/simple_thread.h" -#include "base/threading/thread_task_runner_handle.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -// A thread that runs a callback. -class RunCallbackThread : public SimpleThread { - public: - explicit RunCallbackThread(const Closure& callback) - : SimpleThread("RunCallbackThread"), callback_(callback) {} - - private: - // SimpleThread: - void Run() override { callback_.Run(); } - - const Closure callback_; - - DISALLOW_COPY_AND_ASSIGN(RunCallbackThread); -}; - -// Runs a callback on a new thread synchronously. -void RunCallbackOnNewThreadSynchronously(const Closure& callback) { - RunCallbackThread run_callback_thread(callback); - run_callback_thread.Start(); - run_callback_thread.Join(); -} - -void ExpectCalledOnValidThread(ThreadCheckerImpl* thread_checker) { - ASSERT_TRUE(thread_checker); - - // This should bind |thread_checker| to the current thread if it wasn't - // already bound to a thread. - EXPECT_TRUE(thread_checker->CalledOnValidThread()); - - // Since |thread_checker| is now bound to the current thread, another call to - // CalledOnValidThread() should return true. - EXPECT_TRUE(thread_checker->CalledOnValidThread()); -} - -void ExpectNotCalledOnValidThread(ThreadCheckerImpl* thread_checker) { - ASSERT_TRUE(thread_checker); - EXPECT_FALSE(thread_checker->CalledOnValidThread()); -} - -void ExpectNotCalledOnValidThreadWithSequenceTokenAndThreadTaskRunnerHandle( - ThreadCheckerImpl* thread_checker, - SequenceToken sequence_token) { - ThreadTaskRunnerHandle thread_task_runner_handle( - MakeRefCounted<TestSimpleTaskRunner>()); - ScopedSetSequenceTokenForCurrentThread - scoped_set_sequence_token_for_current_thread(sequence_token); - ExpectNotCalledOnValidThread(thread_checker); -} - -} // namespace - -TEST(ThreadCheckerTest, AllowedSameThreadNoSequenceToken) { - ThreadCheckerImpl thread_checker; - EXPECT_TRUE(thread_checker.CalledOnValidThread()); -} - -TEST(ThreadCheckerTest, - AllowedSameThreadAndSequenceDifferentTasksWithThreadTaskRunnerHandle) { - ThreadTaskRunnerHandle thread_task_runner_handle( - MakeRefCounted<TestSimpleTaskRunner>()); - - std::unique_ptr<ThreadCheckerImpl> thread_checker; - const SequenceToken sequence_token = SequenceToken::Create(); - - { - ScopedSetSequenceTokenForCurrentThread - scoped_set_sequence_token_for_current_thread(sequence_token); - thread_checker.reset(new ThreadCheckerImpl); - } - - { - ScopedSetSequenceTokenForCurrentThread - scoped_set_sequence_token_for_current_thread(sequence_token); - EXPECT_TRUE(thread_checker->CalledOnValidThread()); - } -} - -TEST(ThreadCheckerTest, - AllowedSameThreadSequenceAndTaskNoThreadTaskRunnerHandle) { - ScopedSetSequenceTokenForCurrentThread - scoped_set_sequence_token_for_current_thread(SequenceToken::Create()); - ThreadCheckerImpl thread_checker; - EXPECT_TRUE(thread_checker.CalledOnValidThread()); -} - -TEST(ThreadCheckerTest, - DisallowedSameThreadAndSequenceDifferentTasksNoThreadTaskRunnerHandle) { - std::unique_ptr<ThreadCheckerImpl> thread_checker; - - { - ScopedSetSequenceTokenForCurrentThread - scoped_set_sequence_token_for_current_thread(SequenceToken::Create()); - thread_checker.reset(new ThreadCheckerImpl); - } - - { - ScopedSetSequenceTokenForCurrentThread - scoped_set_sequence_token_for_current_thread(SequenceToken::Create()); - EXPECT_FALSE(thread_checker->CalledOnValidThread()); - } -} - -TEST(ThreadCheckerTest, DisallowedDifferentThreadsNoSequenceToken) { - ThreadCheckerImpl thread_checker; - RunCallbackOnNewThreadSynchronously( - Bind(&ExpectNotCalledOnValidThread, Unretained(&thread_checker))); -} - -TEST(ThreadCheckerTest, DisallowedDifferentThreadsSameSequence) { - ThreadTaskRunnerHandle thread_task_runner_handle( - MakeRefCounted<TestSimpleTaskRunner>()); - const SequenceToken sequence_token(SequenceToken::Create()); - - ScopedSetSequenceTokenForCurrentThread - scoped_set_sequence_token_for_current_thread(sequence_token); - ThreadCheckerImpl thread_checker; - EXPECT_TRUE(thread_checker.CalledOnValidThread()); - - RunCallbackOnNewThreadSynchronously(Bind( - &ExpectNotCalledOnValidThreadWithSequenceTokenAndThreadTaskRunnerHandle, - Unretained(&thread_checker), sequence_token)); -} - -TEST(ThreadCheckerTest, DisallowedSameThreadDifferentSequence) { - std::unique_ptr<ThreadCheckerImpl> thread_checker; - - ThreadTaskRunnerHandle thread_task_runner_handle( - MakeRefCounted<TestSimpleTaskRunner>()); - - { - ScopedSetSequenceTokenForCurrentThread - scoped_set_sequence_token_for_current_thread(SequenceToken::Create()); - thread_checker.reset(new ThreadCheckerImpl); - } - - { - // Different SequenceToken. - ScopedSetSequenceTokenForCurrentThread - scoped_set_sequence_token_for_current_thread(SequenceToken::Create()); - EXPECT_FALSE(thread_checker->CalledOnValidThread()); - } - - // No SequenceToken. - EXPECT_FALSE(thread_checker->CalledOnValidThread()); -} - -TEST(ThreadCheckerTest, DetachFromThread) { - ThreadCheckerImpl thread_checker; - thread_checker.DetachFromThread(); - - // Verify that CalledOnValidThread() returns true when called on a different - // thread after a call to DetachFromThread(). - RunCallbackOnNewThreadSynchronously( - Bind(&ExpectCalledOnValidThread, Unretained(&thread_checker))); - - EXPECT_FALSE(thread_checker.CalledOnValidThread()); -} - -TEST(ThreadCheckerTest, DetachFromThreadWithSequenceToken) { - ThreadTaskRunnerHandle thread_task_runner_handle( - MakeRefCounted<TestSimpleTaskRunner>()); - ScopedSetSequenceTokenForCurrentThread - scoped_set_sequence_token_for_current_thread(SequenceToken::Create()); - ThreadCheckerImpl thread_checker; - thread_checker.DetachFromThread(); - - // Verify that CalledOnValidThread() returns true when called on a different - // thread after a call to DetachFromThread(). - RunCallbackOnNewThreadSynchronously( - Bind(&ExpectCalledOnValidThread, Unretained(&thread_checker))); - - EXPECT_FALSE(thread_checker.CalledOnValidThread()); -} - -namespace { - -// This fixture is a helper for unit testing the thread checker macros as it is -// not possible to inline ExpectDeathOnOtherThread() and -// ExpectNoDeathOnOtherThreadAfterDetach() as lambdas since binding -// |Unretained(&my_sequence_checker)| wouldn't compile on non-dcheck builds -// where it won't be defined. -class ThreadCheckerMacroTest : public testing::Test { - public: - ThreadCheckerMacroTest() = default; - - void ExpectDeathOnOtherThread() { -#if DCHECK_IS_ON() - EXPECT_DCHECK_DEATH({ DCHECK_CALLED_ON_VALID_THREAD(my_thread_checker_); }); -#else - // Happily no-ops on non-dcheck builds. - DCHECK_CALLED_ON_VALID_THREAD(my_thread_checker_); -#endif - } - - void ExpectNoDeathOnOtherThreadAfterDetach() { - DCHECK_CALLED_ON_VALID_THREAD(my_thread_checker_); - DCHECK_CALLED_ON_VALID_THREAD(my_thread_checker_) - << "Make sure it compiles when DCHECK is off"; - } - - protected: - THREAD_CHECKER(my_thread_checker_); - - private: - DISALLOW_COPY_AND_ASSIGN(ThreadCheckerMacroTest); -}; - -} // namespace - -TEST_F(ThreadCheckerMacroTest, Macros) { - THREAD_CHECKER(my_thread_checker); - - RunCallbackOnNewThreadSynchronously(Bind( - &ThreadCheckerMacroTest::ExpectDeathOnOtherThread, Unretained(this))); - - DETACH_FROM_THREAD(my_thread_checker_); - - RunCallbackOnNewThreadSynchronously( - Bind(&ThreadCheckerMacroTest::ExpectNoDeathOnOtherThreadAfterDetach, - Unretained(this))); -} - -} // namespace base
diff --git a/base/threading/thread_collision_warner_unittest.cc b/base/threading/thread_collision_warner_unittest.cc deleted file mode 100644 index cd56768..0000000 --- a/base/threading/thread_collision_warner_unittest.cc +++ /dev/null
@@ -1,382 +0,0 @@ -// 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/threading/thread_collision_warner.h" - -#include <memory> - -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "base/synchronization/lock.h" -#include "base/threading/platform_thread.h" -#include "base/threading/simple_thread.h" -#include "testing/gtest/include/gtest/gtest.h" - -// '' : local class member function does not have a body -MSVC_PUSH_DISABLE_WARNING(4822) - - -#if defined(NDEBUG) - -// Would cause a memory leak otherwise. -#undef DFAKE_MUTEX -#define DFAKE_MUTEX(obj) std::unique_ptr<base::AsserterBase> obj - -// In Release, we expect the AsserterBase::warn() to not happen. -#define EXPECT_NDEBUG_FALSE_DEBUG_TRUE EXPECT_FALSE - -#else - -// In Debug, we expect the AsserterBase::warn() to happen. -#define EXPECT_NDEBUG_FALSE_DEBUG_TRUE EXPECT_TRUE - -#endif - - -namespace { - -// This is the asserter used with ThreadCollisionWarner instead of the default -// DCheckAsserter. The method fail_state is used to know if a collision took -// place. -class AssertReporter : public base::AsserterBase { - public: - AssertReporter() - : failed_(false) {} - - void warn() override { failed_ = true; } - - ~AssertReporter() override = default; - - bool fail_state() const { return failed_; } - void reset() { failed_ = false; } - - private: - bool failed_; -}; - -} // namespace - -TEST(ThreadCollisionTest, BookCriticalSection) { - AssertReporter* local_reporter = new AssertReporter(); - - base::ThreadCollisionWarner warner(local_reporter); - EXPECT_FALSE(local_reporter->fail_state()); - - { // Pin section. - DFAKE_SCOPED_LOCK_THREAD_LOCKED(warner); - EXPECT_FALSE(local_reporter->fail_state()); - { // Pin section. - DFAKE_SCOPED_LOCK_THREAD_LOCKED(warner); - EXPECT_FALSE(local_reporter->fail_state()); - } - } -} - -TEST(ThreadCollisionTest, ScopedRecursiveBookCriticalSection) { - AssertReporter* local_reporter = new AssertReporter(); - - base::ThreadCollisionWarner warner(local_reporter); - EXPECT_FALSE(local_reporter->fail_state()); - - { // Pin section. - DFAKE_SCOPED_RECURSIVE_LOCK(warner); - EXPECT_FALSE(local_reporter->fail_state()); - { // Pin section again (allowed by DFAKE_SCOPED_RECURSIVE_LOCK) - DFAKE_SCOPED_RECURSIVE_LOCK(warner); - EXPECT_FALSE(local_reporter->fail_state()); - } // Unpin section. - } // Unpin section. - - // Check that section is not pinned - { // Pin section. - DFAKE_SCOPED_LOCK(warner); - EXPECT_FALSE(local_reporter->fail_state()); - } // Unpin section. -} - -TEST(ThreadCollisionTest, ScopedBookCriticalSection) { - AssertReporter* local_reporter = new AssertReporter(); - - base::ThreadCollisionWarner warner(local_reporter); - EXPECT_FALSE(local_reporter->fail_state()); - - { // Pin section. - DFAKE_SCOPED_LOCK(warner); - EXPECT_FALSE(local_reporter->fail_state()); - } // Unpin section. - - { // Pin section. - DFAKE_SCOPED_LOCK(warner); - EXPECT_FALSE(local_reporter->fail_state()); - { - // Pin section again (not allowed by DFAKE_SCOPED_LOCK) - DFAKE_SCOPED_LOCK(warner); - EXPECT_NDEBUG_FALSE_DEBUG_TRUE(local_reporter->fail_state()); - // Reset the status of warner for further tests. - local_reporter->reset(); - } // Unpin section. - } // Unpin section. - - { - // Pin section. - DFAKE_SCOPED_LOCK(warner); - EXPECT_FALSE(local_reporter->fail_state()); - } // Unpin section. -} - -TEST(ThreadCollisionTest, MTBookCriticalSectionTest) { - class NonThreadSafeQueue { - public: - explicit NonThreadSafeQueue(base::AsserterBase* asserter) - : push_pop_(asserter) { - } - - void push(int value) { - DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_); - } - - int pop() { - DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_); - return 0; - } - - private: - DFAKE_MUTEX(push_pop_); - - DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue); - }; - - class QueueUser : public base::DelegateSimpleThread::Delegate { - public: - explicit QueueUser(NonThreadSafeQueue* queue) : queue_(queue) {} - - void Run() override { - queue_->push(0); - queue_->pop(); - } - - private: - NonThreadSafeQueue* queue_; - }; - - AssertReporter* local_reporter = new AssertReporter(); - - NonThreadSafeQueue queue(local_reporter); - - QueueUser queue_user_a(&queue); - QueueUser queue_user_b(&queue); - - base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a"); - base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b"); - - thread_a.Start(); - thread_b.Start(); - - thread_a.Join(); - thread_b.Join(); - - EXPECT_NDEBUG_FALSE_DEBUG_TRUE(local_reporter->fail_state()); -} - -TEST(ThreadCollisionTest, MTScopedBookCriticalSectionTest) { - // Queue with a 5 seconds push execution time, hopefuly the two used threads - // in the test will enter the push at same time. - class NonThreadSafeQueue { - public: - explicit NonThreadSafeQueue(base::AsserterBase* asserter) - : push_pop_(asserter) { - } - - void push(int value) { - DFAKE_SCOPED_LOCK(push_pop_); - base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(5)); - } - - int pop() { - DFAKE_SCOPED_LOCK(push_pop_); - return 0; - } - - private: - DFAKE_MUTEX(push_pop_); - - DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue); - }; - - class QueueUser : public base::DelegateSimpleThread::Delegate { - public: - explicit QueueUser(NonThreadSafeQueue* queue) : queue_(queue) {} - - void Run() override { - queue_->push(0); - queue_->pop(); - } - - private: - NonThreadSafeQueue* queue_; - }; - - AssertReporter* local_reporter = new AssertReporter(); - - NonThreadSafeQueue queue(local_reporter); - - QueueUser queue_user_a(&queue); - QueueUser queue_user_b(&queue); - - base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a"); - base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b"); - - thread_a.Start(); - thread_b.Start(); - - thread_a.Join(); - thread_b.Join(); - - EXPECT_NDEBUG_FALSE_DEBUG_TRUE(local_reporter->fail_state()); -} - -TEST(ThreadCollisionTest, MTSynchedScopedBookCriticalSectionTest) { - // Queue with a 2 seconds push execution time, hopefuly the two used threads - // in the test will enter the push at same time. - class NonThreadSafeQueue { - public: - explicit NonThreadSafeQueue(base::AsserterBase* asserter) - : push_pop_(asserter) { - } - - void push(int value) { - DFAKE_SCOPED_LOCK(push_pop_); - base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(2)); - } - - int pop() { - DFAKE_SCOPED_LOCK(push_pop_); - return 0; - } - - private: - DFAKE_MUTEX(push_pop_); - - DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue); - }; - - // This time the QueueUser class protects the non thread safe queue with - // a lock. - class QueueUser : public base::DelegateSimpleThread::Delegate { - public: - QueueUser(NonThreadSafeQueue* queue, base::Lock* lock) - : queue_(queue), lock_(lock) {} - - void Run() override { - { - base::AutoLock auto_lock(*lock_); - queue_->push(0); - } - { - base::AutoLock auto_lock(*lock_); - queue_->pop(); - } - } - private: - NonThreadSafeQueue* queue_; - base::Lock* lock_; - }; - - AssertReporter* local_reporter = new AssertReporter(); - - NonThreadSafeQueue queue(local_reporter); - - base::Lock lock; - - QueueUser queue_user_a(&queue, &lock); - QueueUser queue_user_b(&queue, &lock); - - base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a"); - base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b"); - - thread_a.Start(); - thread_b.Start(); - - thread_a.Join(); - thread_b.Join(); - - EXPECT_FALSE(local_reporter->fail_state()); -} - -TEST(ThreadCollisionTest, MTSynchedScopedRecursiveBookCriticalSectionTest) { - // Queue with a 2 seconds push execution time, hopefuly the two used threads - // in the test will enter the push at same time. - class NonThreadSafeQueue { - public: - explicit NonThreadSafeQueue(base::AsserterBase* asserter) - : push_pop_(asserter) { - } - - void push(int) { - DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_); - bar(); - base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(2)); - } - - int pop() { - DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_); - return 0; - } - - void bar() { - DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_); - } - - private: - DFAKE_MUTEX(push_pop_); - - DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue); - }; - - // This time the QueueUser class protects the non thread safe queue with - // a lock. - class QueueUser : public base::DelegateSimpleThread::Delegate { - public: - QueueUser(NonThreadSafeQueue* queue, base::Lock* lock) - : queue_(queue), lock_(lock) {} - - void Run() override { - { - base::AutoLock auto_lock(*lock_); - queue_->push(0); - } - { - base::AutoLock auto_lock(*lock_); - queue_->bar(); - } - { - base::AutoLock auto_lock(*lock_); - queue_->pop(); - } - } - private: - NonThreadSafeQueue* queue_; - base::Lock* lock_; - }; - - AssertReporter* local_reporter = new AssertReporter(); - - NonThreadSafeQueue queue(local_reporter); - - base::Lock lock; - - QueueUser queue_user_a(&queue, &lock); - QueueUser queue_user_b(&queue, &lock); - - base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a"); - base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b"); - - thread_a.Start(); - thread_b.Start(); - - thread_a.Join(); - thread_b.Join(); - - EXPECT_FALSE(local_reporter->fail_state()); -}
diff --git a/base/threading/thread_id_name_manager_unittest.cc b/base/threading/thread_id_name_manager_unittest.cc deleted file mode 100644 index 350dc0f..0000000 --- a/base/threading/thread_id_name_manager_unittest.cc +++ /dev/null
@@ -1,93 +0,0 @@ -// 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/threading/thread_id_name_manager.h" - -#include "base/threading/platform_thread.h" -#include "base/threading/thread.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/platform_test.h" - -typedef PlatformTest ThreadIdNameManagerTest; - -namespace { - -const char kAThread[] = "a thread"; -const char kBThread[] = "b thread"; - -TEST_F(ThreadIdNameManagerTest, AddThreads) { - base::ThreadIdNameManager* manager = base::ThreadIdNameManager::GetInstance(); - base::Thread thread_a(kAThread); - base::Thread thread_b(kBThread); - - thread_a.StartAndWaitForTesting(); - thread_b.StartAndWaitForTesting(); - - EXPECT_STREQ(kAThread, manager->GetName(thread_a.GetThreadId())); - EXPECT_STREQ(kBThread, manager->GetName(thread_b.GetThreadId())); - - thread_b.Stop(); - thread_a.Stop(); -} - -TEST_F(ThreadIdNameManagerTest, RemoveThreads) { - base::ThreadIdNameManager* manager = base::ThreadIdNameManager::GetInstance(); - base::Thread thread_a(kAThread); - - thread_a.StartAndWaitForTesting(); - { - base::Thread thread_b(kBThread); - thread_b.StartAndWaitForTesting(); - thread_b.Stop(); - } - EXPECT_STREQ(kAThread, manager->GetName(thread_a.GetThreadId())); - - thread_a.Stop(); - EXPECT_STREQ("", manager->GetName(thread_a.GetThreadId())); -} - -TEST_F(ThreadIdNameManagerTest, RestartThread) { - base::ThreadIdNameManager* manager = base::ThreadIdNameManager::GetInstance(); - base::Thread thread_a(kAThread); - - thread_a.StartAndWaitForTesting(); - base::PlatformThreadId a_id = thread_a.GetThreadId(); - EXPECT_STREQ(kAThread, manager->GetName(a_id)); - thread_a.Stop(); - - thread_a.StartAndWaitForTesting(); - EXPECT_STREQ("", manager->GetName(a_id)); - EXPECT_STREQ(kAThread, manager->GetName(thread_a.GetThreadId())); - thread_a.Stop(); -} - -TEST_F(ThreadIdNameManagerTest, ThreadNameInterning) { - base::ThreadIdNameManager* manager = base::ThreadIdNameManager::GetInstance(); - - base::PlatformThreadId a_id = base::PlatformThread::CurrentId(); - base::PlatformThread::SetName("First Name"); - std::string version = manager->GetName(a_id); - - base::PlatformThread::SetName("New name"); - EXPECT_NE(version, manager->GetName(a_id)); - base::PlatformThread::SetName(""); -} - -TEST_F(ThreadIdNameManagerTest, ResettingNameKeepsCorrectInternedValue) { - base::ThreadIdNameManager* manager = base::ThreadIdNameManager::GetInstance(); - - base::PlatformThreadId a_id = base::PlatformThread::CurrentId(); - base::PlatformThread::SetName("Test Name"); - std::string version = manager->GetName(a_id); - - base::PlatformThread::SetName("New name"); - EXPECT_NE(version, manager->GetName(a_id)); - - base::PlatformThread::SetName("Test Name"); - EXPECT_EQ(version, manager->GetName(a_id)); - - base::PlatformThread::SetName(""); -} - -} // namespace
diff --git a/base/threading/thread_local_storage_unittest.cc b/base/threading/thread_local_storage_unittest.cc deleted file mode 100644 index 006f928..0000000 --- a/base/threading/thread_local_storage_unittest.cc +++ /dev/null
@@ -1,278 +0,0 @@ -// 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/threading/thread_local_storage.h" - -#if defined(OS_WIN) -#include <windows.h> -#include <process.h> -#endif - -#include "base/macros.h" -#include "base/no_destructor.h" -#include "base/threading/simple_thread.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(OS_WIN) -// Ignore warnings about ptr->int conversions that we use when -// storing ints into ThreadLocalStorage. -#pragma warning(disable : 4311 4312) -#endif - -namespace base { - -#if defined(OS_POSIX) - -namespace internal { - -// This class is friended by ThreadLocalStorage. -class ThreadLocalStorageTestInternal { - public: - static bool HasBeenDestroyed() { - return ThreadLocalStorage::HasBeenDestroyed(); - } -}; - -} // namespace internal - -#endif // defined(OS_POSIX) - -namespace { - -const int kInitialTlsValue = 0x5555; -const int kFinalTlsValue = 0x7777; -// How many times must a destructor be called before we really are done. -const int kNumberDestructorCallRepetitions = 3; - -void ThreadLocalStorageCleanup(void* value); - -ThreadLocalStorage::Slot& TLSSlot() { - static NoDestructor<ThreadLocalStorage::Slot> slot( - &ThreadLocalStorageCleanup); - return *slot; -} - -class ThreadLocalStorageRunner : public DelegateSimpleThread::Delegate { - public: - explicit ThreadLocalStorageRunner(int* tls_value_ptr) - : tls_value_ptr_(tls_value_ptr) {} - - ~ThreadLocalStorageRunner() override = default; - - void Run() override { - *tls_value_ptr_ = kInitialTlsValue; - TLSSlot().Set(tls_value_ptr_); - - int* ptr = static_cast<int*>(TLSSlot().Get()); - EXPECT_EQ(ptr, tls_value_ptr_); - EXPECT_EQ(*ptr, kInitialTlsValue); - *tls_value_ptr_ = 0; - - ptr = static_cast<int*>(TLSSlot().Get()); - EXPECT_EQ(ptr, tls_value_ptr_); - EXPECT_EQ(*ptr, 0); - - *ptr = kFinalTlsValue + kNumberDestructorCallRepetitions; - } - - private: - int* tls_value_ptr_; - DISALLOW_COPY_AND_ASSIGN(ThreadLocalStorageRunner); -}; - - -void ThreadLocalStorageCleanup(void *value) { - int *ptr = reinterpret_cast<int*>(value); - // Destructors should never be called with a NULL. - ASSERT_NE(reinterpret_cast<int*>(NULL), ptr); - if (*ptr == kFinalTlsValue) - return; // We've been called enough times. - ASSERT_LT(kFinalTlsValue, *ptr); - ASSERT_GE(kFinalTlsValue + kNumberDestructorCallRepetitions, *ptr); - --*ptr; // Move closer to our target. - // Tell tls that we're not done with this thread, and still need destruction. - TLSSlot().Set(value); -} - -#if defined(OS_POSIX) -constexpr intptr_t kDummyValue = 0xABCD; -constexpr size_t kKeyCount = 20; - -// The order in which pthread keys are destructed is not specified by the POSIX -// specification. Hopefully, of the 20 keys we create, some of them should be -// destroyed after the TLS key is destroyed. -class UseTLSDuringDestructionRunner { - public: - UseTLSDuringDestructionRunner() = default; - - // The order in which pthread_key destructors are called is not well defined. - // Hopefully, by creating 10 both before and after initializing TLS on the - // thread, at least 1 will be called after TLS destruction. - void Run() { - ASSERT_FALSE(internal::ThreadLocalStorageTestInternal::HasBeenDestroyed()); - - // Create 10 pthread keys before initializing TLS on the thread. - size_t slot_index = 0; - for (; slot_index < 10; ++slot_index) { - CreateTlsKeyWithDestructor(slot_index); - } - - // Initialize the Chrome TLS system. It's possible that base::Thread has - // already initialized Chrome TLS, but we don't rely on that. - slot_.Set(reinterpret_cast<void*>(kDummyValue)); - - // Create 10 pthread keys after initializing TLS on the thread. - for (; slot_index < kKeyCount; ++slot_index) { - CreateTlsKeyWithDestructor(slot_index); - } - } - - bool teardown_works_correctly() { return teardown_works_correctly_; } - - private: - struct TLSState { - pthread_key_t key; - bool* teardown_works_correctly; - }; - - // The POSIX TLS destruction API takes as input a single C-function, which is - // called with the current |value| of a (key, value) pair. We need this - // function to do two things: set the |value| to nullptr, which requires - // knowing the associated |key|, and update the |teardown_works_correctly_| - // state. - // - // To accomplish this, we set the value to an instance of TLSState, which - // contains |key| as well as a pointer to |teardown_works_correctly|. - static void ThreadLocalDestructor(void* value) { - TLSState* state = static_cast<TLSState*>(value); - int result = pthread_setspecific(state->key, nullptr); - ASSERT_EQ(result, 0); - - // If this path is hit, then the thread local destructor was called after - // the Chrome-TLS destructor and the internal state was updated correctly. - // No further checks are necessary. - if (internal::ThreadLocalStorageTestInternal::HasBeenDestroyed()) { - *(state->teardown_works_correctly) = true; - return; - } - - // If this path is hit, then the thread local destructor was called before - // the Chrome-TLS destructor is hit. The ThreadLocalStorage::Slot should - // still function correctly. - ASSERT_EQ(reinterpret_cast<intptr_t>(slot_.Get()), kDummyValue); - } - - void CreateTlsKeyWithDestructor(size_t index) { - ASSERT_LT(index, kKeyCount); - - tls_states_[index].teardown_works_correctly = &teardown_works_correctly_; - int result = pthread_key_create( - &(tls_states_[index].key), - UseTLSDuringDestructionRunner::ThreadLocalDestructor); - ASSERT_EQ(result, 0); - - result = pthread_setspecific(tls_states_[index].key, &tls_states_[index]); - ASSERT_EQ(result, 0); - } - - static base::ThreadLocalStorage::Slot slot_; - bool teardown_works_correctly_ = false; - TLSState tls_states_[kKeyCount]; - - DISALLOW_COPY_AND_ASSIGN(UseTLSDuringDestructionRunner); -}; - -base::ThreadLocalStorage::Slot UseTLSDuringDestructionRunner::slot_; - -void* UseTLSTestThreadRun(void* input) { - UseTLSDuringDestructionRunner* runner = - static_cast<UseTLSDuringDestructionRunner*>(input); - runner->Run(); - return nullptr; -} - -#endif // defined(OS_POSIX) - -} // namespace - -TEST(ThreadLocalStorageTest, Basics) { - ThreadLocalStorage::Slot slot; - slot.Set(reinterpret_cast<void*>(123)); - int value = reinterpret_cast<intptr_t>(slot.Get()); - EXPECT_EQ(value, 123); -} - -#if defined(THREAD_SANITIZER) || \ - (defined(OS_WIN) && defined(ARCH_CPU_X86_64) && !defined(NDEBUG)) -// Do not run the test under ThreadSanitizer. Because this test iterates its -// own TSD destructor for the maximum possible number of times, TSan can't jump -// in after the last destructor invocation, therefore the destructor remains -// unsynchronized with the following users of the same TSD slot. This results -// in race reports between the destructor and functions in other tests. -// -// It is disabled on Win x64 with incremental linking (i.e. "Debug") pending -// resolution of http://crbug.com/251251. -#define MAYBE_TLSDestructors DISABLED_TLSDestructors -#else -#define MAYBE_TLSDestructors TLSDestructors -#endif -TEST(ThreadLocalStorageTest, MAYBE_TLSDestructors) { - // Create a TLS index with a destructor. Create a set of - // threads that set the TLS, while the destructor cleans it up. - // After the threads finish, verify that the value is cleaned up. - const int kNumThreads = 5; - int values[kNumThreads]; - ThreadLocalStorageRunner* thread_delegates[kNumThreads]; - DelegateSimpleThread* threads[kNumThreads]; - - // Spawn the threads. - for (int index = 0; index < kNumThreads; index++) { - values[index] = kInitialTlsValue; - thread_delegates[index] = new ThreadLocalStorageRunner(&values[index]); - threads[index] = new DelegateSimpleThread(thread_delegates[index], - "tls thread"); - threads[index]->Start(); - } - - // Wait for the threads to finish. - for (int index = 0; index < kNumThreads; index++) { - threads[index]->Join(); - delete threads[index]; - delete thread_delegates[index]; - - // Verify that the destructor was called and that we reset. - EXPECT_EQ(values[index], kFinalTlsValue); - } -} - -TEST(ThreadLocalStorageTest, TLSReclaim) { - // Creates and destroys many TLS slots and ensures they all zero-inited. - for (int i = 0; i < 1000; ++i) { - ThreadLocalStorage::Slot slot(nullptr); - EXPECT_EQ(nullptr, slot.Get()); - slot.Set(reinterpret_cast<void*>(0xBAADF00D)); - EXPECT_EQ(reinterpret_cast<void*>(0xBAADF00D), slot.Get()); - } -} - -#if defined(OS_POSIX) -// Unlike POSIX, Windows does not iterate through the OS TLS to cleanup any -// values there. Instead a per-module thread destruction function is called. -// However, it is not possible to perform a check after this point (as the code -// is detached from the thread), so this check remains POSIX only. -TEST(ThreadLocalStorageTest, UseTLSDuringDestruction) { - UseTLSDuringDestructionRunner runner; - pthread_t thread; - int result = pthread_create(&thread, nullptr, UseTLSTestThreadRun, &runner); - ASSERT_EQ(result, 0); - - result = pthread_join(thread, nullptr); - ASSERT_EQ(result, 0); - - EXPECT_TRUE(runner.teardown_works_correctly()); -} -#endif // defined(OS_POSIX) - -} // namespace base
diff --git a/base/threading/thread_local_unittest.cc b/base/threading/thread_local_unittest.cc deleted file mode 100644 index 54f2ad2..0000000 --- a/base/threading/thread_local_unittest.cc +++ /dev/null
@@ -1,164 +0,0 @@ -// 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/logging.h" -#include "base/threading/simple_thread.h" -#include "base/threading/thread_local.h" -#include "base/synchronization/waitable_event.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -class ThreadLocalTesterBase : public base::DelegateSimpleThreadPool::Delegate { - public: - typedef base::ThreadLocalPointer<char> TLPType; - - ThreadLocalTesterBase(TLPType* tlp, base::WaitableEvent* done) - : tlp_(tlp), - done_(done) { - } - ~ThreadLocalTesterBase() override = default; - - protected: - TLPType* tlp_; - base::WaitableEvent* done_; -}; - -class SetThreadLocal : public ThreadLocalTesterBase { - public: - SetThreadLocal(TLPType* tlp, base::WaitableEvent* done) - : ThreadLocalTesterBase(tlp, done), val_(nullptr) {} - ~SetThreadLocal() override = default; - - void set_value(char* val) { val_ = val; } - - void Run() override { - DCHECK(!done_->IsSignaled()); - tlp_->Set(val_); - done_->Signal(); - } - - private: - char* val_; -}; - -class GetThreadLocal : public ThreadLocalTesterBase { - public: - GetThreadLocal(TLPType* tlp, base::WaitableEvent* done) - : ThreadLocalTesterBase(tlp, done), ptr_(nullptr) {} - ~GetThreadLocal() override = default; - - void set_ptr(char** ptr) { ptr_ = ptr; } - - void Run() override { - DCHECK(!done_->IsSignaled()); - *ptr_ = tlp_->Get(); - done_->Signal(); - } - - private: - char** ptr_; -}; - -} // namespace - -// In this test, we start 2 threads which will access a ThreadLocalPointer. We -// make sure the default is NULL, and the pointers are unique to the threads. -TEST(ThreadLocalTest, Pointer) { - base::DelegateSimpleThreadPool tp1("ThreadLocalTest tp1", 1); - base::DelegateSimpleThreadPool tp2("ThreadLocalTest tp1", 1); - tp1.Start(); - tp2.Start(); - - base::ThreadLocalPointer<char> tlp; - - static char* const kBogusPointer = reinterpret_cast<char*>(0x1234); - - char* tls_val; - base::WaitableEvent done(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - - GetThreadLocal getter(&tlp, &done); - getter.set_ptr(&tls_val); - - // Check that both threads defaulted to NULL. - tls_val = kBogusPointer; - done.Reset(); - tp1.AddWork(&getter); - done.Wait(); - EXPECT_EQ(static_cast<char*>(nullptr), tls_val); - - tls_val = kBogusPointer; - done.Reset(); - tp2.AddWork(&getter); - done.Wait(); - EXPECT_EQ(static_cast<char*>(nullptr), tls_val); - - SetThreadLocal setter(&tlp, &done); - setter.set_value(kBogusPointer); - - // Have thread 1 set their pointer value to kBogusPointer. - done.Reset(); - tp1.AddWork(&setter); - done.Wait(); - - tls_val = nullptr; - done.Reset(); - tp1.AddWork(&getter); - done.Wait(); - EXPECT_EQ(kBogusPointer, tls_val); - - // Make sure thread 2 is still NULL - tls_val = kBogusPointer; - done.Reset(); - tp2.AddWork(&getter); - done.Wait(); - EXPECT_EQ(static_cast<char*>(nullptr), tls_val); - - // Set thread 2 to kBogusPointer + 1. - setter.set_value(kBogusPointer + 1); - - done.Reset(); - tp2.AddWork(&setter); - done.Wait(); - - tls_val = nullptr; - done.Reset(); - tp2.AddWork(&getter); - done.Wait(); - EXPECT_EQ(kBogusPointer + 1, tls_val); - - // Make sure thread 1 is still kBogusPointer. - tls_val = nullptr; - done.Reset(); - tp1.AddWork(&getter); - done.Wait(); - EXPECT_EQ(kBogusPointer, tls_val); - - tp1.JoinAll(); - tp2.JoinAll(); -} - -TEST(ThreadLocalTest, Boolean) { - { - base::ThreadLocalBoolean tlb; - EXPECT_FALSE(tlb.Get()); - - tlb.Set(false); - EXPECT_FALSE(tlb.Get()); - - tlb.Set(true); - EXPECT_TRUE(tlb.Get()); - } - - // Our slot should have been freed, we're all reset. - { - base::ThreadLocalBoolean tlb; - EXPECT_FALSE(tlb.Get()); - } -} - -} // namespace base
diff --git a/base/threading/thread_restrictions_unittest.cc b/base/threading/thread_restrictions_unittest.cc deleted file mode 100644 index a957a9a..0000000 --- a/base/threading/thread_restrictions_unittest.cc +++ /dev/null
@@ -1,137 +0,0 @@ -// 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/threading/thread_restrictions.h" - -#include <utility> - -#include "base/bind.h" -#include "base/callback.h" -#include "base/macros.h" -#include "base/test/gtest_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -class ThreadRestrictionsTest : public testing::Test { - public: - ThreadRestrictionsTest() = default; - ~ThreadRestrictionsTest() override { - internal::ResetThreadRestrictionsForTesting(); - } - - private: - DISALLOW_COPY_AND_ASSIGN(ThreadRestrictionsTest); -}; - -} // namespace - -TEST_F(ThreadRestrictionsTest, BlockingAllowedByDefault) { - AssertBlockingAllowed(); -} - -TEST_F(ThreadRestrictionsTest, ScopedDisallowBlocking) { - { - ScopedDisallowBlocking scoped_disallow_blocking; - EXPECT_DCHECK_DEATH({ AssertBlockingAllowed(); }); - } - AssertBlockingAllowed(); -} - -TEST_F(ThreadRestrictionsTest, ScopedAllowBlocking) { - ScopedDisallowBlocking scoped_disallow_blocking; - { - ScopedAllowBlocking scoped_allow_blocking; - AssertBlockingAllowed(); - } - EXPECT_DCHECK_DEATH({ AssertBlockingAllowed(); }); -} - -TEST_F(ThreadRestrictionsTest, ScopedAllowBlockingForTesting) { - ScopedDisallowBlocking scoped_disallow_blocking; - { - ScopedAllowBlockingForTesting scoped_allow_blocking_for_testing; - AssertBlockingAllowed(); - } - EXPECT_DCHECK_DEATH({ AssertBlockingAllowed(); }); -} - -TEST_F(ThreadRestrictionsTest, BaseSyncPrimitivesAllowedByDefault) {} - -TEST_F(ThreadRestrictionsTest, DisallowBaseSyncPrimitives) { - DisallowBaseSyncPrimitives(); - EXPECT_DCHECK_DEATH({ internal::AssertBaseSyncPrimitivesAllowed(); }); -} - -TEST_F(ThreadRestrictionsTest, ScopedAllowBaseSyncPrimitives) { - DisallowBaseSyncPrimitives(); - ScopedAllowBaseSyncPrimitives scoped_allow_base_sync_primitives; - internal::AssertBaseSyncPrimitivesAllowed(); -} - -TEST_F(ThreadRestrictionsTest, ScopedAllowBaseSyncPrimitivesResetsState) { - DisallowBaseSyncPrimitives(); - { ScopedAllowBaseSyncPrimitives scoped_allow_base_sync_primitives; } - EXPECT_DCHECK_DEATH({ internal::AssertBaseSyncPrimitivesAllowed(); }); -} - -TEST_F(ThreadRestrictionsTest, - ScopedAllowBaseSyncPrimitivesWithBlockingDisallowed) { - ScopedDisallowBlocking scoped_disallow_blocking; - DisallowBaseSyncPrimitives(); - - // This should DCHECK because blocking is not allowed in this scope - // and OutsideBlockingScope is not passed to the constructor. - EXPECT_DCHECK_DEATH( - { ScopedAllowBaseSyncPrimitives scoped_allow_base_sync_primitives; }); -} - -TEST_F(ThreadRestrictionsTest, - ScopedAllowBaseSyncPrimitivesOutsideBlockingScope) { - ScopedDisallowBlocking scoped_disallow_blocking; - DisallowBaseSyncPrimitives(); - ScopedAllowBaseSyncPrimitivesOutsideBlockingScope - scoped_allow_base_sync_primitives; - internal::AssertBaseSyncPrimitivesAllowed(); -} - -TEST_F(ThreadRestrictionsTest, - ScopedAllowBaseSyncPrimitivesOutsideBlockingScopeResetsState) { - DisallowBaseSyncPrimitives(); - { - ScopedAllowBaseSyncPrimitivesOutsideBlockingScope - scoped_allow_base_sync_primitives; - } - EXPECT_DCHECK_DEATH({ internal::AssertBaseSyncPrimitivesAllowed(); }); -} - -TEST_F(ThreadRestrictionsTest, ScopedAllowBaseSyncPrimitivesForTesting) { - DisallowBaseSyncPrimitives(); - ScopedAllowBaseSyncPrimitivesForTesting - scoped_allow_base_sync_primitives_for_testing; - internal::AssertBaseSyncPrimitivesAllowed(); -} - -TEST_F(ThreadRestrictionsTest, - ScopedAllowBaseSyncPrimitivesForTestingResetsState) { - DisallowBaseSyncPrimitives(); - { - ScopedAllowBaseSyncPrimitivesForTesting - scoped_allow_base_sync_primitives_for_testing; - } - EXPECT_DCHECK_DEATH({ internal::AssertBaseSyncPrimitivesAllowed(); }); -} - -TEST_F(ThreadRestrictionsTest, - ScopedAllowBaseSyncPrimitivesForTestingWithBlockingDisallowed) { - ScopedDisallowBlocking scoped_disallow_blocking; - DisallowBaseSyncPrimitives(); - // This should not DCHECK. - ScopedAllowBaseSyncPrimitivesForTesting - scoped_allow_base_sync_primitives_for_testing; -} - -} // namespace base
diff --git a/base/threading/thread_task_runner_handle_unittest.cc b/base/threading/thread_task_runner_handle_unittest.cc deleted file mode 100644 index 1aa02d1..0000000 --- a/base/threading/thread_task_runner_handle_unittest.cc +++ /dev/null
@@ -1,122 +0,0 @@ -// 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/threading/thread_task_runner_handle.h" - -#include "base/memory/ref_counted.h" -#include "base/test/gtest_util.h" -#include "base/test/test_simple_task_runner.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(ThreadTaskRunnerHandleTest, Basic) { - scoped_refptr<SingleThreadTaskRunner> task_runner(new TestSimpleTaskRunner); - - EXPECT_FALSE(ThreadTaskRunnerHandle::IsSet()); - { - ThreadTaskRunnerHandle ttrh1(task_runner); - EXPECT_TRUE(ThreadTaskRunnerHandle::IsSet()); - EXPECT_EQ(task_runner, ThreadTaskRunnerHandle::Get()); - } - EXPECT_FALSE(ThreadTaskRunnerHandle::IsSet()); -} - -TEST(ThreadTaskRunnerHandleTest, DeathOnImplicitOverride) { - scoped_refptr<SingleThreadTaskRunner> task_runner(new TestSimpleTaskRunner); - scoped_refptr<SingleThreadTaskRunner> overidding_task_runner( - new TestSimpleTaskRunner); - - ThreadTaskRunnerHandle ttrh(task_runner); - EXPECT_DCHECK_DEATH( - { ThreadTaskRunnerHandle overriding_ttrh(overidding_task_runner); }); -} - -TEST(ThreadTaskRunnerHandleTest, OverrideForTestingExistingTTRH) { - scoped_refptr<SingleThreadTaskRunner> task_runner_1(new TestSimpleTaskRunner); - scoped_refptr<SingleThreadTaskRunner> task_runner_2(new TestSimpleTaskRunner); - scoped_refptr<SingleThreadTaskRunner> task_runner_3(new TestSimpleTaskRunner); - scoped_refptr<SingleThreadTaskRunner> task_runner_4(new TestSimpleTaskRunner); - - EXPECT_FALSE(ThreadTaskRunnerHandle::IsSet()); - { - // TTRH in place prior to override. - ThreadTaskRunnerHandle ttrh1(task_runner_1); - EXPECT_TRUE(ThreadTaskRunnerHandle::IsSet()); - EXPECT_EQ(task_runner_1, ThreadTaskRunnerHandle::Get()); - - { - // Override. - ScopedClosureRunner undo_override_2 = - ThreadTaskRunnerHandle::OverrideForTesting(task_runner_2); - EXPECT_TRUE(ThreadTaskRunnerHandle::IsSet()); - EXPECT_EQ(task_runner_2, ThreadTaskRunnerHandle::Get()); - - { - // Nested override. - ScopedClosureRunner undo_override_3 = - ThreadTaskRunnerHandle::OverrideForTesting(task_runner_3); - EXPECT_TRUE(ThreadTaskRunnerHandle::IsSet()); - EXPECT_EQ(task_runner_3, ThreadTaskRunnerHandle::Get()); - } - - // Back to single override. - EXPECT_TRUE(ThreadTaskRunnerHandle::IsSet()); - EXPECT_EQ(task_runner_2, ThreadTaskRunnerHandle::Get()); - - { - // Backup to double override with another TTRH. - ScopedClosureRunner undo_override_4 = - ThreadTaskRunnerHandle::OverrideForTesting(task_runner_4); - EXPECT_TRUE(ThreadTaskRunnerHandle::IsSet()); - EXPECT_EQ(task_runner_4, ThreadTaskRunnerHandle::Get()); - } - } - - // Back to simple TTRH. - EXPECT_TRUE(ThreadTaskRunnerHandle::IsSet()); - EXPECT_EQ(task_runner_1, ThreadTaskRunnerHandle::Get()); - } - EXPECT_FALSE(ThreadTaskRunnerHandle::IsSet()); -} - -TEST(ThreadTaskRunnerHandleTest, OverrideForTestingNoExistingTTRH) { - scoped_refptr<SingleThreadTaskRunner> task_runner_1(new TestSimpleTaskRunner); - scoped_refptr<SingleThreadTaskRunner> task_runner_2(new TestSimpleTaskRunner); - - EXPECT_FALSE(ThreadTaskRunnerHandle::IsSet()); - { - // Override with no TTRH in place. - ScopedClosureRunner undo_override_1 = - ThreadTaskRunnerHandle::OverrideForTesting(task_runner_1); - EXPECT_TRUE(ThreadTaskRunnerHandle::IsSet()); - EXPECT_EQ(task_runner_1, ThreadTaskRunnerHandle::Get()); - - { - // Nested override works the same. - ScopedClosureRunner undo_override_2 = - ThreadTaskRunnerHandle::OverrideForTesting(task_runner_2); - EXPECT_TRUE(ThreadTaskRunnerHandle::IsSet()); - EXPECT_EQ(task_runner_2, ThreadTaskRunnerHandle::Get()); - } - - // Back to single override. - EXPECT_TRUE(ThreadTaskRunnerHandle::IsSet()); - EXPECT_EQ(task_runner_1, ThreadTaskRunnerHandle::Get()); - } - EXPECT_FALSE(ThreadTaskRunnerHandle::IsSet()); -} - -TEST(ThreadTaskRunnerHandleTest, DeathOnTTRHOverOverride) { - scoped_refptr<SingleThreadTaskRunner> task_runner(new TestSimpleTaskRunner); - scoped_refptr<SingleThreadTaskRunner> overidding_task_runner( - new TestSimpleTaskRunner); - - ScopedClosureRunner undo_override = - ThreadTaskRunnerHandle::OverrideForTesting(task_runner); - EXPECT_DCHECK_DEATH( - { ThreadTaskRunnerHandle overriding_ttrh(overidding_task_runner); }); -} - -} // namespace base
diff --git a/base/threading/thread_unittest.cc b/base/threading/thread_unittest.cc deleted file mode 100644 index a1a9ed3..0000000 --- a/base/threading/thread_unittest.cc +++ /dev/null
@@ -1,579 +0,0 @@ -// 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/threading/thread.h" - -#include <stddef.h> -#include <stdint.h> - -#include <utility> -#include <vector> - -#include "base/bind.h" -#include "base/debug/leak_annotations.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/message_loop/message_loop.h" -#include "base/message_loop/message_loop_current.h" -#include "base/run_loop.h" -#include "base/single_thread_task_runner.h" -#include "base/synchronization/waitable_event.h" -#include "base/test/gtest_util.h" -#include "base/third_party/dynamic_annotations/dynamic_annotations.h" -#include "base/threading/platform_thread.h" -#include "base/time/time.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/platform_test.h" - -using base::Thread; - -typedef PlatformTest ThreadTest; - -namespace { - -void ToggleValue(bool* value) { - ANNOTATE_BENIGN_RACE(value, "Test-only data race on boolean " - "in base/thread_unittest"); - *value = !*value; -} - -class SleepInsideInitThread : public Thread { - public: - SleepInsideInitThread() : Thread("none") { - init_called_ = false; - ANNOTATE_BENIGN_RACE( - this, "Benign test-only data race on vptr - http://crbug.com/98219"); - } - ~SleepInsideInitThread() override { Stop(); } - - void Init() override { - base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(500)); - init_called_ = true; - } - bool InitCalled() { return init_called_; } - - private: - bool init_called_; - - DISALLOW_COPY_AND_ASSIGN(SleepInsideInitThread); -}; - -enum ThreadEvent { - // Thread::Init() was called. - THREAD_EVENT_INIT = 0, - - // The MessageLoop for the thread was deleted. - THREAD_EVENT_MESSAGE_LOOP_DESTROYED, - - // Thread::CleanUp() was called. - THREAD_EVENT_CLEANUP, - - // Keep at end of list. - THREAD_NUM_EVENTS -}; - -typedef std::vector<ThreadEvent> EventList; - -class CaptureToEventList : public Thread { - public: - // This Thread pushes events into the vector |event_list| to show - // the order they occured in. |event_list| must remain valid for the - // lifetime of this thread. - explicit CaptureToEventList(EventList* event_list) - : Thread("none"), - event_list_(event_list) { - } - - ~CaptureToEventList() override { Stop(); } - - void Init() override { event_list_->push_back(THREAD_EVENT_INIT); } - - void CleanUp() override { event_list_->push_back(THREAD_EVENT_CLEANUP); } - - private: - EventList* event_list_; - - DISALLOW_COPY_AND_ASSIGN(CaptureToEventList); -}; - -// Observer that writes a value into |event_list| when a message loop has been -// destroyed. -class CapturingDestructionObserver - : public base::MessageLoopCurrent::DestructionObserver { - public: - // |event_list| must remain valid throughout the observer's lifetime. - explicit CapturingDestructionObserver(EventList* event_list) - : event_list_(event_list) { - } - - // DestructionObserver implementation: - void WillDestroyCurrentMessageLoop() override { - event_list_->push_back(THREAD_EVENT_MESSAGE_LOOP_DESTROYED); - event_list_ = nullptr; - } - - private: - EventList* event_list_; - - DISALLOW_COPY_AND_ASSIGN(CapturingDestructionObserver); -}; - -// Task that adds a destruction observer to the current message loop. -void RegisterDestructionObserver( - base::MessageLoopCurrent::DestructionObserver* observer) { - base::MessageLoopCurrent::Get()->AddDestructionObserver(observer); -} - -// Task that calls GetThreadId() of |thread|, stores the result into |id|, then -// signal |event|. -void ReturnThreadId(base::Thread* thread, - base::PlatformThreadId* id, - base::WaitableEvent* event) { - *id = thread->GetThreadId(); - event->Signal(); -} - -} // namespace - -TEST_F(ThreadTest, StartWithOptions_StackSize) { - Thread a("StartWithStackSize"); - // Ensure that the thread can work with only 12 kb and still process a - // message. At the same time, we should scale with the bitness of the system - // where 12 kb is definitely not enough. - // 12 kb = 3072 Slots on a 32-bit system, so we'll scale based off of that. - Thread::Options options; -#if defined(ADDRESS_SANITIZER) || !defined(NDEBUG) - // ASan bloats the stack variables and overflows the 3072 slot stack. Some - // debug builds also grow the stack too much. - options.stack_size = 2 * 3072 * sizeof(uintptr_t); -#else - options.stack_size = 3072 * sizeof(uintptr_t); -#endif - EXPECT_TRUE(a.StartWithOptions(options)); - EXPECT_TRUE(a.message_loop()); - EXPECT_TRUE(a.IsRunning()); - - base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC, - base::WaitableEvent::InitialState::NOT_SIGNALED); - a.task_runner()->PostTask( - FROM_HERE, - base::BindOnce(&base::WaitableEvent::Signal, base::Unretained(&event))); - event.Wait(); -} - -// Intentional test-only race for otherwise untestable code, won't fix. -// https://crbug.com/634383 -#if !defined(THREAD_SANITIZER) -TEST_F(ThreadTest, StartWithOptions_NonJoinable) { - Thread* a = new Thread("StartNonJoinable"); - // Non-joinable threads have to be leaked for now (see - // Thread::Options::joinable for details). - ANNOTATE_LEAKING_OBJECT_PTR(a); - - Thread::Options options; - options.joinable = false; - EXPECT_TRUE(a->StartWithOptions(options)); - EXPECT_TRUE(a->message_loop()); - EXPECT_TRUE(a->IsRunning()); - - // Without this call this test is racy. The above IsRunning() succeeds because - // of an early-return condition while between Start() and StopSoon(), after - // invoking StopSoon() below this early-return condition is no longer - // satisfied and the real |is_running_| bit has to be checked. It could still - // be false if the message loop hasn't started for real in practice. This is - // only a requirement for this test because the non-joinable property forces - // it to use StopSoon() and not wait for a complete Stop(). - EXPECT_TRUE(a->WaitUntilThreadStarted()); - - // Make the thread block until |block_event| is signaled. - base::WaitableEvent block_event( - base::WaitableEvent::ResetPolicy::AUTOMATIC, - base::WaitableEvent::InitialState::NOT_SIGNALED); - a->task_runner()->PostTask(FROM_HERE, - base::BindOnce(&base::WaitableEvent::Wait, - base::Unretained(&block_event))); - - a->StopSoon(); - EXPECT_TRUE(a->IsRunning()); - - // Unblock the task and give a bit of extra time to unwind QuitWhenIdle(). - block_event.Signal(); - base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20)); - - // The thread should now have stopped on its own. - EXPECT_FALSE(a->IsRunning()); -} -#endif - -TEST_F(ThreadTest, TwoTasksOnJoinableThread) { - bool was_invoked = false; - { - Thread a("TwoTasksOnJoinableThread"); - EXPECT_TRUE(a.Start()); - EXPECT_TRUE(a.message_loop()); - - // Test that all events are dispatched before the Thread object is - // destroyed. We do this by dispatching a sleep event before the - // event that will toggle our sentinel value. - a.task_runner()->PostTask( - FROM_HERE, base::BindOnce(static_cast<void (*)(base::TimeDelta)>( - &base::PlatformThread::Sleep), - base::TimeDelta::FromMilliseconds(20))); - a.task_runner()->PostTask(FROM_HERE, - base::BindOnce(&ToggleValue, &was_invoked)); - } - EXPECT_TRUE(was_invoked); -} - -TEST_F(ThreadTest, DestroyWhileRunningIsSafe) { - Thread a("DestroyWhileRunningIsSafe"); - EXPECT_TRUE(a.Start()); - EXPECT_TRUE(a.WaitUntilThreadStarted()); -} - -// TODO(gab): Enable this test when destroying a non-joinable Thread instance -// is supported (proposal @ https://crbug.com/629139#c14). -TEST_F(ThreadTest, DISABLED_DestroyWhileRunningNonJoinableIsSafe) { - { - Thread a("DestroyWhileRunningNonJoinableIsSafe"); - Thread::Options options; - options.joinable = false; - EXPECT_TRUE(a.StartWithOptions(options)); - EXPECT_TRUE(a.WaitUntilThreadStarted()); - } - - // Attempt to catch use-after-frees from the non-joinable thread in the - // scope of this test if any. - base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20)); -} - -TEST_F(ThreadTest, StopSoon) { - Thread a("StopSoon"); - EXPECT_TRUE(a.Start()); - EXPECT_TRUE(a.message_loop()); - EXPECT_TRUE(a.IsRunning()); - a.StopSoon(); - a.Stop(); - EXPECT_FALSE(a.message_loop()); - EXPECT_FALSE(a.IsRunning()); -} - -TEST_F(ThreadTest, StopTwiceNop) { - Thread a("StopTwiceNop"); - EXPECT_TRUE(a.Start()); - EXPECT_TRUE(a.message_loop()); - EXPECT_TRUE(a.IsRunning()); - a.StopSoon(); - // Calling StopSoon() a second time should be a nop. - a.StopSoon(); - a.Stop(); - // Same with Stop(). - a.Stop(); - EXPECT_FALSE(a.message_loop()); - EXPECT_FALSE(a.IsRunning()); - // Calling them when not running should also nop. - a.StopSoon(); - a.Stop(); -} - -// TODO(gab): Enable this test in conjunction with re-enabling the sequence -// check in Thread::Stop() as part of http://crbug.com/629139. -TEST_F(ThreadTest, DISABLED_StopOnNonOwningThreadIsDeath) { - Thread a("StopOnNonOwningThreadDeath"); - EXPECT_TRUE(a.StartAndWaitForTesting()); - - Thread b("NonOwningThread"); - b.Start(); - EXPECT_DCHECK_DEATH({ - // Stopping |a| on |b| isn't allowed. - b.task_runner()->PostTask( - FROM_HERE, base::BindOnce(&Thread::Stop, base::Unretained(&a))); - // Block here so the DCHECK on |b| always happens in this scope. - base::PlatformThread::Sleep(base::TimeDelta::Max()); - }); -} - -TEST_F(ThreadTest, TransferOwnershipAndStop) { - std::unique_ptr<Thread> a = - std::make_unique<Thread>("TransferOwnershipAndStop"); - EXPECT_TRUE(a->StartAndWaitForTesting()); - EXPECT_TRUE(a->IsRunning()); - - Thread b("TakingOwnershipThread"); - b.Start(); - - base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, - base::WaitableEvent::InitialState::NOT_SIGNALED); - - // a->DetachFromSequence() should allow |b| to use |a|'s Thread API. - a->DetachFromSequence(); - b.task_runner()->PostTask( - FROM_HERE, base::BindOnce( - [](std::unique_ptr<Thread> thread_to_stop, - base::WaitableEvent* event_to_signal) -> void { - thread_to_stop->Stop(); - event_to_signal->Signal(); - }, - std::move(a), base::Unretained(&event))); - - event.Wait(); -} - -TEST_F(ThreadTest, StartTwice) { - Thread a("StartTwice"); - - EXPECT_FALSE(a.message_loop()); - EXPECT_FALSE(a.IsRunning()); - - EXPECT_TRUE(a.Start()); - EXPECT_TRUE(a.message_loop()); - EXPECT_TRUE(a.IsRunning()); - - a.Stop(); - EXPECT_FALSE(a.message_loop()); - EXPECT_FALSE(a.IsRunning()); - - EXPECT_TRUE(a.Start()); - EXPECT_TRUE(a.message_loop()); - EXPECT_TRUE(a.IsRunning()); - - a.Stop(); - EXPECT_FALSE(a.message_loop()); - EXPECT_FALSE(a.IsRunning()); -} - -// Intentional test-only race for otherwise untestable code, won't fix. -// https://crbug.com/634383 -#if !defined(THREAD_SANITIZER) -TEST_F(ThreadTest, StartTwiceNonJoinableNotAllowed) { - LOG(ERROR) << __FUNCTION__; - Thread* a = new Thread("StartTwiceNonJoinable"); - // Non-joinable threads have to be leaked for now (see - // Thread::Options::joinable for details). - ANNOTATE_LEAKING_OBJECT_PTR(a); - - Thread::Options options; - options.joinable = false; - EXPECT_TRUE(a->StartWithOptions(options)); - EXPECT_TRUE(a->message_loop()); - EXPECT_TRUE(a->IsRunning()); - - // Signaled when last task on |a| is processed. - base::WaitableEvent last_task_event( - base::WaitableEvent::ResetPolicy::AUTOMATIC, - base::WaitableEvent::InitialState::NOT_SIGNALED); - a->task_runner()->PostTask( - FROM_HERE, base::BindOnce(&base::WaitableEvent::Signal, - base::Unretained(&last_task_event))); - - // StopSoon() is non-blocking, Yield() to |a|, wait for last task to be - // processed and a little more for QuitWhenIdle() to unwind before considering - // the thread "stopped". - a->StopSoon(); - base::PlatformThread::YieldCurrentThread(); - last_task_event.Wait(); - base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20)); - - // This test assumes that the above was sufficient to let the thread fully - // stop. - ASSERT_FALSE(a->IsRunning()); - - // Restarting it should not be allowed. - EXPECT_DCHECK_DEATH(a->Start()); -} -#endif - -TEST_F(ThreadTest, ThreadName) { - Thread a("ThreadName"); - EXPECT_TRUE(a.Start()); - EXPECT_EQ("ThreadName", a.thread_name()); -} - -TEST_F(ThreadTest, ThreadId) { - Thread a("ThreadId0"); - Thread b("ThreadId1"); - a.Start(); - b.Start(); - - // Post a task that calls GetThreadId() on the created thread. - base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC, - base::WaitableEvent::InitialState::NOT_SIGNALED); - base::PlatformThreadId id_from_new_thread; - a.task_runner()->PostTask( - FROM_HERE, - base::BindOnce(ReturnThreadId, &a, &id_from_new_thread, &event)); - - // Call GetThreadId() on the current thread before calling event.Wait() so - // that this test can find a race issue with TSAN. - base::PlatformThreadId id_from_current_thread = a.GetThreadId(); - - // Check if GetThreadId() returns consistent value in both threads. - event.Wait(); - EXPECT_EQ(id_from_current_thread, id_from_new_thread); - - // A started thread should have a valid ID. - EXPECT_NE(base::kInvalidThreadId, a.GetThreadId()); - EXPECT_NE(base::kInvalidThreadId, b.GetThreadId()); - - // Each thread should have a different thread ID. - EXPECT_NE(a.GetThreadId(), b.GetThreadId()); -} - -TEST_F(ThreadTest, ThreadIdWithRestart) { - Thread a("ThreadIdWithRestart"); - base::PlatformThreadId previous_id = base::kInvalidThreadId; - - for (size_t i = 0; i < 16; ++i) { - EXPECT_TRUE(a.Start()); - base::PlatformThreadId current_id = a.GetThreadId(); - EXPECT_NE(previous_id, current_id); - previous_id = current_id; - a.Stop(); - } -} - -// Make sure Init() is called after Start() and before -// WaitUntilThreadInitialized() returns. -TEST_F(ThreadTest, SleepInsideInit) { - SleepInsideInitThread t; - EXPECT_FALSE(t.InitCalled()); - t.StartAndWaitForTesting(); - EXPECT_TRUE(t.InitCalled()); -} - -// Make sure that the destruction sequence is: -// -// (1) Thread::CleanUp() -// (2) MessageLoop::~MessageLoop() -// MessageLoopCurrent::DestructionObservers called. -TEST_F(ThreadTest, CleanUp) { - EventList captured_events; - CapturingDestructionObserver loop_destruction_observer(&captured_events); - - { - // Start a thread which writes its event into |captured_events|. - CaptureToEventList t(&captured_events); - EXPECT_TRUE(t.Start()); - EXPECT_TRUE(t.message_loop()); - EXPECT_TRUE(t.IsRunning()); - - // Register an observer that writes into |captured_events| once the - // thread's message loop is destroyed. - t.task_runner()->PostTask( - FROM_HERE, - base::BindOnce(&RegisterDestructionObserver, - base::Unretained(&loop_destruction_observer))); - - // Upon leaving this scope, the thread is deleted. - } - - // Check the order of events during shutdown. - ASSERT_EQ(static_cast<size_t>(THREAD_NUM_EVENTS), captured_events.size()); - EXPECT_EQ(THREAD_EVENT_INIT, captured_events[0]); - EXPECT_EQ(THREAD_EVENT_CLEANUP, captured_events[1]); - EXPECT_EQ(THREAD_EVENT_MESSAGE_LOOP_DESTROYED, captured_events[2]); -} - -TEST_F(ThreadTest, ThreadNotStarted) { - Thread a("Inert"); - EXPECT_FALSE(a.task_runner()); -} - -TEST_F(ThreadTest, MultipleWaitUntilThreadStarted) { - Thread a("MultipleWaitUntilThreadStarted"); - EXPECT_TRUE(a.Start()); - // It's OK to call WaitUntilThreadStarted() multiple times. - EXPECT_TRUE(a.WaitUntilThreadStarted()); - EXPECT_TRUE(a.WaitUntilThreadStarted()); -} - -TEST_F(ThreadTest, FlushForTesting) { - Thread a("FlushForTesting"); - - // Flushing a non-running thread should be a no-op. - a.FlushForTesting(); - - ASSERT_TRUE(a.Start()); - - // Flushing a thread with no tasks shouldn't block. - a.FlushForTesting(); - - constexpr base::TimeDelta kSleepPerTestTask = - base::TimeDelta::FromMilliseconds(50); - constexpr size_t kNumSleepTasks = 5; - - const base::TimeTicks ticks_before_post = base::TimeTicks::Now(); - - for (size_t i = 0; i < kNumSleepTasks; ++i) { - a.task_runner()->PostTask( - FROM_HERE, - base::BindOnce(&base::PlatformThread::Sleep, kSleepPerTestTask)); - } - - // All tasks should have executed, as reflected by the elapsed time. - a.FlushForTesting(); - EXPECT_GE(base::TimeTicks::Now() - ticks_before_post, - kNumSleepTasks * kSleepPerTestTask); - - a.Stop(); - - // Flushing a stopped thread should be a no-op. - a.FlushForTesting(); -} - -namespace { - -// A Thread which uses a MessageLoop on the stack. It won't start a real -// underlying thread (instead its messages can be processed by a RunLoop on the -// stack). -class ExternalMessageLoopThread : public Thread { - public: - ExternalMessageLoopThread() : Thread("ExternalMessageLoopThread") {} - - ~ExternalMessageLoopThread() override { Stop(); } - - void InstallMessageLoop() { SetMessageLoop(&external_message_loop_); } - - void VerifyUsingExternalMessageLoop( - bool expected_using_external_message_loop) { - EXPECT_EQ(expected_using_external_message_loop, - using_external_message_loop()); - } - - private: - base::MessageLoop external_message_loop_; - - DISALLOW_COPY_AND_ASSIGN(ExternalMessageLoopThread); -}; - -} // namespace - -TEST_F(ThreadTest, ExternalMessageLoop) { - ExternalMessageLoopThread a; - EXPECT_FALSE(a.message_loop()); - EXPECT_FALSE(a.IsRunning()); - a.VerifyUsingExternalMessageLoop(false); - - a.InstallMessageLoop(); - EXPECT_TRUE(a.message_loop()); - EXPECT_TRUE(a.IsRunning()); - a.VerifyUsingExternalMessageLoop(true); - - bool ran = false; - a.task_runner()->PostTask( - FROM_HERE, base::BindOnce([](bool* toggled) { *toggled = true; }, &ran)); - base::RunLoop().RunUntilIdle(); - EXPECT_TRUE(ran); - - a.Stop(); - EXPECT_FALSE(a.message_loop()); - EXPECT_FALSE(a.IsRunning()); - a.VerifyUsingExternalMessageLoop(true); - - // Confirm that running any remaining tasks posted from Stop() goes smoothly - // (e.g. https://codereview.chromium.org/2135413003/#ps300001 crashed if - // StopSoon() posted Thread::ThreadQuitHelper() while |run_loop_| was null). - base::RunLoop().RunUntilIdle(); -}
diff --git a/base/threading/watchdog_unittest.cc b/base/threading/watchdog_unittest.cc deleted file mode 100644 index f534a86..0000000 --- a/base/threading/watchdog_unittest.cc +++ /dev/null
@@ -1,141 +0,0 @@ -// 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/threading/watchdog.h" - -#include "base/logging.h" -#include "base/macros.h" -#include "base/synchronization/spin_wait.h" -#include "base/threading/platform_thread.h" -#include "base/time/time.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -//------------------------------------------------------------------------------ -// Provide a derived class to facilitate testing. - -class WatchdogCounter : public Watchdog { - public: - WatchdogCounter(const TimeDelta& duration, - const std::string& thread_watched_name, - bool enabled) - : Watchdog(duration, thread_watched_name, enabled), - alarm_counter_(0) { - } - - ~WatchdogCounter() override = default; - - void Alarm() override { - alarm_counter_++; - Watchdog::Alarm(); - } - - int alarm_counter() { return alarm_counter_; } - - private: - int alarm_counter_; - - DISALLOW_COPY_AND_ASSIGN(WatchdogCounter); -}; - -class WatchdogTest : public testing::Test { - public: - void SetUp() override { Watchdog::ResetStaticData(); } -}; - -} // namespace - -//------------------------------------------------------------------------------ -// Actual tests - -// Minimal constructor/destructor test. -TEST_F(WatchdogTest, StartupShutdownTest) { - Watchdog watchdog1(TimeDelta::FromMilliseconds(300), "Disabled", false); - Watchdog watchdog2(TimeDelta::FromMilliseconds(300), "Enabled", true); -} - -// Test ability to call Arm and Disarm repeatedly. -TEST_F(WatchdogTest, ArmDisarmTest) { - Watchdog watchdog1(TimeDelta::FromMilliseconds(300), "Disabled", false); - watchdog1.Arm(); - watchdog1.Disarm(); - watchdog1.Arm(); - watchdog1.Disarm(); - - Watchdog watchdog2(TimeDelta::FromMilliseconds(300), "Enabled", true); - watchdog2.Arm(); - watchdog2.Disarm(); - watchdog2.Arm(); - watchdog2.Disarm(); -} - -// Make sure a basic alarm fires when the time has expired. -TEST_F(WatchdogTest, AlarmTest) { - WatchdogCounter watchdog(TimeDelta::FromMilliseconds(10), "Enabled", true); - watchdog.Arm(); - SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(5), - watchdog.alarm_counter() > 0); - EXPECT_EQ(1, watchdog.alarm_counter()); -} - -// Make sure a basic alarm fires when the time has expired. -TEST_F(WatchdogTest, AlarmPriorTimeTest) { - WatchdogCounter watchdog(TimeDelta(), "Enabled2", true); - // Set a time in the past. - watchdog.ArmSomeTimeDeltaAgo(TimeDelta::FromSeconds(2)); - // It should instantly go off, but certainly in less than 5 minutes. - SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(5), - watchdog.alarm_counter() > 0); - - EXPECT_EQ(1, watchdog.alarm_counter()); -} - -// Make sure a disable alarm does nothing, even if we arm it. -TEST_F(WatchdogTest, ConstructorDisabledTest) { - WatchdogCounter watchdog(TimeDelta::FromMilliseconds(10), "Disabled", false); - watchdog.Arm(); - // Alarm should not fire, as it was disabled. - PlatformThread::Sleep(TimeDelta::FromMilliseconds(500)); - EXPECT_EQ(0, watchdog.alarm_counter()); -} - -// Make sure Disarming will prevent firing, even after Arming. -TEST_F(WatchdogTest, DisarmTest) { - WatchdogCounter watchdog(TimeDelta::FromSeconds(1), "Enabled3", true); - - TimeTicks start = TimeTicks::Now(); - watchdog.Arm(); - // Sleep a bit, but not past the alarm point. - PlatformThread::Sleep(TimeDelta::FromMilliseconds(100)); - watchdog.Disarm(); - TimeTicks end = TimeTicks::Now(); - - if (end - start > TimeDelta::FromMilliseconds(500)) { - LOG(WARNING) << "100ms sleep took over 500ms, making the results of this " - << "timing-sensitive test suspicious. Aborting now."; - return; - } - - // Alarm should not have fired before it was disarmed. - EXPECT_EQ(0, watchdog.alarm_counter()); - - // Sleep past the point where it would have fired if it wasn't disarmed, - // and verify that it didn't fire. - PlatformThread::Sleep(TimeDelta::FromSeconds(1)); - EXPECT_EQ(0, watchdog.alarm_counter()); - - // ...but even after disarming, we can still use the alarm... - // Set a time greater than the timeout into the past. - watchdog.ArmSomeTimeDeltaAgo(TimeDelta::FromSeconds(10)); - // It should almost instantly go off, but certainly in less than 5 minutes. - SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(5), - watchdog.alarm_counter() > 0); - - EXPECT_EQ(1, watchdog.alarm_counter()); -} - -} // namespace base
diff --git a/base/time/pr_time_unittest.cc b/base/time/pr_time_unittest.cc deleted file mode 100644 index 341d778..0000000 --- a/base/time/pr_time_unittest.cc +++ /dev/null
@@ -1,289 +0,0 @@ -// 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 <stdint.h> -#include <time.h> - -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "base/third_party/nspr/prtime.h" -#include "base/time/time.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -using base::Time; - -namespace { - -// time_t representation of 15th Oct 2007 12:45:00 PDT -PRTime comparison_time_pdt = 1192477500 * Time::kMicrosecondsPerSecond; - -// Time with positive tz offset and fractional seconds: -// 2013-07-08T11:28:12.441381+02:00 -PRTime comparison_time_2 = INT64_C(1373275692441381); // represented as GMT - -// Specialized test fixture allowing time strings without timezones to be -// tested by comparing them to a known time in the local zone. -class PRTimeTest : public testing::Test { - protected: - void SetUp() override { - // Use mktime to get a time_t, and turn it into a PRTime by converting - // seconds to microseconds. Use 15th Oct 2007 12:45:00 local. This - // must be a time guaranteed to be outside of a DST fallback hour in - // any timezone. - struct tm local_comparison_tm = { - 0, // second - 45, // minute - 12, // hour - 15, // day of month - 10 - 1, // month - 2007 - 1900, // year - 0, // day of week (ignored, output only) - 0, // day of year (ignored, output only) - -1 // DST in effect, -1 tells mktime to figure it out - }; - comparison_time_local_ = - mktime(&local_comparison_tm) * Time::kMicrosecondsPerSecond; - ASSERT_GT(comparison_time_local_, 0); - - const int microseconds = 441381; - struct tm local_comparison_tm_2 = { - 12, // second - 28, // minute - 11, // hour - 8, // day of month - 7 - 1, // month - 2013 - 1900, // year - 0, // day of week (ignored, output only) - 0, // day of year (ignored, output only) - -1 // DST in effect, -1 tells mktime to figure it out - }; - comparison_time_local_2_ = - mktime(&local_comparison_tm_2) * Time::kMicrosecondsPerSecond; - ASSERT_GT(comparison_time_local_2_, 0); - comparison_time_local_2_ += microseconds; - } - - PRTime comparison_time_local_; - PRTime comparison_time_local_2_; -}; - -// Tests the PR_ParseTimeString nspr helper function for -// a variety of time strings. -TEST_F(PRTimeTest, ParseTimeTest1) { - time_t current_time = 0; - time(¤t_time); - - struct tm local_time = {}; - char time_buf[64] = {}; -#if defined(OS_WIN) - localtime_s(&local_time, ¤t_time); - asctime_s(time_buf, arraysize(time_buf), &local_time); -#elif defined(OS_POSIX) || defined(OS_FUCHSIA) - localtime_r(¤t_time, &local_time); - asctime_r(&local_time, time_buf); -#endif - - PRTime current_time64 = static_cast<PRTime>(current_time) * PR_USEC_PER_SEC; - - PRTime parsed_time = 0; - PRStatus result = PR_ParseTimeString(time_buf, PR_FALSE, &parsed_time); - EXPECT_EQ(PR_SUCCESS, result); - EXPECT_EQ(current_time64, parsed_time); -} - -TEST_F(PRTimeTest, ParseTimeTest2) { - PRTime parsed_time = 0; - PRStatus result = PR_ParseTimeString("Mon, 15 Oct 2007 19:45:00 GMT", - PR_FALSE, &parsed_time); - EXPECT_EQ(PR_SUCCESS, result); - EXPECT_EQ(comparison_time_pdt, parsed_time); -} - -TEST_F(PRTimeTest, ParseTimeTest3) { - PRTime parsed_time = 0; - PRStatus result = PR_ParseTimeString("15 Oct 07 12:45:00", PR_FALSE, - &parsed_time); - EXPECT_EQ(PR_SUCCESS, result); - EXPECT_EQ(comparison_time_local_, parsed_time); -} - -TEST_F(PRTimeTest, ParseTimeTest4) { - PRTime parsed_time = 0; - PRStatus result = PR_ParseTimeString("15 Oct 07 19:45 GMT", PR_FALSE, - &parsed_time); - EXPECT_EQ(PR_SUCCESS, result); - EXPECT_EQ(comparison_time_pdt, parsed_time); -} - -TEST_F(PRTimeTest, ParseTimeTest5) { - PRTime parsed_time = 0; - PRStatus result = PR_ParseTimeString("Mon Oct 15 12:45 PDT 2007", - PR_FALSE, &parsed_time); - EXPECT_EQ(PR_SUCCESS, result); - EXPECT_EQ(comparison_time_pdt, parsed_time); -} - -TEST_F(PRTimeTest, ParseTimeTest6) { - PRTime parsed_time = 0; - PRStatus result = PR_ParseTimeString("Monday, Oct 15, 2007 12:45 PM", - PR_FALSE, &parsed_time); - EXPECT_EQ(PR_SUCCESS, result); - EXPECT_EQ(comparison_time_local_, parsed_time); -} - -TEST_F(PRTimeTest, ParseTimeTest7) { - PRTime parsed_time = 0; - PRStatus result = PR_ParseTimeString("10/15/07 12:45:00 PM", PR_FALSE, - &parsed_time); - EXPECT_EQ(PR_SUCCESS, result); - EXPECT_EQ(comparison_time_local_, parsed_time); -} - -TEST_F(PRTimeTest, ParseTimeTest8) { - PRTime parsed_time = 0; - PRStatus result = PR_ParseTimeString("10/15/07 12:45:00. PM", PR_FALSE, - &parsed_time); - EXPECT_EQ(PR_SUCCESS, result); - EXPECT_EQ(comparison_time_local_, parsed_time); -} - -TEST_F(PRTimeTest, ParseTimeTest9) { - PRTime parsed_time = 0; - PRStatus result = PR_ParseTimeString("10/15/07 12:45:00.0 PM", PR_FALSE, - &parsed_time); - EXPECT_EQ(PR_SUCCESS, result); - EXPECT_EQ(comparison_time_local_, parsed_time); -} - -TEST_F(PRTimeTest, ParseTimeTest10) { - PRTime parsed_time = 0; - PRStatus result = PR_ParseTimeString("15-OCT-2007 12:45pm", PR_FALSE, - &parsed_time); - EXPECT_EQ(PR_SUCCESS, result); - EXPECT_EQ(comparison_time_local_, parsed_time); -} - -TEST_F(PRTimeTest, ParseTimeTest11) { - PRTime parsed_time = 0; - PRStatus result = PR_ParseTimeString("16 Oct 2007 4:45-JST (Tuesday)", - PR_FALSE, &parsed_time); - EXPECT_EQ(PR_SUCCESS, result); - EXPECT_EQ(comparison_time_pdt, parsed_time); -} - -// hh:mm timezone offset. -TEST_F(PRTimeTest, ParseTimeTest12) { - PRTime parsed_time = 0; - PRStatus result = PR_ParseTimeString("2013-07-08T11:28:12.441381+02:00", - PR_FALSE, &parsed_time); - EXPECT_EQ(PR_SUCCESS, result); - EXPECT_EQ(comparison_time_2, parsed_time); -} - -// hhmm timezone offset. -TEST_F(PRTimeTest, ParseTimeTest13) { - PRTime parsed_time = 0; - PRStatus result = PR_ParseTimeString("2013-07-08T11:28:12.441381+0200", - PR_FALSE, &parsed_time); - EXPECT_EQ(PR_SUCCESS, result); - EXPECT_EQ(comparison_time_2, parsed_time); -} - -// hh timezone offset. -TEST_F(PRTimeTest, ParseTimeTest14) { - PRTime parsed_time = 0; - PRStatus result = PR_ParseTimeString("2013-07-08T11:28:12.4413819+02", - PR_FALSE, &parsed_time); - EXPECT_EQ(PR_SUCCESS, result); - EXPECT_EQ(comparison_time_2, parsed_time); -} - -// 5 digits fractional second. -TEST_F(PRTimeTest, ParseTimeTest15) { - PRTime parsed_time = 0; - PRStatus result = PR_ParseTimeString("2013-07-08T09:28:12.44138Z", - PR_FALSE, &parsed_time); - EXPECT_EQ(PR_SUCCESS, result); - EXPECT_EQ(comparison_time_2-1, parsed_time); -} - -// Fractional seconds, local timezone. -TEST_F(PRTimeTest, ParseTimeTest16) { - PRTime parsed_time = 0; - PRStatus result = PR_ParseTimeString("2013-07-08T11:28:12.441381", - PR_FALSE, &parsed_time); - EXPECT_EQ(PR_SUCCESS, result); - EXPECT_EQ(comparison_time_local_2_, parsed_time); -} - -// "Z" (=GMT) timezone. -TEST_F(PRTimeTest, ParseTimeTest17) { - PRTime parsed_time = 0; - PRStatus result = PR_ParseTimeString("2013-07-08T09:28:12.441381Z", - PR_FALSE, &parsed_time); - EXPECT_EQ(PR_SUCCESS, result); - EXPECT_EQ(comparison_time_2, parsed_time); -} - -// "T" delimiter replaced by space. -TEST_F(PRTimeTest, ParseTimeTest18) { - PRTime parsed_time = 0; - PRStatus result = PR_ParseTimeString("2013-07-08 09:28:12.441381Z", - PR_FALSE, &parsed_time); - EXPECT_EQ(PR_SUCCESS, result); - EXPECT_EQ(comparison_time_2, parsed_time); -} - -TEST_F(PRTimeTest, ParseTimeTestInvalid1) { - PRTime parsed_time = 0; - PRStatus result = PR_ParseTimeString("201-07-08T09:28:12.441381Z", - PR_FALSE, &parsed_time); - EXPECT_EQ(PR_FAILURE, result); -} - -TEST_F(PRTimeTest, ParseTimeTestInvalid2) { - PRTime parsed_time = 0; - PRStatus result = PR_ParseTimeString("2013-007-08T09:28:12.441381Z", - PR_FALSE, &parsed_time); - EXPECT_EQ(PR_FAILURE, result); -} - -TEST_F(PRTimeTest, ParseTimeTestInvalid3) { - PRTime parsed_time = 0; - PRStatus result = PR_ParseTimeString("2013-07-008T09:28:12.441381Z", - PR_FALSE, &parsed_time); - EXPECT_EQ(PR_FAILURE, result); -} - -// This test should not crash when compiled with Visual C++ 2005 (see -// http://crbug.com/4387). -TEST_F(PRTimeTest, ParseTimeTestOutOfRange) { - PRTime parsed_time = 0; - // Note the lack of timezone in the time string. The year has to be 3001. - // The date has to be after 23:59:59, December 31, 3000, US Pacific Time, so - // we use January 2, 3001 to make sure it's after the magic maximum in any - // timezone. - PRStatus result = PR_ParseTimeString("Sun Jan 2 00:00:00 3001", - PR_FALSE, &parsed_time); - EXPECT_EQ(PR_SUCCESS, result); -} - -TEST_F(PRTimeTest, ParseTimeTestNotNormalized1) { - PRTime parsed_time = 0; - PRStatus result = PR_ParseTimeString("Mon Oct 15 12:44:60 PDT 2007", - PR_FALSE, &parsed_time); - EXPECT_EQ(PR_SUCCESS, result); - EXPECT_EQ(comparison_time_pdt, parsed_time); -} - -TEST_F(PRTimeTest, ParseTimeTestNotNormalized2) { - PRTime parsed_time = 0; - PRStatus result = PR_ParseTimeString("Sun Oct 14 36:45 PDT 2007", - PR_FALSE, &parsed_time); - EXPECT_EQ(PR_SUCCESS, result); - EXPECT_EQ(comparison_time_pdt, parsed_time); -} - -} // namespace
diff --git a/base/time/time_unittest.cc b/base/time/time_unittest.cc deleted file mode 100644 index 0471dd4..0000000 --- a/base/time/time_unittest.cc +++ /dev/null
@@ -1,1588 +0,0 @@ -// 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/time/time.h" - -#include <stdint.h> -#include <time.h> -#include <limits> -#include <string> - -#include "base/build_time.h" -#include "base/compiler_specific.h" -#include "base/logging.h" -#include "base/macros.h" -#include "base/strings/stringprintf.h" -#include "base/threading/platform_thread.h" -#include "base/time/time_override.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(OS_ANDROID) -#include "base/android/jni_android.h" -#elif defined(OS_IOS) -#include "base/ios/ios_util.h" -#elif defined(OS_WIN) -#include <windows.h> -#endif - -namespace base { - -namespace { - -TEST(TimeTestOutOfBounds, FromExplodedOutOfBoundsTime) { - // FromUTCExploded must set time to Time(0) and failure, if the day is set to - // 31 on a 28-30 day month. Test |exploded| returns Time(0) on 31st of - // February and 31st of April. New implementation handles this. - - const struct DateTestData { - Time::Exploded explode; - bool is_valid; - } kDateTestData[] = { - // 31st of February - {{2016, 2, 0, 31, 12, 30, 0, 0}, true}, - // 31st of April - {{2016, 4, 0, 31, 8, 43, 0, 0}, true}, - // Negative month - {{2016, -5, 0, 2, 4, 10, 0, 0}, false}, - // Negative date of month - {{2016, 6, 0, -15, 2, 50, 0, 0}, false}, - // Negative hours - {{2016, 7, 0, 10, -11, 29, 0, 0}, false}, - // Negative minutes - {{2016, 3, 0, 14, 10, -29, 0, 0}, false}, - // Negative seconds - {{2016, 10, 0, 25, 7, 47, -30, 0}, false}, - // Negative milliseconds - {{2016, 10, 0, 25, 7, 47, 20, -500}, false}, - // Hours are too large - {{2016, 7, 0, 10, 26, 29, 0, 0}, false}, - // Minutes are too large - {{2016, 3, 0, 14, 10, 78, 0, 0}, false}, - // Seconds are too large - {{2016, 10, 0, 25, 7, 47, 234, 0}, false}, - // Milliseconds are too large - {{2016, 10, 0, 25, 6, 31, 23, 1643}, false}, - // Test overflow. Time is valid, but overflow case - // results in Time(0). - {{9840633, 1, 0, 1, 1, 1, 0, 0}, true}, - // Underflow will fail as well. - {{-9840633, 1, 0, 1, 1, 1, 0, 0}, true}, - // Test integer overflow and underflow cases for the values themselves. - {{std::numeric_limits<int>::min(), 1, 0, 1, 1, 1, 0, 0}, true}, - {{std::numeric_limits<int>::max(), 1, 0, 1, 1, 1, 0, 0}, true}, - {{2016, std::numeric_limits<int>::min(), 0, 1, 1, 1, 0, 0}, false}, - {{2016, std::numeric_limits<int>::max(), 0, 1, 1, 1, 0, 0}, false}, - }; - - for (const auto& test : kDateTestData) { - EXPECT_EQ(test.explode.HasValidValues(), test.is_valid); - - base::Time result; - EXPECT_FALSE(base::Time::FromUTCExploded(test.explode, &result)); - EXPECT_TRUE(result.is_null()); - EXPECT_FALSE(base::Time::FromLocalExploded(test.explode, &result)); - EXPECT_TRUE(result.is_null()); - } -} - -// Specialized test fixture allowing time strings without timezones to be -// tested by comparing them to a known time in the local zone. -// See also pr_time_unittests.cc -class TimeTest : public testing::Test { - protected: - void SetUp() override { - // Use mktime to get a time_t, and turn it into a PRTime by converting - // seconds to microseconds. Use 15th Oct 2007 12:45:00 local. This - // must be a time guaranteed to be outside of a DST fallback hour in - // any timezone. - struct tm local_comparison_tm = { - 0, // second - 45, // minute - 12, // hour - 15, // day of month - 10 - 1, // month - 2007 - 1900, // year - 0, // day of week (ignored, output only) - 0, // day of year (ignored, output only) - -1 // DST in effect, -1 tells mktime to figure it out - }; - - time_t converted_time = mktime(&local_comparison_tm); - ASSERT_GT(converted_time, 0); - comparison_time_local_ = Time::FromTimeT(converted_time); - - // time_t representation of 15th Oct 2007 12:45:00 PDT - comparison_time_pdt_ = Time::FromTimeT(1192477500); - } - - Time comparison_time_local_; - Time comparison_time_pdt_; -}; - -// Test conversion to/from TimeDeltas elapsed since the Windows epoch. -// Conversions should be idempotent and non-lossy. -TEST_F(TimeTest, DeltaSinceWindowsEpoch) { - const TimeDelta delta = TimeDelta::FromMicroseconds(123); - EXPECT_EQ(delta, - Time::FromDeltaSinceWindowsEpoch(delta).ToDeltaSinceWindowsEpoch()); - - const Time now = Time::Now(); - const Time actual = - Time::FromDeltaSinceWindowsEpoch(now.ToDeltaSinceWindowsEpoch()); - EXPECT_EQ(now, actual); - - // Null times should remain null after a round-trip conversion. This is an - // important invariant for the common use case of serialization + - // deserialization. - const Time should_be_null = - Time::FromDeltaSinceWindowsEpoch(Time().ToDeltaSinceWindowsEpoch()); - EXPECT_TRUE(should_be_null.is_null()); -} - -// Test conversion to/from time_t. -TEST_F(TimeTest, TimeT) { - EXPECT_EQ(10, Time().FromTimeT(10).ToTimeT()); - EXPECT_EQ(10.0, Time().FromTimeT(10).ToDoubleT()); - - // Conversions of 0 should stay 0. - EXPECT_EQ(0, Time().ToTimeT()); - EXPECT_EQ(0, Time::FromTimeT(0).ToInternalValue()); -} - -// Test conversions to/from time_t and exploding/unexploding (utc time). -TEST_F(TimeTest, UTCTimeT) { - // C library time and exploded time. - time_t now_t_1 = time(nullptr); - struct tm tms; -#if defined(OS_WIN) - gmtime_s(&tms, &now_t_1); -#elif defined(OS_POSIX) || defined(OS_FUCHSIA) - gmtime_r(&now_t_1, &tms); -#endif - - // Convert to ours. - Time our_time_1 = Time::FromTimeT(now_t_1); - Time::Exploded exploded; - our_time_1.UTCExplode(&exploded); - - // This will test both our exploding and our time_t -> Time conversion. - EXPECT_EQ(tms.tm_year + 1900, exploded.year); - EXPECT_EQ(tms.tm_mon + 1, exploded.month); - EXPECT_EQ(tms.tm_mday, exploded.day_of_month); - EXPECT_EQ(tms.tm_hour, exploded.hour); - EXPECT_EQ(tms.tm_min, exploded.minute); - EXPECT_EQ(tms.tm_sec, exploded.second); - - // Convert exploded back to the time struct. - Time our_time_2; - EXPECT_TRUE(Time::FromUTCExploded(exploded, &our_time_2)); - EXPECT_TRUE(our_time_1 == our_time_2); - - time_t now_t_2 = our_time_2.ToTimeT(); - EXPECT_EQ(now_t_1, now_t_2); -} - -// Test conversions to/from time_t and exploding/unexploding (local time). -TEST_F(TimeTest, LocalTimeT) { -#if defined(OS_IOS) && TARGET_OS_SIMULATOR - // The function CFTimeZoneCopySystem() fails to determine the system timezone - // when running iOS 11.0 simulator on an host running High Sierra and return - // the "GMT" timezone. This causes Time::LocalExplode and localtime_r values - // to differ by the local timezone offset. Disable the test if simulating - // iOS 10.0 as it is not possible to check the version of the host mac. - // TODO(crbug.com/782033): remove this once support for iOS pre-11.0 is - // dropped or when the bug in CFTimeZoneCopySystem() is fixed. - if (ios::IsRunningOnIOS10OrLater() && !ios::IsRunningOnIOS11OrLater()) { - return; - } -#endif - - // C library time and exploded time. - time_t now_t_1 = time(nullptr); - struct tm tms; -#if defined(OS_WIN) - localtime_s(&tms, &now_t_1); -#elif defined(OS_POSIX) || defined(OS_FUCHSIA) - localtime_r(&now_t_1, &tms); -#endif - - // Convert to ours. - Time our_time_1 = Time::FromTimeT(now_t_1); - Time::Exploded exploded; - our_time_1.LocalExplode(&exploded); - - // This will test both our exploding and our time_t -> Time conversion. - EXPECT_EQ(tms.tm_year + 1900, exploded.year); - EXPECT_EQ(tms.tm_mon + 1, exploded.month); - EXPECT_EQ(tms.tm_mday, exploded.day_of_month); - EXPECT_EQ(tms.tm_hour, exploded.hour); - EXPECT_EQ(tms.tm_min, exploded.minute); - EXPECT_EQ(tms.tm_sec, exploded.second); - - // Convert exploded back to the time struct. - Time our_time_2; - EXPECT_TRUE(Time::FromLocalExploded(exploded, &our_time_2)); - EXPECT_TRUE(our_time_1 == our_time_2); - - time_t now_t_2 = our_time_2.ToTimeT(); - EXPECT_EQ(now_t_1, now_t_2); -} - -// Test conversions to/from javascript time. -TEST_F(TimeTest, JsTime) { - Time epoch = Time::FromJsTime(0.0); - EXPECT_EQ(epoch, Time::UnixEpoch()); - Time t = Time::FromJsTime(700000.3); - EXPECT_EQ(700.0003, t.ToDoubleT()); - t = Time::FromDoubleT(800.73); - EXPECT_EQ(800730.0, t.ToJsTime()); -} - -#if defined(OS_POSIX) || defined(OS_FUCHSIA) -TEST_F(TimeTest, FromTimeVal) { - Time now = Time::Now(); - Time also_now = Time::FromTimeVal(now.ToTimeVal()); - EXPECT_EQ(now, also_now); -} -#endif // defined(OS_POSIX) || defined(OS_FUCHSIA) - -TEST_F(TimeTest, FromExplodedWithMilliseconds) { - // Some platform implementations of FromExploded are liable to drop - // milliseconds if we aren't careful. - Time now = Time::NowFromSystemTime(); - Time::Exploded exploded1 = {0}; - now.UTCExplode(&exploded1); - exploded1.millisecond = 500; - Time time; - EXPECT_TRUE(Time::FromUTCExploded(exploded1, &time)); - Time::Exploded exploded2 = {0}; - time.UTCExplode(&exploded2); - EXPECT_EQ(exploded1.millisecond, exploded2.millisecond); -} - -TEST_F(TimeTest, ZeroIsSymmetric) { - Time zero_time(Time::FromTimeT(0)); - EXPECT_EQ(0, zero_time.ToTimeT()); - - EXPECT_EQ(0.0, zero_time.ToDoubleT()); -} - -TEST_F(TimeTest, LocalExplode) { - Time a = Time::Now(); - Time::Exploded exploded; - a.LocalExplode(&exploded); - - Time b; - EXPECT_TRUE(Time::FromLocalExploded(exploded, &b)); - - // The exploded structure doesn't have microseconds, and on Mac & Linux, the - // internal OS conversion uses seconds, which will cause truncation. So we - // can only make sure that the delta is within one second. - EXPECT_TRUE((a - b) < TimeDelta::FromSeconds(1)); -} - -TEST_F(TimeTest, UTCExplode) { - Time a = Time::Now(); - Time::Exploded exploded; - a.UTCExplode(&exploded); - - Time b; - EXPECT_TRUE(Time::FromUTCExploded(exploded, &b)); - EXPECT_TRUE((a - b) < TimeDelta::FromSeconds(1)); -} - -TEST_F(TimeTest, LocalMidnight) { - Time::Exploded exploded; - Time::Now().LocalMidnight().LocalExplode(&exploded); - EXPECT_EQ(0, exploded.hour); - EXPECT_EQ(0, exploded.minute); - EXPECT_EQ(0, exploded.second); - EXPECT_EQ(0, exploded.millisecond); -} - -TEST_F(TimeTest, ParseTimeTest1) { - time_t current_time = 0; - time(¤t_time); - - struct tm local_time = {}; - char time_buf[64] = {}; -#if defined(OS_WIN) - localtime_s(&local_time, ¤t_time); - asctime_s(time_buf, arraysize(time_buf), &local_time); -#elif defined(OS_POSIX) || defined(OS_FUCHSIA) - localtime_r(¤t_time, &local_time); - asctime_r(&local_time, time_buf); -#endif - - Time parsed_time; - EXPECT_TRUE(Time::FromString(time_buf, &parsed_time)); - EXPECT_EQ(current_time, parsed_time.ToTimeT()); -} - -TEST_F(TimeTest, DayOfWeekSunday) { - Time time; - EXPECT_TRUE(Time::FromString("Sun, 06 May 2012 12:00:00 GMT", &time)); - Time::Exploded exploded; - time.UTCExplode(&exploded); - EXPECT_EQ(0, exploded.day_of_week); -} - -TEST_F(TimeTest, DayOfWeekWednesday) { - Time time; - EXPECT_TRUE(Time::FromString("Wed, 09 May 2012 12:00:00 GMT", &time)); - Time::Exploded exploded; - time.UTCExplode(&exploded); - EXPECT_EQ(3, exploded.day_of_week); -} - -TEST_F(TimeTest, DayOfWeekSaturday) { - Time time; - EXPECT_TRUE(Time::FromString("Sat, 12 May 2012 12:00:00 GMT", &time)); - Time::Exploded exploded; - time.UTCExplode(&exploded); - EXPECT_EQ(6, exploded.day_of_week); -} - -TEST_F(TimeTest, ParseTimeTest2) { - Time parsed_time; - EXPECT_TRUE(Time::FromString("Mon, 15 Oct 2007 19:45:00 GMT", &parsed_time)); - EXPECT_EQ(comparison_time_pdt_, parsed_time); -} - -TEST_F(TimeTest, ParseTimeTest3) { - Time parsed_time; - EXPECT_TRUE(Time::FromString("15 Oct 07 12:45:00", &parsed_time)); - EXPECT_EQ(comparison_time_local_, parsed_time); -} - -TEST_F(TimeTest, ParseTimeTest4) { - Time parsed_time; - EXPECT_TRUE(Time::FromString("15 Oct 07 19:45 GMT", &parsed_time)); - EXPECT_EQ(comparison_time_pdt_, parsed_time); -} - -TEST_F(TimeTest, ParseTimeTest5) { - Time parsed_time; - EXPECT_TRUE(Time::FromString("Mon Oct 15 12:45 PDT 2007", &parsed_time)); - EXPECT_EQ(comparison_time_pdt_, parsed_time); -} - -TEST_F(TimeTest, ParseTimeTest6) { - Time parsed_time; - EXPECT_TRUE(Time::FromString("Monday, Oct 15, 2007 12:45 PM", &parsed_time)); - EXPECT_EQ(comparison_time_local_, parsed_time); -} - -TEST_F(TimeTest, ParseTimeTest7) { - Time parsed_time; - EXPECT_TRUE(Time::FromString("10/15/07 12:45:00 PM", &parsed_time)); - EXPECT_EQ(comparison_time_local_, parsed_time); -} - -TEST_F(TimeTest, ParseTimeTest8) { - Time parsed_time; - EXPECT_TRUE(Time::FromString("15-OCT-2007 12:45pm", &parsed_time)); - EXPECT_EQ(comparison_time_local_, parsed_time); -} - -TEST_F(TimeTest, ParseTimeTest9) { - Time parsed_time; - EXPECT_TRUE(Time::FromString("16 Oct 2007 4:45-JST (Tuesday)", &parsed_time)); - EXPECT_EQ(comparison_time_pdt_, parsed_time); -} - -TEST_F(TimeTest, ParseTimeTest10) { - Time parsed_time; - EXPECT_TRUE(Time::FromString("15/10/07 12:45", &parsed_time)); - EXPECT_EQ(parsed_time, comparison_time_local_); -} - -// Test some of edge cases around epoch, etc. -TEST_F(TimeTest, ParseTimeTestEpoch0) { - Time parsed_time; - - // time_t == epoch == 0 - EXPECT_TRUE(Time::FromString("Thu Jan 01 01:00:00 +0100 1970", - &parsed_time)); - EXPECT_EQ(0, parsed_time.ToTimeT()); - EXPECT_TRUE(Time::FromString("Thu Jan 01 00:00:00 GMT 1970", - &parsed_time)); - EXPECT_EQ(0, parsed_time.ToTimeT()); -} - -TEST_F(TimeTest, ParseTimeTestEpoch1) { - Time parsed_time; - - // time_t == 1 second after epoch == 1 - EXPECT_TRUE(Time::FromString("Thu Jan 01 01:00:01 +0100 1970", - &parsed_time)); - EXPECT_EQ(1, parsed_time.ToTimeT()); - EXPECT_TRUE(Time::FromString("Thu Jan 01 00:00:01 GMT 1970", - &parsed_time)); - EXPECT_EQ(1, parsed_time.ToTimeT()); -} - -TEST_F(TimeTest, ParseTimeTestEpoch2) { - Time parsed_time; - - // time_t == 2 seconds after epoch == 2 - EXPECT_TRUE(Time::FromString("Thu Jan 01 01:00:02 +0100 1970", - &parsed_time)); - EXPECT_EQ(2, parsed_time.ToTimeT()); - EXPECT_TRUE(Time::FromString("Thu Jan 01 00:00:02 GMT 1970", - &parsed_time)); - EXPECT_EQ(2, parsed_time.ToTimeT()); -} - -TEST_F(TimeTest, ParseTimeTestEpochNeg1) { - Time parsed_time; - - // time_t == 1 second before epoch == -1 - EXPECT_TRUE(Time::FromString("Thu Jan 01 00:59:59 +0100 1970", - &parsed_time)); - EXPECT_EQ(-1, parsed_time.ToTimeT()); - EXPECT_TRUE(Time::FromString("Wed Dec 31 23:59:59 GMT 1969", - &parsed_time)); - EXPECT_EQ(-1, parsed_time.ToTimeT()); -} - -// If time_t is 32 bits, a date after year 2038 will overflow time_t and -// cause timegm() to return -1. The parsed time should not be 1 second -// before epoch. -TEST_F(TimeTest, ParseTimeTestEpochNotNeg1) { - Time parsed_time; - - EXPECT_TRUE(Time::FromString("Wed Dec 31 23:59:59 GMT 2100", - &parsed_time)); - EXPECT_NE(-1, parsed_time.ToTimeT()); -} - -TEST_F(TimeTest, ParseTimeTestEpochNeg2) { - Time parsed_time; - - // time_t == 2 seconds before epoch == -2 - EXPECT_TRUE(Time::FromString("Thu Jan 01 00:59:58 +0100 1970", - &parsed_time)); - EXPECT_EQ(-2, parsed_time.ToTimeT()); - EXPECT_TRUE(Time::FromString("Wed Dec 31 23:59:58 GMT 1969", - &parsed_time)); - EXPECT_EQ(-2, parsed_time.ToTimeT()); -} - -TEST_F(TimeTest, ParseTimeTestEpoch1960) { - Time parsed_time; - - // time_t before Epoch, in 1960 - EXPECT_TRUE(Time::FromString("Wed Jun 29 19:40:01 +0100 1960", - &parsed_time)); - EXPECT_EQ(-299999999, parsed_time.ToTimeT()); - EXPECT_TRUE(Time::FromString("Wed Jun 29 18:40:01 GMT 1960", - &parsed_time)); - EXPECT_EQ(-299999999, parsed_time.ToTimeT()); - EXPECT_TRUE(Time::FromString("Wed Jun 29 17:40:01 GMT 1960", - &parsed_time)); - EXPECT_EQ(-300003599, parsed_time.ToTimeT()); -} - -TEST_F(TimeTest, ParseTimeTestEmpty) { - Time parsed_time; - EXPECT_FALSE(Time::FromString("", &parsed_time)); -} - -TEST_F(TimeTest, ParseTimeTestInvalidString) { - Time parsed_time; - EXPECT_FALSE(Time::FromString("Monday morning 2000", &parsed_time)); -} - -TEST_F(TimeTest, ExplodeBeforeUnixEpoch) { - static const int kUnixEpochYear = 1970; // In case this changes (ha!). - Time t; - Time::Exploded exploded; - - t = Time::UnixEpoch() - TimeDelta::FromMicroseconds(1); - t.UTCExplode(&exploded); - EXPECT_TRUE(exploded.HasValidValues()); - // Should be 1969-12-31 23:59:59 999 milliseconds (and 999 microseconds). - EXPECT_EQ(kUnixEpochYear - 1, exploded.year); - EXPECT_EQ(12, exploded.month); - EXPECT_EQ(31, exploded.day_of_month); - EXPECT_EQ(23, exploded.hour); - EXPECT_EQ(59, exploded.minute); - EXPECT_EQ(59, exploded.second); - EXPECT_EQ(999, exploded.millisecond); - - t = Time::UnixEpoch() - TimeDelta::FromMicroseconds(1000); - t.UTCExplode(&exploded); - EXPECT_TRUE(exploded.HasValidValues()); - // Should be 1969-12-31 23:59:59 999 milliseconds. - EXPECT_EQ(kUnixEpochYear - 1, exploded.year); - EXPECT_EQ(12, exploded.month); - EXPECT_EQ(31, exploded.day_of_month); - EXPECT_EQ(23, exploded.hour); - EXPECT_EQ(59, exploded.minute); - EXPECT_EQ(59, exploded.second); - EXPECT_EQ(999, exploded.millisecond); - - t = Time::UnixEpoch() - TimeDelta::FromMicroseconds(1001); - t.UTCExplode(&exploded); - EXPECT_TRUE(exploded.HasValidValues()); - // Should be 1969-12-31 23:59:59 998 milliseconds (and 999 microseconds). - EXPECT_EQ(kUnixEpochYear - 1, exploded.year); - EXPECT_EQ(12, exploded.month); - EXPECT_EQ(31, exploded.day_of_month); - EXPECT_EQ(23, exploded.hour); - EXPECT_EQ(59, exploded.minute); - EXPECT_EQ(59, exploded.second); - EXPECT_EQ(998, exploded.millisecond); - - t = Time::UnixEpoch() - TimeDelta::FromMilliseconds(1000); - t.UTCExplode(&exploded); - EXPECT_TRUE(exploded.HasValidValues()); - // Should be 1969-12-31 23:59:59. - EXPECT_EQ(kUnixEpochYear - 1, exploded.year); - EXPECT_EQ(12, exploded.month); - EXPECT_EQ(31, exploded.day_of_month); - EXPECT_EQ(23, exploded.hour); - EXPECT_EQ(59, exploded.minute); - EXPECT_EQ(59, exploded.second); - EXPECT_EQ(0, exploded.millisecond); - - t = Time::UnixEpoch() - TimeDelta::FromMilliseconds(1001); - t.UTCExplode(&exploded); - EXPECT_TRUE(exploded.HasValidValues()); - // Should be 1969-12-31 23:59:58 999 milliseconds. - EXPECT_EQ(kUnixEpochYear - 1, exploded.year); - EXPECT_EQ(12, exploded.month); - EXPECT_EQ(31, exploded.day_of_month); - EXPECT_EQ(23, exploded.hour); - EXPECT_EQ(59, exploded.minute); - EXPECT_EQ(58, exploded.second); - EXPECT_EQ(999, exploded.millisecond); - - // Make sure we still handle at/after Unix epoch correctly. - t = Time::UnixEpoch(); - t.UTCExplode(&exploded); - EXPECT_TRUE(exploded.HasValidValues()); - // Should be 1970-12-31 00:00:00 0 milliseconds. - EXPECT_EQ(kUnixEpochYear, exploded.year); - EXPECT_EQ(1, exploded.month); - EXPECT_EQ(1, exploded.day_of_month); - EXPECT_EQ(0, exploded.hour); - EXPECT_EQ(0, exploded.minute); - EXPECT_EQ(0, exploded.second); - EXPECT_EQ(0, exploded.millisecond); - - t = Time::UnixEpoch() + TimeDelta::FromMicroseconds(1); - t.UTCExplode(&exploded); - EXPECT_TRUE(exploded.HasValidValues()); - // Should be 1970-01-01 00:00:00 0 milliseconds (and 1 microsecond). - EXPECT_EQ(kUnixEpochYear, exploded.year); - EXPECT_EQ(1, exploded.month); - EXPECT_EQ(1, exploded.day_of_month); - EXPECT_EQ(0, exploded.hour); - EXPECT_EQ(0, exploded.minute); - EXPECT_EQ(0, exploded.second); - EXPECT_EQ(0, exploded.millisecond); - - t = Time::UnixEpoch() + TimeDelta::FromMicroseconds(1000); - t.UTCExplode(&exploded); - EXPECT_TRUE(exploded.HasValidValues()); - // Should be 1970-01-01 00:00:00 1 millisecond. - EXPECT_EQ(kUnixEpochYear, exploded.year); - EXPECT_EQ(1, exploded.month); - EXPECT_EQ(1, exploded.day_of_month); - EXPECT_EQ(0, exploded.hour); - EXPECT_EQ(0, exploded.minute); - EXPECT_EQ(0, exploded.second); - EXPECT_EQ(1, exploded.millisecond); - - t = Time::UnixEpoch() + TimeDelta::FromMilliseconds(1000); - t.UTCExplode(&exploded); - EXPECT_TRUE(exploded.HasValidValues()); - // Should be 1970-01-01 00:00:01. - EXPECT_EQ(kUnixEpochYear, exploded.year); - EXPECT_EQ(1, exploded.month); - EXPECT_EQ(1, exploded.day_of_month); - EXPECT_EQ(0, exploded.hour); - EXPECT_EQ(0, exploded.minute); - EXPECT_EQ(1, exploded.second); - EXPECT_EQ(0, exploded.millisecond); - - t = Time::UnixEpoch() + TimeDelta::FromMilliseconds(1001); - t.UTCExplode(&exploded); - EXPECT_TRUE(exploded.HasValidValues()); - // Should be 1970-01-01 00:00:01 1 millisecond. - EXPECT_EQ(kUnixEpochYear, exploded.year); - EXPECT_EQ(1, exploded.month); - EXPECT_EQ(1, exploded.day_of_month); - EXPECT_EQ(0, exploded.hour); - EXPECT_EQ(0, exploded.minute); - EXPECT_EQ(1, exploded.second); - EXPECT_EQ(1, exploded.millisecond); -} - -TEST_F(TimeTest, Max) { - Time max = Time::Max(); - EXPECT_TRUE(max.is_max()); - EXPECT_EQ(max, Time::Max()); - EXPECT_GT(max, Time::Now()); - EXPECT_GT(max, Time()); -} - -TEST_F(TimeTest, MaxConversions) { - Time t = Time::Max(); - EXPECT_EQ(std::numeric_limits<int64_t>::max(), t.ToInternalValue()); - - t = Time::FromDoubleT(std::numeric_limits<double>::infinity()); - EXPECT_TRUE(t.is_max()); - EXPECT_EQ(std::numeric_limits<double>::infinity(), t.ToDoubleT()); - - t = Time::FromJsTime(std::numeric_limits<double>::infinity()); - EXPECT_TRUE(t.is_max()); - EXPECT_EQ(std::numeric_limits<double>::infinity(), t.ToJsTime()); - - t = Time::FromTimeT(std::numeric_limits<time_t>::max()); - EXPECT_TRUE(t.is_max()); - EXPECT_EQ(std::numeric_limits<time_t>::max(), t.ToTimeT()); - -#if defined(OS_POSIX) || defined(OS_FUCHSIA) - struct timeval tval; - tval.tv_sec = std::numeric_limits<time_t>::max(); - tval.tv_usec = static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1; - t = Time::FromTimeVal(tval); - EXPECT_TRUE(t.is_max()); - tval = t.ToTimeVal(); - EXPECT_EQ(std::numeric_limits<time_t>::max(), tval.tv_sec); - EXPECT_EQ(static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1, - tval.tv_usec); -#endif - -#if defined(OS_MACOSX) - t = Time::FromCFAbsoluteTime(std::numeric_limits<CFAbsoluteTime>::infinity()); - EXPECT_TRUE(t.is_max()); - EXPECT_EQ(std::numeric_limits<CFAbsoluteTime>::infinity(), - t.ToCFAbsoluteTime()); -#endif - -#if defined(OS_WIN) - FILETIME ftime; - ftime.dwHighDateTime = std::numeric_limits<DWORD>::max(); - ftime.dwLowDateTime = std::numeric_limits<DWORD>::max(); - t = Time::FromFileTime(ftime); - EXPECT_TRUE(t.is_max()); - ftime = t.ToFileTime(); - EXPECT_EQ(std::numeric_limits<DWORD>::max(), ftime.dwHighDateTime); - EXPECT_EQ(std::numeric_limits<DWORD>::max(), ftime.dwLowDateTime); -#endif -} - -#if defined(OS_MACOSX) -TEST_F(TimeTest, TimeTOverflow) { - Time t = Time::FromInternalValue(std::numeric_limits<int64_t>::max() - 1); - EXPECT_FALSE(t.is_max()); - EXPECT_EQ(std::numeric_limits<time_t>::max(), t.ToTimeT()); -} -#endif - -#if defined(OS_ANDROID) -TEST_F(TimeTest, FromLocalExplodedCrashOnAndroid) { - // This crashed inside Time:: FromLocalExploded() on Android 4.1.2. - // See http://crbug.com/287821 - Time::Exploded midnight = {2013, // year - 10, // month - 0, // day_of_week - 13, // day_of_month - 0, // hour - 0, // minute - 0, // second - }; - // The string passed to putenv() must be a char* and the documentation states - // that it 'becomes part of the environment', so use a static buffer. - static char buffer[] = "TZ=America/Santiago"; - putenv(buffer); - tzset(); - Time t; - EXPECT_TRUE(Time::FromLocalExploded(midnight, &t)); - EXPECT_EQ(1381633200, t.ToTimeT()); -} -#endif // OS_ANDROID - -TEST_F(TimeTest, FromExploded_MinMax) { - Time::Exploded exploded = {0}; - exploded.month = 1; - exploded.day_of_month = 1; - - Time parsed_time; - - if (Time::kExplodedMinYear != std::numeric_limits<int>::min()) { - exploded.year = Time::kExplodedMinYear; - EXPECT_TRUE(Time::FromUTCExploded(exploded, &parsed_time)); -#if defined(OS_POSIX) || defined(OS_FUCHSIA) - // On Windows, January 1, 1601 00:00:00 is actually the null time. - EXPECT_FALSE(parsed_time.is_null()); -#endif - -#if !defined(OS_ANDROID) && !defined(OS_MACOSX) - // The dates earlier than |kExplodedMinYear| that don't work are OS version - // dependent on Android and Mac (for example, macOS 10.13 seems to support - // dates before 1902). - exploded.year--; - EXPECT_FALSE(Time::FromUTCExploded(exploded, &parsed_time)); - EXPECT_TRUE(parsed_time.is_null()); -#endif - } - - if (Time::kExplodedMaxYear != std::numeric_limits<int>::max()) { - exploded.year = Time::kExplodedMaxYear; - exploded.month = 12; - exploded.day_of_month = 31; - exploded.hour = 23; - exploded.minute = 59; - exploded.second = 59; - exploded.millisecond = 999; - EXPECT_TRUE(Time::FromUTCExploded(exploded, &parsed_time)); - EXPECT_FALSE(parsed_time.is_null()); - - exploded.year++; - EXPECT_FALSE(Time::FromUTCExploded(exploded, &parsed_time)); - EXPECT_TRUE(parsed_time.is_null()); - } -} - -class TimeOverride { - public: - static Time Now() { - now_time_ += TimeDelta::FromSeconds(1); - return now_time_; - } - - static Time now_time_; -}; - -// static -Time TimeOverride::now_time_; - -TEST_F(TimeTest, NowOverride) { - TimeOverride::now_time_ = Time::UnixEpoch(); - - // 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, subtle::TimeNowIgnoringOverride()); - EXPECT_GT(Time::Max(), subtle::TimeNowIgnoringOverride()); - EXPECT_LT(build_time, Time::NowFromSystemTime()); - EXPECT_GT(Time::Max(), Time::NowFromSystemTime()); - EXPECT_LT(build_time, subtle::TimeNowFromSystemTimeIgnoringOverride()); - EXPECT_GT(Time::Max(), subtle::TimeNowFromSystemTimeIgnoringOverride()); - - { - // Set override. - subtle::ScopedTimeClockOverrides overrides(&TimeOverride::Now, nullptr, - nullptr); - - // Overridden value is returned and incremented when Now() or - // NowFromSystemTime() is called. - EXPECT_EQ(Time::UnixEpoch() + TimeDelta::FromSeconds(1), Time::Now()); - EXPECT_EQ(Time::UnixEpoch() + TimeDelta::FromSeconds(2), Time::Now()); - EXPECT_EQ(Time::UnixEpoch() + TimeDelta::FromSeconds(3), - Time::NowFromSystemTime()); - EXPECT_EQ(Time::UnixEpoch() + TimeDelta::FromSeconds(4), - Time::NowFromSystemTime()); - - // IgnoringOverride methods still return real time. - EXPECT_LT(build_time, subtle::TimeNowIgnoringOverride()); - EXPECT_GT(Time::Max(), subtle::TimeNowIgnoringOverride()); - EXPECT_LT(build_time, subtle::TimeNowFromSystemTimeIgnoringOverride()); - EXPECT_GT(Time::Max(), subtle::TimeNowFromSystemTimeIgnoringOverride()); - - // IgnoringOverride methods didn't call NowOverrideClock::Now(). - EXPECT_EQ(Time::UnixEpoch() + TimeDelta::FromSeconds(5), Time::Now()); - EXPECT_EQ(Time::UnixEpoch() + TimeDelta::FromSeconds(6), - Time::NowFromSystemTime()); - } - - // All methods return real time again. - EXPECT_LT(build_time, Time::Now()); - EXPECT_GT(Time::Max(), Time::Now()); - EXPECT_LT(build_time, subtle::TimeNowIgnoringOverride()); - EXPECT_GT(Time::Max(), subtle::TimeNowIgnoringOverride()); - EXPECT_LT(build_time, Time::NowFromSystemTime()); - EXPECT_GT(Time::Max(), Time::NowFromSystemTime()); - EXPECT_LT(build_time, subtle::TimeNowFromSystemTimeIgnoringOverride()); - EXPECT_GT(Time::Max(), subtle::TimeNowFromSystemTimeIgnoringOverride()); -} - -TEST(TimeTicks, Deltas) { - for (int index = 0; index < 50; index++) { - TimeTicks ticks_start = TimeTicks::Now(); - base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10)); - TimeTicks ticks_stop = TimeTicks::Now(); - TimeDelta delta = ticks_stop - ticks_start; - // Note: Although we asked for a 10ms sleep, if the - // time clock has a finer granularity than the Sleep() - // clock, it is quite possible to wakeup early. Here - // is how that works: - // Time(ms timer) Time(us timer) - // 5 5010 - // 6 6010 - // 7 7010 - // 8 8010 - // 9 9000 - // Elapsed 4ms 3990us - // - // Unfortunately, our InMilliseconds() function truncates - // rather than rounds. We should consider fixing this - // so that our averages come out better. - EXPECT_GE(delta.InMilliseconds(), 9); - EXPECT_GE(delta.InMicroseconds(), 9000); - EXPECT_EQ(delta.InSeconds(), 0); - } -} - -static void HighResClockTest(TimeTicks (*GetTicks)()) { - // IsHighResolution() is false on some systems. Since the product still works - // even if it's false, it makes this entire test questionable. - if (!TimeTicks::IsHighResolution()) - return; - - // Why do we loop here? - // We're trying to measure that intervals increment in a VERY small amount - // of time -- less than 15ms. Unfortunately, if we happen to have a - // context switch in the middle of our test, the context switch could easily - // exceed our limit. So, we iterate on this several times. As long as we're - // able to detect the fine-granularity timers at least once, then the test - // has succeeded. - - const int kTargetGranularityUs = 15000; // 15ms - - bool success = false; - int retries = 100; // Arbitrary. - TimeDelta delta; - while (!success && retries--) { - TimeTicks ticks_start = GetTicks(); - // Loop until we can detect that the clock has changed. Non-HighRes timers - // will increment in chunks, e.g. 15ms. By spinning until we see a clock - // change, we detect the minimum time between measurements. - do { - delta = GetTicks() - ticks_start; - } while (delta.InMilliseconds() == 0); - - if (delta.InMicroseconds() <= kTargetGranularityUs) - success = true; - } - - // In high resolution mode, we expect to see the clock increment - // in intervals less than 15ms. - EXPECT_TRUE(success); -} - -TEST(TimeTicks, HighRes) { - HighResClockTest(&TimeTicks::Now); -} - -class TimeTicksOverride { - public: - static TimeTicks Now() { - now_ticks_ += TimeDelta::FromSeconds(1); - return now_ticks_; - } - - static TimeTicks now_ticks_; -}; - -// static -TimeTicks TimeTicksOverride::now_ticks_; - -TEST(TimeTicks, NowOverride) { - TimeTicksOverride::now_ticks_ = TimeTicks::Min(); - - // Override is not active. All Now() methods should return a sensible value. - EXPECT_LT(TimeTicks::Min(), TimeTicks::UnixEpoch()); - EXPECT_LT(TimeTicks::UnixEpoch(), TimeTicks::Now()); - EXPECT_GT(TimeTicks::Max(), TimeTicks::Now()); - EXPECT_LT(TimeTicks::UnixEpoch(), subtle::TimeTicksNowIgnoringOverride()); - EXPECT_GT(TimeTicks::Max(), subtle::TimeTicksNowIgnoringOverride()); - - { - // Set override. - subtle::ScopedTimeClockOverrides overrides(nullptr, &TimeTicksOverride::Now, - nullptr); - - // Overridden value is returned and incremented when Now() is called. - EXPECT_EQ(TimeTicks::Min() + TimeDelta::FromSeconds(1), TimeTicks::Now()); - EXPECT_EQ(TimeTicks::Min() + TimeDelta::FromSeconds(2), TimeTicks::Now()); - - // NowIgnoringOverride() still returns real ticks. - EXPECT_LT(TimeTicks::UnixEpoch(), subtle::TimeTicksNowIgnoringOverride()); - EXPECT_GT(TimeTicks::Max(), subtle::TimeTicksNowIgnoringOverride()); - - // IgnoringOverride methods didn't call NowOverrideTickClock::NowTicks(). - EXPECT_EQ(TimeTicks::Min() + TimeDelta::FromSeconds(3), TimeTicks::Now()); - } - - // All methods return real ticks again. - EXPECT_LT(TimeTicks::UnixEpoch(), TimeTicks::Now()); - EXPECT_GT(TimeTicks::Max(), TimeTicks::Now()); - EXPECT_LT(TimeTicks::UnixEpoch(), subtle::TimeTicksNowIgnoringOverride()); - EXPECT_GT(TimeTicks::Max(), subtle::TimeTicksNowIgnoringOverride()); -} - -class ThreadTicksOverride { - public: - static ThreadTicks Now() { - now_ticks_ += TimeDelta::FromSeconds(1); - return now_ticks_; - } - - static ThreadTicks now_ticks_; -}; - -// static -ThreadTicks ThreadTicksOverride::now_ticks_; - -// IOS doesn't support ThreadTicks::Now(). -#if defined(OS_IOS) -#define MAYBE_NowOverride DISABLED_NowOverride -#else -#define MAYBE_NowOverride NowOverride -#endif -TEST(ThreadTicks, MAYBE_NowOverride) { - ThreadTicksOverride::now_ticks_ = ThreadTicks::Min(); - - // 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_LE(initial_thread_ticks, subtle::ThreadTicksNowIgnoringOverride()); - EXPECT_GT(ThreadTicks::Max(), subtle::ThreadTicksNowIgnoringOverride()); - - { - // Set override. - subtle::ScopedTimeClockOverrides overrides(nullptr, nullptr, - &ThreadTicksOverride::Now); - - // Overridden value is returned and incremented when Now() is called. - EXPECT_EQ(ThreadTicks::Min() + TimeDelta::FromSeconds(1), - ThreadTicks::Now()); - EXPECT_EQ(ThreadTicks::Min() + TimeDelta::FromSeconds(2), - ThreadTicks::Now()); - - // NowIgnoringOverride() still returns real ticks. - EXPECT_LE(initial_thread_ticks, subtle::ThreadTicksNowIgnoringOverride()); - EXPECT_GT(ThreadTicks::Max(), subtle::ThreadTicksNowIgnoringOverride()); - - // IgnoringOverride methods didn't call NowOverrideTickClock::NowTicks(). - EXPECT_EQ(ThreadTicks::Min() + TimeDelta::FromSeconds(3), - ThreadTicks::Now()); - } - - // All methods return real ticks again. - EXPECT_LE(initial_thread_ticks, ThreadTicks::Now()); - EXPECT_GT(ThreadTicks::Max(), ThreadTicks::Now()); - EXPECT_LE(initial_thread_ticks, subtle::ThreadTicksNowIgnoringOverride()); - EXPECT_GT(ThreadTicks::Max(), subtle::ThreadTicksNowIgnoringOverride()); -} - -// Fails frequently on Android http://crbug.com/352633 with: -// Expected: (delta_thread.InMicroseconds()) > (0), actual: 0 vs 0 -#if defined(OS_ANDROID) -#define MAYBE_ThreadNow DISABLED_ThreadNow -#else -#define MAYBE_ThreadNow ThreadNow -#endif -TEST(ThreadTicks, MAYBE_ThreadNow) { - if (ThreadTicks::IsSupported()) { - ThreadTicks::WaitUntilInitialized(); - TimeTicks begin = TimeTicks::Now(); - ThreadTicks begin_thread = ThreadTicks::Now(); - // Make sure that ThreadNow value is non-zero. - EXPECT_GT(begin_thread, ThreadTicks()); - // Sleep for 10 milliseconds to get the thread de-scheduled. - base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10)); - ThreadTicks end_thread = ThreadTicks::Now(); - TimeTicks end = TimeTicks::Now(); - TimeDelta delta = end - begin; - TimeDelta delta_thread = end_thread - begin_thread; - // Make sure that some thread time have elapsed. - EXPECT_GT(delta_thread.InMicroseconds(), 0); - // But the thread time is at least 9ms less than clock time. - TimeDelta difference = delta - delta_thread; - EXPECT_GE(difference.InMicroseconds(), 9000); - } -} - -TEST(TimeTicks, SnappedToNextTickBasic) { - base::TimeTicks phase = base::TimeTicks::FromInternalValue(4000); - base::TimeDelta interval = base::TimeDelta::FromMicroseconds(1000); - base::TimeTicks timestamp; - - // Timestamp in previous interval. - timestamp = base::TimeTicks::FromInternalValue(3500); - EXPECT_EQ(4000, - timestamp.SnappedToNextTick(phase, interval).ToInternalValue()); - - // Timestamp in next interval. - timestamp = base::TimeTicks::FromInternalValue(4500); - EXPECT_EQ(5000, - timestamp.SnappedToNextTick(phase, interval).ToInternalValue()); - - // Timestamp multiple intervals before. - timestamp = base::TimeTicks::FromInternalValue(2500); - EXPECT_EQ(3000, - timestamp.SnappedToNextTick(phase, interval).ToInternalValue()); - - // Timestamp multiple intervals after. - timestamp = base::TimeTicks::FromInternalValue(6500); - EXPECT_EQ(7000, - timestamp.SnappedToNextTick(phase, interval).ToInternalValue()); - - // Timestamp on previous interval. - timestamp = base::TimeTicks::FromInternalValue(3000); - EXPECT_EQ(3000, - timestamp.SnappedToNextTick(phase, interval).ToInternalValue()); - - // Timestamp on next interval. - timestamp = base::TimeTicks::FromInternalValue(5000); - EXPECT_EQ(5000, - timestamp.SnappedToNextTick(phase, interval).ToInternalValue()); - - // Timestamp equal to phase. - timestamp = base::TimeTicks::FromInternalValue(4000); - EXPECT_EQ(4000, - timestamp.SnappedToNextTick(phase, interval).ToInternalValue()); -} - -TEST(TimeTicks, SnappedToNextTickOverflow) { - // int(big_timestamp / interval) < 0, so this causes a crash if the number of - // intervals elapsed is attempted to be stored in an int. - base::TimeTicks phase = base::TimeTicks::FromInternalValue(0); - base::TimeDelta interval = base::TimeDelta::FromMicroseconds(4000); - base::TimeTicks big_timestamp = - base::TimeTicks::FromInternalValue(8635916564000); - - EXPECT_EQ(8635916564000, - big_timestamp.SnappedToNextTick(phase, interval).ToInternalValue()); - EXPECT_EQ(8635916564000, - big_timestamp.SnappedToNextTick(big_timestamp, interval) - .ToInternalValue()); -} - -#if defined(OS_ANDROID) -TEST(TimeTicks, Android_FromUptimeMillis_ClocksMatch) { - JNIEnv* const env = android::AttachCurrentThread(); - android::ScopedJavaLocalRef<jclass> clazz( - android::GetClass(env, "android/os/SystemClock")); - ASSERT_TRUE(clazz.obj()); - const jmethodID method_id = - android::MethodID::Get<android::MethodID::TYPE_STATIC>( - env, clazz.obj(), "uptimeMillis", "()J"); - ASSERT_FALSE(!method_id); - // Subtract 1ms from the expected lower bound to allow millisecon-level - // truncation performed in uptimeMillis(). - const TimeTicks lower_bound_ticks = - TimeTicks::Now() - TimeDelta::FromMilliseconds(1); - const TimeTicks converted_ticks = TimeTicks::FromUptimeMillis( - env->CallStaticLongMethod(clazz.obj(), method_id)); - const TimeTicks upper_bound_ticks = TimeTicks::Now(); - EXPECT_LE(lower_bound_ticks, converted_ticks); - EXPECT_GE(upper_bound_ticks, converted_ticks); -} -#endif // OS_ANDROID - -TEST(TimeDelta, FromAndIn) { - // static_assert also checks that the contained expression is a constant - // expression, meaning all its components are suitable for initializing global - // variables. - static_assert(TimeDelta::FromDays(2) == TimeDelta::FromHours(48), ""); - static_assert(TimeDelta::FromHours(3) == TimeDelta::FromMinutes(180), ""); - static_assert(TimeDelta::FromMinutes(2) == TimeDelta::FromSeconds(120), ""); - static_assert(TimeDelta::FromSeconds(2) == TimeDelta::FromMilliseconds(2000), - ""); - static_assert( - TimeDelta::FromMilliseconds(2) == TimeDelta::FromMicroseconds(2000), ""); - static_assert( - TimeDelta::FromSecondsD(2.3) == TimeDelta::FromMilliseconds(2300), ""); - static_assert( - TimeDelta::FromMillisecondsD(2.5) == TimeDelta::FromMicroseconds(2500), - ""); - EXPECT_EQ(TimeDelta::FromDays(13).InDays(), 13); - EXPECT_EQ(TimeDelta::FromHours(13).InHours(), 13); - EXPECT_EQ(TimeDelta::FromMinutes(13).InMinutes(), 13); - EXPECT_EQ(TimeDelta::FromSeconds(13).InSeconds(), 13); - EXPECT_EQ(TimeDelta::FromSeconds(13).InSecondsF(), 13.0); - EXPECT_EQ(TimeDelta::FromMilliseconds(13).InMilliseconds(), 13); - EXPECT_EQ(TimeDelta::FromMilliseconds(13).InMillisecondsF(), 13.0); - EXPECT_EQ(TimeDelta::FromSecondsD(13.1).InSeconds(), 13); - EXPECT_EQ(TimeDelta::FromSecondsD(13.1).InSecondsF(), 13.1); - EXPECT_EQ(TimeDelta::FromMillisecondsD(13.3).InMilliseconds(), 13); - EXPECT_EQ(TimeDelta::FromMillisecondsD(13.3).InMillisecondsF(), 13.3); - EXPECT_EQ(TimeDelta::FromMicroseconds(13).InMicroseconds(), 13); - EXPECT_EQ(TimeDelta::FromMicrosecondsD(13.3).InMicroseconds(), 13); - EXPECT_EQ(TimeDelta::FromMillisecondsD(3.45678).InMillisecondsF(), 3.456); - EXPECT_EQ(TimeDelta::FromNanoseconds(12345).InNanoseconds(), 12000); - EXPECT_EQ(TimeDelta::FromNanosecondsD(12345.678).InNanoseconds(), 12000); -} - -#if defined(OS_POSIX) || defined(OS_FUCHSIA) -TEST(TimeDelta, TimeSpecConversion) { - TimeDelta delta = TimeDelta::FromSeconds(0); - struct timespec result = delta.ToTimeSpec(); - EXPECT_EQ(result.tv_sec, 0); - EXPECT_EQ(result.tv_nsec, 0); - EXPECT_EQ(delta, TimeDelta::FromTimeSpec(result)); - - delta = TimeDelta::FromSeconds(1); - result = delta.ToTimeSpec(); - EXPECT_EQ(result.tv_sec, 1); - EXPECT_EQ(result.tv_nsec, 0); - EXPECT_EQ(delta, TimeDelta::FromTimeSpec(result)); - - delta = TimeDelta::FromMicroseconds(1); - result = delta.ToTimeSpec(); - EXPECT_EQ(result.tv_sec, 0); - EXPECT_EQ(result.tv_nsec, 1000); - EXPECT_EQ(delta, TimeDelta::FromTimeSpec(result)); - - delta = TimeDelta::FromMicroseconds(Time::kMicrosecondsPerSecond + 1); - result = delta.ToTimeSpec(); - EXPECT_EQ(result.tv_sec, 1); - EXPECT_EQ(result.tv_nsec, 1000); - EXPECT_EQ(delta, TimeDelta::FromTimeSpec(result)); -} -#endif // defined(OS_POSIX) || defined(OS_FUCHSIA) - -// Our internal time format is serialized in things like databases, so it's -// important that it's consistent across all our platforms. We use the 1601 -// Windows epoch as the internal format across all platforms. -TEST(TimeDelta, WindowsEpoch) { - Time::Exploded exploded; - exploded.year = 1970; - exploded.month = 1; - exploded.day_of_week = 0; // Should be unusued. - exploded.day_of_month = 1; - exploded.hour = 0; - exploded.minute = 0; - exploded.second = 0; - exploded.millisecond = 0; - Time t; - EXPECT_TRUE(Time::FromUTCExploded(exploded, &t)); - // Unix 1970 epoch. - EXPECT_EQ(INT64_C(11644473600000000), t.ToInternalValue()); - - // We can't test 1601 epoch, since the system time functions on Linux - // only compute years starting from 1900. -} - -// We could define this separately for Time, TimeTicks and TimeDelta but the -// definitions would be identical anyway. -template <class Any> -std::string AnyToString(Any any) { - std::ostringstream oss; - oss << any; - return oss.str(); -} - -TEST(TimeDelta, Magnitude) { - constexpr int64_t zero = 0; - static_assert(TimeDelta::FromMicroseconds(zero) == - TimeDelta::FromMicroseconds(zero).magnitude(), - ""); - - constexpr int64_t one = 1; - constexpr int64_t negative_one = -1; - static_assert(TimeDelta::FromMicroseconds(one) == - TimeDelta::FromMicroseconds(one).magnitude(), - ""); - static_assert(TimeDelta::FromMicroseconds(one) == - TimeDelta::FromMicroseconds(negative_one).magnitude(), - ""); - - constexpr int64_t max_int64_minus_one = - std::numeric_limits<int64_t>::max() - 1; - constexpr int64_t min_int64_plus_two = - std::numeric_limits<int64_t>::min() + 2; - static_assert( - TimeDelta::FromMicroseconds(max_int64_minus_one) == - TimeDelta::FromMicroseconds(max_int64_minus_one).magnitude(), - ""); - static_assert(TimeDelta::FromMicroseconds(max_int64_minus_one) == - TimeDelta::FromMicroseconds(min_int64_plus_two).magnitude(), - ""); -} - -TEST(TimeDelta, ZeroMinMax) { - constexpr TimeDelta kZero; - static_assert(kZero.is_zero(), ""); - - constexpr TimeDelta kMax = TimeDelta::Max(); - static_assert(kMax.is_max(), ""); - static_assert(kMax == TimeDelta::Max(), ""); - static_assert(kMax > TimeDelta::FromDays(100 * 365), ""); - static_assert(kMax > kZero, ""); - - constexpr TimeDelta kMin = TimeDelta::Min(); - static_assert(kMin.is_min(), ""); - static_assert(kMin == TimeDelta::Min(), ""); - static_assert(kMin < TimeDelta::FromDays(-100 * 365), ""); - static_assert(kMin < kZero, ""); -} - -TEST(TimeDelta, MaxConversions) { - // static_assert also confirms constexpr works as intended. - constexpr TimeDelta kMax = TimeDelta::Max(); - static_assert(kMax.ToInternalValue() == std::numeric_limits<int64_t>::max(), - ""); - EXPECT_EQ(kMax.InDays(), std::numeric_limits<int>::max()); - EXPECT_EQ(kMax.InHours(), std::numeric_limits<int>::max()); - EXPECT_EQ(kMax.InMinutes(), std::numeric_limits<int>::max()); - EXPECT_EQ(kMax.InSecondsF(), std::numeric_limits<double>::infinity()); - EXPECT_EQ(kMax.InSeconds(), std::numeric_limits<int64_t>::max()); - EXPECT_EQ(kMax.InMillisecondsF(), std::numeric_limits<double>::infinity()); - EXPECT_EQ(kMax.InMilliseconds(), std::numeric_limits<int64_t>::max()); - EXPECT_EQ(kMax.InMillisecondsRoundedUp(), std::numeric_limits<int64_t>::max()); - - static_assert(TimeDelta::FromDays(std::numeric_limits<int>::max()).is_max(), - ""); - - static_assert(TimeDelta::FromHours(std::numeric_limits<int>::max()).is_max(), - ""); - - static_assert( - TimeDelta::FromMinutes(std::numeric_limits<int>::max()).is_max(), ""); - - constexpr int64_t max_int = std::numeric_limits<int64_t>::max(); - constexpr int64_t min_int = std::numeric_limits<int64_t>::min(); - - static_assert( - TimeDelta::FromSeconds(max_int / Time::kMicrosecondsPerSecond + 1) - .is_max(), - ""); - - static_assert( - TimeDelta::FromMilliseconds(max_int / Time::kMillisecondsPerSecond + 1) - .is_max(), - ""); - - static_assert(TimeDelta::FromMicroseconds(max_int).is_max(), ""); - - static_assert( - TimeDelta::FromSeconds(min_int / Time::kMicrosecondsPerSecond - 1) - .is_min(), - ""); - - static_assert( - TimeDelta::FromMilliseconds(min_int / Time::kMillisecondsPerSecond - 1) - .is_min(), - ""); - - static_assert(TimeDelta::FromMicroseconds(min_int).is_min(), ""); - - static_assert( - TimeDelta::FromMicroseconds(std::numeric_limits<int64_t>::min()).is_min(), - ""); - - // Floating point arithmetic resulting in infinity isn't constexpr in C++14. - EXPECT_TRUE(TimeDelta::FromSecondsD(std::numeric_limits<double>::infinity()) - .is_max()); - - // Note that max_int/min_int will be rounded when converted to doubles - they - // can't be exactly represented. - constexpr double max_d = static_cast<double>(max_int); - constexpr double min_d = static_cast<double>(min_int); - - static_assert( - TimeDelta::FromSecondsD(max_d / Time::kMicrosecondsPerSecond + 1) - .is_max(), - ""); - - // Floating point arithmetic resulting in infinity isn't constexpr in C++14. - EXPECT_TRUE( - TimeDelta::FromMillisecondsD(std::numeric_limits<double>::infinity()) - .is_max()); - - static_assert( - TimeDelta::FromMillisecondsD(max_d / Time::kMillisecondsPerSecond * 2) - .is_max(), - ""); - - static_assert( - TimeDelta::FromSecondsD(min_d / Time::kMicrosecondsPerSecond - 1) - .is_min(), - ""); - - static_assert( - TimeDelta::FromMillisecondsD(min_d / Time::kMillisecondsPerSecond * 2) - .is_min(), - ""); -} - -TEST(TimeDelta, NumericOperators) { - constexpr double d = 0.5; - EXPECT_EQ(TimeDelta::FromMilliseconds(500), - (TimeDelta::FromMilliseconds(1000) * d)); - static_assert(TimeDelta::FromMilliseconds(2000) == - (TimeDelta::FromMilliseconds(1000) / d), - ""); - EXPECT_EQ(TimeDelta::FromMilliseconds(500), - (TimeDelta::FromMilliseconds(1000) *= d)); - static_assert(TimeDelta::FromMilliseconds(2000) == - (TimeDelta::FromMilliseconds(1000) /= d), - ""); - EXPECT_EQ(TimeDelta::FromMilliseconds(500), - (d * TimeDelta::FromMilliseconds(1000))); - - constexpr float f = 0.5; - EXPECT_EQ(TimeDelta::FromMilliseconds(500), - (TimeDelta::FromMilliseconds(1000) * f)); - static_assert(TimeDelta::FromMilliseconds(2000) == - (TimeDelta::FromMilliseconds(1000) / f), - ""); - EXPECT_EQ(TimeDelta::FromMilliseconds(500), - (TimeDelta::FromMilliseconds(1000) *= f)); - static_assert(TimeDelta::FromMilliseconds(2000) == - (TimeDelta::FromMilliseconds(1000) /= f), - ""); - EXPECT_EQ(TimeDelta::FromMilliseconds(500), - (f * TimeDelta::FromMilliseconds(1000))); - - constexpr int i = 2; - EXPECT_EQ(TimeDelta::FromMilliseconds(2000), - (TimeDelta::FromMilliseconds(1000) * i)); - static_assert(TimeDelta::FromMilliseconds(500) == - (TimeDelta::FromMilliseconds(1000) / i), - ""); - EXPECT_EQ(TimeDelta::FromMilliseconds(2000), - (TimeDelta::FromMilliseconds(1000) *= i)); - static_assert(TimeDelta::FromMilliseconds(500) == - (TimeDelta::FromMilliseconds(1000) /= i), - ""); - EXPECT_EQ(TimeDelta::FromMilliseconds(2000), - (i * TimeDelta::FromMilliseconds(1000))); - - constexpr int64_t i64 = 2; - EXPECT_EQ(TimeDelta::FromMilliseconds(2000), - (TimeDelta::FromMilliseconds(1000) * i64)); - static_assert(TimeDelta::FromMilliseconds(500) == - (TimeDelta::FromMilliseconds(1000) / i64), - ""); - EXPECT_EQ(TimeDelta::FromMilliseconds(2000), - (TimeDelta::FromMilliseconds(1000) *= i64)); - static_assert(TimeDelta::FromMilliseconds(500) == - (TimeDelta::FromMilliseconds(1000) /= i64), - ""); - EXPECT_EQ(TimeDelta::FromMilliseconds(2000), - (i64 * TimeDelta::FromMilliseconds(1000))); - - EXPECT_EQ(TimeDelta::FromMilliseconds(500), - (TimeDelta::FromMilliseconds(1000) * 0.5)); - static_assert(TimeDelta::FromMilliseconds(2000) == - (TimeDelta::FromMilliseconds(1000) / 0.5), - ""); - EXPECT_EQ(TimeDelta::FromMilliseconds(500), - (TimeDelta::FromMilliseconds(1000) *= 0.5)); - static_assert(TimeDelta::FromMilliseconds(2000) == - (TimeDelta::FromMilliseconds(1000) /= 0.5), - ""); - EXPECT_EQ(TimeDelta::FromMilliseconds(500), - (0.5 * TimeDelta::FromMilliseconds(1000))); - - EXPECT_EQ(TimeDelta::FromMilliseconds(2000), - (TimeDelta::FromMilliseconds(1000) * 2)); - static_assert(TimeDelta::FromMilliseconds(500) == - (TimeDelta::FromMilliseconds(1000) / 2), - ""); - EXPECT_EQ(TimeDelta::FromMilliseconds(2000), - (TimeDelta::FromMilliseconds(1000) *= 2)); - static_assert(TimeDelta::FromMilliseconds(500) == - (TimeDelta::FromMilliseconds(1000) /= 2), - ""); - EXPECT_EQ(TimeDelta::FromMilliseconds(2000), - (2 * TimeDelta::FromMilliseconds(1000))); -} - -// Basic test of operators between TimeDeltas (without overflow -- next test -// handles overflow). -TEST(TimeDelta, TimeDeltaOperators) { - constexpr TimeDelta kElevenSeconds = TimeDelta::FromSeconds(11); - constexpr TimeDelta kThreeSeconds = TimeDelta::FromSeconds(3); - - EXPECT_EQ(TimeDelta::FromSeconds(14), kElevenSeconds + kThreeSeconds); - EXPECT_EQ(TimeDelta::FromSeconds(14), kThreeSeconds + kElevenSeconds); - EXPECT_EQ(TimeDelta::FromSeconds(8), kElevenSeconds - kThreeSeconds); - EXPECT_EQ(TimeDelta::FromSeconds(-8), kThreeSeconds - kElevenSeconds); - static_assert(3 == kElevenSeconds / kThreeSeconds, ""); - static_assert(0 == kThreeSeconds / kElevenSeconds, ""); - static_assert(TimeDelta::FromSeconds(2) == kElevenSeconds % kThreeSeconds, - ""); -} - -TEST(TimeDelta, Overflows) { - // Some sanity checks. static_assert's used were possible to verify constexpr - // evaluation at the same time. - static_assert(TimeDelta::Max().is_max(), ""); - static_assert(-TimeDelta::Max() < TimeDelta(), ""); - static_assert(-TimeDelta::Max() > TimeDelta::Min(), ""); - static_assert(TimeDelta() > -TimeDelta::Max(), ""); - - TimeDelta large_delta = TimeDelta::Max() - TimeDelta::FromMilliseconds(1); - TimeDelta large_negative = -large_delta; - EXPECT_GT(TimeDelta(), large_negative); - EXPECT_FALSE(large_delta.is_max()); - EXPECT_FALSE((-large_negative).is_min()); - constexpr TimeDelta kOneSecond = TimeDelta::FromSeconds(1); - - // Test +, -, * and / operators. - EXPECT_TRUE((large_delta + kOneSecond).is_max()); - EXPECT_TRUE((large_negative + (-kOneSecond)).is_min()); - EXPECT_TRUE((large_negative - kOneSecond).is_min()); - EXPECT_TRUE((large_delta - (-kOneSecond)).is_max()); - EXPECT_TRUE((large_delta * 2).is_max()); - EXPECT_TRUE((large_delta * -2).is_min()); - EXPECT_TRUE((large_delta / 0.5).is_max()); - EXPECT_TRUE((large_delta / -0.5).is_min()); - - // Test that double conversions overflow to infinity. - EXPECT_EQ((large_delta + kOneSecond).InSecondsF(), - std::numeric_limits<double>::infinity()); - EXPECT_EQ((large_delta + kOneSecond).InMillisecondsF(), - std::numeric_limits<double>::infinity()); - EXPECT_EQ((large_delta + kOneSecond).InMicrosecondsF(), - std::numeric_limits<double>::infinity()); - - // Test +=, -=, *= and /= operators. - TimeDelta delta = large_delta; - delta += kOneSecond; - EXPECT_TRUE(delta.is_max()); - delta = large_negative; - delta += -kOneSecond; - EXPECT_TRUE((delta).is_min()); - - delta = large_negative; - delta -= kOneSecond; - EXPECT_TRUE((delta).is_min()); - delta = large_delta; - delta -= -kOneSecond; - EXPECT_TRUE(delta.is_max()); - - delta = large_delta; - delta *= 2; - EXPECT_TRUE(delta.is_max()); - delta = large_negative; - delta *= 1.5; - EXPECT_TRUE((delta).is_min()); - - delta = large_delta; - delta /= 0.5; - EXPECT_TRUE(delta.is_max()); - delta = large_negative; - delta /= 0.5; - EXPECT_TRUE((delta).is_min()); - - // Test operations with Time and TimeTicks. - EXPECT_TRUE((large_delta + Time::Now()).is_max()); - EXPECT_TRUE((large_delta + TimeTicks::Now()).is_max()); - EXPECT_TRUE((Time::Now() + large_delta).is_max()); - EXPECT_TRUE((TimeTicks::Now() + large_delta).is_max()); - - Time time_now = Time::Now(); - EXPECT_EQ(kOneSecond, (time_now + kOneSecond) - time_now); - EXPECT_EQ(-kOneSecond, (time_now - kOneSecond) - time_now); - - TimeTicks ticks_now = TimeTicks::Now(); - EXPECT_EQ(-kOneSecond, (ticks_now - kOneSecond) - ticks_now); - EXPECT_EQ(kOneSecond, (ticks_now + kOneSecond) - ticks_now); -} - -TEST(TimeDeltaLogging, DCheckEqCompiles) { - DCHECK_EQ(TimeDelta(), TimeDelta()); -} - -TEST(TimeDeltaLogging, EmptyIsZero) { - constexpr TimeDelta kZero; - EXPECT_EQ("0 s", AnyToString(kZero)); -} - -TEST(TimeDeltaLogging, FiveHundredMs) { - constexpr TimeDelta kFiveHundredMs = TimeDelta::FromMilliseconds(500); - EXPECT_EQ("0.5 s", AnyToString(kFiveHundredMs)); -} - -TEST(TimeDeltaLogging, MinusTenSeconds) { - constexpr TimeDelta kMinusTenSeconds = TimeDelta::FromSeconds(-10); - EXPECT_EQ("-10 s", AnyToString(kMinusTenSeconds)); -} - -TEST(TimeDeltaLogging, DoesNotMessUpFormattingFlags) { - std::ostringstream oss; - std::ios_base::fmtflags flags_before = oss.flags(); - oss << TimeDelta(); - EXPECT_EQ(flags_before, oss.flags()); -} - -TEST(TimeDeltaLogging, DoesNotMakeStreamBad) { - std::ostringstream oss; - oss << TimeDelta(); - EXPECT_TRUE(oss.good()); -} - -TEST(TimeLogging, DCheckEqCompiles) { - DCHECK_EQ(Time(), Time()); -} - -TEST(TimeLogging, ChromeBirthdate) { - Time birthdate; - ASSERT_TRUE(Time::FromString("Tue, 02 Sep 2008 09:42:18 GMT", &birthdate)); - EXPECT_EQ("2008-09-02 09:42:18.000 UTC", AnyToString(birthdate)); -} - -TEST(TimeLogging, DoesNotMessUpFormattingFlags) { - std::ostringstream oss; - std::ios_base::fmtflags flags_before = oss.flags(); - oss << Time(); - EXPECT_EQ(flags_before, oss.flags()); -} - -TEST(TimeLogging, DoesNotMakeStreamBad) { - std::ostringstream oss; - oss << Time(); - EXPECT_TRUE(oss.good()); -} - -TEST(TimeTicksLogging, DCheckEqCompiles) { - DCHECK_EQ(TimeTicks(), TimeTicks()); -} - -TEST(TimeTicksLogging, ZeroTime) { - TimeTicks zero; - EXPECT_EQ("0 bogo-microseconds", AnyToString(zero)); -} - -TEST(TimeTicksLogging, FortyYearsLater) { - TimeTicks forty_years_later = - TimeTicks() + TimeDelta::FromDays(365.25 * 40); - EXPECT_EQ("1262304000000000 bogo-microseconds", - AnyToString(forty_years_later)); -} - -TEST(TimeTicksLogging, DoesNotMessUpFormattingFlags) { - std::ostringstream oss; - std::ios_base::fmtflags flags_before = oss.flags(); - oss << TimeTicks(); - EXPECT_EQ(flags_before, oss.flags()); -} - -TEST(TimeTicksLogging, DoesNotMakeStreamBad) { - std::ostringstream oss; - oss << TimeTicks(); - EXPECT_TRUE(oss.good()); -} - -} // namespace - -} // namespace base
diff --git a/base/time/time_win_unittest.cc b/base/time/time_win_unittest.cc deleted file mode 100644 index 24cd731..0000000 --- a/base/time/time_win_unittest.cc +++ /dev/null
@@ -1,365 +0,0 @@ -// 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 <windows.h> -#include <mmsystem.h> -#include <process.h> -#include <stdint.h> - -#include <cmath> -#include <limits> -#include <vector> - -#include "base/threading/platform_thread.h" -#include "base/time/time.h" -#include "base/win/registry.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -// For TimeDelta::ConstexprInitialization -constexpr int kExpectedDeltaInMilliseconds = 10; -constexpr TimeDelta kConstexprTimeDelta = - TimeDelta::FromMilliseconds(kExpectedDeltaInMilliseconds); - -class MockTimeTicks : public TimeTicks { - public: - static DWORD Ticker() { - return static_cast<int>(InterlockedIncrement(&ticker_)); - } - - static void InstallTicker() { - old_tick_function_ = SetMockTickFunction(&Ticker); - ticker_ = -5; - } - - static void UninstallTicker() { - SetMockTickFunction(old_tick_function_); - } - - private: - static volatile LONG ticker_; - static TickFunctionType old_tick_function_; -}; - -volatile LONG MockTimeTicks::ticker_; -MockTimeTicks::TickFunctionType MockTimeTicks::old_tick_function_; - -HANDLE g_rollover_test_start; - -unsigned __stdcall RolloverTestThreadMain(void* param) { - int64_t counter = reinterpret_cast<int64_t>(param); - DWORD rv = WaitForSingleObject(g_rollover_test_start, INFINITE); - EXPECT_EQ(rv, WAIT_OBJECT_0); - - TimeTicks last = TimeTicks::Now(); - for (int index = 0; index < counter; index++) { - TimeTicks now = TimeTicks::Now(); - int64_t milliseconds = (now - last).InMilliseconds(); - // This is a tight loop; we could have looped faster than our - // measurements, so the time might be 0 millis. - EXPECT_GE(milliseconds, 0); - EXPECT_LT(milliseconds, 250); - last = now; - } - return 0; -} - -} // namespace - -// This test spawns many threads, and can occasionally fail due to resource -// exhaustion in the presence of ASan. -#if defined(ADDRESS_SANITIZER) -#define MAYBE_WinRollover DISABLED_WinRollover -#else -#define MAYBE_WinRollover WinRollover -#endif -TEST(TimeTicks, MAYBE_WinRollover) { - // The internal counter rolls over at ~49days. We'll use a mock - // timer to test this case. - // Basic test algorithm: - // 1) Set clock to rollover - N - // 2) Create N threads - // 3) Start the threads - // 4) Each thread loops through TimeTicks() N times - // 5) Each thread verifies integrity of result. - - const int kThreads = 8; - // Use int64_t so we can cast into a void* without a compiler warning. - const int64_t kChecks = 10; - - // It takes a lot of iterations to reproduce the bug! - // (See bug 1081395) - for (int loop = 0; loop < 4096; loop++) { - // Setup - MockTimeTicks::InstallTicker(); - g_rollover_test_start = CreateEvent(0, TRUE, FALSE, 0); - HANDLE threads[kThreads]; - - for (int index = 0; index < kThreads; index++) { - void* argument = reinterpret_cast<void*>(kChecks); - unsigned thread_id; - threads[index] = reinterpret_cast<HANDLE>( - _beginthreadex(NULL, 0, RolloverTestThreadMain, argument, 0, - &thread_id)); - EXPECT_NE((HANDLE)NULL, threads[index]); - } - - // Start! - SetEvent(g_rollover_test_start); - - // Wait for threads to finish - for (int index = 0; index < kThreads; index++) { - DWORD rv = WaitForSingleObject(threads[index], INFINITE); - EXPECT_EQ(rv, WAIT_OBJECT_0); - // Since using _beginthreadex() (as opposed to _beginthread), - // an explicit CloseHandle() is supposed to be called. - CloseHandle(threads[index]); - } - - CloseHandle(g_rollover_test_start); - - // Teardown - MockTimeTicks::UninstallTicker(); - } -} - -TEST(TimeTicks, SubMillisecondTimers) { - // IsHighResolution() is false on some systems. Since the product still works - // even if it's false, it makes this entire test questionable. - if (!TimeTicks::IsHighResolution()) - return; - - const int kRetries = 1000; - bool saw_submillisecond_timer = false; - - // Run kRetries attempts to see a sub-millisecond timer. - for (int index = 0; index < kRetries; index++) { - TimeTicks last_time = TimeTicks::Now(); - TimeDelta delta; - // Spin until the clock has detected a change. - do { - delta = TimeTicks::Now() - last_time; - } while (delta.InMicroseconds() == 0); - if (delta.InMicroseconds() < 1000) { - saw_submillisecond_timer = true; - break; - } - } - EXPECT_TRUE(saw_submillisecond_timer); -} - -TEST(TimeTicks, TimeGetTimeCaps) { - // Test some basic assumptions that we expect about how timeGetDevCaps works. - - TIMECAPS caps; - MMRESULT status = timeGetDevCaps(&caps, sizeof(caps)); - ASSERT_EQ(static_cast<MMRESULT>(MMSYSERR_NOERROR), status); - - EXPECT_GE(static_cast<int>(caps.wPeriodMin), 1); - EXPECT_GT(static_cast<int>(caps.wPeriodMax), 1); - EXPECT_GE(static_cast<int>(caps.wPeriodMin), 1); - EXPECT_GT(static_cast<int>(caps.wPeriodMax), 1); - printf("timeGetTime range is %d to %dms\n", caps.wPeriodMin, - caps.wPeriodMax); -} - -TEST(TimeTicks, QueryPerformanceFrequency) { - // Test some basic assumptions that we expect about QPC. - - LARGE_INTEGER frequency; - BOOL rv = QueryPerformanceFrequency(&frequency); - EXPECT_EQ(TRUE, rv); - EXPECT_GT(frequency.QuadPart, 1000000); // Expect at least 1MHz - printf("QueryPerformanceFrequency is %5.2fMHz\n", - frequency.QuadPart / 1000000.0); -} - -TEST(TimeTicks, TimerPerformance) { - // Verify that various timer mechanisms can always complete quickly. - // Note: This is a somewhat arbitrary test. - const int kLoops = 10000; - - typedef TimeTicks (*TestFunc)(); - struct TestCase { - TestFunc func; - const char *description; - }; - // Cheating a bit here: assumes sizeof(TimeTicks) == sizeof(Time) - // in order to create a single test case list. - static_assert(sizeof(TimeTicks) == sizeof(Time), - "TimeTicks and Time must be the same size"); - std::vector<TestCase> cases; - cases.push_back({reinterpret_cast<TestFunc>(&Time::Now), "Time::Now"}); - cases.push_back({&TimeTicks::Now, "TimeTicks::Now"}); - - if (ThreadTicks::IsSupported()) { - ThreadTicks::WaitUntilInitialized(); - cases.push_back( - {reinterpret_cast<TestFunc>(&ThreadTicks::Now), "ThreadTicks::Now"}); - } - - for (const auto& test_case : cases) { - TimeTicks start = TimeTicks::Now(); - for (int index = 0; index < kLoops; index++) - test_case.func(); - TimeTicks stop = TimeTicks::Now(); - // Turning off the check for acceptible delays. Without this check, - // the test really doesn't do much other than measure. But the - // measurements are still useful for testing timers on various platforms. - // The reason to remove the check is because the tests run on many - // buildbots, some of which are VMs. These machines can run horribly - // slow, and there is really no value for checking against a max timer. - //const int kMaxTime = 35; // Maximum acceptible milliseconds for test. - //EXPECT_LT((stop - start).InMilliseconds(), kMaxTime); - printf("%s: %1.2fus per call\n", test_case.description, - (stop - start).InMillisecondsF() * 1000 / kLoops); - } -} - -TEST(TimeTicks, TSCTicksPerSecond) { - if (ThreadTicks::IsSupported()) { - ThreadTicks::WaitUntilInitialized(); - - // Read the CPU frequency from the registry. - base::win::RegKey processor_key( - HKEY_LOCAL_MACHINE, - L"Hardware\\Description\\System\\CentralProcessor\\0", KEY_QUERY_VALUE); - ASSERT_TRUE(processor_key.Valid()); - DWORD processor_mhz_from_registry; - ASSERT_EQ(ERROR_SUCCESS, - processor_key.ReadValueDW(L"~MHz", &processor_mhz_from_registry)); - - // Expect the measured TSC frequency to be similar to the processor - // frequency from the registry (0.5% error). - double tsc_mhz_measured = ThreadTicks::TSCTicksPerSecond() / 1e6; - EXPECT_NEAR(tsc_mhz_measured, processor_mhz_from_registry, - 0.005 * processor_mhz_from_registry); - } -} - -TEST(TimeTicks, FromQPCValue) { - if (!TimeTicks::IsHighResolution()) - return; - - LARGE_INTEGER frequency; - ASSERT_TRUE(QueryPerformanceFrequency(&frequency)); - const int64_t ticks_per_second = frequency.QuadPart; - ASSERT_GT(ticks_per_second, 0); - - // Generate the tick values to convert, advancing the tick count by varying - // amounts. These values will ensure that both the fast and overflow-safe - // conversion logic in FromQPCValue() is tested, and across the entire range - // of possible QPC tick values. - std::vector<int64_t> test_cases; - test_cases.push_back(0); - const int kNumAdvancements = 100; - int64_t ticks = 0; - int64_t ticks_increment = 10; - for (int i = 0; i < kNumAdvancements; ++i) { - test_cases.push_back(ticks); - ticks += ticks_increment; - ticks_increment = ticks_increment * 6 / 5; - } - test_cases.push_back(Time::kQPCOverflowThreshold - 1); - test_cases.push_back(Time::kQPCOverflowThreshold); - test_cases.push_back(Time::kQPCOverflowThreshold + 1); - ticks = Time::kQPCOverflowThreshold + 10; - ticks_increment = 10; - for (int i = 0; i < kNumAdvancements; ++i) { - test_cases.push_back(ticks); - ticks += ticks_increment; - ticks_increment = ticks_increment * 6 / 5; - } - test_cases.push_back(std::numeric_limits<int64_t>::max()); - - // Test that the conversions using FromQPCValue() match those computed here - // using simple floating-point arithmetic. The floating-point math provides - // enough precision for all reasonable values to confirm that the - // implementation is correct to the microsecond, and for "very large" values - // it confirms that the answer is very close to correct. - for (int64_t ticks : test_cases) { - const double expected_microseconds_since_origin = - (static_cast<double>(ticks) * Time::kMicrosecondsPerSecond) / - ticks_per_second; - const TimeTicks converted_value = TimeTicks::FromQPCValue(ticks); - const double converted_microseconds_since_origin = - static_cast<double>((converted_value - TimeTicks()).InMicroseconds()); - // When we test with very large numbers we end up in a range where adjacent - // double values are far apart - 512.0 apart in one test failure. In that - // situation it makes no sense for our epsilon to be 1.0 - it should be - // the difference between adjacent doubles. - double epsilon = nextafter(expected_microseconds_since_origin, INFINITY) - - expected_microseconds_since_origin; - // Epsilon must be at least 1.0 because converted_microseconds_since_origin - // comes from an integral value and the rounding is not perfect. - if (epsilon < 1.0) - epsilon = 1.0; - EXPECT_NEAR(expected_microseconds_since_origin, - converted_microseconds_since_origin, epsilon) - << "ticks=" << ticks << ", to be converted via logic path: " - << (ticks < Time::kQPCOverflowThreshold ? "FAST" : "SAFE"); - } -} - -TEST(TimeDelta, ConstexprInitialization) { - // Make sure that TimeDelta works around crbug.com/635974 - EXPECT_EQ(kExpectedDeltaInMilliseconds, kConstexprTimeDelta.InMilliseconds()); -} - -TEST(TimeDelta, FromFileTime) { - FILETIME ft; - ft.dwLowDateTime = 1001; - ft.dwHighDateTime = 0; - - // 100100 ns ~= 100 us. - EXPECT_EQ(TimeDelta::FromMicroseconds(100), TimeDelta::FromFileTime(ft)); - - ft.dwLowDateTime = 0; - ft.dwHighDateTime = 1; - - // 2^32 * 100 ns ~= 2^32 * 10 us. - EXPECT_EQ(TimeDelta::FromMicroseconds((1ull << 32) / 10), - TimeDelta::FromFileTime(ft)); -} - -TEST(HighResolutionTimer, GetUsage) { - EXPECT_EQ(0.0, Time::GetHighResolutionTimerUsage()); - - Time::ResetHighResolutionTimerUsage(); - - // 0% usage since the timer isn't activated regardless of how much time has - // elapsed. - EXPECT_EQ(0.0, Time::GetHighResolutionTimerUsage()); - Sleep(10); - EXPECT_EQ(0.0, Time::GetHighResolutionTimerUsage()); - - Time::ActivateHighResolutionTimer(true); - Time::ResetHighResolutionTimerUsage(); - - Sleep(20); - // 100% usage since the timer has been activated entire time. - EXPECT_EQ(100.0, Time::GetHighResolutionTimerUsage()); - - Time::ActivateHighResolutionTimer(false); - Sleep(20); - double usage1 = Time::GetHighResolutionTimerUsage(); - // usage1 should be about 50%. - EXPECT_LT(usage1, 100.0); - EXPECT_GT(usage1, 0.0); - - Time::ActivateHighResolutionTimer(true); - Sleep(10); - Time::ActivateHighResolutionTimer(false); - double usage2 = Time::GetHighResolutionTimerUsage(); - // usage2 should be about 60%. - EXPECT_LT(usage2, 100.0); - EXPECT_GT(usage2, usage1); - - Time::ResetHighResolutionTimerUsage(); - EXPECT_EQ(0.0, Time::GetHighResolutionTimerUsage()); -} - -} // namespace base
diff --git a/base/timer/hi_res_timer_manager_unittest.cc b/base/timer/hi_res_timer_manager_unittest.cc deleted file mode 100644 index 3860c09..0000000 --- a/base/timer/hi_res_timer_manager_unittest.cc +++ /dev/null
@@ -1,62 +0,0 @@ -// 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/timer/hi_res_timer_manager.h" - -#include <memory> -#include <utility> - -#include "base/power_monitor/power_monitor.h" -#include "base/power_monitor/power_monitor_device_source.h" -#include "base/test/scoped_task_environment.h" -#include "base/time/time.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -#if defined(OS_WIN) -TEST(HiResTimerManagerTest, ToggleOnOff) { - // The power monitor creates Window to receive power notifications from - // Windows, which makes this test flaky if you run while the machine - // goes in or out of AC power. - test::ScopedTaskEnvironment scoped_task_environment( - test::ScopedTaskEnvironment::MainThreadType::UI); - std::unique_ptr<base::PowerMonitorSource> power_monitor_source( - new base::PowerMonitorDeviceSource()); - std::unique_ptr<base::PowerMonitor> power_monitor( - new base::PowerMonitor(std::move(power_monitor_source))); - - HighResolutionTimerManager manager; - // Simulate a on-AC power event to get to a known initial state. - manager.OnPowerStateChange(false); - - // Loop a few times to test power toggling. - for (int times = 0; times != 3; ++times) { - // The manager has the high resolution clock enabled now. - EXPECT_TRUE(manager.hi_res_clock_available()); - // But the Time class has it off, because it hasn't been activated. - EXPECT_FALSE(base::Time::IsHighResolutionTimerInUse()); - - // Activate the high resolution timer. - base::Time::ActivateHighResolutionTimer(true); - EXPECT_TRUE(base::Time::IsHighResolutionTimerInUse()); - - // Simulate a on-battery power event. - manager.OnPowerStateChange(true); - EXPECT_FALSE(manager.hi_res_clock_available()); - EXPECT_FALSE(base::Time::IsHighResolutionTimerInUse()); - - // Back to on-AC power. - manager.OnPowerStateChange(false); - EXPECT_TRUE(manager.hi_res_clock_available()); - EXPECT_TRUE(base::Time::IsHighResolutionTimerInUse()); - - // De-activate the high resolution timer. - base::Time::ActivateHighResolutionTimer(false); - } -} -#endif // defined(OS_WIN) - -} // namespace base
diff --git a/base/timer/mock_timer_unittest.cc b/base/timer/mock_timer_unittest.cc deleted file mode 100644 index 61716a4..0000000 --- a/base/timer/mock_timer_unittest.cc +++ /dev/null
@@ -1,80 +0,0 @@ -// 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/timer/mock_timer.h" - -#include "base/macros.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -void CallMeMaybe(int *number) { - (*number)++; -} - -TEST(MockTimerTest, FiresOnce) { - int calls = 0; - base::MockTimer timer(false, false); - base::TimeDelta delay = base::TimeDelta::FromSeconds(2); - timer.Start(FROM_HERE, delay, - base::Bind(&CallMeMaybe, - base::Unretained(&calls))); - EXPECT_EQ(delay, timer.GetCurrentDelay()); - EXPECT_TRUE(timer.IsRunning()); - timer.Fire(); - EXPECT_FALSE(timer.IsRunning()); - EXPECT_EQ(1, calls); -} - -TEST(MockTimerTest, FiresRepeatedly) { - int calls = 0; - base::MockTimer timer(true, true); - base::TimeDelta delay = base::TimeDelta::FromSeconds(2); - timer.Start(FROM_HERE, delay, - base::Bind(&CallMeMaybe, - base::Unretained(&calls))); - timer.Fire(); - EXPECT_TRUE(timer.IsRunning()); - timer.Fire(); - timer.Fire(); - EXPECT_TRUE(timer.IsRunning()); - EXPECT_EQ(3, calls); -} - -TEST(MockTimerTest, Stops) { - int calls = 0; - base::MockTimer timer(true, true); - base::TimeDelta delay = base::TimeDelta::FromSeconds(2); - timer.Start(FROM_HERE, delay, - base::Bind(&CallMeMaybe, - base::Unretained(&calls))); - EXPECT_TRUE(timer.IsRunning()); - timer.Stop(); - EXPECT_FALSE(timer.IsRunning()); -} - -class HasWeakPtr : public base::SupportsWeakPtr<HasWeakPtr> { - public: - HasWeakPtr() = default; - virtual ~HasWeakPtr() = default; - - private: - DISALLOW_COPY_AND_ASSIGN(HasWeakPtr); -}; - -TEST(MockTimerTest, DoesNotRetainClosure) { - HasWeakPtr *has_weak_ptr = new HasWeakPtr(); - base::WeakPtr<HasWeakPtr> weak_ptr(has_weak_ptr->AsWeakPtr()); - base::MockTimer timer(false, false); - base::TimeDelta delay = base::TimeDelta::FromSeconds(2); - ASSERT_TRUE(weak_ptr.get()); - timer.Start(FROM_HERE, delay, - base::Bind(base::DoNothing::Repeatedly<HasWeakPtr*>(), - base::Owned(has_weak_ptr))); - ASSERT_TRUE(weak_ptr.get()); - timer.Fire(); - ASSERT_FALSE(weak_ptr.get()); -} - -} // namespace
diff --git a/base/timer/timer_unittest.cc b/base/timer/timer_unittest.cc deleted file mode 100644 index ae587bf..0000000 --- a/base/timer/timer_unittest.cc +++ /dev/null
@@ -1,904 +0,0 @@ -// 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/timer/timer.h" - -#include <stddef.h> - -#include <memory> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/callback.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/memory/ref_counted.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "base/sequenced_task_runner.h" -#include "base/synchronization/waitable_event.h" -#include "base/task_scheduler/post_task.h" -#include "base/test/scoped_task_environment.h" -#include "base/test/test_mock_time_task_runner.h" -#include "base/threading/platform_thread.h" -#include "base/threading/sequenced_task_runner_handle.h" -#include "base/threading/thread.h" -#include "base/time/tick_clock.h" -#include "base/time/time.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -// The message loops on which each timer should be tested. -const MessageLoop::Type testing_message_loops[] = { - MessageLoop::TYPE_DEFAULT, MessageLoop::TYPE_IO, -#if !defined(OS_IOS) // iOS does not allow direct running of the UI loop. - MessageLoop::TYPE_UI, -#endif -}; - -const int kNumTestingMessageLoops = arraysize(testing_message_loops); - -class Receiver { - public: - Receiver() : count_(0) {} - void OnCalled() { count_++; } - bool WasCalled() { return count_ > 0; } - int TimesCalled() { return count_; } - - private: - int count_; -}; - -// A basic helper class that can start a one-shot timer and signal a -// WaitableEvent when this timer fires. -class OneShotTimerTesterBase { - public: - // |did_run|, if provided, will be signaled when Run() fires. - explicit OneShotTimerTesterBase( - WaitableEvent* did_run = nullptr, - const TimeDelta& delay = TimeDelta::FromMilliseconds(10)) - : did_run_(did_run), delay_(delay) {} - - virtual ~OneShotTimerTesterBase() = default; - - void Start() { - started_time_ = TimeTicks::Now(); - timer_->Start(FROM_HERE, delay_, this, &OneShotTimerTesterBase::Run); - } - - bool IsRunning() { return timer_->IsRunning(); } - - TimeTicks started_time() const { return started_time_; } - TimeDelta delay() const { return delay_; } - - protected: - virtual void Run() { - if (did_run_) { - EXPECT_FALSE(did_run_->IsSignaled()); - did_run_->Signal(); - } - } - - std::unique_ptr<OneShotTimer> timer_ = std::make_unique<OneShotTimer>(); - - private: - WaitableEvent* const did_run_; - const TimeDelta delay_; - TimeTicks started_time_; - - DISALLOW_COPY_AND_ASSIGN(OneShotTimerTesterBase); -}; - -// Extends functionality of OneShotTimerTesterBase with the abilities to wait -// until the timer fires and to change task runner for the timer. -class OneShotTimerTester : public OneShotTimerTesterBase { - public: - // |did_run|, if provided, will be signaled when Run() fires. - explicit OneShotTimerTester( - WaitableEvent* did_run = nullptr, - const TimeDelta& delay = TimeDelta::FromMilliseconds(10)) - : OneShotTimerTesterBase(did_run, delay), - quit_closure_(run_loop_.QuitClosure()) {} - - ~OneShotTimerTester() override = default; - - void SetTaskRunner(scoped_refptr<SequencedTaskRunner> task_runner) { - timer_->SetTaskRunner(std::move(task_runner)); - - // Run() will be invoked on |task_runner| but |run_loop_|'s QuitClosure - // needs to run on this thread (where the MessageLoop lives). - quit_closure_ = Bind(IgnoreResult(&SequencedTaskRunner::PostTask), - SequencedTaskRunnerHandle::Get(), FROM_HERE, - run_loop_.QuitClosure()); - } - - // Blocks until Run() executes and confirms that Run() didn't fire before - // |delay_| expired. - void WaitAndConfirmTimerFiredAfterDelay() { - run_loop_.Run(); - - EXPECT_NE(TimeTicks(), started_time()); - EXPECT_GE(TimeTicks::Now() - started_time(), delay()); - } - - protected: - // Overridable method to do things on Run() before signaling events/closures - // managed by this helper. - virtual void OnRun() {} - - private: - void Run() override { - OnRun(); - OneShotTimerTesterBase::Run(); - quit_closure_.Run(); - } - - RunLoop run_loop_; - Closure quit_closure_; - - DISALLOW_COPY_AND_ASSIGN(OneShotTimerTester); -}; - -class OneShotSelfDeletingTimerTester : public OneShotTimerTester { - protected: - void OnRun() override { timer_.reset(); } -}; - -constexpr int kNumRepeats = 10; - -class RepeatingTimerTester { - public: - explicit RepeatingTimerTester(WaitableEvent* did_run, const TimeDelta& delay) - : counter_(kNumRepeats), - quit_closure_(run_loop_.QuitClosure()), - did_run_(did_run), - delay_(delay) {} - - void Start() { - started_time_ = TimeTicks::Now(); - timer_.Start(FROM_HERE, delay_, this, &RepeatingTimerTester::Run); - } - - void WaitAndConfirmTimerFiredRepeatedlyAfterDelay() { - run_loop_.Run(); - - EXPECT_NE(TimeTicks(), started_time_); - EXPECT_GE(TimeTicks::Now() - started_time_, kNumRepeats * delay_); - } - - private: - void Run() { - if (--counter_ == 0) { - if (did_run_) { - EXPECT_FALSE(did_run_->IsSignaled()); - did_run_->Signal(); - } - timer_.Stop(); - quit_closure_.Run(); - } - } - - RepeatingTimer timer_; - int counter_; - - RunLoop run_loop_; - Closure quit_closure_; - WaitableEvent* const did_run_; - - const TimeDelta delay_; - TimeTicks started_time_; - - DISALLOW_COPY_AND_ASSIGN(RepeatingTimerTester); -}; - -// Basic test with same setup as RunTest_OneShotTimers_Cancel below to confirm -// that |did_run_a| would be signaled in that test if it wasn't for the -// deletion. -void RunTest_OneShotTimers(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - WaitableEvent did_run_a(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - OneShotTimerTester a(&did_run_a); - a.Start(); - - OneShotTimerTester b; - b.Start(); - - b.WaitAndConfirmTimerFiredAfterDelay(); - - EXPECT_TRUE(did_run_a.IsSignaled()); -} - -void RunTest_OneShotTimers_Cancel(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - WaitableEvent did_run_a(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - OneShotTimerTester* a = new OneShotTimerTester(&did_run_a); - - // This should run before the timer expires. - SequencedTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, a); - - // Now start the timer. - a->Start(); - - OneShotTimerTester b; - b.Start(); - - b.WaitAndConfirmTimerFiredAfterDelay(); - - EXPECT_FALSE(did_run_a.IsSignaled()); -} - -void RunTest_OneShotSelfDeletingTimer(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - OneShotSelfDeletingTimerTester f; - f.Start(); - f.WaitAndConfirmTimerFiredAfterDelay(); -} - -void RunTest_RepeatingTimer(MessageLoop::Type message_loop_type, - const TimeDelta& delay) { - MessageLoop loop(message_loop_type); - - RepeatingTimerTester f(nullptr, delay); - f.Start(); - f.WaitAndConfirmTimerFiredRepeatedlyAfterDelay(); -} - -void RunTest_RepeatingTimer_Cancel(MessageLoop::Type message_loop_type, - const TimeDelta& delay) { - MessageLoop loop(message_loop_type); - - WaitableEvent did_run_a(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - RepeatingTimerTester* a = new RepeatingTimerTester(&did_run_a, delay); - - // This should run before the timer expires. - SequencedTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, a); - - // Now start the timer. - a->Start(); - - RepeatingTimerTester b(nullptr, delay); - b.Start(); - - b.WaitAndConfirmTimerFiredRepeatedlyAfterDelay(); - - // |a| should not have fired despite |b| starting after it on the same - // sequence and being complete by now. - EXPECT_FALSE(did_run_a.IsSignaled()); -} - -class DelayTimerTarget { - public: - bool signaled() const { return signaled_; } - - void Signal() { - ASSERT_FALSE(signaled_); - signaled_ = true; - } - - private: - bool signaled_ = false; -}; - -void RunTest_DelayTimer_NoCall(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - // If Delay is never called, the timer shouldn't go off. - DelayTimerTarget target; - DelayTimer timer(FROM_HERE, TimeDelta::FromMilliseconds(1), &target, - &DelayTimerTarget::Signal); - - OneShotTimerTester tester; - tester.Start(); - tester.WaitAndConfirmTimerFiredAfterDelay(); - - ASSERT_FALSE(target.signaled()); -} - -void RunTest_DelayTimer_OneCall(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - DelayTimerTarget target; - DelayTimer timer(FROM_HERE, TimeDelta::FromMilliseconds(1), &target, - &DelayTimerTarget::Signal); - timer.Reset(); - - OneShotTimerTester tester(nullptr, TimeDelta::FromMilliseconds(100)); - tester.Start(); - tester.WaitAndConfirmTimerFiredAfterDelay(); - - ASSERT_TRUE(target.signaled()); -} - -struct ResetHelper { - ResetHelper(DelayTimer* timer, DelayTimerTarget* target) - : timer_(timer), target_(target) {} - - void Reset() { - ASSERT_FALSE(target_->signaled()); - timer_->Reset(); - } - - private: - DelayTimer* const timer_; - DelayTimerTarget* const target_; -}; - -void RunTest_DelayTimer_Reset(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - // If Delay is never called, the timer shouldn't go off. - DelayTimerTarget target; - DelayTimer timer(FROM_HERE, TimeDelta::FromMilliseconds(50), &target, - &DelayTimerTarget::Signal); - timer.Reset(); - - ResetHelper reset_helper(&timer, &target); - - OneShotTimer timers[20]; - for (size_t i = 0; i < arraysize(timers); ++i) { - timers[i].Start(FROM_HERE, TimeDelta::FromMilliseconds(i * 10), - &reset_helper, &ResetHelper::Reset); - } - - OneShotTimerTester tester(nullptr, TimeDelta::FromMilliseconds(300)); - tester.Start(); - tester.WaitAndConfirmTimerFiredAfterDelay(); - - ASSERT_TRUE(target.signaled()); -} - -class DelayTimerFatalTarget { - public: - void Signal() { - ASSERT_TRUE(false); - } -}; - -void RunTest_DelayTimer_Deleted(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - DelayTimerFatalTarget target; - - { - DelayTimer timer(FROM_HERE, TimeDelta::FromMilliseconds(50), &target, - &DelayTimerFatalTarget::Signal); - timer.Reset(); - } - - // When the timer is deleted, the DelayTimerFatalTarget should never be - // called. - PlatformThread::Sleep(TimeDelta::FromMilliseconds(100)); -} - -} // namespace - -//----------------------------------------------------------------------------- -// Each test is run against each type of MessageLoop. That way we are sure -// that timers work properly in all configurations. - -TEST(TimerTest, OneShotTimers) { - for (int i = 0; i < kNumTestingMessageLoops; i++) { - RunTest_OneShotTimers(testing_message_loops[i]); - } -} - -TEST(TimerTest, OneShotTimers_Cancel) { - for (int i = 0; i < kNumTestingMessageLoops; i++) { - RunTest_OneShotTimers_Cancel(testing_message_loops[i]); - } -} - -// If underline timer does not handle properly, we will crash or fail -// in full page heap environment. -TEST(TimerTest, OneShotSelfDeletingTimer) { - for (int i = 0; i < kNumTestingMessageLoops; i++) { - RunTest_OneShotSelfDeletingTimer(testing_message_loops[i]); - } -} - -TEST(TimerTest, OneShotTimer_CustomTaskRunner) { - // A MessageLoop is required for the timer events on the other thread to - // communicate back to the Timer under test. - MessageLoop loop; - - Thread other_thread("OneShotTimer_CustomTaskRunner"); - other_thread.Start(); - - WaitableEvent did_run(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - OneShotTimerTester f(&did_run); - f.SetTaskRunner(other_thread.task_runner()); - f.Start(); - EXPECT_TRUE(f.IsRunning() || did_run.IsSignaled()); - - f.WaitAndConfirmTimerFiredAfterDelay(); - EXPECT_TRUE(did_run.IsSignaled()); - - // |f| should already have communicated back to this |loop| before invoking - // Run() and as such this thread should already be aware that |f| is no longer - // running. - EXPECT_TRUE(loop.IsIdleForTesting()); - EXPECT_FALSE(f.IsRunning()); -} - -TEST(TimerTest, OneShotTimerWithTickClock) { - scoped_refptr<TestMockTimeTaskRunner> task_runner( - new TestMockTimeTaskRunner(Time::Now(), TimeTicks::Now())); - MessageLoop message_loop; - message_loop.SetTaskRunner(task_runner); - Receiver receiver; - OneShotTimer timer(task_runner->GetMockTickClock()); - timer.Start(FROM_HERE, TimeDelta::FromSeconds(1), - Bind(&Receiver::OnCalled, Unretained(&receiver))); - task_runner->FastForwardBy(TimeDelta::FromSeconds(1)); - EXPECT_TRUE(receiver.WasCalled()); -} - -TEST(TimerTest, RepeatingTimer) { - for (int i = 0; i < kNumTestingMessageLoops; i++) { - RunTest_RepeatingTimer(testing_message_loops[i], - TimeDelta::FromMilliseconds(10)); - } -} - -TEST(TimerTest, RepeatingTimer_Cancel) { - for (int i = 0; i < kNumTestingMessageLoops; i++) { - RunTest_RepeatingTimer_Cancel(testing_message_loops[i], - TimeDelta::FromMilliseconds(10)); - } -} - -TEST(TimerTest, RepeatingTimerZeroDelay) { - for (int i = 0; i < kNumTestingMessageLoops; i++) { - RunTest_RepeatingTimer(testing_message_loops[i], - TimeDelta::FromMilliseconds(0)); - } -} - -TEST(TimerTest, RepeatingTimerZeroDelay_Cancel) { - for (int i = 0; i < kNumTestingMessageLoops; i++) { - RunTest_RepeatingTimer_Cancel(testing_message_loops[i], - TimeDelta::FromMilliseconds(0)); - } -} - -TEST(TimerTest, RepeatingTimerWithTickClock) { - scoped_refptr<TestMockTimeTaskRunner> task_runner( - new TestMockTimeTaskRunner(Time::Now(), TimeTicks::Now())); - MessageLoop message_loop; - message_loop.SetTaskRunner(task_runner); - Receiver receiver; - const int expected_times_called = 10; - RepeatingTimer timer(task_runner->GetMockTickClock()); - timer.Start(FROM_HERE, TimeDelta::FromSeconds(1), - Bind(&Receiver::OnCalled, Unretained(&receiver))); - task_runner->FastForwardBy(TimeDelta::FromSeconds(expected_times_called)); - timer.Stop(); - EXPECT_EQ(expected_times_called, receiver.TimesCalled()); -} - -TEST(TimerTest, DelayTimer_NoCall) { - for (int i = 0; i < kNumTestingMessageLoops; i++) { - RunTest_DelayTimer_NoCall(testing_message_loops[i]); - } -} - -TEST(TimerTest, DelayTimer_OneCall) { - for (int i = 0; i < kNumTestingMessageLoops; i++) { - RunTest_DelayTimer_OneCall(testing_message_loops[i]); - } -} - -// It's flaky on the buildbot, http://crbug.com/25038. -TEST(TimerTest, DISABLED_DelayTimer_Reset) { - for (int i = 0; i < kNumTestingMessageLoops; i++) { - RunTest_DelayTimer_Reset(testing_message_loops[i]); - } -} - -TEST(TimerTest, DelayTimer_Deleted) { - for (int i = 0; i < kNumTestingMessageLoops; i++) { - RunTest_DelayTimer_Deleted(testing_message_loops[i]); - } -} - -TEST(TimerTest, DelayTimerWithTickClock) { - scoped_refptr<TestMockTimeTaskRunner> task_runner( - new TestMockTimeTaskRunner(Time::Now(), TimeTicks::Now())); - MessageLoop message_loop; - message_loop.SetTaskRunner(task_runner); - Receiver receiver; - DelayTimer timer(FROM_HERE, TimeDelta::FromSeconds(1), &receiver, - &Receiver::OnCalled, task_runner->GetMockTickClock()); - task_runner->FastForwardBy(TimeDelta::FromMilliseconds(999)); - EXPECT_FALSE(receiver.WasCalled()); - timer.Reset(); - task_runner->FastForwardBy(TimeDelta::FromMilliseconds(999)); - EXPECT_FALSE(receiver.WasCalled()); - timer.Reset(); - task_runner->FastForwardBy(TimeDelta::FromSeconds(1)); - EXPECT_TRUE(receiver.WasCalled()); -} - -TEST(TimerTest, MessageLoopShutdown) { - // This test is designed to verify that shutdown of the - // message loop does not cause crashes if there were pending - // timers not yet fired. It may only trigger exceptions - // if debug heap checking is enabled. - WaitableEvent did_run(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - { - OneShotTimerTesterBase a(&did_run); - OneShotTimerTesterBase b(&did_run); - OneShotTimerTesterBase c(&did_run); - OneShotTimerTesterBase d(&did_run); - { - MessageLoop loop; - a.Start(); - b.Start(); - } // MessageLoop destructs by falling out of scope. - } // OneShotTimers destruct. SHOULD NOT CRASH, of course. - - EXPECT_FALSE(did_run.IsSignaled()); -} - -// Ref counted class which owns a Timer. The class passes a reference to itself -// via the |user_task| parameter in Timer::Start(). |Timer::user_task_| might -// end up holding the last reference to the class. -class OneShotSelfOwningTimerTester - : public RefCounted<OneShotSelfOwningTimerTester> { - public: - OneShotSelfOwningTimerTester() = default; - - void StartTimer() { - // Start timer with long delay in order to test the timer getting destroyed - // while a timer task is still pending. - timer_.Start(FROM_HERE, TimeDelta::FromDays(1), - base::Bind(&OneShotSelfOwningTimerTester::Run, this)); - } - - private: - friend class RefCounted<OneShotSelfOwningTimerTester>; - ~OneShotSelfOwningTimerTester() = default; - - void Run() { - ADD_FAILURE() << "Timer unexpectedly fired."; - } - - OneShotTimer timer_; - - DISALLOW_COPY_AND_ASSIGN(OneShotSelfOwningTimerTester); -}; - -TEST(TimerTest, MessageLoopShutdownSelfOwningTimer) { - // This test verifies that shutdown of the message loop does not cause crashes - // if there is a pending timer not yet fired and |Timer::user_task_| owns the - // timer. The test may only trigger exceptions if debug heap checking is - // enabled. - - MessageLoop loop; - scoped_refptr<OneShotSelfOwningTimerTester> tester = - new OneShotSelfOwningTimerTester(); - - std::move(tester)->StartTimer(); - // |Timer::user_task_| owns sole reference to |tester|. - - // MessageLoop destructs by falling out of scope. SHOULD NOT CRASH. -} - -void TimerTestCallback() { -} - -TEST(TimerTest, NonRepeatIsRunning) { - { - MessageLoop loop; - Timer timer(false, false); - EXPECT_FALSE(timer.IsRunning()); - timer.Start(FROM_HERE, TimeDelta::FromDays(1), Bind(&TimerTestCallback)); - EXPECT_TRUE(timer.IsRunning()); - timer.Stop(); - EXPECT_FALSE(timer.IsRunning()); - EXPECT_TRUE(timer.user_task().is_null()); - } - - { - Timer timer(true, false); - MessageLoop loop; - EXPECT_FALSE(timer.IsRunning()); - timer.Start(FROM_HERE, TimeDelta::FromDays(1), Bind(&TimerTestCallback)); - EXPECT_TRUE(timer.IsRunning()); - timer.Stop(); - EXPECT_FALSE(timer.IsRunning()); - ASSERT_FALSE(timer.user_task().is_null()); - timer.Reset(); - EXPECT_TRUE(timer.IsRunning()); - } -} - -TEST(TimerTest, NonRepeatMessageLoopDeath) { - Timer timer(false, false); - { - MessageLoop loop; - EXPECT_FALSE(timer.IsRunning()); - timer.Start(FROM_HERE, TimeDelta::FromDays(1), Bind(&TimerTestCallback)); - EXPECT_TRUE(timer.IsRunning()); - } - EXPECT_FALSE(timer.IsRunning()); - EXPECT_TRUE(timer.user_task().is_null()); -} - -TEST(TimerTest, RetainRepeatIsRunning) { - MessageLoop loop; - Timer timer(FROM_HERE, TimeDelta::FromDays(1), Bind(&TimerTestCallback), - true); - EXPECT_FALSE(timer.IsRunning()); - timer.Reset(); - EXPECT_TRUE(timer.IsRunning()); - timer.Stop(); - EXPECT_FALSE(timer.IsRunning()); - timer.Reset(); - EXPECT_TRUE(timer.IsRunning()); -} - -TEST(TimerTest, RetainNonRepeatIsRunning) { - MessageLoop loop; - Timer timer(FROM_HERE, TimeDelta::FromDays(1), Bind(&TimerTestCallback), - false); - EXPECT_FALSE(timer.IsRunning()); - timer.Reset(); - EXPECT_TRUE(timer.IsRunning()); - timer.Stop(); - EXPECT_FALSE(timer.IsRunning()); - timer.Reset(); - EXPECT_TRUE(timer.IsRunning()); -} - -//----------------------------------------------------------------------------- - -namespace { - -bool g_callback_happened1 = false; -bool g_callback_happened2 = false; - -void ClearAllCallbackHappened() { - g_callback_happened1 = false; - g_callback_happened2 = false; -} - -void SetCallbackHappened1() { - g_callback_happened1 = true; - RunLoop::QuitCurrentWhenIdleDeprecated(); -} - -void SetCallbackHappened2() { - g_callback_happened2 = true; - RunLoop::QuitCurrentWhenIdleDeprecated(); -} - -} // namespace - -TEST(TimerTest, ContinuationStopStart) { - { - ClearAllCallbackHappened(); - MessageLoop loop; - Timer timer(false, false); - timer.Start(FROM_HERE, TimeDelta::FromMilliseconds(10), - Bind(&SetCallbackHappened1)); - timer.Stop(); - timer.Start(FROM_HERE, TimeDelta::FromMilliseconds(40), - Bind(&SetCallbackHappened2)); - RunLoop().Run(); - EXPECT_FALSE(g_callback_happened1); - EXPECT_TRUE(g_callback_happened2); - } -} - -TEST(TimerTest, ContinuationReset) { - { - ClearAllCallbackHappened(); - MessageLoop loop; - Timer timer(false, false); - timer.Start(FROM_HERE, TimeDelta::FromMilliseconds(10), - Bind(&SetCallbackHappened1)); - timer.Reset(); - // Since Reset happened before task ran, the user_task must not be cleared: - ASSERT_FALSE(timer.user_task().is_null()); - RunLoop().Run(); - EXPECT_TRUE(g_callback_happened1); - } -} - -namespace { - -// Fixture for tests requiring ScopedTaskEnvironment. Includes a WaitableEvent -// so that cases may Wait() on one thread and Signal() (explicitly, or -// implicitly via helper methods) on another. -class TimerSequenceTest : public testing::Test { - public: - TimerSequenceTest() - : event_(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED) {} - - // Block until Signal() is called on another thread. - void Wait() { event_.Wait(); } - - void Signal() { event_.Signal(); } - - // Helper to augment a task with a subsequent call to Signal(). - Closure TaskWithSignal(const Closure& task) { - return Bind(&TimerSequenceTest::RunTaskAndSignal, Unretained(this), task); - } - - // Create the timer. - void CreateTimer() { timer_.reset(new OneShotTimer); } - - // Schedule an event on the timer. - void StartTimer(TimeDelta delay, const Closure& task) { - timer_->Start(FROM_HERE, delay, task); - } - - void SetTaskRunnerForTimer(scoped_refptr<SequencedTaskRunner> task_runner) { - timer_->SetTaskRunner(std::move(task_runner)); - } - - // Tell the timer to abandon the task. - void AbandonTask() { - EXPECT_TRUE(timer_->IsRunning()); - // Reset() to call Timer::AbandonScheduledTask() - timer_->Reset(); - EXPECT_TRUE(timer_->IsRunning()); - timer_->Stop(); - EXPECT_FALSE(timer_->IsRunning()); - } - - static void VerifyAffinity(const SequencedTaskRunner* task_runner) { - EXPECT_TRUE(task_runner->RunsTasksInCurrentSequence()); - } - - // Delete the timer. - void DeleteTimer() { timer_.reset(); } - - private: - void RunTaskAndSignal(const Closure& task) { - task.Run(); - Signal(); - } - - base::test::ScopedTaskEnvironment scoped_task_environment_; - WaitableEvent event_; - std::unique_ptr<OneShotTimer> timer_; - - DISALLOW_COPY_AND_ASSIGN(TimerSequenceTest); -}; - -} // namespace - -TEST_F(TimerSequenceTest, OneShotTimerTaskOnPoolSequence) { - scoped_refptr<SequencedTaskRunner> task_runner = - base::CreateSequencedTaskRunnerWithTraits({}); - - base::RunLoop run_loop_; - - // Timer is created on this thread. - CreateTimer(); - - // Task will execute on a pool thread. - SetTaskRunnerForTimer(task_runner); - StartTimer(TimeDelta::FromMilliseconds(1), - Bind(IgnoreResult(&SequencedTaskRunner::PostTask), - SequencedTaskRunnerHandle::Get(), FROM_HERE, - run_loop_.QuitClosure())); - - // Spin the loop so that the delayed task fires on it, which will forward it - // to |task_runner|. And since the Timer's task is one that posts back to this - // MessageLoop to quit, we finally unblock. - run_loop_.Run(); - - // Timer will be destroyed on this thread. - DeleteTimer(); -} - -TEST_F(TimerSequenceTest, OneShotTimerUsedOnPoolSequence) { - scoped_refptr<SequencedTaskRunner> task_runner = - base::CreateSequencedTaskRunnerWithTraits({}); - - // Timer is created on this thread. - CreateTimer(); - - // Task will be scheduled from a pool thread. - task_runner->PostTask( - FROM_HERE, BindOnce(&TimerSequenceTest::StartTimer, Unretained(this), - TimeDelta::FromMilliseconds(1), - Bind(&TimerSequenceTest::Signal, Unretained(this)))); - Wait(); - - // Timer must be destroyed on pool thread, too. - task_runner->PostTask( - FROM_HERE, - TaskWithSignal(Bind(&TimerSequenceTest::DeleteTimer, Unretained(this)))); - Wait(); -} - -TEST_F(TimerSequenceTest, OneShotTimerTwoSequencesAbandonTask) { - scoped_refptr<SequencedTaskRunner> task_runner1 = - base::CreateSequencedTaskRunnerWithTraits({}); - scoped_refptr<SequencedTaskRunner> task_runner2 = - base::CreateSequencedTaskRunnerWithTraits({}); - - // Create timer on sequence #1. - task_runner1->PostTask( - FROM_HERE, - TaskWithSignal(Bind(&TimerSequenceTest::CreateTimer, Unretained(this)))); - Wait(); - - // And tell it to execute on a different sequence (#2). - task_runner1->PostTask( - FROM_HERE, TaskWithSignal(Bind(&TimerSequenceTest::SetTaskRunnerForTimer, - Unretained(this), task_runner2))); - Wait(); - - // Task will be scheduled from sequence #1. - task_runner1->PostTask( - FROM_HERE, BindOnce(&TimerSequenceTest::StartTimer, Unretained(this), - TimeDelta::FromHours(1), DoNothing())); - - // Abandon task - must be called from scheduling sequence (#1). - task_runner1->PostTask( - FROM_HERE, - TaskWithSignal(Bind(&TimerSequenceTest::AbandonTask, Unretained(this)))); - Wait(); - - // Timer must be destroyed on the sequence it was scheduled from (#1). - task_runner1->PostTask( - FROM_HERE, - TaskWithSignal(Bind(&TimerSequenceTest::DeleteTimer, Unretained(this)))); - Wait(); -} - -TEST_F(TimerSequenceTest, OneShotTimerUsedAndTaskedOnDifferentSequences) { - scoped_refptr<SequencedTaskRunner> task_runner1 = - base::CreateSequencedTaskRunnerWithTraits({}); - scoped_refptr<SequencedTaskRunner> task_runner2 = - base::CreateSequencedTaskRunnerWithTraits({}); - - // Create timer on sequence #1. - task_runner1->PostTask( - FROM_HERE, - TaskWithSignal(Bind(&TimerSequenceTest::CreateTimer, Unretained(this)))); - Wait(); - - // And tell it to execute on a different sequence (#2). - task_runner1->PostTask( - FROM_HERE, TaskWithSignal(Bind(&TimerSequenceTest::SetTaskRunnerForTimer, - Unretained(this), task_runner2))); - Wait(); - - // Task will be scheduled from sequence #1. - task_runner1->PostTask( - FROM_HERE, - BindOnce(&TimerSequenceTest::StartTimer, Unretained(this), - TimeDelta::FromMilliseconds(1), - TaskWithSignal(Bind(&TimerSequenceTest::VerifyAffinity, - Unretained(task_runner2.get()))))); - - Wait(); - - // Timer must be destroyed on the sequence it was scheduled from (#1). - task_runner1->PostTask( - FROM_HERE, - TaskWithSignal(Bind(&TimerSequenceTest::DeleteTimer, Unretained(this)))); - Wait(); -} - -} // namespace base
diff --git a/base/tools_sanity_unittest.cc b/base/tools_sanity_unittest.cc deleted file mode 100644 index 761559e..0000000 --- a/base/tools_sanity_unittest.cc +++ /dev/null
@@ -1,387 +0,0 @@ -// 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 contains intentional memory errors, some of which may lead to -// crashes if the test is ran without special memory testing tools. We use these -// errors to verify the sanity of the tools. - -#include <stddef.h> - -#include "base/atomicops.h" -#include "base/debug/asan_invalid_access.h" -#include "base/debug/profiler.h" -#include "base/third_party/dynamic_annotations/dynamic_annotations.h" -#include "base/threading/thread.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -const base::subtle::Atomic32 kMagicValue = 42; - -// Helper for memory accesses that can potentially corrupt memory or cause a -// crash during a native run. -#if defined(ADDRESS_SANITIZER) -#if defined(OS_IOS) -// EXPECT_DEATH is not supported on IOS. -#define HARMFUL_ACCESS(action,error_regexp) do { action; } while (0) -#else -#define HARMFUL_ACCESS(action,error_regexp) EXPECT_DEATH(action,error_regexp) -#endif // !OS_IOS -#else -#define HARMFUL_ACCESS(action, error_regexp) -#define HARMFUL_ACCESS_IS_NOOP -#endif - -void DoReadUninitializedValue(char *ptr) { - // Comparison with 64 is to prevent clang from optimizing away the - // jump -- valgrind only catches jumps and conditional moves, but clang uses - // the borrow flag if the condition is just `*ptr == '\0'`. We no longer - // support valgrind, but this constant should be fine to keep as-is. - if (*ptr == 64) { - VLOG(1) << "Uninit condition is true"; - } else { - VLOG(1) << "Uninit condition is false"; - } -} - -void ReadUninitializedValue(char *ptr) { -#if defined(MEMORY_SANITIZER) - EXPECT_DEATH(DoReadUninitializedValue(ptr), - "use-of-uninitialized-value"); -#else - DoReadUninitializedValue(ptr); -#endif -} - -#ifndef HARMFUL_ACCESS_IS_NOOP -void ReadValueOutOfArrayBoundsLeft(char *ptr) { - char c = ptr[-2]; - VLOG(1) << "Reading a byte out of bounds: " << c; -} - -void ReadValueOutOfArrayBoundsRight(char *ptr, size_t size) { - char c = ptr[size + 1]; - VLOG(1) << "Reading a byte out of bounds: " << c; -} - -void WriteValueOutOfArrayBoundsLeft(char *ptr) { - ptr[-1] = kMagicValue; -} - -void WriteValueOutOfArrayBoundsRight(char *ptr, size_t size) { - ptr[size] = kMagicValue; -} -#endif // HARMFUL_ACCESS_IS_NOOP - -void MakeSomeErrors(char *ptr, size_t size) { - ReadUninitializedValue(ptr); - - HARMFUL_ACCESS(ReadValueOutOfArrayBoundsLeft(ptr), - "2 bytes to the left"); - HARMFUL_ACCESS(ReadValueOutOfArrayBoundsRight(ptr, size), - "1 bytes to the right"); - HARMFUL_ACCESS(WriteValueOutOfArrayBoundsLeft(ptr), - "1 bytes to the left"); - HARMFUL_ACCESS(WriteValueOutOfArrayBoundsRight(ptr, size), - "0 bytes to the right"); -} - -} // namespace - -// A memory leak detector should report an error in this test. -TEST(ToolsSanityTest, MemoryLeak) { - // Without the |volatile|, clang optimizes away the next two lines. - int* volatile leak = new int[256]; // Leak some memory intentionally. - leak[4] = 1; // Make sure the allocated memory is used. -} - -#if (defined(ADDRESS_SANITIZER) && defined(OS_IOS)) -// Because iOS doesn't support death tests, each of the following tests will -// crash the whole program under Asan. -#define MAYBE_AccessesToNewMemory DISABLED_AccessesToNewMemory -#define MAYBE_AccessesToMallocMemory DISABLED_AccessesToMallocMemory -#else -#define MAYBE_AccessesToNewMemory AccessesToNewMemory -#define MAYBE_AccessesToMallocMemory AccessesToMallocMemory -#endif // (defined(ADDRESS_SANITIZER) && defined(OS_IOS)) - -// The following tests pass with Clang r170392, but not r172454, which -// makes AddressSanitizer detect errors in them. We disable these tests under -// AddressSanitizer until we fully switch to Clang r172454. After that the -// tests should be put back under the (defined(OS_IOS) || defined(OS_WIN)) -// clause above. -// See also http://crbug.com/172614. -#if defined(ADDRESS_SANITIZER) -#define MAYBE_SingleElementDeletedWithBraces \ - DISABLED_SingleElementDeletedWithBraces -#define MAYBE_ArrayDeletedWithoutBraces DISABLED_ArrayDeletedWithoutBraces -#else -#define MAYBE_ArrayDeletedWithoutBraces ArrayDeletedWithoutBraces -#define MAYBE_SingleElementDeletedWithBraces SingleElementDeletedWithBraces -#endif // defined(ADDRESS_SANITIZER) - -TEST(ToolsSanityTest, MAYBE_AccessesToNewMemory) { - char *foo = new char[10]; - MakeSomeErrors(foo, 10); - delete [] foo; - // Use after delete. - HARMFUL_ACCESS(foo[5] = 0, "heap-use-after-free"); -} - -TEST(ToolsSanityTest, MAYBE_AccessesToMallocMemory) { - char *foo = reinterpret_cast<char*>(malloc(10)); - MakeSomeErrors(foo, 10); - free(foo); - // Use after free. - HARMFUL_ACCESS(foo[5] = 0, "heap-use-after-free"); -} - -#if defined(ADDRESS_SANITIZER) - -static int* allocateArray() { - // Clang warns about the mismatched new[]/delete if they occur in the same - // function. - return new int[10]; -} - -// This test may corrupt memory if not compiled with AddressSanitizer. -TEST(ToolsSanityTest, MAYBE_ArrayDeletedWithoutBraces) { - // Without the |volatile|, clang optimizes away the next two lines. - int* volatile foo = allocateArray(); - delete foo; -} -#endif - -#if defined(ADDRESS_SANITIZER) -static int* allocateScalar() { - // Clang warns about the mismatched new/delete[] if they occur in the same - // function. - return new int; -} - -// This test may corrupt memory if not compiled with AddressSanitizer. -TEST(ToolsSanityTest, MAYBE_SingleElementDeletedWithBraces) { - // Without the |volatile|, clang optimizes away the next two lines. - int* volatile foo = allocateScalar(); - (void) foo; - delete [] foo; -} -#endif - -#if defined(ADDRESS_SANITIZER) - -TEST(ToolsSanityTest, DISABLED_AddressSanitizerNullDerefCrashTest) { - // Intentionally crash to make sure AddressSanitizer is running. - // This test should not be ran on bots. - int* volatile zero = NULL; - *zero = 0; -} - -TEST(ToolsSanityTest, DISABLED_AddressSanitizerLocalOOBCrashTest) { - // Intentionally crash to make sure AddressSanitizer is instrumenting - // the local variables. - // This test should not be ran on bots. - int array[5]; - // Work around the OOB warning reported by Clang. - int* volatile access = &array[5]; - *access = 43; -} - -namespace { -int g_asan_test_global_array[10]; -} // namespace - -TEST(ToolsSanityTest, DISABLED_AddressSanitizerGlobalOOBCrashTest) { - // Intentionally crash to make sure AddressSanitizer is instrumenting - // the global variables. - // This test should not be ran on bots. - - // Work around the OOB warning reported by Clang. - int* volatile access = g_asan_test_global_array - 1; - *access = 43; -} - -#ifndef HARMFUL_ACCESS_IS_NOOP -TEST(ToolsSanityTest, AsanHeapOverflow) { - HARMFUL_ACCESS(debug::AsanHeapOverflow() ,"to the right"); -} - -TEST(ToolsSanityTest, AsanHeapUnderflow) { - HARMFUL_ACCESS(debug::AsanHeapUnderflow(), "to the left"); -} - -TEST(ToolsSanityTest, AsanHeapUseAfterFree) { - HARMFUL_ACCESS(debug::AsanHeapUseAfterFree(), "heap-use-after-free"); -} - -#if defined(OS_WIN) -// The ASAN runtime doesn't detect heap corruption, this needs fixing before -// ASAN builds can ship to the wild. See https://crbug.com/818747. -TEST(ToolsSanityTest, DISABLED_AsanCorruptHeapBlock) { - HARMFUL_ACCESS(debug::AsanCorruptHeapBlock(), ""); -} - -TEST(ToolsSanityTest, DISABLED_AsanCorruptHeap) { - // This test will kill the process by raising an exception, there's no - // particular string to look for in the stack trace. - EXPECT_DEATH(debug::AsanCorruptHeap(), ""); -} -#endif // OS_WIN -#endif // !HARMFUL_ACCESS_IS_NOOP - -#endif // ADDRESS_SANITIZER - -namespace { - -// We use caps here just to ensure that the method name doesn't interfere with -// the wildcarded suppressions. -class TOOLS_SANITY_TEST_CONCURRENT_THREAD : public PlatformThread::Delegate { - public: - explicit TOOLS_SANITY_TEST_CONCURRENT_THREAD(bool *value) : value_(value) {} - ~TOOLS_SANITY_TEST_CONCURRENT_THREAD() override = default; - void ThreadMain() override { - *value_ = true; - - // Sleep for a few milliseconds so the two threads are more likely to live - // simultaneously. Otherwise we may miss the report due to mutex - // lock/unlock's inside thread creation code in pure-happens-before mode... - PlatformThread::Sleep(TimeDelta::FromMilliseconds(100)); - } - private: - bool *value_; -}; - -class ReleaseStoreThread : public PlatformThread::Delegate { - public: - explicit ReleaseStoreThread(base::subtle::Atomic32 *value) : value_(value) {} - ~ReleaseStoreThread() override = default; - void ThreadMain() override { - base::subtle::Release_Store(value_, kMagicValue); - - // Sleep for a few milliseconds so the two threads are more likely to live - // simultaneously. Otherwise we may miss the report due to mutex - // lock/unlock's inside thread creation code in pure-happens-before mode... - PlatformThread::Sleep(TimeDelta::FromMilliseconds(100)); - } - private: - base::subtle::Atomic32 *value_; -}; - -class AcquireLoadThread : public PlatformThread::Delegate { - public: - explicit AcquireLoadThread(base::subtle::Atomic32 *value) : value_(value) {} - ~AcquireLoadThread() override = default; - void ThreadMain() override { - // Wait for the other thread to make Release_Store - PlatformThread::Sleep(TimeDelta::FromMilliseconds(100)); - base::subtle::Acquire_Load(value_); - } - private: - base::subtle::Atomic32 *value_; -}; - -void RunInParallel(PlatformThread::Delegate *d1, PlatformThread::Delegate *d2) { - PlatformThreadHandle a; - PlatformThreadHandle b; - PlatformThread::Create(0, d1, &a); - PlatformThread::Create(0, d2, &b); - PlatformThread::Join(a); - PlatformThread::Join(b); -} - -#if defined(THREAD_SANITIZER) -void DataRace() { - bool *shared = new bool(false); - TOOLS_SANITY_TEST_CONCURRENT_THREAD thread1(shared), thread2(shared); - RunInParallel(&thread1, &thread2); - EXPECT_TRUE(*shared); - delete shared; - // We're in a death test - crash. - CHECK(0); -} -#endif - -} // namespace - -#if defined(THREAD_SANITIZER) -// A data race detector should report an error in this test. -TEST(ToolsSanityTest, DataRace) { - // The suppression regexp must match that in base/debug/tsan_suppressions.cc. - EXPECT_DEATH(DataRace(), "1 race:base/tools_sanity_unittest.cc"); -} -#endif - -TEST(ToolsSanityTest, AnnotateBenignRace) { - bool shared = false; - ANNOTATE_BENIGN_RACE(&shared, "Intentional race - make sure doesn't show up"); - TOOLS_SANITY_TEST_CONCURRENT_THREAD thread1(&shared), thread2(&shared); - RunInParallel(&thread1, &thread2); - EXPECT_TRUE(shared); -} - -TEST(ToolsSanityTest, AtomicsAreIgnored) { - base::subtle::Atomic32 shared = 0; - ReleaseStoreThread thread1(&shared); - AcquireLoadThread thread2(&shared); - RunInParallel(&thread1, &thread2); - EXPECT_EQ(kMagicValue, shared); -} - -#if defined(CFI_ERROR_MSG) -class A { - public: - A(): n_(0) {} - virtual void f() { n_++; } - protected: - int n_; -}; - -class B: public A { - public: - void f() override { n_--; } -}; - -class C: public B { - public: - void f() override { n_ += 2; } -}; - -NOINLINE void KillVptrAndCall(A *obj) { - *reinterpret_cast<void **>(obj) = 0; - obj->f(); -} - -TEST(ToolsSanityTest, BadVirtualCallNull) { - A a; - B b; - EXPECT_DEATH({ KillVptrAndCall(&a); KillVptrAndCall(&b); }, CFI_ERROR_MSG); -} - -NOINLINE void OverwriteVptrAndCall(B *obj, A *vptr) { - *reinterpret_cast<void **>(obj) = *reinterpret_cast<void **>(vptr); - obj->f(); -} - -TEST(ToolsSanityTest, BadVirtualCallWrongType) { - A a; - B b; - C c; - EXPECT_DEATH({ OverwriteVptrAndCall(&b, &a); OverwriteVptrAndCall(&b, &c); }, - CFI_ERROR_MSG); -} - -#endif // CFI_ERROR_MSG - -#undef CFI_ERROR_MSG -#undef MAYBE_AccessesToNewMemory -#undef MAYBE_AccessesToMallocMemory -#undef MAYBE_ArrayDeletedWithoutBraces -#undef MAYBE_SingleElementDeletedWithBraces -#undef HARMFUL_ACCESS -#undef HARMFUL_ACCESS_IS_NOOP - -} // namespace base
diff --git a/base/trace_event/blame_context_unittest.cc b/base/trace_event/blame_context_unittest.cc deleted file mode 100644 index 12e7857..0000000 --- a/base/trace_event/blame_context_unittest.cc +++ /dev/null
@@ -1,175 +0,0 @@ -// 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/trace_event/blame_context.h" - -#include "base/json/json_writer.h" -#include "base/message_loop/message_loop.h" -#include "base/test/trace_event_analyzer.h" -#include "base/trace_event/trace_event_argument.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace trace_event { -namespace { - -const char kTestBlameContextCategory[] = "test"; -const char kDisabledTestBlameContextCategory[] = "disabled-by-default-test"; -const char kTestBlameContextName[] = "TestBlameContext"; -const char kTestBlameContextType[] = "TestBlameContextType"; -const char kTestBlameContextScope[] = "TestBlameContextScope"; - -class TestBlameContext : public BlameContext { - public: - explicit TestBlameContext(int id) - : BlameContext(kTestBlameContextCategory, - kTestBlameContextName, - kTestBlameContextType, - kTestBlameContextScope, - id, - nullptr) {} - - TestBlameContext(int id, const TestBlameContext& parent) - : BlameContext(kTestBlameContextCategory, - kTestBlameContextName, - kTestBlameContextType, - kTestBlameContextScope, - id, - &parent) {} - - protected: - void AsValueInto(trace_event::TracedValue* state) override { - BlameContext::AsValueInto(state); - state->SetBoolean("crossStreams", false); - } -}; - -class DisabledTestBlameContext : public BlameContext { - public: - explicit DisabledTestBlameContext(int id) - : BlameContext(kDisabledTestBlameContextCategory, - kTestBlameContextName, - kTestBlameContextType, - kTestBlameContextScope, - id, - nullptr) {} -}; - -class BlameContextTest : public testing::Test { - protected: - MessageLoop loop_; -}; - -TEST_F(BlameContextTest, EnterAndLeave) { - using trace_analyzer::Query; - trace_analyzer::Start("*"); - { - TestBlameContext blame_context(0x1234); - blame_context.Initialize(); - blame_context.Enter(); - blame_context.Leave(); - } - auto analyzer = trace_analyzer::Stop(); - - trace_analyzer::TraceEventVector events; - Query q = Query::EventPhaseIs(TRACE_EVENT_PHASE_ENTER_CONTEXT) || - Query::EventPhaseIs(TRACE_EVENT_PHASE_LEAVE_CONTEXT); - analyzer->FindEvents(q, &events); - - EXPECT_EQ(2u, events.size()); - EXPECT_EQ(TRACE_EVENT_PHASE_ENTER_CONTEXT, events[0]->phase); - EXPECT_EQ(kTestBlameContextCategory, events[0]->category); - EXPECT_EQ(kTestBlameContextName, events[0]->name); - EXPECT_EQ("0x1234", events[0]->id); - EXPECT_EQ(TRACE_EVENT_PHASE_LEAVE_CONTEXT, events[1]->phase); - EXPECT_EQ(kTestBlameContextCategory, events[1]->category); - EXPECT_EQ(kTestBlameContextName, events[1]->name); - EXPECT_EQ("0x1234", events[1]->id); -} - -TEST_F(BlameContextTest, DifferentCategories) { - // Ensure there is no cross talk between blame contexts from different - // categories. - using trace_analyzer::Query; - trace_analyzer::Start("*"); - { - TestBlameContext blame_context(0x1234); - DisabledTestBlameContext disabled_blame_context(0x5678); - blame_context.Initialize(); - blame_context.Enter(); - blame_context.Leave(); - disabled_blame_context.Initialize(); - disabled_blame_context.Enter(); - disabled_blame_context.Leave(); - } - auto analyzer = trace_analyzer::Stop(); - - trace_analyzer::TraceEventVector events; - Query q = Query::EventPhaseIs(TRACE_EVENT_PHASE_ENTER_CONTEXT) || - Query::EventPhaseIs(TRACE_EVENT_PHASE_LEAVE_CONTEXT); - analyzer->FindEvents(q, &events); - - // None of the events from the disabled-by-default category should show up. - EXPECT_EQ(2u, events.size()); - EXPECT_EQ(TRACE_EVENT_PHASE_ENTER_CONTEXT, events[0]->phase); - EXPECT_EQ(kTestBlameContextCategory, events[0]->category); - EXPECT_EQ(kTestBlameContextName, events[0]->name); - EXPECT_EQ("0x1234", events[0]->id); - EXPECT_EQ(TRACE_EVENT_PHASE_LEAVE_CONTEXT, events[1]->phase); - EXPECT_EQ(kTestBlameContextCategory, events[1]->category); - EXPECT_EQ(kTestBlameContextName, events[1]->name); - EXPECT_EQ("0x1234", events[1]->id); -} - -TEST_F(BlameContextTest, TakeSnapshot) { - using trace_analyzer::Query; - trace_analyzer::Start("*"); - { - TestBlameContext parent_blame_context(0x5678); - TestBlameContext blame_context(0x1234, parent_blame_context); - parent_blame_context.Initialize(); - blame_context.Initialize(); - blame_context.TakeSnapshot(); - } - auto analyzer = trace_analyzer::Stop(); - - trace_analyzer::TraceEventVector events; - Query q = Query::EventPhaseIs(TRACE_EVENT_PHASE_SNAPSHOT_OBJECT); - analyzer->FindEvents(q, &events); - - // We should have 3 snapshots: one for both calls to Initialize() and one from - // the explicit call to TakeSnapshot(). - EXPECT_EQ(3u, events.size()); - EXPECT_EQ(kTestBlameContextCategory, events[0]->category); - EXPECT_EQ(kTestBlameContextType, events[0]->name); - EXPECT_EQ("0x5678", events[0]->id); - EXPECT_TRUE(events[0]->HasArg("snapshot")); - - EXPECT_EQ(kTestBlameContextCategory, events[1]->category); - EXPECT_EQ(kTestBlameContextType, events[1]->name); - EXPECT_EQ("0x1234", events[1]->id); - EXPECT_TRUE(events[0]->HasArg("snapshot")); - - EXPECT_EQ(kTestBlameContextCategory, events[2]->category); - EXPECT_EQ(kTestBlameContextType, events[2]->name); - EXPECT_EQ("0x1234", events[2]->id); - EXPECT_TRUE(events[0]->HasArg("snapshot")); - - const char kExpectedSnapshotJson[] = - "{" - "\"crossStreams\":false," - "\"parent\":{" - "\"id_ref\":\"0x5678\"," - "\"scope\":\"TestBlameContextScope\"" - "}" - "}"; - - std::string snapshot_json; - JSONWriter::Write(*events[2]->GetKnownArgAsValue("snapshot"), &snapshot_json); - EXPECT_EQ(kExpectedSnapshotJson, snapshot_json); -} - -} // namepace -} // namespace trace_event -} // namespace base
diff --git a/base/trace_event/etw_manifest/BUILD.gn b/base/trace_event/etw_manifest/BUILD.gn deleted file mode 100644 index 19c4ecf..0000000 --- a/base/trace_event/etw_manifest/BUILD.gn +++ /dev/null
@@ -1,29 +0,0 @@ -# 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. - -import("//build/win/message_compiler.gni") - -assert(is_win, "This only runs on Windows.") - -message_compiler("chrome_events_win") { - visibility = [ - "//base/*", - "//chrome:main_dll", - ] - - sources = [ - "chrome_events_win.man", - ] - - user_mode_logging = true - - # The only code generated from chrome_events_win.man is a header file that - # is included by trace_event_etw_export_win.cc, so there is no need to - # compile any generated code. The other thing which compile_generated_code - # controls in this context is linking in the .res file generated from the - # manifest. However this is only needed for ETW provider registration which - # is done by UIforETW (https://github.com/google/UIforETW) and therefore the - # manifest resource can be skipped in Chrome. - compile_generated_code = false -}
diff --git a/base/trace_event/event_name_filter_unittest.cc b/base/trace_event/event_name_filter_unittest.cc deleted file mode 100644 index 134be0d..0000000 --- a/base/trace_event/event_name_filter_unittest.cc +++ /dev/null
@@ -1,42 +0,0 @@ -// 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/trace_event/event_name_filter.h" - -#include "base/memory/ptr_util.h" -#include "base/trace_event/trace_event_impl.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace trace_event { - -const TraceEvent& MakeTraceEvent(const char* name) { - static TraceEvent event; - event.Reset(); - event.Initialize(0, TimeTicks(), ThreadTicks(), 'b', nullptr, name, "", 0, 0, - 0, nullptr, nullptr, nullptr, nullptr, 0); - return event; -} - -TEST(TraceEventNameFilterTest, Whitelist) { - auto empty_whitelist = - std::make_unique<EventNameFilter::EventNamesWhitelist>(); - auto filter = std::make_unique<EventNameFilter>(std::move(empty_whitelist)); - - // No events should be filtered if the whitelist is empty. - EXPECT_FALSE(filter->FilterTraceEvent(MakeTraceEvent("foo"))); - - auto whitelist = std::make_unique<EventNameFilter::EventNamesWhitelist>(); - whitelist->insert("foo"); - whitelist->insert("bar"); - filter = std::make_unique<EventNameFilter>(std::move(whitelist)); - EXPECT_TRUE(filter->FilterTraceEvent(MakeTraceEvent("foo"))); - EXPECT_FALSE(filter->FilterTraceEvent(MakeTraceEvent("fooz"))); - EXPECT_FALSE(filter->FilterTraceEvent(MakeTraceEvent("afoo"))); - EXPECT_TRUE(filter->FilterTraceEvent(MakeTraceEvent("bar"))); - EXPECT_FALSE(filter->FilterTraceEvent(MakeTraceEvent("foobar"))); -} - -} // namespace trace_event -} // namespace base
diff --git a/base/trace_event/heap_profiler_allocation_context_tracker_unittest.cc b/base/trace_event/heap_profiler_allocation_context_tracker_unittest.cc deleted file mode 100644 index c26149e..0000000 --- a/base/trace_event/heap_profiler_allocation_context_tracker_unittest.cc +++ /dev/null
@@ -1,350 +0,0 @@ -// 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 <stddef.h> - -#include <iterator> - -#include "base/memory/ref_counted.h" -#include "base/pending_task.h" -#include "base/trace_event/heap_profiler.h" -#include "base/trace_event/heap_profiler_allocation_context.h" -#include "base/trace_event/heap_profiler_allocation_context_tracker.h" -#include "base/trace_event/memory_dump_manager.h" -#include "base/trace_event/trace_event.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace trace_event { - -// Define all strings once, because the pseudo stack requires pointer equality, -// and string interning is unreliable. -const char kThreadName[] = "TestThread"; -const char kCupcake[] = "Cupcake"; -const char kDonut[] = "Donut"; -const char kEclair[] = "Eclair"; -const char kFroyo[] = "Froyo"; -const char kGingerbread[] = "Gingerbread"; - -const char kFilteringTraceConfig[] = - "{" - " \"event_filters\": [" - " {" - " \"excluded_categories\": []," - " \"filter_args\": {}," - " \"filter_predicate\": \"heap_profiler_predicate\"," - " \"included_categories\": [" - " \"*\"," - " \"" TRACE_DISABLED_BY_DEFAULT("Testing") "\"]" - " }" - " ]" - "}"; - -// Asserts that the fixed-size array |expected_backtrace| matches the backtrace -// in |AllocationContextTracker::GetContextSnapshot|. -template <size_t N> -void AssertBacktraceEquals(const StackFrame(&expected_backtrace)[N]) { - AllocationContext ctx; - ASSERT_TRUE(AllocationContextTracker::GetInstanceForCurrentThread() - ->GetContextSnapshot(&ctx)); - - auto* actual = std::begin(ctx.backtrace.frames); - auto* actual_bottom = actual + ctx.backtrace.frame_count; - auto expected = std::begin(expected_backtrace); - auto expected_bottom = std::end(expected_backtrace); - - // Note that this requires the pointers to be equal, this is not doing a deep - // string comparison. - for (; actual != actual_bottom && expected != expected_bottom; - actual++, expected++) - ASSERT_EQ(*expected, *actual); - - // Ensure that the height of the stacks is the same. - ASSERT_EQ(actual, actual_bottom); - ASSERT_EQ(expected, expected_bottom); -} - -void AssertBacktraceContainsOnlyThreadName() { - StackFrame t = StackFrame::FromThreadName(kThreadName); - AllocationContext ctx; - ASSERT_TRUE(AllocationContextTracker::GetInstanceForCurrentThread() - ->GetContextSnapshot(&ctx)); - - ASSERT_EQ(1u, ctx.backtrace.frame_count); - ASSERT_EQ(t, ctx.backtrace.frames[0]); -} - -class AllocationContextTrackerTest : public testing::Test { - public: - void SetUp() override { - AllocationContextTracker::SetCaptureMode( - AllocationContextTracker::CaptureMode::PSEUDO_STACK); - // Enabling memory-infra category sets default memory dump config which - // includes filters for capturing pseudo stack. - TraceConfig config(kFilteringTraceConfig); - TraceLog::GetInstance()->SetEnabled(config, TraceLog::FILTERING_MODE); - AllocationContextTracker::SetCurrentThreadName(kThreadName); - } - - void TearDown() override { - AllocationContextTracker::SetCaptureMode( - AllocationContextTracker::CaptureMode::DISABLED); - TraceLog::GetInstance()->SetDisabled(TraceLog::FILTERING_MODE); - } -}; - -// Check that |TRACE_EVENT| macros push and pop to the pseudo stack correctly. -TEST_F(AllocationContextTrackerTest, PseudoStackScopedTrace) { - StackFrame t = StackFrame::FromThreadName(kThreadName); - StackFrame c = StackFrame::FromTraceEventName(kCupcake); - StackFrame d = StackFrame::FromTraceEventName(kDonut); - StackFrame e = StackFrame::FromTraceEventName(kEclair); - StackFrame f = StackFrame::FromTraceEventName(kFroyo); - - AssertBacktraceContainsOnlyThreadName(); - - { - TRACE_EVENT0("Testing", kCupcake); - StackFrame frame_c[] = {t, c}; - AssertBacktraceEquals(frame_c); - - { - TRACE_EVENT0("Testing", kDonut); - StackFrame frame_cd[] = {t, c, d}; - AssertBacktraceEquals(frame_cd); - } - - AssertBacktraceEquals(frame_c); - - { - TRACE_EVENT0("Testing", kEclair); - StackFrame frame_ce[] = {t, c, e}; - AssertBacktraceEquals(frame_ce); - } - - { - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("NotTesting"), kDonut); - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("Testing"), kCupcake); - StackFrame frame_cc[] = {t, c, c}; - AssertBacktraceEquals(frame_cc); - } - - AssertBacktraceEquals(frame_c); - } - - AssertBacktraceContainsOnlyThreadName(); - - { - TRACE_EVENT0("Testing", kFroyo); - StackFrame frame_f[] = {t, f}; - AssertBacktraceEquals(frame_f); - } - - AssertBacktraceContainsOnlyThreadName(); -} - -// Same as |PseudoStackScopedTrace|, but now test the |TRACE_EVENT_BEGIN| and -// |TRACE_EVENT_END| macros. -TEST_F(AllocationContextTrackerTest, PseudoStackBeginEndTrace) { - StackFrame t = StackFrame::FromThreadName(kThreadName); - StackFrame c = StackFrame::FromTraceEventName(kCupcake); - StackFrame d = StackFrame::FromTraceEventName(kDonut); - StackFrame e = StackFrame::FromTraceEventName(kEclair); - StackFrame f = StackFrame::FromTraceEventName(kFroyo); - - StackFrame frame_c[] = {t, c}; - StackFrame frame_cd[] = {t, c, d}; - StackFrame frame_ce[] = {t, c, e}; - StackFrame frame_f[] = {t, f}; - - AssertBacktraceContainsOnlyThreadName(); - - TRACE_EVENT_BEGIN0("Testing", kCupcake); - AssertBacktraceEquals(frame_c); - - TRACE_EVENT_BEGIN0("Testing", kDonut); - AssertBacktraceEquals(frame_cd); - TRACE_EVENT_END0("Testing", kDonut); - - AssertBacktraceEquals(frame_c); - - TRACE_EVENT_BEGIN0("Testing", kEclair); - AssertBacktraceEquals(frame_ce); - TRACE_EVENT_END0("Testing", kEclair); - - AssertBacktraceEquals(frame_c); - TRACE_EVENT_END0("Testing", kCupcake); - - AssertBacktraceContainsOnlyThreadName(); - - TRACE_EVENT_BEGIN0("Testing", kFroyo); - AssertBacktraceEquals(frame_f); - TRACE_EVENT_END0("Testing", kFroyo); - - AssertBacktraceContainsOnlyThreadName(); -} - -TEST_F(AllocationContextTrackerTest, PseudoStackMixedTrace) { - StackFrame t = StackFrame::FromThreadName(kThreadName); - StackFrame c = StackFrame::FromTraceEventName(kCupcake); - StackFrame d = StackFrame::FromTraceEventName(kDonut); - StackFrame e = StackFrame::FromTraceEventName(kEclair); - StackFrame f = StackFrame::FromTraceEventName(kFroyo); - - StackFrame frame_c[] = {t, c}; - StackFrame frame_cd[] = {t, c, d}; - StackFrame frame_e[] = {t, e}; - StackFrame frame_ef[] = {t, e, f}; - - AssertBacktraceContainsOnlyThreadName(); - - TRACE_EVENT_BEGIN0("Testing", kCupcake); - AssertBacktraceEquals(frame_c); - - { - TRACE_EVENT0("Testing", kDonut); - AssertBacktraceEquals(frame_cd); - } - - AssertBacktraceEquals(frame_c); - TRACE_EVENT_END0("Testing", kCupcake); - AssertBacktraceContainsOnlyThreadName(); - - { - TRACE_EVENT0("Testing", kEclair); - AssertBacktraceEquals(frame_e); - - TRACE_EVENT_BEGIN0("Testing", kFroyo); - AssertBacktraceEquals(frame_ef); - TRACE_EVENT_END0("Testing", kFroyo); - AssertBacktraceEquals(frame_e); - } - - AssertBacktraceContainsOnlyThreadName(); -} - -TEST_F(AllocationContextTrackerTest, MixedStackWithProgramCounter) { - StackFrame t = StackFrame::FromThreadName(kThreadName); - StackFrame c = StackFrame::FromTraceEventName(kCupcake); - StackFrame f = StackFrame::FromTraceEventName(kFroyo); - const void* pc1 = reinterpret_cast<void*>(0x1000); - const void* pc2 = reinterpret_cast<void*>(0x2000); - StackFrame n1 = StackFrame::FromProgramCounter(pc1); - StackFrame n2 = StackFrame::FromProgramCounter(pc2); - - StackFrame frame_c[] = {t, c}; - StackFrame frame_cd[] = {t, c, n1}; - StackFrame frame_e[] = {t, n2, n1}; - StackFrame frame_ef[] = {t, n2, n1, f}; - - AssertBacktraceContainsOnlyThreadName(); - - AllocationContextTracker::SetCaptureMode( - AllocationContextTracker::CaptureMode::MIXED_STACK); - - TRACE_EVENT_BEGIN0("Testing", kCupcake); - AssertBacktraceEquals(frame_c); - - { - TRACE_HEAP_PROFILER_API_SCOPED_WITH_PROGRAM_COUNTER e1(pc1); - AssertBacktraceEquals(frame_cd); - } - - AssertBacktraceEquals(frame_c); - TRACE_EVENT_END0("Testing", kCupcake); - AssertBacktraceContainsOnlyThreadName(); - - { - TRACE_HEAP_PROFILER_API_SCOPED_WITH_PROGRAM_COUNTER e1(pc2); - TRACE_HEAP_PROFILER_API_SCOPED_WITH_PROGRAM_COUNTER e2(pc1); - AssertBacktraceEquals(frame_e); - - TRACE_EVENT0("Testing", kFroyo); - AssertBacktraceEquals(frame_ef); - } - - AssertBacktraceContainsOnlyThreadName(); - AllocationContextTracker::SetCaptureMode( - AllocationContextTracker::CaptureMode::DISABLED); -} - -TEST_F(AllocationContextTrackerTest, BacktraceTakesTop) { - StackFrame t = StackFrame::FromThreadName(kThreadName); - StackFrame c = StackFrame::FromTraceEventName(kCupcake); - StackFrame f = StackFrame::FromTraceEventName(kFroyo); - - // Push 11 events onto the pseudo stack. - TRACE_EVENT0("Testing", kCupcake); - TRACE_EVENT0("Testing", kCupcake); - TRACE_EVENT0("Testing", kCupcake); - - TRACE_EVENT0("Testing", kCupcake); - TRACE_EVENT0("Testing", kCupcake); - TRACE_EVENT0("Testing", kCupcake); - TRACE_EVENT0("Testing", kCupcake); - - TRACE_EVENT0("Testing", kCupcake); - TRACE_EVENT0("Testing", kDonut); - TRACE_EVENT0("Testing", kEclair); - TRACE_EVENT0("Testing", kFroyo); - - { - TRACE_EVENT0("Testing", kGingerbread); - AllocationContext ctx; - ASSERT_TRUE(AllocationContextTracker::GetInstanceForCurrentThread() - ->GetContextSnapshot(&ctx)); - - // The pseudo stack relies on pointer equality, not deep string comparisons. - ASSERT_EQ(t, ctx.backtrace.frames[0]); - ASSERT_EQ(c, ctx.backtrace.frames[1]); - ASSERT_EQ(f, ctx.backtrace.frames[11]); - } - - { - AllocationContext ctx; - ASSERT_TRUE(AllocationContextTracker::GetInstanceForCurrentThread() - ->GetContextSnapshot(&ctx)); - ASSERT_EQ(t, ctx.backtrace.frames[0]); - ASSERT_EQ(c, ctx.backtrace.frames[1]); - ASSERT_EQ(f, ctx.backtrace.frames[11]); - } -} - -TEST_F(AllocationContextTrackerTest, TrackCategoryName) { - const char kContext1[] = "context1"; - const char kContext2[] = "context2"; - { - // The context from the scoped task event should be used as type name. - TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION event1(kContext1); - AllocationContext ctx1; - ASSERT_TRUE(AllocationContextTracker::GetInstanceForCurrentThread() - ->GetContextSnapshot(&ctx1)); - ASSERT_EQ(kContext1, ctx1.type_name); - - // In case of nested events, the last event's context should be used. - TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION event2(kContext2); - AllocationContext ctx2; - ASSERT_TRUE(AllocationContextTracker::GetInstanceForCurrentThread() - ->GetContextSnapshot(&ctx2)); - ASSERT_EQ(kContext2, ctx2.type_name); - } - - // Type should be nullptr without task event. - AllocationContext ctx; - ASSERT_TRUE(AllocationContextTracker::GetInstanceForCurrentThread() - ->GetContextSnapshot(&ctx)); - ASSERT_FALSE(ctx.type_name); -} - -TEST_F(AllocationContextTrackerTest, IgnoreAllocationTest) { - TRACE_EVENT0("Testing", kCupcake); - TRACE_EVENT0("Testing", kDonut); - HEAP_PROFILER_SCOPED_IGNORE; - AllocationContext ctx; - ASSERT_FALSE(AllocationContextTracker::GetInstanceForCurrentThread() - ->GetContextSnapshot(&ctx)); -} - -} // namespace trace_event -} // namespace base
diff --git a/base/trace_event/heap_profiler_heap_dump_writer_unittest.cc b/base/trace_event/heap_profiler_heap_dump_writer_unittest.cc deleted file mode 100644 index 93e8fee..0000000 --- a/base/trace_event/heap_profiler_heap_dump_writer_unittest.cc +++ /dev/null
@@ -1,330 +0,0 @@ -// 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/trace_event/heap_profiler_heap_dump_writer.h" - -#include <stddef.h> - -#include <memory> -#include <set> -#include <string> - -#include "base/json/json_reader.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/trace_event/heap_profiler_allocation_context.h" -#include "base/trace_event/heap_profiler_stack_frame_deduplicator.h" -#include "base/trace_event/heap_profiler_type_name_deduplicator.h" -#include "base/trace_event/trace_event_argument.h" -#include "base/values.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -using base::trace_event::StackFrame; - -// Define all strings once, because the deduplicator requires pointer equality, -// and string interning is unreliable. -StackFrame kBrowserMain = StackFrame::FromTraceEventName("BrowserMain"); -StackFrame kRendererMain = StackFrame::FromTraceEventName("RendererMain"); -StackFrame kCreateWidget = StackFrame::FromTraceEventName("CreateWidget"); -StackFrame kInitialize = StackFrame::FromTraceEventName("Initialize"); -StackFrame kGetBitmap = StackFrame::FromTraceEventName("GetBitmap"); - -const char kInt[] = "int"; -const char kBool[] = "bool"; -const char kString[] = "string"; - -} // namespace - -namespace base { -namespace trace_event { -namespace internal { - -std::unique_ptr<const Value> WriteAndReadBack(const std::set<Entry>& entries) { - std::unique_ptr<TracedValue> traced_value = Serialize(entries); - std::string json; - traced_value->AppendAsTraceFormat(&json); - return JSONReader::Read(json); -} - -std::unique_ptr<const DictionaryValue> WriteAndReadBackEntry(Entry entry) { - std::set<Entry> input_entries; - input_entries.insert(entry); - - std::unique_ptr<const Value> json_dict = WriteAndReadBack(input_entries); - - // Note: Ideally these should use |ASSERT_TRUE| instead of |EXPECT_TRUE|, but - // |ASSERT_TRUE| can only be used in void functions. - const DictionaryValue* dictionary; - EXPECT_TRUE(json_dict->GetAsDictionary(&dictionary)); - - const ListValue* json_entries; - EXPECT_TRUE(dictionary->GetList("entries", &json_entries)); - - const DictionaryValue* json_entry; - EXPECT_TRUE(json_entries->GetDictionary(0, &json_entry)); - - return json_entry->CreateDeepCopy(); -} - -// Given a desired stack frame ID and type ID, looks up the entry in the set and -// asserts that it is present and has the expected size and count. -void AssertSizeAndCountEq(const std::set<Entry>& entries, - int stack_frame_id, - int type_id, - const AllocationMetrics& expected) { - // The comparison operator for |Entry| does not take size into account, so by - // setting only stack frame ID and type ID, the real entry can be found. - Entry entry; - entry.stack_frame_id = stack_frame_id; - entry.type_id = type_id; - auto it = entries.find(entry); - - ASSERT_NE(entries.end(), it) << "No entry found for sf = " << stack_frame_id - << ", type = " << type_id << "."; - ASSERT_EQ(expected.size, it->size) << "Wrong size for sf = " << stack_frame_id - << ", type = " << type_id << "."; - ASSERT_EQ(expected.count, it->count) - << "Wrong count for sf = " << stack_frame_id << ", type = " << type_id - << "."; -} - -// Given a desired stack frame ID and type ID, asserts that no entry was dumped -// for that that particular combination of stack frame and type. -void AssertNotDumped(const std::set<Entry>& entries, - int stack_frame_id, - int type_id) { - // The comparison operator for |Entry| does not take size into account, so by - // setting only stack frame ID and type ID, the real entry can be found. - Entry entry; - entry.stack_frame_id = stack_frame_id; - entry.type_id = type_id; - auto it = entries.find(entry); - ASSERT_EQ(entries.end(), it) - << "Entry should not be present for sf = " << stack_frame_id - << ", type = " << type_id << "."; -} - -TEST(HeapDumpWriterTest, BacktraceIndex) { - Entry entry; - entry.stack_frame_id = -1; // -1 means empty backtrace. - entry.type_id = 0; - entry.size = 1; - entry.count = 1; - - std::unique_ptr<const DictionaryValue> json_entry = - WriteAndReadBackEntry(entry); - - // For an empty backtrace, the "bt" key cannot reference a stack frame. - // Instead it should be set to the empty string. - std::string backtrace_index; - ASSERT_TRUE(json_entry->GetString("bt", &backtrace_index)); - ASSERT_EQ("", backtrace_index); - - // Also verify that a non-negative backtrace index is dumped properly. - entry.stack_frame_id = 2; - json_entry = WriteAndReadBackEntry(entry); - ASSERT_TRUE(json_entry->GetString("bt", &backtrace_index)); - ASSERT_EQ("2", backtrace_index); -} - -TEST(HeapDumpWriterTest, TypeId) { - Entry entry; - entry.type_id = -1; // -1 means sum over all types. - entry.stack_frame_id = 0; - entry.size = 1; - entry.count = 1; - - std::unique_ptr<const DictionaryValue> json_entry = - WriteAndReadBackEntry(entry); - - // Entries for the cumulative size of all types should not have the "type" - // key set. - ASSERT_FALSE(json_entry->HasKey("type")); - - // Also verify that a non-negative type ID is dumped properly. - entry.type_id = 2; - json_entry = WriteAndReadBackEntry(entry); - std::string type_id; - ASSERT_TRUE(json_entry->GetString("type", &type_id)); - ASSERT_EQ("2", type_id); -} - -TEST(HeapDumpWriterTest, SizeAndCountAreHexadecimal) { - // Take a number between 2^63 and 2^64 (or between 2^31 and 2^32 if |size_t| - // is not 64 bits). - const size_t large_value = - sizeof(size_t) == 8 ? 0xffffffffffffffc5 : 0xffffff9d; - const char* large_value_str = - sizeof(size_t) == 8 ? "ffffffffffffffc5" : "ffffff9d"; - Entry entry; - entry.type_id = 0; - entry.stack_frame_id = 0; - entry.size = large_value; - entry.count = large_value; - - std::unique_ptr<const DictionaryValue> json_entry = - WriteAndReadBackEntry(entry); - - std::string size; - ASSERT_TRUE(json_entry->GetString("size", &size)); - ASSERT_EQ(large_value_str, size); - - std::string count; - ASSERT_TRUE(json_entry->GetString("count", &count)); - ASSERT_EQ(large_value_str, count); -} - -TEST(HeapDumpWriterTest, BacktraceTypeNameTable) { - std::unordered_map<AllocationContext, AllocationMetrics> metrics_by_context; - - AllocationContext ctx; - ctx.backtrace.frames[0] = kBrowserMain; - ctx.backtrace.frames[1] = kCreateWidget; - ctx.backtrace.frame_count = 2; - ctx.type_name = kInt; - - // 10 bytes with context { type: int, bt: [BrowserMain, CreateWidget] }. - metrics_by_context[ctx] = {10, 5}; - - ctx.type_name = kBool; - - // 18 bytes with context { type: bool, bt: [BrowserMain, CreateWidget] }. - metrics_by_context[ctx] = {18, 18}; - - ctx.backtrace.frames[0] = kRendererMain; - ctx.backtrace.frames[1] = kInitialize; - ctx.backtrace.frame_count = 2; - - // 30 bytes with context { type: bool, bt: [RendererMain, Initialize] }. - metrics_by_context[ctx] = {30, 30}; - - ctx.type_name = kString; - - // 19 bytes with context { type: string, bt: [RendererMain, Initialize] }. - metrics_by_context[ctx] = {19, 4}; - - // At this point the heap looks like this: - // - // | | CrWidget <- BrMain | Init <- RenMain | Sum | - // +--------+--------------------+-----------------+-------------+ - // | | size count | size count | size count | - // | int | 10 5 | 0 0 | 10 5 | - // | bool | 18 18 | 30 30 | 48 48 | - // | string | 0 0 | 19 4 | 19 4 | - // +--------+--------------------+-----------------+-------------+ - // | Sum | 28 23 | 49 34 | 77 57 | - - auto stack_frame_deduplicator = WrapUnique(new StackFrameDeduplicator); - auto type_name_deduplicator = WrapUnique(new TypeNameDeduplicator); - HeapDumpWriter writer(stack_frame_deduplicator.get(), - type_name_deduplicator.get(), 10u); - const std::set<Entry>& dump = writer.Summarize(metrics_by_context); - - // Get the indices of the backtraces and types by adding them again to the - // deduplicator. Because they were added before, the same number is returned. - StackFrame bt0[] = {kRendererMain, kInitialize}; - StackFrame bt1[] = {kBrowserMain, kCreateWidget}; - int bt_renderer_main = stack_frame_deduplicator->Insert(bt0, bt0 + 1); - int bt_browser_main = stack_frame_deduplicator->Insert(bt1, bt1 + 1); - int bt_renderer_main_initialize = - stack_frame_deduplicator->Insert(bt0, bt0 + 2); - int bt_browser_main_create_widget = - stack_frame_deduplicator->Insert(bt1, bt1 + 2); - int type_id_int = type_name_deduplicator->Insert(kInt); - int type_id_bool = type_name_deduplicator->Insert(kBool); - int type_id_string = type_name_deduplicator->Insert(kString); - - // Full heap should have size 77. - AssertSizeAndCountEq(dump, -1, -1, {77, 57}); - - // 49 bytes in 34 chunks were allocated in RendererMain and children. Also - // check the type breakdown. - AssertSizeAndCountEq(dump, bt_renderer_main, -1, {49, 34}); - AssertSizeAndCountEq(dump, bt_renderer_main, type_id_bool, {30, 30}); - AssertSizeAndCountEq(dump, bt_renderer_main, type_id_string, {19, 4}); - - // 28 bytes in 23 chunks were allocated in BrowserMain and children. Also - // check the type breakdown. - AssertSizeAndCountEq(dump, bt_browser_main, -1, {28, 23}); - AssertSizeAndCountEq(dump, bt_browser_main, type_id_int, {10, 5}); - AssertSizeAndCountEq(dump, bt_browser_main, type_id_bool, {18, 18}); - - // In this test all bytes are allocated in leaf nodes, so check again one - // level deeper. - AssertSizeAndCountEq(dump, bt_renderer_main_initialize, -1, {49, 34}); - AssertSizeAndCountEq(dump, bt_renderer_main_initialize, type_id_bool, - {30, 30}); - AssertSizeAndCountEq(dump, bt_renderer_main_initialize, type_id_string, - {19, 4}); - AssertSizeAndCountEq(dump, bt_browser_main_create_widget, -1, {28, 23}); - AssertSizeAndCountEq(dump, bt_browser_main_create_widget, type_id_int, - {10, 5}); - AssertSizeAndCountEq(dump, bt_browser_main_create_widget, type_id_bool, - {18, 18}); - - // The type breakdown of the entrie heap should have been dumped as well. - AssertSizeAndCountEq(dump, -1, type_id_int, {10, 5}); - AssertSizeAndCountEq(dump, -1, type_id_bool, {48, 48}); - AssertSizeAndCountEq(dump, -1, type_id_string, {19, 4}); -} - -TEST(HeapDumpWriterTest, InsignificantValuesNotDumped) { - std::unordered_map<AllocationContext, AllocationMetrics> metrics_by_context; - - AllocationContext ctx; - ctx.backtrace.frames[0] = kBrowserMain; - ctx.backtrace.frames[1] = kCreateWidget; - ctx.backtrace.frame_count = 2; - - // 0.5 KiB and 1 chunk in BrowserMain -> CreateWidget itself. - metrics_by_context[ctx] = {512, 1}; - - // 1 MiB and 1 chunk in BrowserMain -> CreateWidget -> GetBitmap. - ctx.backtrace.frames[2] = kGetBitmap; - ctx.backtrace.frame_count = 3; - metrics_by_context[ctx] = {1024 * 1024, 1}; - - // 400B and 1 chunk in BrowserMain -> CreateWidget -> Initialize. - ctx.backtrace.frames[2] = kInitialize; - ctx.backtrace.frame_count = 3; - metrics_by_context[ctx] = {400, 1}; - - auto stack_frame_deduplicator = WrapUnique(new StackFrameDeduplicator); - auto type_name_deduplicator = WrapUnique(new TypeNameDeduplicator); - HeapDumpWriter writer(stack_frame_deduplicator.get(), - type_name_deduplicator.get(), 512u); - const std::set<Entry>& dump = writer.Summarize(metrics_by_context); - - // Get the indices of the backtraces and types by adding them again to the - // deduplicator. Because they were added before, the same number is returned. - StackFrame bt0[] = {kBrowserMain, kCreateWidget, kGetBitmap}; - StackFrame bt1[] = {kBrowserMain, kCreateWidget, kInitialize}; - int bt_browser_main = stack_frame_deduplicator->Insert(bt0, bt0 + 1); - int bt_create_widget = stack_frame_deduplicator->Insert(bt0, bt0 + 2); - int bt_get_bitmap = stack_frame_deduplicator->Insert(bt0, bt0 + 3); - int bt_initialize = stack_frame_deduplicator->Insert(bt1, bt1 + 3); - - // Full heap should have size of 1 MiB + .9 KiB and 3 chunks. - AssertSizeAndCountEq(dump, -1, -1 /* No type specified */, - {1024 * 1024 + 512 + 400, 3}); - - // |GetBitmap| allocated 1 MiB and 1 chunk. - AssertSizeAndCountEq(dump, bt_get_bitmap, -1, {1024 * 1024, 1}); - - // Because |GetBitmap| was dumped, all of its parent nodes should have been - // dumped too. |CreateWidget| has 1 MiB in |GetBitmap|, 400 bytes in - // |Initialize|, and 512 bytes of its own and each in 1 chunk. - AssertSizeAndCountEq(dump, bt_create_widget, -1, - {1024 * 1024 + 400 + 512, 3}); - AssertSizeAndCountEq(dump, bt_browser_main, -1, {1024 * 1024 + 400 + 512, 3}); - - // Initialize was not significant, it should not have been dumped. - AssertNotDumped(dump, bt_initialize, -1); -} - -} // namespace internal -} // namespace trace_event -} // namespace base
diff --git a/base/trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc b/base/trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc deleted file mode 100644 index 194c7aa..0000000 --- a/base/trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc +++ /dev/null
@@ -1,152 +0,0 @@ -// 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/trace_event/heap_profiler_stack_frame_deduplicator.h" - -#include <iterator> -#include <memory> - -#include "base/macros.h" -#include "base/trace_event/heap_profiler_allocation_context.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace trace_event { - -// Define all strings once, because the deduplicator requires pointer equality, -// and string interning is unreliable. -StackFrame kBrowserMain = StackFrame::FromTraceEventName("BrowserMain"); -StackFrame kRendererMain = StackFrame::FromTraceEventName("RendererMain"); -StackFrame kCreateWidget = StackFrame::FromTraceEventName("CreateWidget"); -StackFrame kInitialize = StackFrame::FromTraceEventName("Initialize"); -StackFrame kMalloc = StackFrame::FromTraceEventName("malloc"); - -TEST(StackFrameDeduplicatorTest, SingleBacktrace) { - StackFrame bt[] = {kBrowserMain, kCreateWidget, kMalloc}; - - // The call tree should look like this (index in brackets). - // - // BrowserMain [0] - // CreateWidget [1] - // malloc [2] - - std::unique_ptr<StackFrameDeduplicator> dedup(new StackFrameDeduplicator); - ASSERT_EQ(2, dedup->Insert(std::begin(bt), std::end(bt))); - - auto iter = dedup->begin(); - ASSERT_EQ(kBrowserMain, (iter + 0)->frame); - ASSERT_EQ(-1, (iter + 0)->parent_frame_index); - - ASSERT_EQ(kCreateWidget, (iter + 1)->frame); - ASSERT_EQ(0, (iter + 1)->parent_frame_index); - - ASSERT_EQ(kMalloc, (iter + 2)->frame); - ASSERT_EQ(1, (iter + 2)->parent_frame_index); - - ASSERT_TRUE(iter + 3 == dedup->end()); -} - -TEST(StackFrameDeduplicatorTest, SingleBacktraceWithNull) { - StackFrame null_frame = StackFrame::FromTraceEventName(nullptr); - StackFrame bt[] = {kBrowserMain, null_frame, kMalloc}; - - // Deduplicator doesn't care about what's inside StackFrames, - // and handles nullptr StackFrame values as any other. - // - // So the call tree should look like this (index in brackets). - // - // BrowserMain [0] - // (null) [1] - // malloc [2] - - std::unique_ptr<StackFrameDeduplicator> dedup(new StackFrameDeduplicator); - ASSERT_EQ(2, dedup->Insert(std::begin(bt), std::end(bt))); - - auto iter = dedup->begin(); - ASSERT_EQ(kBrowserMain, (iter + 0)->frame); - ASSERT_EQ(-1, (iter + 0)->parent_frame_index); - - ASSERT_EQ(null_frame, (iter + 1)->frame); - ASSERT_EQ(0, (iter + 1)->parent_frame_index); - - ASSERT_EQ(kMalloc, (iter + 2)->frame); - ASSERT_EQ(1, (iter + 2)->parent_frame_index); - - ASSERT_TRUE(iter + 3 == dedup->end()); -} - -// Test that there can be different call trees (there can be multiple bottom -// frames). Also verify that frames with the same name but a different caller -// are represented as distinct nodes. -TEST(StackFrameDeduplicatorTest, MultipleRoots) { - StackFrame bt0[] = {kBrowserMain, kCreateWidget}; - StackFrame bt1[] = {kRendererMain, kCreateWidget}; - - // The call tree should look like this (index in brackets). - // - // BrowserMain [0] - // CreateWidget [1] - // RendererMain [2] - // CreateWidget [3] - // - // Note that there will be two instances of CreateWidget, - // with different parents. - - std::unique_ptr<StackFrameDeduplicator> dedup(new StackFrameDeduplicator); - ASSERT_EQ(1, dedup->Insert(std::begin(bt0), std::end(bt0))); - ASSERT_EQ(3, dedup->Insert(std::begin(bt1), std::end(bt1))); - - auto iter = dedup->begin(); - ASSERT_EQ(kBrowserMain, (iter + 0)->frame); - ASSERT_EQ(-1, (iter + 0)->parent_frame_index); - - ASSERT_EQ(kCreateWidget, (iter + 1)->frame); - ASSERT_EQ(0, (iter + 1)->parent_frame_index); - - ASSERT_EQ(kRendererMain, (iter + 2)->frame); - ASSERT_EQ(-1, (iter + 2)->parent_frame_index); - - ASSERT_EQ(kCreateWidget, (iter + 3)->frame); - ASSERT_EQ(2, (iter + 3)->parent_frame_index); - - ASSERT_TRUE(iter + 4 == dedup->end()); -} - -TEST(StackFrameDeduplicatorTest, Deduplication) { - StackFrame bt0[] = {kBrowserMain, kCreateWidget}; - StackFrame bt1[] = {kBrowserMain, kInitialize}; - - // The call tree should look like this (index in brackets). - // - // BrowserMain [0] - // CreateWidget [1] - // Initialize [2] - // - // Note that BrowserMain will be re-used. - - std::unique_ptr<StackFrameDeduplicator> dedup(new StackFrameDeduplicator); - ASSERT_EQ(1, dedup->Insert(std::begin(bt0), std::end(bt0))); - ASSERT_EQ(2, dedup->Insert(std::begin(bt1), std::end(bt1))); - - auto iter = dedup->begin(); - ASSERT_EQ(kBrowserMain, (iter + 0)->frame); - ASSERT_EQ(-1, (iter + 0)->parent_frame_index); - - ASSERT_EQ(kCreateWidget, (iter + 1)->frame); - ASSERT_EQ(0, (iter + 1)->parent_frame_index); - - ASSERT_EQ(kInitialize, (iter + 2)->frame); - ASSERT_EQ(0, (iter + 2)->parent_frame_index); - - ASSERT_TRUE(iter + 3 == dedup->end()); - - // Inserting the same backtrace again should return the index of the existing - // node. - ASSERT_EQ(1, dedup->Insert(std::begin(bt0), std::end(bt0))); - ASSERT_EQ(2, dedup->Insert(std::begin(bt1), std::end(bt1))); - ASSERT_TRUE(dedup->begin() + 3 == dedup->end()); -} - -} // namespace trace_event -} // namespace base
diff --git a/base/trace_event/heap_profiler_type_name_deduplicator_unittest.cc b/base/trace_event/heap_profiler_type_name_deduplicator_unittest.cc deleted file mode 100644 index f97808b..0000000 --- a/base/trace_event/heap_profiler_type_name_deduplicator_unittest.cc +++ /dev/null
@@ -1,83 +0,0 @@ -// 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 <memory> -#include <string> - -#include "base/json/json_reader.h" -#include "base/trace_event/heap_profiler_type_name_deduplicator.h" -#include "base/values.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace trace_event { - -namespace { - -// Define all strings once, because the deduplicator requires pointer equality, -// and string interning is unreliable. -const char kInt[] = "int"; -const char kBool[] = "bool"; -const char kString[] = "string"; -const char kNeedsEscape[] = "\"quotes\""; - -std::unique_ptr<Value> DumpAndReadBack( - const TypeNameDeduplicator& deduplicator) { - std::string json; - deduplicator.AppendAsTraceFormat(&json); - return JSONReader::Read(json); -} - -// Inserts a single type name into a new TypeNameDeduplicator instance and -// checks if the value gets inserted and the exported value for |type_name| is -// the same as |expected_value|. -void TestInsertTypeAndReadback(const char* type_name, - const char* expected_value) { - std::unique_ptr<TypeNameDeduplicator> dedup(new TypeNameDeduplicator); - ASSERT_EQ(1, dedup->Insert(type_name)); - - std::unique_ptr<Value> type_names = DumpAndReadBack(*dedup); - ASSERT_NE(nullptr, type_names); - - const DictionaryValue* dictionary; - ASSERT_TRUE(type_names->GetAsDictionary(&dictionary)); - - // When the type name was inserted, it got ID 1. The exported key "1" - // should be equal to |expected_value|. - std::string value; - ASSERT_TRUE(dictionary->GetString("1", &value)); - ASSERT_EQ(expected_value, value); -} - -} // namespace - -TEST(TypeNameDeduplicatorTest, Deduplication) { - // The type IDs should be like this: - // 0: [unknown] - // 1: int - // 2: bool - // 3: string - - std::unique_ptr<TypeNameDeduplicator> dedup(new TypeNameDeduplicator); - ASSERT_EQ(1, dedup->Insert(kInt)); - ASSERT_EQ(2, dedup->Insert(kBool)); - ASSERT_EQ(3, dedup->Insert(kString)); - - // Inserting again should return the same IDs. - ASSERT_EQ(2, dedup->Insert(kBool)); - ASSERT_EQ(1, dedup->Insert(kInt)); - ASSERT_EQ(3, dedup->Insert(kString)); - - // A null pointer should yield type ID 0. - ASSERT_EQ(0, dedup->Insert(nullptr)); -} - -TEST(TypeNameDeduplicatorTest, EscapeTypeName) { - // Reading json should not fail, because the type name should have been - // escaped properly and exported value should contain quotes. - TestInsertTypeAndReadback(kNeedsEscape, kNeedsEscape); -} - -} // namespace trace_event -} // namespace base
diff --git a/base/trace_event/java_heap_dump_provider_android_unittest.cc b/base/trace_event/java_heap_dump_provider_android_unittest.cc deleted file mode 100644 index 9b9eb17..0000000 --- a/base/trace_event/java_heap_dump_provider_android_unittest.cc +++ /dev/null
@@ -1,23 +0,0 @@ -// 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/trace_event/java_heap_dump_provider_android.h" - -#include "base/trace_event/process_memory_dump.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace trace_event { - -TEST(JavaHeapDumpProviderTest, JavaHeapDump) { - auto* jhdp = JavaHeapDumpProvider::GetInstance(); - MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::DETAILED}; - std::unique_ptr<ProcessMemoryDump> pmd( - new ProcessMemoryDump(nullptr, dump_args)); - - jhdp->OnMemoryDump(dump_args, pmd.get()); -} - -} // namespace trace_event -} // namespace base
diff --git a/base/trace_event/memory_allocator_dump_unittest.cc b/base/trace_event/memory_allocator_dump_unittest.cc deleted file mode 100644 index 3818629..0000000 --- a/base/trace_event/memory_allocator_dump_unittest.cc +++ /dev/null
@@ -1,179 +0,0 @@ -// 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/trace_event/memory_allocator_dump.h" - -#include <stdint.h> - -#include "base/format_macros.h" -#include "base/strings/stringprintf.h" -#include "base/trace_event/heap_profiler_serialization_state.h" -#include "base/trace_event/memory_allocator_dump_guid.h" -#include "base/trace_event/memory_dump_provider.h" -#include "base/trace_event/process_memory_dump.h" -#include "base/trace_event/trace_event_argument.h" -#include "base/values.h" -#include "build_config.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using testing::ElementsAre; -using testing::Eq; -using testing::ByRef; -using testing::IsEmpty; -using testing::Contains; - -namespace base { -namespace trace_event { - -namespace { - -class FakeMemoryAllocatorDumpProvider : public MemoryDumpProvider { - public: - bool OnMemoryDump(const MemoryDumpArgs& args, - ProcessMemoryDump* pmd) override { - MemoryAllocatorDump* root_heap = - pmd->CreateAllocatorDump("foobar_allocator"); - - root_heap->AddScalar(MemoryAllocatorDump::kNameSize, - MemoryAllocatorDump::kUnitsBytes, 4096); - root_heap->AddScalar(MemoryAllocatorDump::kNameObjectCount, - MemoryAllocatorDump::kUnitsObjects, 42); - root_heap->AddScalar("attr1", "units1", 1234); - root_heap->AddString("attr2", "units2", "string_value"); - - MemoryAllocatorDump* sub_heap = - pmd->CreateAllocatorDump("foobar_allocator/sub_heap"); - sub_heap->AddScalar(MemoryAllocatorDump::kNameSize, - MemoryAllocatorDump::kUnitsBytes, 1); - sub_heap->AddScalar(MemoryAllocatorDump::kNameObjectCount, - MemoryAllocatorDump::kUnitsObjects, 3); - - pmd->CreateAllocatorDump("foobar_allocator/sub_heap/empty"); - // Leave the rest of sub heap deliberately uninitialized, to check that - // CreateAllocatorDump returns a properly zero-initialized object. - - return true; - } -}; - -void CheckString(const MemoryAllocatorDump* dump, - const std::string& name, - const char* expected_units, - const std::string& expected_value) { - MemoryAllocatorDump::Entry expected(name, expected_units, expected_value); - EXPECT_THAT(dump->entries(), Contains(Eq(ByRef(expected)))); -} - -void CheckScalar(const MemoryAllocatorDump* dump, - const std::string& name, - const char* expected_units, - uint64_t expected_value) { - MemoryAllocatorDump::Entry expected(name, expected_units, expected_value); - EXPECT_THAT(dump->entries(), Contains(Eq(ByRef(expected)))); -} - -} // namespace - -TEST(MemoryAllocatorDumpTest, GuidGeneration) { - std::unique_ptr<MemoryAllocatorDump> mad(new MemoryAllocatorDump( - "foo", MemoryDumpLevelOfDetail::FIRST, MemoryAllocatorDumpGuid(0x42u))); - ASSERT_EQ("42", mad->guid().ToString()); -} - -TEST(MemoryAllocatorDumpTest, DumpIntoProcessMemoryDump) { - FakeMemoryAllocatorDumpProvider fmadp; - MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::DETAILED}; - ProcessMemoryDump pmd(new HeapProfilerSerializationState, dump_args); - - fmadp.OnMemoryDump(dump_args, &pmd); - - ASSERT_EQ(3u, pmd.allocator_dumps().size()); - - const MemoryAllocatorDump* root_heap = - pmd.GetAllocatorDump("foobar_allocator"); - ASSERT_NE(nullptr, root_heap); - EXPECT_EQ("foobar_allocator", root_heap->absolute_name()); - CheckScalar(root_heap, MemoryAllocatorDump::kNameSize, - MemoryAllocatorDump::kUnitsBytes, 4096); - CheckScalar(root_heap, MemoryAllocatorDump::kNameObjectCount, - MemoryAllocatorDump::kUnitsObjects, 42); - CheckScalar(root_heap, "attr1", "units1", 1234); - CheckString(root_heap, "attr2", "units2", "string_value"); - - const MemoryAllocatorDump* sub_heap = - pmd.GetAllocatorDump("foobar_allocator/sub_heap"); - ASSERT_NE(nullptr, sub_heap); - EXPECT_EQ("foobar_allocator/sub_heap", sub_heap->absolute_name()); - CheckScalar(sub_heap, MemoryAllocatorDump::kNameSize, - MemoryAllocatorDump::kUnitsBytes, 1); - CheckScalar(sub_heap, MemoryAllocatorDump::kNameObjectCount, - MemoryAllocatorDump::kUnitsObjects, 3); - const MemoryAllocatorDump* empty_sub_heap = - pmd.GetAllocatorDump("foobar_allocator/sub_heap/empty"); - ASSERT_NE(nullptr, empty_sub_heap); - EXPECT_EQ("foobar_allocator/sub_heap/empty", empty_sub_heap->absolute_name()); - - EXPECT_THAT(empty_sub_heap->entries(), IsEmpty()); - - // Check that calling serialization routines doesn't cause a crash. - std::unique_ptr<TracedValue> traced_value(new TracedValue); - pmd.SerializeAllocatorDumpsInto(traced_value.get()); - pmd.SerializeHeapProfilerDumpsInto(traced_value.get()); -} - -TEST(MemoryAllocatorDumpTest, GetSize) { - MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::DETAILED}; - ProcessMemoryDump pmd(new HeapProfilerSerializationState, dump_args); - MemoryAllocatorDump* dump = pmd.CreateAllocatorDump("allocator_for_size"); - dump->AddScalar(MemoryAllocatorDump::kNameSize, - MemoryAllocatorDump::kUnitsBytes, 1); - dump->AddScalar("foo", MemoryAllocatorDump::kUnitsBytes, 2); - EXPECT_EQ(1u, dump->GetSizeInternal()); -} - -TEST(MemoryAllocatorDumpTest, ReadValues) { - MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::DETAILED}; - ProcessMemoryDump pmd(new HeapProfilerSerializationState, dump_args); - MemoryAllocatorDump* dump = pmd.CreateAllocatorDump("allocator_for_size"); - dump->AddScalar("one", "byte", 1); - dump->AddString("one", "object", "one"); - - MemoryAllocatorDump::Entry expected_scalar("one", "byte", 1); - MemoryAllocatorDump::Entry expected_string("one", "object", "one"); - EXPECT_THAT(dump->entries(), ElementsAre(Eq(ByRef(expected_scalar)), - Eq(ByRef(expected_string)))); -} - -TEST(MemoryAllocatorDumpTest, MovingAnEntry) { - MemoryAllocatorDump::Entry expected_entry("one", "byte", 1); - MemoryAllocatorDump::Entry from_entry("one", "byte", 1); - MemoryAllocatorDump::Entry to_entry = std::move(from_entry); - EXPECT_EQ(expected_entry, to_entry); -} - -// DEATH tests are not supported in Android/iOS/Fuchsia. -#if !defined(NDEBUG) && !defined(OS_ANDROID) && !defined(OS_IOS) && \ - !defined(OS_FUCHSIA) -TEST(MemoryAllocatorDumpTest, ForbidDuplicatesDeathTest) { - FakeMemoryAllocatorDumpProvider fmadp; - MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::DETAILED}; - ProcessMemoryDump pmd(new HeapProfilerSerializationState, dump_args); - pmd.CreateAllocatorDump("foo_allocator"); - pmd.CreateAllocatorDump("bar_allocator/heap"); - ASSERT_DEATH(pmd.CreateAllocatorDump("foo_allocator"), ""); - ASSERT_DEATH(pmd.CreateAllocatorDump("bar_allocator/heap"), ""); - ASSERT_DEATH(pmd.CreateAllocatorDump(""), ""); -} - -TEST(MemoryAllocatorDumpTest, ForbidStringsInBackgroundModeDeathTest) { - MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::BACKGROUND}; - ProcessMemoryDump pmd(new HeapProfilerSerializationState, dump_args); - MemoryAllocatorDump* dump = pmd.CreateAllocatorDump("malloc"); - ASSERT_DEATH(dump->AddString("foo", "bar", "baz"), ""); -} -#endif - -} // namespace trace_event -} // namespace base
diff --git a/base/trace_event/memory_dump_manager_unittest.cc b/base/trace_event/memory_dump_manager_unittest.cc deleted file mode 100644 index 8ed5fb3..0000000 --- a/base/trace_event/memory_dump_manager_unittest.cc +++ /dev/null
@@ -1,884 +0,0 @@ -// 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/trace_event/memory_dump_manager.h" - -#include <stdint.h> - -#include <memory> -#include <utility> -#include <vector> - -#include "base/base_switches.h" -#include "base/callback.h" -#include "base/command_line.h" -#include "base/debug/thread_heap_usage_tracker.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/run_loop.h" -#include "base/single_thread_task_runner.h" -#include "base/synchronization/waitable_event.h" -#include "base/task_scheduler/post_task.h" -#include "base/test/scoped_task_environment.h" -#include "base/test/test_io_thread.h" -#include "base/threading/platform_thread.h" -#include "base/threading/sequenced_task_runner_handle.h" -#include "base/threading/thread.h" -#include "base/threading/thread_task_runner_handle.h" -#include "base/trace_event/memory_dump_manager_test_utils.h" -#include "base/trace_event/memory_dump_provider.h" -#include "base/trace_event/memory_dump_request_args.h" -#include "base/trace_event/memory_dump_scheduler.h" -#include "base/trace_event/memory_infra_background_whitelist.h" -#include "base/trace_event/process_memory_dump.h" -#include "build_config.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using testing::_; -using testing::AtMost; -using testing::Between; -using testing::Invoke; -using testing::Return; - -namespace base { -namespace trace_event { - -// GTest matchers for MemoryDumpRequestArgs arguments. -MATCHER(IsDetailedDump, "") { - return arg.level_of_detail == MemoryDumpLevelOfDetail::DETAILED; -} - -MATCHER(IsLightDump, "") { - return arg.level_of_detail == MemoryDumpLevelOfDetail::LIGHT; -} - -namespace { - -const char* kMDPName = "TestDumpProvider"; -const char* kWhitelistedMDPName = "WhitelistedTestDumpProvider"; -const char* const kTestMDPWhitelist[] = {kWhitelistedMDPName, nullptr}; - -void RegisterDumpProvider( - MemoryDumpProvider* mdp, - scoped_refptr<base::SingleThreadTaskRunner> task_runner, - const MemoryDumpProvider::Options& options, - const char* name = kMDPName) { - MemoryDumpManager* mdm = MemoryDumpManager::GetInstance(); - mdm->set_dumper_registrations_ignored_for_testing(false); - mdm->RegisterDumpProvider(mdp, name, std::move(task_runner), options); - mdm->set_dumper_registrations_ignored_for_testing(true); -} - -void RegisterDumpProvider( - MemoryDumpProvider* mdp, - scoped_refptr<base::SingleThreadTaskRunner> task_runner) { - RegisterDumpProvider(mdp, task_runner, MemoryDumpProvider::Options()); -} - -void RegisterDumpProviderWithSequencedTaskRunner( - MemoryDumpProvider* mdp, - scoped_refptr<base::SequencedTaskRunner> task_runner, - const MemoryDumpProvider::Options& options) { - MemoryDumpManager* mdm = MemoryDumpManager::GetInstance(); - mdm->set_dumper_registrations_ignored_for_testing(false); - mdm->RegisterDumpProviderWithSequencedTaskRunner(mdp, kMDPName, task_runner, - options); - mdm->set_dumper_registrations_ignored_for_testing(true); -} - -// Posts |task| to |task_runner| and blocks until it is executed. -void PostTaskAndWait(const Location& from_here, - SequencedTaskRunner* task_runner, - base::OnceClosure task) { - base::WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - task_runner->PostTask(from_here, std::move(task)); - task_runner->PostTask(FROM_HERE, base::BindOnce(&WaitableEvent::Signal, - base::Unretained(&event))); - // The SequencedTaskRunner guarantees that |event| will only be signaled after - // |task| is executed. - event.Wait(); -} - -class MockMemoryDumpProvider : public MemoryDumpProvider { - public: - MOCK_METHOD0(Destructor, void()); - MOCK_METHOD2(OnMemoryDump, - bool(const MemoryDumpArgs& args, ProcessMemoryDump* pmd)); - MOCK_METHOD1(OnHeapProfilingEnabled, void(bool enabled)); - MOCK_METHOD1(PollFastMemoryTotal, void(uint64_t* memory_total)); - MOCK_METHOD0(SuspendFastMemoryPolling, void()); - - MockMemoryDumpProvider() : enable_mock_destructor(false) { - ON_CALL(*this, OnMemoryDump(_, _)) - .WillByDefault( - Invoke([](const MemoryDumpArgs&, ProcessMemoryDump* pmd) -> bool { - return true; - })); - - ON_CALL(*this, PollFastMemoryTotal(_)) - .WillByDefault( - Invoke([](uint64_t* memory_total) -> void { NOTREACHED(); })); - } - ~MockMemoryDumpProvider() override { - if (enable_mock_destructor) - Destructor(); - } - - bool enable_mock_destructor; -}; - -class TestSequencedTaskRunner : public SequencedTaskRunner { - public: - TestSequencedTaskRunner() = default; - - void set_enabled(bool value) { enabled_ = value; } - unsigned no_of_post_tasks() const { return num_of_post_tasks_; } - - bool PostNonNestableDelayedTask(const Location& from_here, - OnceClosure task, - TimeDelta delay) override { - NOTREACHED(); - return false; - } - - bool PostDelayedTask(const Location& from_here, - OnceClosure task, - TimeDelta delay) override { - num_of_post_tasks_++; - if (enabled_) { - return task_runner_->PostDelayedTask(from_here, std::move(task), delay); - } - return false; - } - - bool RunsTasksInCurrentSequence() const override { - return task_runner_->RunsTasksInCurrentSequence(); - } - - private: - ~TestSequencedTaskRunner() override = default; - - const scoped_refptr<SequencedTaskRunner> task_runner_ = - CreateSequencedTaskRunnerWithTraits({}); - bool enabled_ = true; - unsigned num_of_post_tasks_ = 0; -}; - -class TestingThreadHeapUsageTracker : public debug::ThreadHeapUsageTracker { - public: - using ThreadHeapUsageTracker::DisableHeapTrackingForTesting; -}; - -} // namespace - -class MemoryDumpManagerTest : public testing::Test { - public: - MemoryDumpManagerTest(bool is_coordinator = false) - : is_coordinator_(is_coordinator) {} - - void SetUp() override { - // Bring up and initialize MemoryDumpManager while single-threaded (before - // instantiating ScopedTaskEnvironment) to avoid data races if worker - // threads use tracing globals early. - mdm_ = MemoryDumpManager::CreateInstanceForTesting(); - ASSERT_EQ(mdm_.get(), MemoryDumpManager::GetInstance()); - - InitializeMemoryDumpManagerForInProcessTesting(is_coordinator_); - - scoped_task_environment_ = std::make_unique<test::ScopedTaskEnvironment>(); - } - - void TearDown() override { - scoped_task_environment_.reset(); - - // Tear down the MemoryDumpManager while single-threaded to mirror logic in - // SetUp(). - mdm_.reset(); - TraceLog::ResetForTesting(); - } - - protected: - // Blocks the current thread (spinning a nested message loop) until the - // memory dump is complete. Returns: - // - return value: the |success| from the CreateProcessDump() callback. - bool RequestProcessDumpAndWait(MemoryDumpType dump_type, - MemoryDumpLevelOfDetail level_of_detail) { - RunLoop run_loop; - bool success = false; - static uint64_t test_guid = 1; - test_guid++; - MemoryDumpRequestArgs request_args{test_guid, dump_type, level_of_detail}; - - // The signature of the callback delivered by MemoryDumpManager is: - // void ProcessMemoryDumpCallback( - // uint64_t dump_guid, - // bool success, - // std::unique_ptr<ProcessMemoryDump> pmd) - // The extra arguments prepended to the |callback| below (the ones with the - // "curried_" prefix) are just passed from the Bind(). This is just to get - // around the limitation of Bind() in supporting only capture-less lambdas. - ProcessMemoryDumpCallback callback = Bind( - [](bool* curried_success, Closure curried_quit_closure, - uint64_t curried_expected_guid, bool success, uint64_t dump_guid, - std::unique_ptr<ProcessMemoryDump> pmd) { - *curried_success = success; - EXPECT_EQ(curried_expected_guid, dump_guid); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - curried_quit_closure); - }, - Unretained(&success), run_loop.QuitClosure(), test_guid); - - mdm_->CreateProcessDump(request_args, callback); - run_loop.Run(); - return success; - } - - void EnableForTracing() { - mdm_->SetupForTracing(TraceConfig::MemoryDumpConfig()); - } - - void EnableForTracingWithTraceConfig(const std::string trace_config_string) { - TraceConfig trace_config(trace_config_string); - mdm_->SetupForTracing(trace_config.memory_dump_config()); - } - - void DisableTracing() { mdm_->TeardownForTracing(); } - - int GetMaxConsecutiveFailuresCount() const { - return MemoryDumpManager::kMaxConsecutiveFailuresCount; - } - - const MemoryDumpProvider::Options kDefaultOptions; - std::unique_ptr<MemoryDumpManager> mdm_; - - private: - // To tear down the singleton instance after each test. - ShadowingAtExitManager at_exit_manager_; - - std::unique_ptr<test::ScopedTaskEnvironment> scoped_task_environment_; - - // Whether the test MemoryDumpManager should be initialized as the - // coordinator. - const bool is_coordinator_; - - DISALLOW_COPY_AND_ASSIGN(MemoryDumpManagerTest); -}; - -class MemoryDumpManagerTestAsCoordinator : public MemoryDumpManagerTest { - public: - MemoryDumpManagerTestAsCoordinator() : MemoryDumpManagerTest(true) {} - - private: - DISALLOW_COPY_AND_ASSIGN(MemoryDumpManagerTestAsCoordinator); -}; - -// Basic sanity checks. Registers a memory dump provider and checks that it is -// called. -TEST_F(MemoryDumpManagerTest, SingleDumper) { - MockMemoryDumpProvider mdp; - RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get()); - - // Now repeat enabling the memory category and check that the dumper is - // invoked this time. - EnableForTracing(); - EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(3); - for (int i = 0; i < 3; ++i) { - EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, - MemoryDumpLevelOfDetail::DETAILED)); - } - DisableTracing(); - - mdm_->UnregisterDumpProvider(&mdp); - - // Finally check the unregister logic: the global dump handler will be invoked - // but not the dump provider, as it has been unregistered. - EnableForTracing(); - EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0); - for (int i = 0; i < 3; ++i) { - EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, - MemoryDumpLevelOfDetail::DETAILED)); - } - DisableTracing(); -} - -// Checks that requesting dumps with high level of detail actually propagates -// the level of the detail properly to OnMemoryDump() call on dump providers. -TEST_F(MemoryDumpManagerTest, CheckMemoryDumpArgs) { - MockMemoryDumpProvider mdp; - - RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get()); - EnableForTracing(); - EXPECT_CALL(mdp, OnMemoryDump(IsDetailedDump(), _)); - EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, - MemoryDumpLevelOfDetail::DETAILED)); - DisableTracing(); - mdm_->UnregisterDumpProvider(&mdp); - - // Check that requesting dumps with low level of detail actually propagates to - // OnMemoryDump() call on dump providers. - RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get()); - EnableForTracing(); - EXPECT_CALL(mdp, OnMemoryDump(IsLightDump(), _)); - EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, - MemoryDumpLevelOfDetail::LIGHT)); - DisableTracing(); - mdm_->UnregisterDumpProvider(&mdp); -} - -// Checks that the HeapProfilerSerializationState object is actually -// shared over time. -TEST_F(MemoryDumpManagerTest, HeapProfilerSerializationState) { - MockMemoryDumpProvider mdp1; - MockMemoryDumpProvider mdp2; - RegisterDumpProvider(&mdp1, nullptr); - RegisterDumpProvider(&mdp2, nullptr); - - EnableForTracing(); - const HeapProfilerSerializationState* heap_profiler_serialization_state = - mdm_->heap_profiler_serialization_state_for_testing().get(); - EXPECT_CALL(mdp1, OnMemoryDump(_, _)) - .Times(2) - .WillRepeatedly( - Invoke([heap_profiler_serialization_state]( - const MemoryDumpArgs&, ProcessMemoryDump* pmd) -> bool { - EXPECT_EQ(heap_profiler_serialization_state, - pmd->heap_profiler_serialization_state().get()); - return true; - })); - EXPECT_CALL(mdp2, OnMemoryDump(_, _)) - .Times(2) - .WillRepeatedly( - Invoke([heap_profiler_serialization_state]( - const MemoryDumpArgs&, ProcessMemoryDump* pmd) -> bool { - EXPECT_EQ(heap_profiler_serialization_state, - pmd->heap_profiler_serialization_state().get()); - return true; - })); - - for (int i = 0; i < 2; ++i) { - EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, - MemoryDumpLevelOfDetail::DETAILED)); - } - - DisableTracing(); -} - -// Checks that the (Un)RegisterDumpProvider logic behaves sanely. -TEST_F(MemoryDumpManagerTest, MultipleDumpers) { - MockMemoryDumpProvider mdp1; - MockMemoryDumpProvider mdp2; - - // Enable only mdp1. - RegisterDumpProvider(&mdp1, ThreadTaskRunnerHandle::Get()); - EnableForTracing(); - EXPECT_CALL(mdp1, OnMemoryDump(_, _)); - EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(0); - EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, - MemoryDumpLevelOfDetail::DETAILED)); - DisableTracing(); - - // Invert: enable mdp2 and disable mdp1. - mdm_->UnregisterDumpProvider(&mdp1); - RegisterDumpProvider(&mdp2, nullptr); - EnableForTracing(); - EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(0); - EXPECT_CALL(mdp2, OnMemoryDump(_, _)); - EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, - MemoryDumpLevelOfDetail::DETAILED)); - DisableTracing(); - - // Enable both mdp1 and mdp2. - RegisterDumpProvider(&mdp1, nullptr); - EnableForTracing(); - EXPECT_CALL(mdp1, OnMemoryDump(_, _)); - EXPECT_CALL(mdp2, OnMemoryDump(_, _)); - EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, - MemoryDumpLevelOfDetail::DETAILED)); - DisableTracing(); -} - -// Checks that the dump provider invocations depend only on the current -// registration state and not on previous registrations and dumps. -// Flaky on iOS, see crbug.com/706874 -#if defined(OS_IOS) -#define MAYBE_RegistrationConsistency DISABLED_RegistrationConsistency -#else -#define MAYBE_RegistrationConsistency RegistrationConsistency -#endif -TEST_F(MemoryDumpManagerTest, MAYBE_RegistrationConsistency) { - MockMemoryDumpProvider mdp; - - RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get()); - - { - EXPECT_CALL(mdp, OnMemoryDump(_, _)); - EnableForTracing(); - EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, - MemoryDumpLevelOfDetail::DETAILED)); - DisableTracing(); - } - - mdm_->UnregisterDumpProvider(&mdp); - - { - EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0); - EnableForTracing(); - EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, - MemoryDumpLevelOfDetail::DETAILED)); - DisableTracing(); - } - - RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get()); - mdm_->UnregisterDumpProvider(&mdp); - - { - EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0); - EnableForTracing(); - EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, - MemoryDumpLevelOfDetail::DETAILED)); - DisableTracing(); - } - - RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get()); - mdm_->UnregisterDumpProvider(&mdp); - RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get()); - - { - EXPECT_CALL(mdp, OnMemoryDump(_, _)); - EnableForTracing(); - EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, - MemoryDumpLevelOfDetail::DETAILED)); - DisableTracing(); - } -} - -// Checks that the MemoryDumpManager respects the thread affinity when a -// MemoryDumpProvider specifies a task_runner(). The test starts creating 8 -// threads and registering a MemoryDumpProvider on each of them. At each -// iteration, one thread is removed, to check the live unregistration logic. -TEST_F(MemoryDumpManagerTest, RespectTaskRunnerAffinity) { - const uint32_t kNumInitialThreads = 8; - - std::vector<std::unique_ptr<Thread>> threads; - std::vector<std::unique_ptr<MockMemoryDumpProvider>> mdps; - - // Create the threads and setup the expectations. Given that at each iteration - // we will pop out one thread/MemoryDumpProvider, each MDP is supposed to be - // invoked a number of times equal to its index. - for (uint32_t i = kNumInitialThreads; i > 0; --i) { - threads.push_back(WrapUnique(new Thread("test thread"))); - auto* thread = threads.back().get(); - thread->Start(); - scoped_refptr<SingleThreadTaskRunner> task_runner = thread->task_runner(); - mdps.push_back(WrapUnique(new MockMemoryDumpProvider())); - auto* mdp = mdps.back().get(); - RegisterDumpProvider(mdp, task_runner, kDefaultOptions); - EXPECT_CALL(*mdp, OnMemoryDump(_, _)) - .Times(i) - .WillRepeatedly(Invoke( - [task_runner](const MemoryDumpArgs&, ProcessMemoryDump*) -> bool { - EXPECT_TRUE(task_runner->RunsTasksInCurrentSequence()); - return true; - })); - } - EnableForTracing(); - - while (!threads.empty()) { - EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, - MemoryDumpLevelOfDetail::DETAILED)); - - // Unregister a MDP and destroy one thread at each iteration to check the - // live unregistration logic. The unregistration needs to happen on the same - // thread the MDP belongs to. - { - RunLoop run_loop; - Closure unregistration = - Bind(&MemoryDumpManager::UnregisterDumpProvider, - Unretained(mdm_.get()), Unretained(mdps.back().get())); - threads.back()->task_runner()->PostTaskAndReply(FROM_HERE, unregistration, - run_loop.QuitClosure()); - run_loop.Run(); - } - mdps.pop_back(); - threads.back()->Stop(); - threads.pop_back(); - } - - DisableTracing(); -} - -// Check that the memory dump calls are always posted on task runner for -// SequencedTaskRunner case and that the dump provider gets disabled when -// PostTask fails, but the dump still succeeds. -TEST_F(MemoryDumpManagerTest, PostTaskForSequencedTaskRunner) { - std::vector<MockMemoryDumpProvider> mdps(3); - scoped_refptr<TestSequencedTaskRunner> task_runner1( - MakeRefCounted<TestSequencedTaskRunner>()); - scoped_refptr<TestSequencedTaskRunner> task_runner2( - MakeRefCounted<TestSequencedTaskRunner>()); - RegisterDumpProviderWithSequencedTaskRunner(&mdps[0], task_runner1, - kDefaultOptions); - RegisterDumpProviderWithSequencedTaskRunner(&mdps[1], task_runner2, - kDefaultOptions); - RegisterDumpProviderWithSequencedTaskRunner(&mdps[2], task_runner2, - kDefaultOptions); - // |mdps[0]| should be disabled permanently after first dump. - EXPECT_CALL(mdps[0], OnMemoryDump(_, _)).Times(0); - EXPECT_CALL(mdps[1], OnMemoryDump(_, _)).Times(2); - EXPECT_CALL(mdps[2], OnMemoryDump(_, _)).Times(2); - - EnableForTracing(); - - task_runner1->set_enabled(false); - EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, - MemoryDumpLevelOfDetail::DETAILED)); - EXPECT_EQ(1u, task_runner1->no_of_post_tasks()); - EXPECT_EQ(1u, task_runner2->no_of_post_tasks()); - - task_runner1->set_enabled(true); - EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, - MemoryDumpLevelOfDetail::DETAILED)); - EXPECT_EQ(2u, task_runner1->no_of_post_tasks()); - EXPECT_EQ(2u, task_runner2->no_of_post_tasks()); - DisableTracing(); -} - -// Checks that providers get disabled after 3 consecutive failures, but not -// otherwise (e.g., if interleaved). -TEST_F(MemoryDumpManagerTest, DisableFailingDumpers) { - MockMemoryDumpProvider mdp1; - MockMemoryDumpProvider mdp2; - - RegisterDumpProvider(&mdp1, nullptr); - RegisterDumpProvider(&mdp2, nullptr); - EnableForTracing(); - - EXPECT_CALL(mdp1, OnMemoryDump(_, _)) - .Times(GetMaxConsecutiveFailuresCount()) - .WillRepeatedly(Return(false)); - - EXPECT_CALL(mdp2, OnMemoryDump(_, _)) - .WillOnce(Return(false)) - .WillOnce(Return(true)) - .WillOnce(Return(false)) - .WillOnce(Return(false)) - .WillOnce(Return(true)) - .WillOnce(Return(false)); - - const int kNumDumps = 2 * GetMaxConsecutiveFailuresCount(); - for (int i = 0; i < kNumDumps; i++) { - EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, - MemoryDumpLevelOfDetail::DETAILED)); - } - - DisableTracing(); -} - -// Sneakily registers an extra memory dump provider while an existing one is -// dumping and expect it to take part in the already active tracing session. -TEST_F(MemoryDumpManagerTest, RegisterDumperWhileDumping) { - MockMemoryDumpProvider mdp1; - MockMemoryDumpProvider mdp2; - - RegisterDumpProvider(&mdp1, nullptr); - EnableForTracing(); - - EXPECT_CALL(mdp1, OnMemoryDump(_, _)) - .Times(4) - .WillOnce(Return(true)) - .WillOnce( - Invoke([&mdp2](const MemoryDumpArgs&, ProcessMemoryDump*) -> bool { - RegisterDumpProvider(&mdp2, nullptr); - return true; - })) - .WillRepeatedly(Return(true)); - - // Depending on the insertion order (before or after mdp1), mdp2 might be - // called also immediately after it gets registered. - EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(Between(2, 3)); - - for (int i = 0; i < 4; i++) { - EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, - MemoryDumpLevelOfDetail::DETAILED)); - } - - DisableTracing(); -} - -// Like RegisterDumperWhileDumping, but unregister the dump provider instead. -TEST_F(MemoryDumpManagerTest, UnregisterDumperWhileDumping) { - MockMemoryDumpProvider mdp1; - MockMemoryDumpProvider mdp2; - - RegisterDumpProvider(&mdp1, ThreadTaskRunnerHandle::Get(), kDefaultOptions); - RegisterDumpProvider(&mdp2, ThreadTaskRunnerHandle::Get(), kDefaultOptions); - EnableForTracing(); - - EXPECT_CALL(mdp1, OnMemoryDump(_, _)) - .Times(4) - .WillOnce(Return(true)) - .WillOnce( - Invoke([&mdp2](const MemoryDumpArgs&, ProcessMemoryDump*) -> bool { - MemoryDumpManager::GetInstance()->UnregisterDumpProvider(&mdp2); - return true; - })) - .WillRepeatedly(Return(true)); - - // Depending on the insertion order (before or after mdp1), mdp2 might have - // been already called when UnregisterDumpProvider happens. - EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(Between(1, 2)); - - for (int i = 0; i < 4; i++) { - EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, - MemoryDumpLevelOfDetail::DETAILED)); - } - - DisableTracing(); -} - -// Checks that the dump does not abort when unregistering a provider while -// dumping from a different thread than the dumping thread. -TEST_F(MemoryDumpManagerTest, UnregisterDumperFromThreadWhileDumping) { - std::vector<std::unique_ptr<TestIOThread>> threads; - std::vector<std::unique_ptr<MockMemoryDumpProvider>> mdps; - - for (int i = 0; i < 2; i++) { - threads.push_back( - WrapUnique(new TestIOThread(TestIOThread::kAutoStart))); - mdps.push_back(WrapUnique(new MockMemoryDumpProvider())); - RegisterDumpProvider(mdps.back().get(), threads.back()->task_runner(), - kDefaultOptions); - } - - int on_memory_dump_call_count = 0; - - // When OnMemoryDump is called on either of the dump providers, it will - // unregister the other one. - for (const std::unique_ptr<MockMemoryDumpProvider>& mdp : mdps) { - int other_idx = (mdps.front() == mdp); - // TestIOThread's task runner must be obtained from the main thread but can - // then be used from other threads. - scoped_refptr<SingleThreadTaskRunner> other_runner = - threads[other_idx]->task_runner(); - MockMemoryDumpProvider* other_mdp = mdps[other_idx].get(); - auto on_dump = [this, other_runner, other_mdp, &on_memory_dump_call_count]( - const MemoryDumpArgs& args, ProcessMemoryDump* pmd) { - PostTaskAndWait(FROM_HERE, other_runner.get(), - base::BindOnce(&MemoryDumpManager::UnregisterDumpProvider, - base::Unretained(&*mdm_), other_mdp)); - on_memory_dump_call_count++; - return true; - }; - - // OnMemoryDump is called once for the provider that dumps first, and zero - // times for the other provider. - EXPECT_CALL(*mdp, OnMemoryDump(_, _)) - .Times(AtMost(1)) - .WillOnce(Invoke(on_dump)); - } - - EnableForTracing(); - EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, - MemoryDumpLevelOfDetail::DETAILED)); - ASSERT_EQ(1, on_memory_dump_call_count); - - DisableTracing(); -} - -// If a thread (with a dump provider living on it) is torn down during a dump -// its dump provider should be skipped but the dump itself should succeed. -TEST_F(MemoryDumpManagerTest, TearDownThreadWhileDumping) { - std::vector<std::unique_ptr<TestIOThread>> threads; - std::vector<std::unique_ptr<MockMemoryDumpProvider>> mdps; - - for (int i = 0; i < 2; i++) { - threads.push_back( - WrapUnique(new TestIOThread(TestIOThread::kAutoStart))); - mdps.push_back(WrapUnique(new MockMemoryDumpProvider())); - RegisterDumpProvider(mdps.back().get(), threads.back()->task_runner(), - kDefaultOptions); - } - - int on_memory_dump_call_count = 0; - - // When OnMemoryDump is called on either of the dump providers, it will - // tear down the thread of the other one. - for (const std::unique_ptr<MockMemoryDumpProvider>& mdp : mdps) { - int other_idx = (mdps.front() == mdp); - TestIOThread* other_thread = threads[other_idx].get(); - // TestIOThread isn't thread-safe and must be stopped on the |main_runner|. - scoped_refptr<SequencedTaskRunner> main_runner = - SequencedTaskRunnerHandle::Get(); - auto on_dump = [other_thread, main_runner, &on_memory_dump_call_count]( - const MemoryDumpArgs& args, ProcessMemoryDump* pmd) { - PostTaskAndWait( - FROM_HERE, main_runner.get(), - base::BindOnce(&TestIOThread::Stop, base::Unretained(other_thread))); - on_memory_dump_call_count++; - return true; - }; - - // OnMemoryDump is called once for the provider that dumps first, and zero - // times for the other provider. - EXPECT_CALL(*mdp, OnMemoryDump(_, _)) - .Times(AtMost(1)) - .WillOnce(Invoke(on_dump)); - } - - EnableForTracing(); - EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, - MemoryDumpLevelOfDetail::DETAILED)); - ASSERT_EQ(1, on_memory_dump_call_count); - - DisableTracing(); -} - -// Checks that the callback is invoked if CreateProcessDump() is called when -// tracing is not enabled. -TEST_F(MemoryDumpManagerTest, TriggerDumpWithoutTracing) { - MockMemoryDumpProvider mdp; - RegisterDumpProvider(&mdp, nullptr); - EXPECT_CALL(mdp, OnMemoryDump(_, _)); - EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, - MemoryDumpLevelOfDetail::DETAILED)); -} - -TEST_F(MemoryDumpManagerTest, BackgroundWhitelisting) { - SetDumpProviderWhitelistForTesting(kTestMDPWhitelist); - - // Standard provider with default options (create dump for current process). - MockMemoryDumpProvider backgroundMdp; - RegisterDumpProvider(&backgroundMdp, nullptr, kDefaultOptions, - kWhitelistedMDPName); - - EnableForTracing(); - - EXPECT_CALL(backgroundMdp, OnMemoryDump(_, _)).Times(1); - EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::SUMMARY_ONLY, - MemoryDumpLevelOfDetail::BACKGROUND)); - DisableTracing(); -} - -// Tests the basics of the UnregisterAndDeleteDumpProviderSoon(): the -// unregistration should actually delete the providers and not leak them. -TEST_F(MemoryDumpManagerTest, UnregisterAndDeleteDumpProviderSoon) { - static const int kNumProviders = 3; - int dtor_count = 0; - std::vector<std::unique_ptr<MemoryDumpProvider>> mdps; - for (int i = 0; i < kNumProviders; ++i) { - std::unique_ptr<MockMemoryDumpProvider> mdp(new MockMemoryDumpProvider); - mdp->enable_mock_destructor = true; - EXPECT_CALL(*mdp, Destructor()) - .WillOnce(Invoke([&dtor_count]() { dtor_count++; })); - RegisterDumpProvider(mdp.get(), nullptr, kDefaultOptions); - mdps.push_back(std::move(mdp)); - } - - while (!mdps.empty()) { - mdm_->UnregisterAndDeleteDumpProviderSoon(std::move(mdps.back())); - mdps.pop_back(); - } - - ASSERT_EQ(kNumProviders, dtor_count); -} - -// This test checks against races when unregistering an unbound dump provider -// from another thread while dumping. It registers one MDP and, when -// OnMemoryDump() is called, it invokes UnregisterAndDeleteDumpProviderSoon() -// from another thread. The OnMemoryDump() and the dtor call are expected to -// happen on the same thread (the MemoryDumpManager utility thread). -TEST_F(MemoryDumpManagerTest, UnregisterAndDeleteDumpProviderSoonDuringDump) { - std::unique_ptr<MockMemoryDumpProvider> mdp(new MockMemoryDumpProvider); - mdp->enable_mock_destructor = true; - RegisterDumpProvider(mdp.get(), nullptr, kDefaultOptions); - - base::PlatformThreadRef thread_ref; - auto self_unregister_from_another_thread = [&mdp, &thread_ref]( - const MemoryDumpArgs&, ProcessMemoryDump*) -> bool { - thread_ref = PlatformThread::CurrentRef(); - TestIOThread thread_for_unregistration(TestIOThread::kAutoStart); - PostTaskAndWait( - FROM_HERE, thread_for_unregistration.task_runner().get(), - base::BindOnce(&MemoryDumpManager::UnregisterAndDeleteDumpProviderSoon, - base::Unretained(MemoryDumpManager::GetInstance()), - std::move(mdp))); - thread_for_unregistration.Stop(); - return true; - }; - EXPECT_CALL(*mdp, OnMemoryDump(_, _)) - .Times(1) - .WillOnce(Invoke(self_unregister_from_another_thread)); - EXPECT_CALL(*mdp, Destructor()) - .Times(1) - .WillOnce(Invoke([&thread_ref]() { - EXPECT_EQ(thread_ref, PlatformThread::CurrentRef()); - })); - - EnableForTracing(); - for (int i = 0; i < 2; ++i) { - EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, - MemoryDumpLevelOfDetail::DETAILED)); - } - DisableTracing(); -} - -// Mock MDP class that tests if the number of OnMemoryDump() calls are expected. -// It is implemented without gmocks since EXPECT_CALL implementation is slow -// when there are 1000s of instances, as required in -// NoStackOverflowWithTooManyMDPs test. -class SimpleMockMemoryDumpProvider : public MemoryDumpProvider { - public: - SimpleMockMemoryDumpProvider(int expected_num_dump_calls) - : expected_num_dump_calls_(expected_num_dump_calls), num_dump_calls_(0) {} - - ~SimpleMockMemoryDumpProvider() override { - EXPECT_EQ(expected_num_dump_calls_, num_dump_calls_); - } - - bool OnMemoryDump(const MemoryDumpArgs& args, - ProcessMemoryDump* pmd) override { - ++num_dump_calls_; - return true; - } - - private: - int expected_num_dump_calls_; - int num_dump_calls_; -}; - -TEST_F(MemoryDumpManagerTest, NoStackOverflowWithTooManyMDPs) { - SetDumpProviderWhitelistForTesting(kTestMDPWhitelist); - - int kMDPCount = 1000; - std::vector<std::unique_ptr<SimpleMockMemoryDumpProvider>> mdps; - for (int i = 0; i < kMDPCount; ++i) { - mdps.push_back(std::make_unique<SimpleMockMemoryDumpProvider>(1)); - RegisterDumpProvider(mdps.back().get(), nullptr); - } - for (int i = 0; i < kMDPCount; ++i) { - mdps.push_back(std::make_unique<SimpleMockMemoryDumpProvider>(3)); - RegisterDumpProvider(mdps.back().get(), nullptr, kDefaultOptions, - kWhitelistedMDPName); - } - std::unique_ptr<Thread> stopped_thread(new Thread("test thread")); - stopped_thread->Start(); - for (int i = 0; i < kMDPCount; ++i) { - mdps.push_back(std::make_unique<SimpleMockMemoryDumpProvider>(0)); - RegisterDumpProvider(mdps.back().get(), stopped_thread->task_runner(), - kDefaultOptions, kWhitelistedMDPName); - } - stopped_thread->Stop(); - - EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, - MemoryDumpLevelOfDetail::DETAILED)); - EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, - MemoryDumpLevelOfDetail::BACKGROUND)); - EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::SUMMARY_ONLY, - MemoryDumpLevelOfDetail::BACKGROUND)); -} - -} // namespace trace_event -} // namespace base
diff --git a/base/trace_event/memory_dump_scheduler_unittest.cc b/base/trace_event/memory_dump_scheduler_unittest.cc deleted file mode 100644 index d5993b6..0000000 --- a/base/trace_event/memory_dump_scheduler_unittest.cc +++ /dev/null
@@ -1,200 +0,0 @@ -// 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/trace_event/memory_dump_scheduler.h" - -#include <memory> - -#include "base/bind.h" -#include "base/single_thread_task_runner.h" -#include "base/synchronization/waitable_event.h" -#include "base/threading/thread.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using ::testing::AtMost; -using ::testing::Invoke; -using ::testing::_; - -namespace base { -namespace trace_event { - -namespace { - -// Wrapper to use gmock on a callback. -struct CallbackWrapper { - MOCK_METHOD1(OnTick, void(MemoryDumpLevelOfDetail)); -}; - -} // namespace - -class MemoryDumpSchedulerTest : public testing::Test { - public: - MemoryDumpSchedulerTest() - : testing::Test(), - evt_(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED), - bg_thread_("MemoryDumpSchedulerTest Thread") { - bg_thread_.Start(); - } - - protected: - MemoryDumpScheduler scheduler_; - WaitableEvent evt_; - CallbackWrapper on_tick_; - Thread bg_thread_; -}; - -TEST_F(MemoryDumpSchedulerTest, SingleTrigger) { - const uint32_t kPeriodMs = 1; - const auto kLevelOfDetail = MemoryDumpLevelOfDetail::DETAILED; - const uint32_t kTicks = 5; - MemoryDumpScheduler::Config config; - config.triggers.push_back({kLevelOfDetail, kPeriodMs}); - config.callback = Bind(&CallbackWrapper::OnTick, Unretained(&on_tick_)); - - testing::InSequence sequence; - EXPECT_CALL(on_tick_, OnTick(_)).Times(kTicks - 1); - EXPECT_CALL(on_tick_, OnTick(_)) - .WillRepeatedly(Invoke( - [this, kLevelOfDetail](MemoryDumpLevelOfDetail level_of_detail) { - EXPECT_EQ(kLevelOfDetail, level_of_detail); - this->evt_.Signal(); - })); - - // Check that Stop() before Start() doesn't cause any error. - scheduler_.Stop(); - - const TimeTicks tstart = TimeTicks::Now(); - scheduler_.Start(config, bg_thread_.task_runner()); - evt_.Wait(); - const double time_ms = (TimeTicks::Now() - tstart).InMillisecondsF(); - - // It takes N-1 ms to perform N ticks of 1ms each. - EXPECT_GE(time_ms, kPeriodMs * (kTicks - 1)); - - // Check that stopping twice doesn't cause any problems. - scheduler_.Stop(); - scheduler_.Stop(); -} - -TEST_F(MemoryDumpSchedulerTest, MultipleTriggers) { - const uint32_t kPeriodLightMs = 3; - const uint32_t kPeriodDetailedMs = 9; - MemoryDumpScheduler::Config config; - const MemoryDumpLevelOfDetail kLight = MemoryDumpLevelOfDetail::LIGHT; - const MemoryDumpLevelOfDetail kDetailed = MemoryDumpLevelOfDetail::DETAILED; - config.triggers.push_back({kLight, kPeriodLightMs}); - config.triggers.push_back({kDetailed, kPeriodDetailedMs}); - config.callback = Bind(&CallbackWrapper::OnTick, Unretained(&on_tick_)); - - TimeTicks t1, t2, t3; - - testing::InSequence sequence; - EXPECT_CALL(on_tick_, OnTick(kDetailed)) - .WillOnce( - Invoke([&t1](MemoryDumpLevelOfDetail) { t1 = TimeTicks::Now(); })); - EXPECT_CALL(on_tick_, OnTick(kLight)).Times(1); - EXPECT_CALL(on_tick_, OnTick(kLight)).Times(1); - EXPECT_CALL(on_tick_, OnTick(kDetailed)) - .WillOnce( - Invoke([&t2](MemoryDumpLevelOfDetail) { t2 = TimeTicks::Now(); })); - EXPECT_CALL(on_tick_, OnTick(kLight)) - .WillOnce( - Invoke([&t3](MemoryDumpLevelOfDetail) { t3 = TimeTicks::Now(); })); - - // Rationale for WillRepeatedly and not just WillOnce: Extra ticks might - // happen if the Stop() takes time. Not an interesting case, but we need to - // avoid gmock to shout in that case. - EXPECT_CALL(on_tick_, OnTick(_)) - .WillRepeatedly( - Invoke([this](MemoryDumpLevelOfDetail) { this->evt_.Signal(); })); - - scheduler_.Start(config, bg_thread_.task_runner()); - evt_.Wait(); - scheduler_.Stop(); - EXPECT_GE((t2 - t1).InMillisecondsF(), kPeriodDetailedMs); - EXPECT_GE((t3 - t2).InMillisecondsF(), kPeriodLightMs); -} - -TEST_F(MemoryDumpSchedulerTest, StartStopQuickly) { - const uint32_t kPeriodMs = 3; - const uint32_t kQuickIterations = 5; - const uint32_t kDetailedTicks = 10; - - MemoryDumpScheduler::Config light_config; - light_config.triggers.push_back({MemoryDumpLevelOfDetail::LIGHT, kPeriodMs}); - light_config.callback = Bind(&CallbackWrapper::OnTick, Unretained(&on_tick_)); - - MemoryDumpScheduler::Config detailed_config; - detailed_config.triggers.push_back( - {MemoryDumpLevelOfDetail::DETAILED, kPeriodMs}); - detailed_config.callback = - Bind(&CallbackWrapper::OnTick, Unretained(&on_tick_)); - - testing::InSequence sequence; - EXPECT_CALL(on_tick_, OnTick(MemoryDumpLevelOfDetail::LIGHT)) - .Times(AtMost(kQuickIterations)); - EXPECT_CALL(on_tick_, OnTick(MemoryDumpLevelOfDetail::DETAILED)) - .Times(kDetailedTicks - 1); - EXPECT_CALL(on_tick_, OnTick(MemoryDumpLevelOfDetail::DETAILED)) - .WillRepeatedly( - Invoke([this](MemoryDumpLevelOfDetail) { this->evt_.Signal(); })); - - const TimeTicks tstart = TimeTicks::Now(); - for (unsigned int i = 0; i < kQuickIterations; i++) { - scheduler_.Start(light_config, bg_thread_.task_runner()); - scheduler_.Stop(); - } - - scheduler_.Start(detailed_config, bg_thread_.task_runner()); - - evt_.Wait(); - const double time_ms = (TimeTicks::Now() - tstart).InMillisecondsF(); - scheduler_.Stop(); - - // It takes N-1 ms to perform N ticks of 1ms each. - EXPECT_GE(time_ms, kPeriodMs * (kDetailedTicks - 1)); -} - -TEST_F(MemoryDumpSchedulerTest, StopAndStartOnAnotherThread) { - const uint32_t kPeriodMs = 1; - const uint32_t kTicks = 3; - MemoryDumpScheduler::Config config; - config.triggers.push_back({MemoryDumpLevelOfDetail::DETAILED, kPeriodMs}); - config.callback = Bind(&CallbackWrapper::OnTick, Unretained(&on_tick_)); - - scoped_refptr<TaskRunner> expected_task_runner = bg_thread_.task_runner(); - testing::InSequence sequence; - EXPECT_CALL(on_tick_, OnTick(_)).Times(kTicks - 1); - EXPECT_CALL(on_tick_, OnTick(_)) - .WillRepeatedly( - Invoke([this, expected_task_runner](MemoryDumpLevelOfDetail) { - EXPECT_TRUE(expected_task_runner->RunsTasksInCurrentSequence()); - this->evt_.Signal(); - })); - - scheduler_.Start(config, bg_thread_.task_runner()); - evt_.Wait(); - scheduler_.Stop(); - bg_thread_.Stop(); - - Thread bg_thread_2("MemoryDumpSchedulerTest Thread 2"); - bg_thread_2.Start(); - evt_.Reset(); - expected_task_runner = bg_thread_2.task_runner(); - EXPECT_CALL(on_tick_, OnTick(_)).Times(kTicks - 1); - EXPECT_CALL(on_tick_, OnTick(_)) - .WillRepeatedly( - Invoke([this, expected_task_runner](MemoryDumpLevelOfDetail) { - EXPECT_TRUE(expected_task_runner->RunsTasksInCurrentSequence()); - this->evt_.Signal(); - })); - scheduler_.Start(config, bg_thread_2.task_runner()); - evt_.Wait(); - scheduler_.Stop(); -} - -} // namespace trace_event -} // namespace base
diff --git a/base/trace_event/memory_peak_detector_unittest.cc b/base/trace_event/memory_peak_detector_unittest.cc deleted file mode 100644 index bc10c80..0000000 --- a/base/trace_event/memory_peak_detector_unittest.cc +++ /dev/null
@@ -1,564 +0,0 @@ -// 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/trace_event/memory_peak_detector.h" - -#include <memory> - -#include "base/bind.h" -#include "base/logging.h" -#include "base/run_loop.h" -#include "base/synchronization/waitable_event.h" -#include "base/threading/platform_thread.h" -#include "base/threading/thread.h" -#include "base/threading/thread_task_runner_handle.h" -#include "base/trace_event/memory_dump_provider.h" -#include "base/trace_event/memory_dump_provider_info.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using ::testing::_; -using ::testing::Invoke; -using ::testing::Return; - -namespace base { -namespace trace_event { - -namespace { - -const TimeDelta kMs = TimeDelta::FromMilliseconds(1); -const MemoryPeakDetector::Config kConfigNoCallbacks( - 1 /* polling_interval_ms */, - 60000 /* min_time_between_peaks_ms */, - false /* enable_verbose_poll_tracing */ - ); - -class MockMemoryDumpProvider : public MemoryDumpProvider { - public: - bool OnMemoryDump(const MemoryDumpArgs&, ProcessMemoryDump*) override { - NOTREACHED(); - return true; - } - - MOCK_METHOD1(PollFastMemoryTotal, void(uint64_t*)); -}; - -// Wrapper to use gmock on a callback. -struct OnPeakDetectedWrapper { - MOCK_METHOD0(OnPeak, void()); -}; - -} // namespace - -class MemoryPeakDetectorTest : public testing::Test { - public: - struct FriendDeleter { - void operator()(MemoryPeakDetector* inst) { delete inst; } - }; - - MemoryPeakDetectorTest() : testing::Test() {} - static const uint64_t kSlidingWindowNumSamples = - MemoryPeakDetector::kSlidingWindowNumSamples; - - std::unique_ptr<MemoryPeakDetector, FriendDeleter> NewInstance() { - return std::unique_ptr<MemoryPeakDetector, FriendDeleter>( - new MemoryPeakDetector()); - } - - void RestartThreadAndReinitializePeakDetector() { - bg_thread_.reset(new Thread("Peak Detector Test Thread")); - bg_thread_->Start(); - peak_detector_ = NewInstance(); - peak_detector_->Setup( - Bind(&MemoryPeakDetectorTest::MockGetDumpProviders, Unretained(this)), - bg_thread_->task_runner(), - Bind(&OnPeakDetectedWrapper::OnPeak, Unretained(&on_peak_callback_))); - } - - void SetUp() override { - get_mdp_call_count_ = 0; - RestartThreadAndReinitializePeakDetector(); - } - - void TearDown() override { - peak_detector_->TearDown(); - bg_thread_->FlushForTesting(); - EXPECT_EQ(MemoryPeakDetector::NOT_INITIALIZED, GetPeakDetectorState()); - bg_thread_.reset(); - dump_providers_.clear(); - } - - // Calls MemoryPeakDetector::state_for_testing() on the bg thread and returns - // the result on the current thread. - MemoryPeakDetector::State GetPeakDetectorState() { - WaitableEvent evt(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - MemoryPeakDetector::State res = MemoryPeakDetector::NOT_INITIALIZED; - auto get_fn = [](MemoryPeakDetector* peak_detector, WaitableEvent* evt, - MemoryPeakDetector::State* res) { - *res = peak_detector->state_for_testing(); - evt->Signal(); - }; - bg_thread_->task_runner()->PostTask( - FROM_HERE, BindOnce(get_fn, Unretained(&*peak_detector_), - Unretained(&evt), Unretained(&res))); - evt.Wait(); - return res; - } - - // Calls MemoryPeakDetector::poll_tasks_count_for_testing() on the bg thread - // and returns the result on the current thread. - uint32_t GetNumPollingTasksRan() { - uint32_t res = 0; - auto get_fn = [](MemoryPeakDetector* peak_detector, WaitableEvent* evt, - uint32_t* res) { - *res = peak_detector->poll_tasks_count_for_testing(); - evt->Signal(); - }; - - WaitableEvent evt(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - bg_thread_->task_runner()->PostTask( - FROM_HERE, BindOnce(get_fn, Unretained(&*peak_detector_), - Unretained(&evt), Unretained(&res))); - evt.Wait(); - return res; - } - - // Runs the peak detector with a mock MDP with the given - // |config|. The mock MDP will invoke the |poll_function| on any call to - // PollFastMemoryTotal(), until |num_samples| have been polled. - // It returns the number of peaks detected. - uint32_t RunWithCustomPollFunction( - MemoryPeakDetector::Config config, - uint32_t num_samples, - RepeatingCallback<uint64_t(uint32_t)> poll_function) { - WaitableEvent evt(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - scoped_refptr<MemoryDumpProviderInfo> mdp = CreateMockDumpProvider(); - dump_providers_.push_back(mdp); - uint32_t cur_sample_idx = 0; - EXPECT_CALL(GetMockMDP(mdp), PollFastMemoryTotal(_)) - .WillRepeatedly(Invoke( - [&cur_sample_idx, &evt, poll_function, num_samples](uint64_t* mem) { - if (cur_sample_idx >= num_samples) { - *mem = 1; - evt.Signal(); - } else { - *mem = poll_function.Run(cur_sample_idx++); - } - })); - - uint32_t num_peaks = 0; - EXPECT_CALL(on_peak_callback_, OnPeak()) - .WillRepeatedly(Invoke([&num_peaks] { num_peaks++; })); - peak_detector_->Start(config); - evt.Wait(); // Wait for |num_samples| invocations of PollFastMemoryTotal(). - peak_detector_->Stop(); - EXPECT_EQ(num_samples, cur_sample_idx); - EXPECT_EQ(MemoryPeakDetector::DISABLED, GetPeakDetectorState()); - return num_peaks; - } - - // Called on the |bg_thread_|. - void MockGetDumpProviders(MemoryPeakDetector::DumpProvidersList* mdps) { - get_mdp_call_count_++; - *mdps = dump_providers_; - } - - uint32_t GetNumGetDumpProvidersCalls() { - bg_thread_->FlushForTesting(); - return get_mdp_call_count_; - } - - scoped_refptr<MemoryDumpProviderInfo> CreateMockDumpProvider() { - std::unique_ptr<MockMemoryDumpProvider> mdp(new MockMemoryDumpProvider()); - MemoryDumpProvider::Options opt; - opt.is_fast_polling_supported = true; - scoped_refptr<MemoryDumpProviderInfo> mdp_info(new MemoryDumpProviderInfo( - mdp.get(), "Mock MDP", nullptr, opt, - false /* whitelisted_for_background_mode */)); - - // The |mdp| instance will be destroyed together with the |mdp_info|. - mdp_info->owned_dump_provider = std::move(mdp); - return mdp_info; - } - - static MockMemoryDumpProvider& GetMockMDP( - const scoped_refptr<MemoryDumpProviderInfo>& mdp_info) { - return *static_cast<MockMemoryDumpProvider*>(mdp_info->dump_provider); - } - - static uint64_t PollFunctionThatCausesPeakViaStdDev(uint32_t sample_idx) { - // Start with a baseline of 50 MB. - if (sample_idx < kSlidingWindowNumSamples) - return 50000 + (sample_idx % 3) * 100; - - // Then 10 samples around 80 MB - if (sample_idx < 10 + kSlidingWindowNumSamples) - return 80000 + (sample_idx % 3) * 200; - - // Than back to 60 MB. - if (sample_idx < 2 * kSlidingWindowNumSamples) - return 60000 + (sample_idx % 3) * 100; - - // Then 20 samples around 120 MB. - if (sample_idx < 20 + 2 * kSlidingWindowNumSamples) - return 120000 + (sample_idx % 3) * 200; - - // Then back to idle to around 50 MB until the end. - return 50000 + (sample_idx % 3) * 100; - } - - protected: - MemoryPeakDetector::DumpProvidersList dump_providers_; - uint32_t get_mdp_call_count_; - std::unique_ptr<MemoryPeakDetector, FriendDeleter> peak_detector_; - std::unique_ptr<Thread> bg_thread_; - OnPeakDetectedWrapper on_peak_callback_; -}; - -const uint64_t MemoryPeakDetectorTest::kSlidingWindowNumSamples; - -TEST_F(MemoryPeakDetectorTest, GetDumpProvidersFunctionCalled) { - EXPECT_EQ(MemoryPeakDetector::DISABLED, GetPeakDetectorState()); - peak_detector_->Start(kConfigNoCallbacks); - EXPECT_EQ(1u, GetNumGetDumpProvidersCalls()); - EXPECT_EQ(MemoryPeakDetector::ENABLED, GetPeakDetectorState()); - - peak_detector_->Stop(); - EXPECT_EQ(MemoryPeakDetector::DISABLED, GetPeakDetectorState()); - EXPECT_EQ(0u, GetNumPollingTasksRan()); -} - -TEST_F(MemoryPeakDetectorTest, ThrottleAndNotifyBeforeInitialize) { - peak_detector_->TearDown(); - - WaitableEvent evt(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - scoped_refptr<MemoryDumpProviderInfo> mdp = CreateMockDumpProvider(); - EXPECT_CALL(GetMockMDP(mdp), PollFastMemoryTotal(_)) - .WillRepeatedly(Invoke([&evt](uint64_t*) { evt.Signal(); })); - dump_providers_.push_back(mdp); - peak_detector_->Throttle(); - peak_detector_->NotifyMemoryDumpProvidersChanged(); - EXPECT_EQ(MemoryPeakDetector::NOT_INITIALIZED, GetPeakDetectorState()); - RestartThreadAndReinitializePeakDetector(); - - peak_detector_->Start(kConfigNoCallbacks); - EXPECT_EQ(MemoryPeakDetector::RUNNING, GetPeakDetectorState()); - evt.Wait(); // Wait for a PollFastMemoryTotal() call. - - peak_detector_->Stop(); - EXPECT_EQ(MemoryPeakDetector::DISABLED, GetPeakDetectorState()); - EXPECT_EQ(1u, GetNumGetDumpProvidersCalls()); - EXPECT_GE(GetNumPollingTasksRan(), 1u); -} - -TEST_F(MemoryPeakDetectorTest, DoubleStop) { - peak_detector_->Start(kConfigNoCallbacks); - EXPECT_EQ(MemoryPeakDetector::ENABLED, GetPeakDetectorState()); - - peak_detector_->Stop(); - EXPECT_EQ(MemoryPeakDetector::DISABLED, GetPeakDetectorState()); - - peak_detector_->Stop(); - EXPECT_EQ(MemoryPeakDetector::DISABLED, GetPeakDetectorState()); - - EXPECT_EQ(1u, GetNumGetDumpProvidersCalls()); - EXPECT_EQ(0u, GetNumPollingTasksRan()); -} - -TEST_F(MemoryPeakDetectorTest, OneDumpProviderRegisteredBeforeStart) { - WaitableEvent evt(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - scoped_refptr<MemoryDumpProviderInfo> mdp = CreateMockDumpProvider(); - EXPECT_CALL(GetMockMDP(mdp), PollFastMemoryTotal(_)) - .WillRepeatedly(Invoke([&evt](uint64_t*) { evt.Signal(); })); - dump_providers_.push_back(mdp); - - peak_detector_->Start(kConfigNoCallbacks); - evt.Wait(); // Signaled when PollFastMemoryTotal() is called on the MockMDP. - EXPECT_EQ(MemoryPeakDetector::RUNNING, GetPeakDetectorState()); - - peak_detector_->Stop(); - EXPECT_EQ(MemoryPeakDetector::DISABLED, GetPeakDetectorState()); - EXPECT_EQ(1u, GetNumGetDumpProvidersCalls()); - EXPECT_GT(GetNumPollingTasksRan(), 0u); -} - -TEST_F(MemoryPeakDetectorTest, ReInitializeAndRebindToNewThread) { - WaitableEvent evt(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - scoped_refptr<MemoryDumpProviderInfo> mdp = CreateMockDumpProvider(); - EXPECT_CALL(GetMockMDP(mdp), PollFastMemoryTotal(_)) - .WillRepeatedly(Invoke([&evt](uint64_t*) { evt.Signal(); })); - dump_providers_.push_back(mdp); - - for (int i = 0; i < 5; ++i) { - evt.Reset(); - peak_detector_->Start(kConfigNoCallbacks); - evt.Wait(); // Wait for a PollFastMemoryTotal() call. - // Check that calling TearDown implicitly does a Stop(). - peak_detector_->TearDown(); - - // Reinitialize and re-bind to a new task runner. - RestartThreadAndReinitializePeakDetector(); - } -} - -TEST_F(MemoryPeakDetectorTest, OneDumpProviderRegisteredOutOfBand) { - peak_detector_->Start(kConfigNoCallbacks); - EXPECT_EQ(MemoryPeakDetector::ENABLED, GetPeakDetectorState()); - EXPECT_EQ(1u, GetNumGetDumpProvidersCalls()); - - // Check that no poll tasks are posted before any dump provider is registered. - PlatformThread::Sleep(5 * kConfigNoCallbacks.polling_interval_ms * kMs); - EXPECT_EQ(0u, GetNumPollingTasksRan()); - - // Registed the MDP After Start() has been issued and expect that the - // PeakDetector transitions ENABLED -> RUNNING on the next - // NotifyMemoryDumpProvidersChanged() call. - WaitableEvent evt(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - scoped_refptr<MemoryDumpProviderInfo> mdp = CreateMockDumpProvider(); - EXPECT_CALL(GetMockMDP(mdp), PollFastMemoryTotal(_)) - .WillRepeatedly(Invoke([&evt](uint64_t*) { evt.Signal(); })); - dump_providers_.push_back(mdp); - peak_detector_->NotifyMemoryDumpProvidersChanged(); - - evt.Wait(); // Signaled when PollFastMemoryTotal() is called on the MockMDP. - EXPECT_EQ(MemoryPeakDetector::RUNNING, GetPeakDetectorState()); - EXPECT_EQ(2u, GetNumGetDumpProvidersCalls()); - - // Now simulate the unregisration and expect that the PeakDetector transitions - // back to ENABLED. - dump_providers_.clear(); - peak_detector_->NotifyMemoryDumpProvidersChanged(); - EXPECT_EQ(MemoryPeakDetector::ENABLED, GetPeakDetectorState()); - EXPECT_EQ(3u, GetNumGetDumpProvidersCalls()); - uint32_t num_poll_tasks = GetNumPollingTasksRan(); - EXPECT_GT(num_poll_tasks, 0u); - - // At this point, no more polling tasks should be posted. - PlatformThread::Sleep(5 * kConfigNoCallbacks.polling_interval_ms * kMs); - peak_detector_->Stop(); - EXPECT_EQ(MemoryPeakDetector::DISABLED, GetPeakDetectorState()); - EXPECT_EQ(num_poll_tasks, GetNumPollingTasksRan()); -} - -// Test that a sequence of Start()/Stop() back-to-back doesn't end up creating -// several outstanding timer tasks and instead respects the polling_interval_ms. -TEST_F(MemoryPeakDetectorTest, StartStopQuickly) { - WaitableEvent evt(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - scoped_refptr<MemoryDumpProviderInfo> mdp = CreateMockDumpProvider(); - dump_providers_.push_back(mdp); - const uint32_t kNumPolls = 20; - uint32_t polls_done = 0; - EXPECT_CALL(GetMockMDP(mdp), PollFastMemoryTotal(_)) - .WillRepeatedly(Invoke([&polls_done, &evt, kNumPolls](uint64_t*) { - if (++polls_done == kNumPolls) - evt.Signal(); - })); - - const TimeTicks tstart = TimeTicks::Now(); - for (int i = 0; i < 5; i++) { - peak_detector_->Start(kConfigNoCallbacks); - peak_detector_->Stop(); - } - - bg_thread_->task_runner()->PostTask( - FROM_HERE, base::BindOnce([](uint32_t* polls_done) { *polls_done = 0; }, - &polls_done)); - - peak_detector_->Start(kConfigNoCallbacks); - EXPECT_EQ(MemoryPeakDetector::RUNNING, GetPeakDetectorState()); - evt.Wait(); // Wait for kNumPolls. - const double time_ms = (TimeTicks::Now() - tstart).InMillisecondsF(); - - EXPECT_GE(time_ms, (kNumPolls - 1) * kConfigNoCallbacks.polling_interval_ms); - peak_detector_->Stop(); -} - -TEST_F(MemoryPeakDetectorTest, RegisterAndUnregisterTwoDumpProviders) { - WaitableEvent evt1(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - WaitableEvent evt2(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - scoped_refptr<MemoryDumpProviderInfo> mdp1 = CreateMockDumpProvider(); - scoped_refptr<MemoryDumpProviderInfo> mdp2 = CreateMockDumpProvider(); - EXPECT_CALL(GetMockMDP(mdp1), PollFastMemoryTotal(_)) - .WillRepeatedly(Invoke([&evt1](uint64_t*) { evt1.Signal(); })); - EXPECT_CALL(GetMockMDP(mdp2), PollFastMemoryTotal(_)) - .WillRepeatedly(Invoke([&evt2](uint64_t*) { evt2.Signal(); })); - - // Register only one MDP and start the detector. - dump_providers_.push_back(mdp1); - peak_detector_->Start(kConfigNoCallbacks); - EXPECT_EQ(MemoryPeakDetector::RUNNING, GetPeakDetectorState()); - - // Wait for one poll task and then register also the other one. - evt1.Wait(); - dump_providers_.push_back(mdp2); - peak_detector_->NotifyMemoryDumpProvidersChanged(); - evt2.Wait(); - EXPECT_EQ(MemoryPeakDetector::RUNNING, GetPeakDetectorState()); - - // Now unregister the first MDP and check that everything is still running. - dump_providers_.erase(dump_providers_.begin()); - peak_detector_->NotifyMemoryDumpProvidersChanged(); - EXPECT_EQ(MemoryPeakDetector::RUNNING, GetPeakDetectorState()); - - // Now unregister both and check that the detector goes to idle. - dump_providers_.clear(); - peak_detector_->NotifyMemoryDumpProvidersChanged(); - EXPECT_EQ(MemoryPeakDetector::ENABLED, GetPeakDetectorState()); - - // Now re-register both and check that the detector re-activates posting - // new polling tasks. - uint32_t num_poll_tasks = GetNumPollingTasksRan(); - evt1.Reset(); - evt2.Reset(); - dump_providers_.push_back(mdp1); - dump_providers_.push_back(mdp2); - peak_detector_->NotifyMemoryDumpProvidersChanged(); - evt1.Wait(); - evt2.Wait(); - EXPECT_EQ(MemoryPeakDetector::RUNNING, GetPeakDetectorState()); - EXPECT_GT(GetNumPollingTasksRan(), num_poll_tasks); - - // Stop everything, tear down the MDPs, restart the detector and check that - // it detector doesn't accidentally try to re-access them. - peak_detector_->Stop(); - EXPECT_EQ(MemoryPeakDetector::DISABLED, GetPeakDetectorState()); - dump_providers_.clear(); - mdp1 = nullptr; - mdp2 = nullptr; - - num_poll_tasks = GetNumPollingTasksRan(); - peak_detector_->Start(kConfigNoCallbacks); - EXPECT_EQ(MemoryPeakDetector::ENABLED, GetPeakDetectorState()); - PlatformThread::Sleep(5 * kConfigNoCallbacks.polling_interval_ms * kMs); - - peak_detector_->Stop(); - EXPECT_EQ(MemoryPeakDetector::DISABLED, GetPeakDetectorState()); - EXPECT_EQ(num_poll_tasks, GetNumPollingTasksRan()); - - EXPECT_EQ(6u, GetNumGetDumpProvidersCalls()); -} - -// Tests the behavior of the static threshold detector, which is supposed to -// detect a peak whenever an increase >= threshold is detected. -TEST_F(MemoryPeakDetectorTest, StaticThreshold) { - const uint32_t kNumSamples = 2 * kSlidingWindowNumSamples; - constexpr uint32_t kNumSamplesPerStep = 10; - constexpr uint64_t kThreshold = 1000000; - peak_detector_->SetStaticThresholdForTesting(kThreshold); - const MemoryPeakDetector::Config kConfig( - 1 /* polling_interval_ms */, 0 /* min_time_between_peaks_ms */, - false /* enable_verbose_poll_tracing */ - ); - - // The mocked PollFastMemoryTotal() will return a step function, - // e.g. (1, 1, 1, 5, 5, 5, ...) where the steps are 2x threshold, in order to - // trigger only the static threshold logic. - auto poll_fn = Bind( - [](const uint32_t kNumSamplesPerStep, const uint64_t kThreshold, - uint32_t sample_idx) -> uint64_t { - return (1 + sample_idx / kNumSamplesPerStep) * 2 * kThreshold; - }, - kNumSamplesPerStep, kThreshold); - uint32_t num_peaks = RunWithCustomPollFunction(kConfig, kNumSamples, poll_fn); - EXPECT_EQ(kNumSamples / kNumSamplesPerStep - 1, num_peaks); -} - -// Checks the throttling logic of Config's |min_time_between_peaks_ms|. -TEST_F(MemoryPeakDetectorTest, PeakCallbackThrottling) { - const size_t kNumSamples = 2 * kSlidingWindowNumSamples; - constexpr uint64_t kThreshold = 1000000; - peak_detector_->SetStaticThresholdForTesting(kThreshold); - const MemoryPeakDetector::Config kConfig( - 1 /* polling_interval_ms */, 4 /* min_time_between_peaks_ms */, - false /* enable_verbose_poll_tracing */ - ); - - // Each mock value returned is N * 2 * threshold, so all of them would be - // eligible to be a peak if throttling wasn't enabled. - auto poll_fn = Bind( - [](uint64_t kThreshold, uint32_t sample_idx) -> uint64_t { - return (sample_idx + 1) * 2 * kThreshold; - }, - kThreshold); - uint32_t num_peaks = RunWithCustomPollFunction(kConfig, kNumSamples, poll_fn); - const uint32_t kExpectedThrottlingRate = - kConfig.min_time_between_peaks_ms / kConfig.polling_interval_ms; - EXPECT_LT(num_peaks, kNumSamples / kExpectedThrottlingRate); -} - -TEST_F(MemoryPeakDetectorTest, StdDev) { - // Set the threshold to some arbitrarily high value, so that the static - // threshold logic is not hit in this test. - constexpr uint64_t kThreshold = 1024 * 1024 * 1024; - peak_detector_->SetStaticThresholdForTesting(kThreshold); - const size_t kNumSamples = 3 * kSlidingWindowNumSamples; - const MemoryPeakDetector::Config kConfig( - 1 /* polling_interval_ms */, 0 /* min_time_between_peaks_ms */, - false /* enable_verbose_poll_tracing */ - ); - - auto poll_fn = Bind(&PollFunctionThatCausesPeakViaStdDev); - uint32_t num_peaks = RunWithCustomPollFunction(kConfig, kNumSamples, poll_fn); - EXPECT_EQ(2u, num_peaks); // 80 MB, 120 MB. -} - -// Tests that Throttle() actually holds back peak notifications. -TEST_F(MemoryPeakDetectorTest, Throttle) { - constexpr uint64_t kThreshold = 1024 * 1024 * 1024; - const uint32_t kNumSamples = 3 * kSlidingWindowNumSamples; - peak_detector_->SetStaticThresholdForTesting(kThreshold); - const MemoryPeakDetector::Config kConfig( - 1 /* polling_interval_ms */, 0 /* min_time_between_peaks_ms */, - false /* enable_verbose_poll_tracing */ - ); - - auto poll_fn = Bind( - [](MemoryPeakDetector* peak_detector, uint32_t sample_idx) -> uint64_t { - if (sample_idx % 20 == 20 - 1) - peak_detector->Throttle(); - return PollFunctionThatCausesPeakViaStdDev(sample_idx); - }, - Unretained(&*peak_detector_)); - uint32_t num_peaks = RunWithCustomPollFunction(kConfig, kNumSamples, poll_fn); - EXPECT_EQ(0u, num_peaks); -} - -// Tests that the windows stddev state is not carried over through -// Stop() -> Start() sequences. -TEST_F(MemoryPeakDetectorTest, RestartClearsState) { - constexpr uint64_t kThreshold = 1024 * 1024 * 1024; - peak_detector_->SetStaticThresholdForTesting(kThreshold); - const size_t kNumSamples = 3 * kSlidingWindowNumSamples; - const MemoryPeakDetector::Config kConfig( - 1 /* polling_interval_ms */, 0 /* min_time_between_peaks_ms */, - false /* enable_verbose_poll_tracing */ - ); - auto poll_fn = Bind( - [](MemoryPeakDetector* peak_detector, - const uint32_t kSlidingWindowNumSamples, - MemoryPeakDetector::Config kConfig, uint32_t sample_idx) -> uint64_t { - if (sample_idx % kSlidingWindowNumSamples == - kSlidingWindowNumSamples - 1) { - peak_detector->Stop(); - peak_detector->Start(kConfig); - } - return PollFunctionThatCausesPeakViaStdDev(sample_idx); - }, - Unretained(&*peak_detector_), kSlidingWindowNumSamples, kConfig); - uint32_t num_peaks = RunWithCustomPollFunction(kConfig, kNumSamples, poll_fn); - EXPECT_EQ(0u, num_peaks); -} - -} // namespace trace_event -} // namespace base
diff --git a/base/trace_event/memory_usage_estimator_unittest.cc b/base/trace_event/memory_usage_estimator_unittest.cc deleted file mode 100644 index 7f8efc7..0000000 --- a/base/trace_event/memory_usage_estimator_unittest.cc +++ /dev/null
@@ -1,265 +0,0 @@ -// 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/trace_event/memory_usage_estimator.h" - -#include <stdlib.h> - -#include "base/memory/ptr_util.h" -#include "base/strings/string16.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(ARCH_CPU_64_BITS) -#define EXPECT_EQ_32_64(_, e, a) EXPECT_EQ(e, a) -#else -#define EXPECT_EQ_32_64(e, _, a) EXPECT_EQ(e, a) -#endif - -namespace base { -namespace trace_event { - -namespace { - -// Test class with predictable memory usage. -class Data { - public: - explicit Data(size_t size = 17): size_(size) { - } - - size_t size() const { return size_; } - - size_t EstimateMemoryUsage() const { - return size_; - } - - bool operator < (const Data& other) const { - return size_ < other.size_; - } - bool operator == (const Data& other) const { - return size_ == other.size_; - } - - struct Hasher { - size_t operator () (const Data& data) const { - return data.size(); - } - }; - - private: - size_t size_; -}; - -} // namespace - -namespace internal { - -// This kills variance of bucket_count across STL implementations. -template <> -size_t HashMapBucketCountForTesting<Data>(size_t) { - return 10; -} -template <> -size_t HashMapBucketCountForTesting<std::pair<const Data, short>>(size_t) { - return 10; -} - -} // namespace internal - -TEST(EstimateMemoryUsageTest, String) { - std::string string(777, 'a'); - EXPECT_EQ(string.capacity() + 1, EstimateMemoryUsage(string)); -} - -TEST(EstimateMemoryUsageTest, String16) { - string16 string(777, 'a'); - EXPECT_EQ(sizeof(char16) * (string.capacity() + 1), - EstimateMemoryUsage(string)); -} - -TEST(EstimateMemoryUsageTest, Arrays) { - // std::array - { - std::array<Data, 10> array; - EXPECT_EQ(170u, EstimateMemoryUsage(array)); - } - - // T[N] - { - Data array[10]; - EXPECT_EQ(170u, EstimateMemoryUsage(array)); - } - - // C array - { - struct Item { - char payload[10]; - }; - Item* array = new Item[7]; - EXPECT_EQ(70u, EstimateMemoryUsage(array, 7)); - delete[] array; - } -} - -TEST(EstimateMemoryUsageTest, UniquePtr) { - // Empty - { - std::unique_ptr<Data> ptr; - EXPECT_EQ(0u, EstimateMemoryUsage(ptr)); - } - - // Not empty - { - std::unique_ptr<Data> ptr(new Data()); - EXPECT_EQ_32_64(21u, 25u, EstimateMemoryUsage(ptr)); - } - - // With a pointer - { - std::unique_ptr<Data*> ptr(new Data*()); - EXPECT_EQ(sizeof(void*), EstimateMemoryUsage(ptr)); - } - - // With an array - { - struct Item { - uint32_t payload[10]; - }; - std::unique_ptr<Item[]> ptr(new Item[7]); - EXPECT_EQ(280u, EstimateMemoryUsage(ptr, 7)); - } -} - -TEST(EstimateMemoryUsageTest, Vector) { - std::vector<Data> vector; - vector.reserve(1000); - - // For an empty vector we should return memory usage of its buffer - size_t capacity = vector.capacity(); - size_t expected_size = capacity * sizeof(Data); - EXPECT_EQ(expected_size, EstimateMemoryUsage(vector)); - - // If vector is not empty, its size should also include memory usages - // of all elements. - for (size_t i = 0; i != capacity / 2; ++i) { - vector.push_back(Data(i)); - expected_size += EstimateMemoryUsage(vector.back()); - } - EXPECT_EQ(expected_size, EstimateMemoryUsage(vector)); -} - -TEST(EstimateMemoryUsageTest, List) { - struct POD { - short data; - }; - std::list<POD> list; - for (int i = 0; i != 1000; ++i) { - list.push_back(POD()); - } - EXPECT_EQ_32_64(12000u, 24000u, EstimateMemoryUsage(list)); -} - -TEST(EstimateMemoryUsageTest, Set) { - std::set<std::pair<int, Data>> set; - for (int i = 0; i != 1000; ++i) { - set.insert({i, Data(i)}); - } - EXPECT_EQ_32_64(523500u, 547500u, EstimateMemoryUsage(set)); -} - -TEST(EstimateMemoryUsageTest, MultiSet) { - std::multiset<bool> set; - for (int i = 0; i != 1000; ++i) { - set.insert((i & 1) != 0); - } - EXPECT_EQ_32_64(16000u, 32000u, EstimateMemoryUsage(set)); -} - -TEST(EstimateMemoryUsageTest, Map) { - std::map<Data, int> map; - for (int i = 0; i != 1000; ++i) { - map.insert({Data(i), i}); - } - EXPECT_EQ_32_64(523500u, 547500u, EstimateMemoryUsage(map)); -} - -TEST(EstimateMemoryUsageTest, MultiMap) { - std::multimap<char, Data> map; - for (int i = 0; i != 1000; ++i) { - map.insert({static_cast<char>(i), Data(i)}); - } - EXPECT_EQ_32_64(523500u, 547500u, EstimateMemoryUsage(map)); -} - -TEST(EstimateMemoryUsageTest, UnorderedSet) { - std::unordered_set<Data, Data::Hasher> set; - for (int i = 0; i != 1000; ++i) { - set.insert(Data(i)); - } - EXPECT_EQ_32_64(511540u, 523580u, EstimateMemoryUsage(set)); -} - -TEST(EstimateMemoryUsageTest, UnorderedMultiSet) { - std::unordered_multiset<Data, Data::Hasher> set; - for (int i = 0; i != 500; ++i) { - set.insert(Data(i)); - set.insert(Data(i)); - } - EXPECT_EQ_32_64(261540u, 273580u, EstimateMemoryUsage(set)); -} - -TEST(EstimateMemoryUsageTest, UnorderedMap) { - std::unordered_map<Data, short, Data::Hasher> map; - for (int i = 0; i != 1000; ++i) { - map.insert({Data(i), static_cast<short>(i)}); - } - EXPECT_EQ_32_64(515540u, 531580u, EstimateMemoryUsage(map)); -} - -TEST(EstimateMemoryUsageTest, UnorderedMultiMap) { - std::unordered_multimap<Data, short, Data::Hasher> map; - for (int i = 0; i != 1000; ++i) { - map.insert({Data(i), static_cast<short>(i)}); - } - EXPECT_EQ_32_64(515540u, 531580u, EstimateMemoryUsage(map)); -} - -TEST(EstimateMemoryUsageTest, Deque) { - std::deque<Data> deque; - - // Pick a large value so that platform-specific accounting - // for deque's blocks is small compared to usage of all items. - constexpr size_t kDataSize = 100000; - for (int i = 0; i != 1500; ++i) { - deque.push_back(Data(kDataSize)); - } - - // Compare against a reasonable minimum (i.e. no overhead). - size_t min_expected_usage = deque.size() * (sizeof(Data) + kDataSize); - EXPECT_LE(min_expected_usage, EstimateMemoryUsage(deque)); -} - -TEST(EstimateMemoryUsageTest, IsStandardContainerComplexIteratorTest) { - struct abstract { - virtual void method() = 0; - }; - - static_assert( - internal::IsStandardContainerComplexIterator<std::list<int>::iterator>(), - ""); - static_assert(internal::IsStandardContainerComplexIterator< - std::list<int>::const_iterator>(), - ""); - static_assert(internal::IsStandardContainerComplexIterator< - std::list<int>::reverse_iterator>(), - ""); - static_assert(internal::IsStandardContainerComplexIterator< - std::list<int>::const_reverse_iterator>(), - ""); - static_assert(!internal::IsStandardContainerComplexIterator<int>(), ""); - static_assert(!internal::IsStandardContainerComplexIterator<abstract*>(), ""); -} - -} // namespace trace_event -} // namespace base
diff --git a/base/trace_event/process_memory_dump_unittest.cc b/base/trace_event/process_memory_dump_unittest.cc deleted file mode 100644 index b33a39e..0000000 --- a/base/trace_event/process_memory_dump_unittest.cc +++ /dev/null
@@ -1,584 +0,0 @@ -// 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/trace_event/process_memory_dump.h" - -#include <stddef.h> - -#include "base/memory/aligned_memory.h" -#include "base/memory/ptr_util.h" -#include "base/memory/shared_memory_tracker.h" -#include "base/process/process_metrics.h" -#include "base/trace_event/memory_allocator_dump_guid.h" -#include "base/trace_event/memory_infra_background_whitelist.h" -#include "base/trace_event/trace_event_argument.h" -#include "base/trace_event/trace_log.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(OS_WIN) -#include <windows.h> -#include "winbase.h" -#elif defined(OS_POSIX) || defined(OS_FUCHSIA) -#include <sys/mman.h> -#endif - -#if defined(OS_IOS) -#include "base/ios/ios_util.h" -#endif - -namespace base { -namespace trace_event { - -namespace { - -const MemoryDumpArgs kDetailedDumpArgs = {MemoryDumpLevelOfDetail::DETAILED}; -const char* const kTestDumpNameWhitelist[] = { - "Whitelisted/TestName", "Whitelisted/TestName_0x?", - "Whitelisted/0x?/TestName", "Whitelisted/0x?", nullptr}; - -TracedValue* GetHeapDump(const ProcessMemoryDump& pmd, const char* name) { - auto it = pmd.heap_dumps().find(name); - return it == pmd.heap_dumps().end() ? nullptr : it->second.get(); -} - -void* Map(size_t size) { -#if defined(OS_WIN) - return ::VirtualAlloc(nullptr, size, MEM_RESERVE | MEM_COMMIT, - PAGE_READWRITE); -#elif defined(OS_POSIX) || defined(OS_FUCHSIA) - return ::mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, - 0, 0); -#endif -} - -void Unmap(void* addr, size_t size) { -#if defined(OS_WIN) - ::VirtualFree(addr, 0, MEM_DECOMMIT); -#elif defined(OS_POSIX) || defined(OS_FUCHSIA) - ::munmap(addr, size); -#else -#error This architecture is not (yet) supported. -#endif -} - -} // namespace - -TEST(ProcessMemoryDumpTest, MoveConstructor) { - auto heap_state = MakeRefCounted<HeapProfilerSerializationState>(); - heap_state->SetStackFrameDeduplicator( - std::make_unique<StackFrameDeduplicator>()); - heap_state->SetTypeNameDeduplicator(std::make_unique<TypeNameDeduplicator>()); - - ProcessMemoryDump pmd1 = ProcessMemoryDump(heap_state, kDetailedDumpArgs); - pmd1.CreateAllocatorDump("mad1"); - pmd1.CreateAllocatorDump("mad2"); - pmd1.AddOwnershipEdge(MemoryAllocatorDumpGuid(42), - MemoryAllocatorDumpGuid(4242)); - - ProcessMemoryDump pmd2(std::move(pmd1)); - - EXPECT_EQ(1u, pmd2.allocator_dumps().count("mad1")); - EXPECT_EQ(1u, pmd2.allocator_dumps().count("mad2")); - EXPECT_EQ(MemoryDumpLevelOfDetail::DETAILED, - pmd2.dump_args().level_of_detail); - EXPECT_EQ(1u, pmd2.allocator_dumps_edges().size()); - EXPECT_EQ(heap_state.get(), pmd2.heap_profiler_serialization_state().get()); - - // Check that calling serialization routines doesn't cause a crash. - auto traced_value = std::make_unique<TracedValue>(); - pmd2.SerializeAllocatorDumpsInto(traced_value.get()); - pmd2.SerializeHeapProfilerDumpsInto(traced_value.get()); -} - -TEST(ProcessMemoryDumpTest, MoveAssignment) { - auto heap_state = MakeRefCounted<HeapProfilerSerializationState>(); - heap_state->SetStackFrameDeduplicator( - std::make_unique<StackFrameDeduplicator>()); - heap_state->SetTypeNameDeduplicator(std::make_unique<TypeNameDeduplicator>()); - - ProcessMemoryDump pmd1 = ProcessMemoryDump(heap_state, kDetailedDumpArgs); - pmd1.CreateAllocatorDump("mad1"); - pmd1.CreateAllocatorDump("mad2"); - pmd1.AddOwnershipEdge(MemoryAllocatorDumpGuid(42), - MemoryAllocatorDumpGuid(4242)); - - ProcessMemoryDump pmd2(nullptr, {MemoryDumpLevelOfDetail::BACKGROUND}); - pmd2.CreateAllocatorDump("malloc"); - - pmd2 = std::move(pmd1); - EXPECT_EQ(1u, pmd2.allocator_dumps().count("mad1")); - EXPECT_EQ(1u, pmd2.allocator_dumps().count("mad2")); - EXPECT_EQ(0u, pmd2.allocator_dumps().count("mad3")); - EXPECT_EQ(MemoryDumpLevelOfDetail::DETAILED, - pmd2.dump_args().level_of_detail); - EXPECT_EQ(1u, pmd2.allocator_dumps_edges().size()); - EXPECT_EQ(heap_state.get(), pmd2.heap_profiler_serialization_state().get()); - - // Check that calling serialization routines doesn't cause a crash. - auto traced_value = std::make_unique<TracedValue>(); - pmd2.SerializeAllocatorDumpsInto(traced_value.get()); - pmd2.SerializeHeapProfilerDumpsInto(traced_value.get()); -} - -TEST(ProcessMemoryDumpTest, Clear) { - std::unique_ptr<ProcessMemoryDump> pmd1( - new ProcessMemoryDump(nullptr, kDetailedDumpArgs)); - pmd1->CreateAllocatorDump("mad1"); - pmd1->CreateAllocatorDump("mad2"); - ASSERT_FALSE(pmd1->allocator_dumps().empty()); - - pmd1->AddOwnershipEdge(MemoryAllocatorDumpGuid(42), - MemoryAllocatorDumpGuid(4242)); - - MemoryAllocatorDumpGuid shared_mad_guid1(1); - MemoryAllocatorDumpGuid shared_mad_guid2(2); - pmd1->CreateSharedGlobalAllocatorDump(shared_mad_guid1); - pmd1->CreateSharedGlobalAllocatorDump(shared_mad_guid2); - - pmd1->Clear(); - ASSERT_TRUE(pmd1->allocator_dumps().empty()); - ASSERT_TRUE(pmd1->allocator_dumps_edges().empty()); - ASSERT_EQ(nullptr, pmd1->GetAllocatorDump("mad1")); - ASSERT_EQ(nullptr, pmd1->GetAllocatorDump("mad2")); - ASSERT_EQ(nullptr, pmd1->GetSharedGlobalAllocatorDump(shared_mad_guid1)); - ASSERT_EQ(nullptr, pmd1->GetSharedGlobalAllocatorDump(shared_mad_guid2)); - - // Check that calling serialization routines doesn't cause a crash. - auto traced_value = std::make_unique<TracedValue>(); - pmd1->SerializeAllocatorDumpsInto(traced_value.get()); - pmd1->SerializeHeapProfilerDumpsInto(traced_value.get()); - - // Check that the pmd can be reused and behaves as expected. - auto* mad1 = pmd1->CreateAllocatorDump("mad1"); - auto* mad3 = pmd1->CreateAllocatorDump("mad3"); - auto* shared_mad1 = pmd1->CreateSharedGlobalAllocatorDump(shared_mad_guid1); - auto* shared_mad2 = - pmd1->CreateWeakSharedGlobalAllocatorDump(shared_mad_guid2); - ASSERT_EQ(4u, pmd1->allocator_dumps().size()); - ASSERT_EQ(mad1, pmd1->GetAllocatorDump("mad1")); - ASSERT_EQ(nullptr, pmd1->GetAllocatorDump("mad2")); - ASSERT_EQ(mad3, pmd1->GetAllocatorDump("mad3")); - ASSERT_EQ(shared_mad1, pmd1->GetSharedGlobalAllocatorDump(shared_mad_guid1)); - ASSERT_EQ(MemoryAllocatorDump::Flags::DEFAULT, shared_mad1->flags()); - ASSERT_EQ(shared_mad2, pmd1->GetSharedGlobalAllocatorDump(shared_mad_guid2)); - ASSERT_EQ(MemoryAllocatorDump::Flags::WEAK, shared_mad2->flags()); - - traced_value.reset(new TracedValue); - pmd1->SerializeAllocatorDumpsInto(traced_value.get()); - pmd1->SerializeHeapProfilerDumpsInto(traced_value.get()); - - pmd1.reset(); -} - -TEST(ProcessMemoryDumpTest, TakeAllDumpsFrom) { - std::unique_ptr<TracedValue> traced_value(new TracedValue); - std::unordered_map<AllocationContext, AllocationMetrics> metrics_by_context; - metrics_by_context[AllocationContext()] = {1, 1}; - TraceEventMemoryOverhead overhead; - - scoped_refptr<HeapProfilerSerializationState> - heap_profiler_serialization_state = new HeapProfilerSerializationState; - heap_profiler_serialization_state->SetStackFrameDeduplicator( - WrapUnique(new StackFrameDeduplicator)); - heap_profiler_serialization_state->SetTypeNameDeduplicator( - WrapUnique(new TypeNameDeduplicator)); - std::unique_ptr<ProcessMemoryDump> pmd1(new ProcessMemoryDump( - heap_profiler_serialization_state.get(), kDetailedDumpArgs)); - auto* mad1_1 = pmd1->CreateAllocatorDump("pmd1/mad1"); - auto* mad1_2 = pmd1->CreateAllocatorDump("pmd1/mad2"); - pmd1->AddOwnershipEdge(mad1_1->guid(), mad1_2->guid()); - pmd1->DumpHeapUsage(metrics_by_context, overhead, "pmd1/heap_dump1"); - pmd1->DumpHeapUsage(metrics_by_context, overhead, "pmd1/heap_dump2"); - - std::unique_ptr<ProcessMemoryDump> pmd2(new ProcessMemoryDump( - heap_profiler_serialization_state.get(), kDetailedDumpArgs)); - auto* mad2_1 = pmd2->CreateAllocatorDump("pmd2/mad1"); - auto* mad2_2 = pmd2->CreateAllocatorDump("pmd2/mad2"); - pmd2->AddOwnershipEdge(mad2_1->guid(), mad2_2->guid()); - pmd2->DumpHeapUsage(metrics_by_context, overhead, "pmd2/heap_dump1"); - pmd2->DumpHeapUsage(metrics_by_context, overhead, "pmd2/heap_dump2"); - - MemoryAllocatorDumpGuid shared_mad_guid1(1); - MemoryAllocatorDumpGuid shared_mad_guid2(2); - auto* shared_mad1 = pmd2->CreateSharedGlobalAllocatorDump(shared_mad_guid1); - auto* shared_mad2 = - pmd2->CreateWeakSharedGlobalAllocatorDump(shared_mad_guid2); - - pmd1->TakeAllDumpsFrom(pmd2.get()); - - // Make sure that pmd2 is empty but still usable after it has been emptied. - ASSERT_TRUE(pmd2->allocator_dumps().empty()); - ASSERT_TRUE(pmd2->allocator_dumps_edges().empty()); - ASSERT_TRUE(pmd2->heap_dumps().empty()); - pmd2->CreateAllocatorDump("pmd2/this_mad_stays_with_pmd2"); - ASSERT_EQ(1u, pmd2->allocator_dumps().size()); - ASSERT_EQ(1u, pmd2->allocator_dumps().count("pmd2/this_mad_stays_with_pmd2")); - pmd2->AddOwnershipEdge(MemoryAllocatorDumpGuid(42), - MemoryAllocatorDumpGuid(4242)); - - // Check that calling serialization routines doesn't cause a crash. - pmd2->SerializeAllocatorDumpsInto(traced_value.get()); - pmd2->SerializeHeapProfilerDumpsInto(traced_value.get()); - - // Free the |pmd2| to check that the memory ownership of the two MAD(s) - // has been transferred to |pmd1|. - pmd2.reset(); - - // Now check that |pmd1| has been effectively merged. - ASSERT_EQ(6u, pmd1->allocator_dumps().size()); - ASSERT_EQ(1u, pmd1->allocator_dumps().count("pmd1/mad1")); - ASSERT_EQ(1u, pmd1->allocator_dumps().count("pmd1/mad2")); - ASSERT_EQ(1u, pmd1->allocator_dumps().count("pmd2/mad1")); - ASSERT_EQ(1u, pmd1->allocator_dumps().count("pmd1/mad2")); - ASSERT_EQ(2u, pmd1->allocator_dumps_edges().size()); - ASSERT_EQ(shared_mad1, pmd1->GetSharedGlobalAllocatorDump(shared_mad_guid1)); - ASSERT_EQ(shared_mad2, pmd1->GetSharedGlobalAllocatorDump(shared_mad_guid2)); - ASSERT_TRUE(MemoryAllocatorDump::Flags::WEAK & shared_mad2->flags()); - ASSERT_EQ(4u, pmd1->heap_dumps().size()); - ASSERT_TRUE(GetHeapDump(*pmd1, "pmd1/heap_dump1") != nullptr); - ASSERT_TRUE(GetHeapDump(*pmd1, "pmd1/heap_dump2") != nullptr); - ASSERT_TRUE(GetHeapDump(*pmd1, "pmd2/heap_dump1") != nullptr); - ASSERT_TRUE(GetHeapDump(*pmd1, "pmd2/heap_dump2") != nullptr); - - // Check that calling serialization routines doesn't cause a crash. - traced_value.reset(new TracedValue); - pmd1->SerializeAllocatorDumpsInto(traced_value.get()); - pmd1->SerializeHeapProfilerDumpsInto(traced_value.get()); - - pmd1.reset(); -} - -TEST(ProcessMemoryDumpTest, OverrideOwnershipEdge) { - std::unique_ptr<ProcessMemoryDump> pmd( - new ProcessMemoryDump(nullptr, kDetailedDumpArgs)); - - auto* shm_dump1 = pmd->CreateAllocatorDump("shared_mem/seg1"); - auto* shm_dump2 = pmd->CreateAllocatorDump("shared_mem/seg2"); - auto* shm_dump3 = pmd->CreateAllocatorDump("shared_mem/seg3"); - auto* shm_dump4 = pmd->CreateAllocatorDump("shared_mem/seg4"); - - // Create one allocation with an auto-assigned guid and mark it as a - // suballocation of "fakealloc/allocated_objects". - auto* child1_dump = pmd->CreateAllocatorDump("shared_mem/child/seg1"); - pmd->AddOverridableOwnershipEdge(child1_dump->guid(), shm_dump1->guid(), - 0 /* importance */); - auto* child2_dump = pmd->CreateAllocatorDump("shared_mem/child/seg2"); - pmd->AddOwnershipEdge(child2_dump->guid(), shm_dump2->guid(), - 3 /* importance */); - MemoryAllocatorDumpGuid shared_mad_guid(1); - pmd->CreateSharedGlobalAllocatorDump(shared_mad_guid); - pmd->AddOverridableOwnershipEdge(shm_dump3->guid(), shared_mad_guid, - 0 /* importance */); - auto* child4_dump = pmd->CreateAllocatorDump("shared_mem/child/seg4"); - pmd->AddOverridableOwnershipEdge(child4_dump->guid(), shm_dump4->guid(), - 4 /* importance */); - - const ProcessMemoryDump::AllocatorDumpEdgesMap& edges = - pmd->allocator_dumps_edges(); - EXPECT_EQ(4u, edges.size()); - EXPECT_EQ(shm_dump1->guid(), edges.find(child1_dump->guid())->second.target); - EXPECT_EQ(0, edges.find(child1_dump->guid())->second.importance); - EXPECT_TRUE(edges.find(child1_dump->guid())->second.overridable); - EXPECT_EQ(shm_dump2->guid(), edges.find(child2_dump->guid())->second.target); - EXPECT_EQ(3, edges.find(child2_dump->guid())->second.importance); - EXPECT_FALSE(edges.find(child2_dump->guid())->second.overridable); - EXPECT_EQ(shared_mad_guid, edges.find(shm_dump3->guid())->second.target); - EXPECT_EQ(0, edges.find(shm_dump3->guid())->second.importance); - EXPECT_TRUE(edges.find(shm_dump3->guid())->second.overridable); - EXPECT_EQ(shm_dump4->guid(), edges.find(child4_dump->guid())->second.target); - EXPECT_EQ(4, edges.find(child4_dump->guid())->second.importance); - EXPECT_TRUE(edges.find(child4_dump->guid())->second.overridable); - - // These should override old edges: - pmd->AddOwnershipEdge(child1_dump->guid(), shm_dump1->guid(), - 1 /* importance */); - pmd->AddOwnershipEdge(shm_dump3->guid(), shared_mad_guid, 2 /* importance */); - // This should not change the old edges. - pmd->AddOverridableOwnershipEdge(child2_dump->guid(), shm_dump2->guid(), - 0 /* importance */); - pmd->AddOwnershipEdge(child4_dump->guid(), shm_dump4->guid(), - 0 /* importance */); - - EXPECT_EQ(4u, edges.size()); - EXPECT_EQ(shm_dump1->guid(), edges.find(child1_dump->guid())->second.target); - EXPECT_EQ(1, edges.find(child1_dump->guid())->second.importance); - EXPECT_FALSE(edges.find(child1_dump->guid())->second.overridable); - EXPECT_EQ(shm_dump2->guid(), edges.find(child2_dump->guid())->second.target); - EXPECT_EQ(3, edges.find(child2_dump->guid())->second.importance); - EXPECT_FALSE(edges.find(child2_dump->guid())->second.overridable); - EXPECT_EQ(shared_mad_guid, edges.find(shm_dump3->guid())->second.target); - EXPECT_EQ(2, edges.find(shm_dump3->guid())->second.importance); - EXPECT_FALSE(edges.find(shm_dump3->guid())->second.overridable); - EXPECT_EQ(shm_dump4->guid(), edges.find(child4_dump->guid())->second.target); - EXPECT_EQ(4, edges.find(child4_dump->guid())->second.importance); - EXPECT_FALSE(edges.find(child4_dump->guid())->second.overridable); -} - -TEST(ProcessMemoryDumpTest, Suballocations) { - std::unique_ptr<ProcessMemoryDump> pmd( - new ProcessMemoryDump(nullptr, kDetailedDumpArgs)); - const std::string allocator_dump_name = "fakealloc/allocated_objects"; - pmd->CreateAllocatorDump(allocator_dump_name); - - // Create one allocation with an auto-assigned guid and mark it as a - // suballocation of "fakealloc/allocated_objects". - auto* pic1_dump = pmd->CreateAllocatorDump("picturemanager/picture1"); - pmd->AddSuballocation(pic1_dump->guid(), allocator_dump_name); - - // Same here, but this time create an allocation with an explicit guid. - auto* pic2_dump = pmd->CreateAllocatorDump("picturemanager/picture2", - MemoryAllocatorDumpGuid(0x42)); - pmd->AddSuballocation(pic2_dump->guid(), allocator_dump_name); - - // Now check that AddSuballocation() has created anonymous child dumps under - // "fakealloc/allocated_objects". - auto anon_node_1_it = pmd->allocator_dumps().find( - allocator_dump_name + "/__" + pic1_dump->guid().ToString()); - ASSERT_NE(pmd->allocator_dumps().end(), anon_node_1_it); - - auto anon_node_2_it = - pmd->allocator_dumps().find(allocator_dump_name + "/__42"); - ASSERT_NE(pmd->allocator_dumps().end(), anon_node_2_it); - - // Finally check that AddSuballocation() has created also the - // edges between the pictures and the anonymous allocator child dumps. - bool found_edge[2]{false, false}; - for (const auto& e : pmd->allocator_dumps_edges()) { - found_edge[0] |= (e.first == pic1_dump->guid() && - e.second.target == anon_node_1_it->second->guid()); - found_edge[1] |= (e.first == pic2_dump->guid() && - e.second.target == anon_node_2_it->second->guid()); - } - ASSERT_TRUE(found_edge[0]); - ASSERT_TRUE(found_edge[1]); - - // Check that calling serialization routines doesn't cause a crash. - std::unique_ptr<TracedValue> traced_value(new TracedValue); - pmd->SerializeAllocatorDumpsInto(traced_value.get()); - pmd->SerializeHeapProfilerDumpsInto(traced_value.get()); - - pmd.reset(); -} - -TEST(ProcessMemoryDumpTest, GlobalAllocatorDumpTest) { - std::unique_ptr<ProcessMemoryDump> pmd( - new ProcessMemoryDump(nullptr, kDetailedDumpArgs)); - MemoryAllocatorDumpGuid shared_mad_guid(1); - auto* shared_mad1 = pmd->CreateWeakSharedGlobalAllocatorDump(shared_mad_guid); - ASSERT_EQ(shared_mad_guid, shared_mad1->guid()); - ASSERT_EQ(MemoryAllocatorDump::Flags::WEAK, shared_mad1->flags()); - - auto* shared_mad2 = pmd->GetSharedGlobalAllocatorDump(shared_mad_guid); - ASSERT_EQ(shared_mad1, shared_mad2); - ASSERT_EQ(MemoryAllocatorDump::Flags::WEAK, shared_mad1->flags()); - - auto* shared_mad3 = pmd->CreateWeakSharedGlobalAllocatorDump(shared_mad_guid); - ASSERT_EQ(shared_mad1, shared_mad3); - ASSERT_EQ(MemoryAllocatorDump::Flags::WEAK, shared_mad1->flags()); - - auto* shared_mad4 = pmd->CreateSharedGlobalAllocatorDump(shared_mad_guid); - ASSERT_EQ(shared_mad1, shared_mad4); - ASSERT_EQ(MemoryAllocatorDump::Flags::DEFAULT, shared_mad1->flags()); - - auto* shared_mad5 = pmd->CreateWeakSharedGlobalAllocatorDump(shared_mad_guid); - ASSERT_EQ(shared_mad1, shared_mad5); - ASSERT_EQ(MemoryAllocatorDump::Flags::DEFAULT, shared_mad1->flags()); -} - -TEST(ProcessMemoryDumpTest, SharedMemoryOwnershipTest) { - std::unique_ptr<ProcessMemoryDump> pmd( - new ProcessMemoryDump(nullptr, kDetailedDumpArgs)); - const ProcessMemoryDump::AllocatorDumpEdgesMap& edges = - pmd->allocator_dumps_edges(); - - auto* client_dump2 = pmd->CreateAllocatorDump("discardable/segment2"); - auto shm_token2 = UnguessableToken::Create(); - MemoryAllocatorDumpGuid shm_local_guid2 = - pmd->GetDumpId(SharedMemoryTracker::GetDumpNameForTracing(shm_token2)); - MemoryAllocatorDumpGuid shm_global_guid2 = - SharedMemoryTracker::GetGlobalDumpIdForTracing(shm_token2); - pmd->AddOverridableOwnershipEdge(shm_local_guid2, shm_global_guid2, - 0 /* importance */); - - pmd->CreateSharedMemoryOwnershipEdge(client_dump2->guid(), shm_token2, - 1 /* importance */); - EXPECT_EQ(2u, edges.size()); - - EXPECT_EQ(shm_global_guid2, edges.find(shm_local_guid2)->second.target); - EXPECT_EQ(1, edges.find(shm_local_guid2)->second.importance); - EXPECT_FALSE(edges.find(shm_local_guid2)->second.overridable); - EXPECT_EQ(shm_local_guid2, edges.find(client_dump2->guid())->second.target); - EXPECT_EQ(1, edges.find(client_dump2->guid())->second.importance); - EXPECT_FALSE(edges.find(client_dump2->guid())->second.overridable); -} - -TEST(ProcessMemoryDumpTest, BackgroundModeTest) { - MemoryDumpArgs background_args = {MemoryDumpLevelOfDetail::BACKGROUND}; - std::unique_ptr<ProcessMemoryDump> pmd( - new ProcessMemoryDump(nullptr, background_args)); - ProcessMemoryDump::is_black_hole_non_fatal_for_testing_ = true; - SetAllocatorDumpNameWhitelistForTesting(kTestDumpNameWhitelist); - MemoryAllocatorDump* black_hole_mad = pmd->GetBlackHoleMad(); - - // Invalid dump names. - EXPECT_EQ(black_hole_mad, - pmd->CreateAllocatorDump("NotWhitelisted/TestName")); - EXPECT_EQ(black_hole_mad, pmd->CreateAllocatorDump("TestName")); - EXPECT_EQ(black_hole_mad, pmd->CreateAllocatorDump("Whitelisted/Test")); - EXPECT_EQ(black_hole_mad, - pmd->CreateAllocatorDump("Not/Whitelisted/TestName")); - EXPECT_EQ(black_hole_mad, - pmd->CreateAllocatorDump("Whitelisted/TestName/Google")); - EXPECT_EQ(black_hole_mad, - pmd->CreateAllocatorDump("Whitelisted/TestName/0x1a2Google")); - EXPECT_EQ(black_hole_mad, - pmd->CreateAllocatorDump("Whitelisted/TestName/__12/Google")); - - // Suballocations. - MemoryAllocatorDumpGuid guid(1); - pmd->AddSuballocation(guid, "malloc/allocated_objects"); - EXPECT_EQ(0u, pmd->allocator_dumps_edges_.size()); - EXPECT_EQ(0u, pmd->allocator_dumps_.size()); - - // Global dumps. - EXPECT_NE(black_hole_mad, pmd->CreateSharedGlobalAllocatorDump(guid)); - EXPECT_NE(black_hole_mad, pmd->CreateWeakSharedGlobalAllocatorDump(guid)); - EXPECT_NE(black_hole_mad, pmd->GetSharedGlobalAllocatorDump(guid)); - - // Valid dump names. - EXPECT_NE(black_hole_mad, pmd->CreateAllocatorDump("Whitelisted/TestName")); - EXPECT_NE(black_hole_mad, - pmd->CreateAllocatorDump("Whitelisted/TestName_0xA1b2")); - EXPECT_NE(black_hole_mad, - pmd->CreateAllocatorDump("Whitelisted/0xaB/TestName")); - - // GetAllocatorDump is consistent. - EXPECT_EQ(black_hole_mad, pmd->GetAllocatorDump("NotWhitelisted/TestName")); - EXPECT_NE(black_hole_mad, pmd->GetAllocatorDump("Whitelisted/TestName")); - - // Test whitelisted entries. - ASSERT_TRUE(IsMemoryAllocatorDumpNameWhitelisted("Whitelisted/TestName")); - - // Global dumps should be whitelisted. - ASSERT_TRUE(IsMemoryAllocatorDumpNameWhitelisted("global/13456")); - - // Global dumps with non-guids should not be. - ASSERT_FALSE(IsMemoryAllocatorDumpNameWhitelisted("global/random")); - - // Random names should not. - ASSERT_FALSE(IsMemoryAllocatorDumpNameWhitelisted("NotWhitelisted/TestName")); - - // Check hex processing. - ASSERT_TRUE(IsMemoryAllocatorDumpNameWhitelisted("Whitelisted/0xA1b2")); -} - -TEST(ProcessMemoryDumpTest, GuidsTest) { - MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::DETAILED}; - - const auto process_token_one = UnguessableToken::Create(); - const auto process_token_two = UnguessableToken::Create(); - - ProcessMemoryDump pmd1(nullptr, dump_args); - pmd1.set_process_token_for_testing(process_token_one); - MemoryAllocatorDump* mad1 = pmd1.CreateAllocatorDump("foo"); - - ProcessMemoryDump pmd2(nullptr, dump_args); - pmd2.set_process_token_for_testing(process_token_one); - MemoryAllocatorDump* mad2 = pmd2.CreateAllocatorDump("foo"); - - // If we don't pass the argument we get a random PMD: - ProcessMemoryDump pmd3(nullptr, dump_args); - MemoryAllocatorDump* mad3 = pmd3.CreateAllocatorDump("foo"); - - // PMD's for different processes produce different GUIDs even for the same - // names: - ProcessMemoryDump pmd4(nullptr, dump_args); - pmd4.set_process_token_for_testing(process_token_two); - MemoryAllocatorDump* mad4 = pmd4.CreateAllocatorDump("foo"); - - ASSERT_EQ(mad1->guid(), mad2->guid()); - - ASSERT_NE(mad2->guid(), mad3->guid()); - ASSERT_NE(mad3->guid(), mad4->guid()); - ASSERT_NE(mad4->guid(), mad2->guid()); - - ASSERT_EQ(mad1->guid(), pmd1.GetDumpId("foo")); -} - -#if defined(COUNT_RESIDENT_BYTES_SUPPORTED) -TEST(ProcessMemoryDumpTest, CountResidentBytes) { - const size_t page_size = ProcessMemoryDump::GetSystemPageSize(); - - // Allocate few page of dirty memory and check if it is resident. - const size_t size1 = 5 * page_size; - void* memory1 = Map(size1); - memset(memory1, 0, size1); - size_t res1 = ProcessMemoryDump::CountResidentBytes(memory1, size1); - ASSERT_EQ(res1, size1); - Unmap(memory1, size1); - - // Allocate a large memory segment (> 8Mib). - const size_t kVeryLargeMemorySize = 15 * 1024 * 1024; - void* memory2 = Map(kVeryLargeMemorySize); - memset(memory2, 0, kVeryLargeMemorySize); - size_t res2 = - ProcessMemoryDump::CountResidentBytes(memory2, kVeryLargeMemorySize); - ASSERT_EQ(res2, kVeryLargeMemorySize); - Unmap(memory2, kVeryLargeMemorySize); -} - -TEST(ProcessMemoryDumpTest, CountResidentBytesInSharedMemory) { -#if defined(OS_IOS) - // TODO(crbug.com/748410): Reenable this test. - if (!base::ios::IsRunningOnIOS10OrLater()) { - return; - } -#endif - - const size_t page_size = ProcessMemoryDump::GetSystemPageSize(); - - // Allocate few page of dirty memory and check if it is resident. - const size_t size1 = 5 * page_size; - SharedMemory shared_memory1; - shared_memory1.CreateAndMapAnonymous(size1); - memset(shared_memory1.memory(), 0, size1); - base::Optional<size_t> res1 = - ProcessMemoryDump::CountResidentBytesInSharedMemory( - shared_memory1.memory(), shared_memory1.mapped_size()); - ASSERT_TRUE(res1.has_value()); - ASSERT_EQ(res1.value(), size1); - shared_memory1.Unmap(); - shared_memory1.Close(); - - // Allocate a large memory segment (> 8Mib). - const size_t kVeryLargeMemorySize = 15 * 1024 * 1024; - SharedMemory shared_memory2; - shared_memory2.CreateAndMapAnonymous(kVeryLargeMemorySize); - memset(shared_memory2.memory(), 0, kVeryLargeMemorySize); - base::Optional<size_t> res2 = - ProcessMemoryDump::CountResidentBytesInSharedMemory( - shared_memory2.memory(), shared_memory2.mapped_size()); - ASSERT_TRUE(res2.has_value()); - ASSERT_EQ(res2.value(), kVeryLargeMemorySize); - shared_memory2.Unmap(); - shared_memory2.Close(); - - // Allocate a large memory segment, but touch about half of all pages. - const size_t kTouchedMemorySize = 7 * 1024 * 1024; - SharedMemory shared_memory3; - shared_memory3.CreateAndMapAnonymous(kVeryLargeMemorySize); - memset(shared_memory3.memory(), 0, kTouchedMemorySize); - base::Optional<size_t> res3 = - ProcessMemoryDump::CountResidentBytesInSharedMemory( - shared_memory3.memory(), shared_memory3.mapped_size()); - ASSERT_TRUE(res3.has_value()); - ASSERT_EQ(res3.value(), kTouchedMemorySize); - shared_memory3.Unmap(); - shared_memory3.Close(); -} -#endif // defined(COUNT_RESIDENT_BYTES_SUPPORTED) - -} // namespace trace_event -} // namespace base
diff --git a/base/trace_event/trace_category_unittest.cc b/base/trace_event/trace_category_unittest.cc deleted file mode 100644 index 964064e..0000000 --- a/base/trace_event/trace_category_unittest.cc +++ /dev/null
@@ -1,148 +0,0 @@ -// 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 <string.h> - -#include <memory> - -#include "base/bind.h" -#include "base/lazy_instance.h" -#include "base/synchronization/lock.h" -#include "base/synchronization/waitable_event.h" -#include "base/threading/thread.h" -#include "base/trace_event/category_registry.h" -#include "base/trace_event/trace_category.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace trace_event { - -// Static initializers are generally forbidden. However, in the past we ran in -// the case of some test using tracing in a static initializer. This test checks -// That the category registry doesn't rely on static initializers itself and is -// functional even if called from another static initializer. -bool Initializer() { - return CategoryRegistry::kCategoryMetadata && - CategoryRegistry::kCategoryMetadata->is_valid(); -} -bool g_initializer_check = Initializer(); - -class TraceCategoryTest : public testing::Test { - public: - void SetUp() override { CategoryRegistry::Initialize(); } - - void TearDown() override { CategoryRegistry::ResetForTesting(); } - - static bool GetOrCreateCategoryByName(const char* name, TraceCategory** cat) { - static LazyInstance<Lock>::Leaky g_lock = LAZY_INSTANCE_INITIALIZER; - bool is_new_cat = false; - *cat = CategoryRegistry::GetCategoryByName(name); - if (!*cat) { - AutoLock lock(g_lock.Get()); - is_new_cat = CategoryRegistry::GetOrCreateCategoryLocked( - name, [](TraceCategory*) {}, cat); - } - return is_new_cat; - }; - - static CategoryRegistry::Range GetAllCategories() { - return CategoryRegistry::GetAllCategories(); - } - - static void TestRaceThreadMain(WaitableEvent* event) { - TraceCategory* cat = nullptr; - event->Wait(); - GetOrCreateCategoryByName("__test_race", &cat); - EXPECT_NE(nullptr, cat); - } -}; - -TEST_F(TraceCategoryTest, Basic) { - ASSERT_NE(nullptr, CategoryRegistry::kCategoryMetadata); - ASSERT_TRUE(CategoryRegistry::kCategoryMetadata->is_valid()); - ASSERT_FALSE(CategoryRegistry::kCategoryMetadata->is_enabled()); - - // Metadata category is built-in and should create a new category. - TraceCategory* cat_meta = nullptr; - const char* kMetadataName = CategoryRegistry::kCategoryMetadata->name(); - ASSERT_FALSE(GetOrCreateCategoryByName(kMetadataName, &cat_meta)); - ASSERT_EQ(CategoryRegistry::kCategoryMetadata, cat_meta); - - TraceCategory* cat_1 = nullptr; - ASSERT_TRUE(GetOrCreateCategoryByName("__test_basic_ab", &cat_1)); - ASSERT_FALSE(cat_1->is_enabled()); - ASSERT_EQ(0u, cat_1->enabled_filters()); - cat_1->set_state_flag(TraceCategory::ENABLED_FOR_RECORDING); - cat_1->set_state_flag(TraceCategory::ENABLED_FOR_FILTERING); - ASSERT_EQ(TraceCategory::ENABLED_FOR_RECORDING | - TraceCategory::ENABLED_FOR_FILTERING, - cat_1->state()); - - cat_1->set_enabled_filters(129); - ASSERT_EQ(129u, cat_1->enabled_filters()); - ASSERT_EQ(cat_1, CategoryRegistry::GetCategoryByStatePtr(cat_1->state_ptr())); - - cat_1->clear_state_flag(TraceCategory::ENABLED_FOR_FILTERING); - ASSERT_EQ(TraceCategory::ENABLED_FOR_RECORDING, cat_1->state()); - ASSERT_EQ(TraceCategory::ENABLED_FOR_RECORDING, *cat_1->state_ptr()); - ASSERT_TRUE(cat_1->is_enabled()); - - TraceCategory* cat_2 = nullptr; - ASSERT_TRUE(GetOrCreateCategoryByName("__test_basic_a", &cat_2)); - ASSERT_FALSE(cat_2->is_enabled()); - cat_2->set_state_flag(TraceCategory::ENABLED_FOR_RECORDING); - - TraceCategory* cat_2_copy = nullptr; - ASSERT_FALSE(GetOrCreateCategoryByName("__test_basic_a", &cat_2_copy)); - ASSERT_EQ(cat_2, cat_2_copy); - - TraceCategory* cat_3 = nullptr; - ASSERT_TRUE( - GetOrCreateCategoryByName("__test_basic_ab,__test_basic_a", &cat_3)); - ASSERT_FALSE(cat_3->is_enabled()); - ASSERT_EQ(0u, cat_3->enabled_filters()); - - int num_test_categories_seen = 0; - for (const TraceCategory& cat : GetAllCategories()) { - if (strcmp(cat.name(), kMetadataName) == 0) - ASSERT_TRUE(CategoryRegistry::IsBuiltinCategory(&cat)); - - if (strncmp(cat.name(), "__test_basic_", 13) == 0) { - ASSERT_FALSE(CategoryRegistry::IsBuiltinCategory(&cat)); - num_test_categories_seen++; - } - } - ASSERT_EQ(3, num_test_categories_seen); - ASSERT_TRUE(g_initializer_check); -} - -// Tries to cover the case of multiple threads creating the same category -// simultaneously. Should never end up with distinct entries with the same name. -TEST_F(TraceCategoryTest, ThreadRaces) { - const int kNumThreads = 32; - std::unique_ptr<Thread> threads[kNumThreads]; - for (int i = 0; i < kNumThreads; i++) { - threads[i].reset(new Thread("test thread")); - threads[i]->Start(); - } - WaitableEvent sync_event(WaitableEvent::ResetPolicy::MANUAL, - WaitableEvent::InitialState::NOT_SIGNALED); - for (int i = 0; i < kNumThreads; i++) { - threads[i]->task_runner()->PostTask( - FROM_HERE, BindOnce(&TestRaceThreadMain, Unretained(&sync_event))); - } - sync_event.Signal(); - for (int i = 0; i < kNumThreads; i++) - threads[i]->Stop(); - - int num_times_seen = 0; - for (const TraceCategory& cat : GetAllCategories()) { - if (strcmp(cat.name(), "__test_race") == 0) - num_times_seen++; - } - ASSERT_EQ(1, num_times_seen); -} - -} // namespace trace_event -} // namespace base
diff --git a/base/trace_event/trace_config_unittest.cc b/base/trace_event/trace_config_unittest.cc deleted file mode 100644 index 3cb6d61..0000000 --- a/base/trace_event/trace_config_unittest.cc +++ /dev/null
@@ -1,673 +0,0 @@ -// 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 <stddef.h> - -#include "base/json/json_reader.h" -#include "base/json/json_writer.h" -#include "base/macros.h" -#include "base/trace_event/memory_dump_manager.h" -#include "base/trace_event/trace_config.h" -#include "base/trace_event/trace_config_memory_test_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace trace_event { - -namespace { - -const char kDefaultTraceConfigString[] = - "{" - "\"enable_argument_filter\":false," - "\"enable_systrace\":false," - "\"record_mode\":\"record-until-full\"" - "}"; - -const char kCustomTraceConfigString[] = - "{" - "\"enable_argument_filter\":true," - "\"enable_systrace\":true," - "\"event_filters\":[" - "{" - "\"excluded_categories\":[\"unfiltered_cat\"]," - "\"filter_args\":{\"event_name_whitelist\":[\"a snake\",\"a dog\"]}," - "\"filter_predicate\":\"event_whitelist_predicate\"," - "\"included_categories\":[\"*\"]" - "}" - "]," - "\"excluded_categories\":[\"excluded\",\"exc_pattern*\"]," - "\"included_categories\":[" - "\"included\"," - "\"inc_pattern*\"," - "\"disabled-by-default-cc\"," - "\"disabled-by-default-memory-infra\"]," - "\"memory_dump_config\":{" - "\"allowed_dump_modes\":[\"background\",\"light\",\"detailed\"]," - "\"heap_profiler_options\":{" - "\"breakdown_threshold_bytes\":10240" - "}," - "\"triggers\":[" - "{" - "\"min_time_between_dumps_ms\":50," - "\"mode\":\"light\"," - "\"type\":\"periodic_interval\"" - "}," - "{" - "\"min_time_between_dumps_ms\":1000," - "\"mode\":\"detailed\"," - "\"type\":\"peak_memory_usage\"" - "}" - "]" - "}," - "\"record_mode\":\"record-continuously\"" - "}"; - -void CheckDefaultTraceConfigBehavior(const TraceConfig& tc) { - EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode()); - EXPECT_FALSE(tc.IsSystraceEnabled()); - EXPECT_FALSE(tc.IsArgumentFilterEnabled()); - - // Default trace config enables every category filter except the - // disabled-by-default-* ones. - EXPECT_TRUE(tc.IsCategoryGroupEnabled("Category1")); - EXPECT_TRUE(tc.IsCategoryGroupEnabled("not-excluded-category")); - EXPECT_FALSE(tc.IsCategoryGroupEnabled("disabled-by-default-cc")); - - EXPECT_TRUE(tc.IsCategoryGroupEnabled("Category1,not-excluded-category")); - EXPECT_TRUE(tc.IsCategoryGroupEnabled("Category1,disabled-by-default-cc")); - EXPECT_FALSE(tc.IsCategoryGroupEnabled( - "disabled-by-default-cc,disabled-by-default-cc2")); -} - -} // namespace - -TEST(TraceConfigTest, TraceConfigFromValidLegacyFormat) { - // From trace options strings - TraceConfig config("", "record-until-full"); - EXPECT_EQ(RECORD_UNTIL_FULL, config.GetTraceRecordMode()); - EXPECT_FALSE(config.IsSystraceEnabled()); - EXPECT_FALSE(config.IsArgumentFilterEnabled()); - EXPECT_STREQ("record-until-full", config.ToTraceOptionsString().c_str()); - - config = TraceConfig("", "record-continuously"); - EXPECT_EQ(RECORD_CONTINUOUSLY, config.GetTraceRecordMode()); - EXPECT_FALSE(config.IsSystraceEnabled()); - EXPECT_FALSE(config.IsArgumentFilterEnabled()); - EXPECT_STREQ("record-continuously", config.ToTraceOptionsString().c_str()); - - config = TraceConfig("", "trace-to-console"); - EXPECT_EQ(ECHO_TO_CONSOLE, config.GetTraceRecordMode()); - EXPECT_FALSE(config.IsSystraceEnabled()); - EXPECT_FALSE(config.IsArgumentFilterEnabled()); - EXPECT_STREQ("trace-to-console", config.ToTraceOptionsString().c_str()); - - config = TraceConfig("", "record-as-much-as-possible"); - EXPECT_EQ(RECORD_AS_MUCH_AS_POSSIBLE, config.GetTraceRecordMode()); - EXPECT_FALSE(config.IsSystraceEnabled()); - EXPECT_FALSE(config.IsArgumentFilterEnabled()); - EXPECT_STREQ("record-as-much-as-possible", - config.ToTraceOptionsString().c_str()); - - config = TraceConfig("", "enable-systrace, record-continuously"); - EXPECT_EQ(RECORD_CONTINUOUSLY, config.GetTraceRecordMode()); - EXPECT_TRUE(config.IsSystraceEnabled()); - EXPECT_FALSE(config.IsArgumentFilterEnabled()); - EXPECT_STREQ("record-continuously,enable-systrace", - config.ToTraceOptionsString().c_str()); - - config = TraceConfig("", "enable-argument-filter,record-as-much-as-possible"); - EXPECT_EQ(RECORD_AS_MUCH_AS_POSSIBLE, config.GetTraceRecordMode()); - EXPECT_FALSE(config.IsSystraceEnabled()); - EXPECT_TRUE(config.IsArgumentFilterEnabled()); - EXPECT_STREQ("record-as-much-as-possible,enable-argument-filter", - config.ToTraceOptionsString().c_str()); - - config = TraceConfig( - "", - "enable-systrace,trace-to-console,enable-argument-filter"); - EXPECT_EQ(ECHO_TO_CONSOLE, config.GetTraceRecordMode()); - EXPECT_TRUE(config.IsSystraceEnabled()); - EXPECT_TRUE(config.IsArgumentFilterEnabled()); - EXPECT_STREQ( - "trace-to-console,enable-systrace,enable-argument-filter", - config.ToTraceOptionsString().c_str()); - - config = TraceConfig( - "", "record-continuously, record-until-full, trace-to-console"); - EXPECT_EQ(ECHO_TO_CONSOLE, config.GetTraceRecordMode()); - EXPECT_FALSE(config.IsSystraceEnabled()); - EXPECT_FALSE(config.IsArgumentFilterEnabled()); - EXPECT_STREQ("trace-to-console", config.ToTraceOptionsString().c_str()); - - // From TraceRecordMode - config = TraceConfig("", RECORD_UNTIL_FULL); - EXPECT_EQ(RECORD_UNTIL_FULL, config.GetTraceRecordMode()); - EXPECT_FALSE(config.IsSystraceEnabled()); - EXPECT_FALSE(config.IsArgumentFilterEnabled()); - EXPECT_STREQ("record-until-full", config.ToTraceOptionsString().c_str()); - - config = TraceConfig("", RECORD_CONTINUOUSLY); - EXPECT_EQ(RECORD_CONTINUOUSLY, config.GetTraceRecordMode()); - EXPECT_FALSE(config.IsSystraceEnabled()); - EXPECT_FALSE(config.IsArgumentFilterEnabled()); - EXPECT_STREQ("record-continuously", config.ToTraceOptionsString().c_str()); - - config = TraceConfig("", ECHO_TO_CONSOLE); - EXPECT_EQ(ECHO_TO_CONSOLE, config.GetTraceRecordMode()); - EXPECT_FALSE(config.IsSystraceEnabled()); - EXPECT_FALSE(config.IsArgumentFilterEnabled()); - EXPECT_STREQ("trace-to-console", config.ToTraceOptionsString().c_str()); - - config = TraceConfig("", RECORD_AS_MUCH_AS_POSSIBLE); - EXPECT_EQ(RECORD_AS_MUCH_AS_POSSIBLE, config.GetTraceRecordMode()); - EXPECT_FALSE(config.IsSystraceEnabled()); - EXPECT_FALSE(config.IsArgumentFilterEnabled()); - EXPECT_STREQ("record-as-much-as-possible", - config.ToTraceOptionsString().c_str()); - - // From category filter strings - config = TraceConfig("included,-excluded,inc_pattern*,-exc_pattern*", ""); - EXPECT_STREQ("included,inc_pattern*,-excluded,-exc_pattern*", - config.ToCategoryFilterString().c_str()); - - config = TraceConfig("only_inc_cat", ""); - EXPECT_STREQ("only_inc_cat", config.ToCategoryFilterString().c_str()); - - config = TraceConfig("-only_exc_cat", ""); - EXPECT_STREQ("-only_exc_cat", config.ToCategoryFilterString().c_str()); - - config = TraceConfig("disabled-by-default-cc,-excluded", ""); - EXPECT_STREQ("disabled-by-default-cc,-excluded", - config.ToCategoryFilterString().c_str()); - - config = TraceConfig("disabled-by-default-cc,included", ""); - EXPECT_STREQ("included,disabled-by-default-cc", - config.ToCategoryFilterString().c_str()); - - // From both trace options and category filter strings - config = TraceConfig("", ""); - EXPECT_EQ(RECORD_UNTIL_FULL, config.GetTraceRecordMode()); - EXPECT_FALSE(config.IsSystraceEnabled()); - EXPECT_FALSE(config.IsArgumentFilterEnabled()); - EXPECT_STREQ("", config.ToCategoryFilterString().c_str()); - EXPECT_STREQ("record-until-full", config.ToTraceOptionsString().c_str()); - - config = TraceConfig("included,-excluded,inc_pattern*,-exc_pattern*", - "enable-systrace, trace-to-console"); - EXPECT_EQ(ECHO_TO_CONSOLE, config.GetTraceRecordMode()); - EXPECT_TRUE(config.IsSystraceEnabled()); - EXPECT_FALSE(config.IsArgumentFilterEnabled()); - EXPECT_STREQ("included,inc_pattern*,-excluded,-exc_pattern*", - config.ToCategoryFilterString().c_str()); - EXPECT_STREQ("trace-to-console,enable-systrace", - config.ToTraceOptionsString().c_str()); - - // From both trace options and category filter strings with spaces. - config = TraceConfig(" included , -excluded, inc_pattern*, ,-exc_pattern* ", - "enable-systrace, ,trace-to-console "); - EXPECT_EQ(ECHO_TO_CONSOLE, config.GetTraceRecordMode()); - EXPECT_TRUE(config.IsSystraceEnabled()); - EXPECT_FALSE(config.IsArgumentFilterEnabled()); - EXPECT_STREQ("included,inc_pattern*,-excluded,-exc_pattern*", - config.ToCategoryFilterString().c_str()); - EXPECT_STREQ("trace-to-console,enable-systrace", - config.ToTraceOptionsString().c_str()); - - // From category filter string and TraceRecordMode - config = TraceConfig("included,-excluded,inc_pattern*,-exc_pattern*", - RECORD_CONTINUOUSLY); - EXPECT_EQ(RECORD_CONTINUOUSLY, config.GetTraceRecordMode()); - EXPECT_FALSE(config.IsSystraceEnabled()); - EXPECT_FALSE(config.IsArgumentFilterEnabled()); - EXPECT_STREQ("included,inc_pattern*,-excluded,-exc_pattern*", - config.ToCategoryFilterString().c_str()); - EXPECT_STREQ("record-continuously", config.ToTraceOptionsString().c_str()); -} - -TEST(TraceConfigTest, TraceConfigFromInvalidLegacyStrings) { - TraceConfig config("", "foo-bar-baz"); - EXPECT_EQ(RECORD_UNTIL_FULL, config.GetTraceRecordMode()); - EXPECT_FALSE(config.IsSystraceEnabled()); - EXPECT_FALSE(config.IsArgumentFilterEnabled()); - EXPECT_STREQ("", config.ToCategoryFilterString().c_str()); - EXPECT_STREQ("record-until-full", config.ToTraceOptionsString().c_str()); - - config = TraceConfig("arbitrary-category", "foo-bar-baz, enable-systrace"); - EXPECT_EQ(RECORD_UNTIL_FULL, config.GetTraceRecordMode()); - EXPECT_TRUE(config.IsSystraceEnabled()); - EXPECT_FALSE(config.IsArgumentFilterEnabled()); - EXPECT_STREQ("arbitrary-category", config.ToCategoryFilterString().c_str()); - EXPECT_STREQ("record-until-full,enable-systrace", - config.ToTraceOptionsString().c_str()); -} - -TEST(TraceConfigTest, ConstructDefaultTraceConfig) { - TraceConfig tc; - EXPECT_STREQ("", tc.ToCategoryFilterString().c_str()); - EXPECT_STREQ(kDefaultTraceConfigString, tc.ToString().c_str()); - CheckDefaultTraceConfigBehavior(tc); - - // Constructors from category filter string and trace option string. - TraceConfig tc_asterisk("*", ""); - EXPECT_STREQ("*", tc_asterisk.ToCategoryFilterString().c_str()); - CheckDefaultTraceConfigBehavior(tc_asterisk); - - TraceConfig tc_empty_category_filter("", ""); - EXPECT_STREQ("", tc_empty_category_filter.ToCategoryFilterString().c_str()); - EXPECT_STREQ(kDefaultTraceConfigString, - tc_empty_category_filter.ToString().c_str()); - CheckDefaultTraceConfigBehavior(tc_empty_category_filter); - - // Constructor from JSON formated config string. - TraceConfig tc_empty_json_string(""); - EXPECT_STREQ("", tc_empty_json_string.ToCategoryFilterString().c_str()); - EXPECT_STREQ(kDefaultTraceConfigString, - tc_empty_json_string.ToString().c_str()); - CheckDefaultTraceConfigBehavior(tc_empty_json_string); - - // Constructor from dictionary value. - DictionaryValue dict; - TraceConfig tc_dict(dict); - EXPECT_STREQ("", tc_dict.ToCategoryFilterString().c_str()); - EXPECT_STREQ(kDefaultTraceConfigString, tc_dict.ToString().c_str()); - CheckDefaultTraceConfigBehavior(tc_dict); -} - -TEST(TraceConfigTest, EmptyAndAsteriskCategoryFilterString) { - TraceConfig tc_empty("", ""); - TraceConfig tc_asterisk("*", ""); - - EXPECT_STREQ("", tc_empty.ToCategoryFilterString().c_str()); - EXPECT_STREQ("*", tc_asterisk.ToCategoryFilterString().c_str()); - - // Both fall back to default config. - CheckDefaultTraceConfigBehavior(tc_empty); - CheckDefaultTraceConfigBehavior(tc_asterisk); - - // They differ only for internal checking. - EXPECT_FALSE(tc_empty.category_filter().IsCategoryEnabled("Category1")); - EXPECT_FALSE( - tc_empty.category_filter().IsCategoryEnabled("not-excluded-category")); - EXPECT_TRUE(tc_asterisk.category_filter().IsCategoryEnabled("Category1")); - EXPECT_TRUE( - tc_asterisk.category_filter().IsCategoryEnabled("not-excluded-category")); -} - -TEST(TraceConfigTest, DisabledByDefaultCategoryFilterString) { - TraceConfig tc("foo,disabled-by-default-foo", ""); - EXPECT_STREQ("foo,disabled-by-default-foo", - tc.ToCategoryFilterString().c_str()); - EXPECT_TRUE(tc.IsCategoryGroupEnabled("foo")); - EXPECT_TRUE(tc.IsCategoryGroupEnabled("disabled-by-default-foo")); - EXPECT_FALSE(tc.IsCategoryGroupEnabled("bar")); - EXPECT_FALSE(tc.IsCategoryGroupEnabled("disabled-by-default-bar")); - - EXPECT_TRUE(tc.event_filters().empty()); - // Enabling only the disabled-by-default-* category means the default ones - // are also enabled. - tc = TraceConfig("disabled-by-default-foo", ""); - EXPECT_STREQ("disabled-by-default-foo", tc.ToCategoryFilterString().c_str()); - EXPECT_TRUE(tc.IsCategoryGroupEnabled("disabled-by-default-foo")); - EXPECT_TRUE(tc.IsCategoryGroupEnabled("foo")); - EXPECT_TRUE(tc.IsCategoryGroupEnabled("bar")); - EXPECT_FALSE(tc.IsCategoryGroupEnabled("disabled-by-default-bar")); -} - -TEST(TraceConfigTest, TraceConfigFromDict) { - // Passing in empty dictionary will result in default trace config. - DictionaryValue dict; - TraceConfig tc(dict); - EXPECT_STREQ(kDefaultTraceConfigString, tc.ToString().c_str()); - EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode()); - EXPECT_FALSE(tc.IsSystraceEnabled()); - EXPECT_FALSE(tc.IsArgumentFilterEnabled()); - EXPECT_STREQ("", tc.ToCategoryFilterString().c_str()); - - std::unique_ptr<Value> default_value( - JSONReader::Read(kDefaultTraceConfigString)); - DCHECK(default_value); - const DictionaryValue* default_dict = nullptr; - bool is_dict = default_value->GetAsDictionary(&default_dict); - DCHECK(is_dict); - TraceConfig default_tc(*default_dict); - EXPECT_STREQ(kDefaultTraceConfigString, default_tc.ToString().c_str()); - EXPECT_EQ(RECORD_UNTIL_FULL, default_tc.GetTraceRecordMode()); - EXPECT_FALSE(default_tc.IsSystraceEnabled()); - EXPECT_FALSE(default_tc.IsArgumentFilterEnabled()); - EXPECT_STREQ("", default_tc.ToCategoryFilterString().c_str()); - - std::unique_ptr<Value> custom_value( - JSONReader::Read(kCustomTraceConfigString)); - DCHECK(custom_value); - const DictionaryValue* custom_dict = nullptr; - is_dict = custom_value->GetAsDictionary(&custom_dict); - DCHECK(is_dict); - TraceConfig custom_tc(*custom_dict); - EXPECT_STREQ(kCustomTraceConfigString, custom_tc.ToString().c_str()); - EXPECT_EQ(RECORD_CONTINUOUSLY, custom_tc.GetTraceRecordMode()); - EXPECT_TRUE(custom_tc.IsSystraceEnabled()); - EXPECT_TRUE(custom_tc.IsArgumentFilterEnabled()); - EXPECT_STREQ( - "included,inc_pattern*," - "disabled-by-default-cc,disabled-by-default-memory-infra," - "-excluded,-exc_pattern*", - custom_tc.ToCategoryFilterString().c_str()); -} - -TEST(TraceConfigTest, TraceConfigFromValidString) { - // Using some non-empty config string. - const char config_string[] = - "{" - "\"enable_argument_filter\":true," - "\"enable_systrace\":true," - "\"event_filters\":[" - "{" - "\"excluded_categories\":[\"unfiltered_cat\"]," - "\"filter_args\":{\"event_name_whitelist\":[\"a snake\",\"a dog\"]}," - "\"filter_predicate\":\"event_whitelist_predicate\"," - "\"included_categories\":[\"*\"]" - "}" - "]," - "\"excluded_categories\":[\"excluded\",\"exc_pattern*\"]," - "\"included_categories\":[\"included\"," - "\"inc_pattern*\"," - "\"disabled-by-default-cc\"]," - "\"record_mode\":\"record-continuously\"" - "}"; - TraceConfig tc(config_string); - - EXPECT_STREQ(config_string, tc.ToString().c_str()); - EXPECT_EQ(RECORD_CONTINUOUSLY, tc.GetTraceRecordMode()); - EXPECT_TRUE(tc.IsSystraceEnabled()); - EXPECT_TRUE(tc.IsArgumentFilterEnabled()); - EXPECT_STREQ( - "included,inc_pattern*,disabled-by-default-cc,-excluded," - "-exc_pattern*", - tc.ToCategoryFilterString().c_str()); - - EXPECT_TRUE(tc.category_filter().IsCategoryEnabled("included")); - EXPECT_TRUE(tc.category_filter().IsCategoryEnabled("inc_pattern_category")); - EXPECT_TRUE(tc.category_filter().IsCategoryEnabled("disabled-by-default-cc")); - EXPECT_FALSE(tc.category_filter().IsCategoryEnabled("excluded")); - EXPECT_FALSE(tc.category_filter().IsCategoryEnabled("exc_pattern_category")); - EXPECT_FALSE( - tc.category_filter().IsCategoryEnabled("disabled-by-default-others")); - EXPECT_FALSE( - tc.category_filter().IsCategoryEnabled("not-excluded-nor-included")); - - EXPECT_TRUE(tc.IsCategoryGroupEnabled("included")); - EXPECT_TRUE(tc.IsCategoryGroupEnabled("inc_pattern_category")); - EXPECT_TRUE(tc.IsCategoryGroupEnabled("disabled-by-default-cc")); - EXPECT_FALSE(tc.IsCategoryGroupEnabled("excluded")); - EXPECT_FALSE(tc.IsCategoryGroupEnabled("exc_pattern_category")); - EXPECT_FALSE(tc.IsCategoryGroupEnabled("disabled-by-default-others")); - EXPECT_FALSE(tc.IsCategoryGroupEnabled("not-excluded-nor-included")); - - EXPECT_TRUE(tc.IsCategoryGroupEnabled("included,excluded")); - EXPECT_FALSE(tc.IsCategoryGroupEnabled("excluded,exc_pattern_category")); - EXPECT_TRUE(tc.IsCategoryGroupEnabled("included")); - - EXPECT_EQ(tc.event_filters().size(), 1u); - const TraceConfig::EventFilterConfig& event_filter = tc.event_filters()[0]; - EXPECT_STREQ("event_whitelist_predicate", - event_filter.predicate_name().c_str()); - EXPECT_EQ(1u, event_filter.category_filter().included_categories().size()); - EXPECT_STREQ("*", - event_filter.category_filter().included_categories()[0].c_str()); - EXPECT_EQ(1u, event_filter.category_filter().excluded_categories().size()); - EXPECT_STREQ("unfiltered_cat", - event_filter.category_filter().excluded_categories()[0].c_str()); - EXPECT_TRUE(event_filter.filter_args()); - - std::string json_out; - base::JSONWriter::Write(*event_filter.filter_args(), &json_out); - EXPECT_STREQ(json_out.c_str(), - "{\"event_name_whitelist\":[\"a snake\",\"a dog\"]}"); - std::unordered_set<std::string> filter_values; - EXPECT_TRUE(event_filter.GetArgAsSet("event_name_whitelist", &filter_values)); - EXPECT_EQ(2u, filter_values.size()); - EXPECT_EQ(1u, filter_values.count("a snake")); - EXPECT_EQ(1u, filter_values.count("a dog")); - - const char config_string_2[] = "{\"included_categories\":[\"*\"]}"; - TraceConfig tc2(config_string_2); - EXPECT_TRUE(tc2.category_filter().IsCategoryEnabled( - "non-disabled-by-default-pattern")); - EXPECT_FALSE( - tc2.category_filter().IsCategoryEnabled("disabled-by-default-pattern")); - EXPECT_TRUE(tc2.IsCategoryGroupEnabled("non-disabled-by-default-pattern")); - EXPECT_FALSE(tc2.IsCategoryGroupEnabled("disabled-by-default-pattern")); - - // Clear - tc.Clear(); - EXPECT_STREQ(tc.ToString().c_str(), - "{" - "\"enable_argument_filter\":false," - "\"enable_systrace\":false," - "\"record_mode\":\"record-until-full\"" - "}"); -} - -TEST(TraceConfigTest, TraceConfigFromInvalidString) { - // The config string needs to be a dictionary correctly formatted as a JSON - // string. Otherwise, it will fall back to the default initialization. - TraceConfig tc(""); - EXPECT_STREQ(kDefaultTraceConfigString, tc.ToString().c_str()); - EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode()); - EXPECT_FALSE(tc.IsSystraceEnabled()); - EXPECT_FALSE(tc.IsArgumentFilterEnabled()); - EXPECT_STREQ("", tc.ToCategoryFilterString().c_str()); - CheckDefaultTraceConfigBehavior(tc); - - tc = TraceConfig("This is an invalid config string."); - EXPECT_STREQ(kDefaultTraceConfigString, tc.ToString().c_str()); - EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode()); - EXPECT_FALSE(tc.IsSystraceEnabled()); - EXPECT_FALSE(tc.IsArgumentFilterEnabled()); - EXPECT_STREQ("", tc.ToCategoryFilterString().c_str()); - CheckDefaultTraceConfigBehavior(tc); - - tc = TraceConfig("[\"This\", \"is\", \"not\", \"a\", \"dictionary\"]"); - EXPECT_STREQ(kDefaultTraceConfigString, tc.ToString().c_str()); - EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode()); - EXPECT_FALSE(tc.IsSystraceEnabled()); - EXPECT_FALSE(tc.IsArgumentFilterEnabled()); - EXPECT_STREQ("", tc.ToCategoryFilterString().c_str()); - CheckDefaultTraceConfigBehavior(tc); - - tc = TraceConfig("{\"record_mode\": invalid-value-needs-double-quote}"); - EXPECT_STREQ(kDefaultTraceConfigString, tc.ToString().c_str()); - EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode()); - EXPECT_FALSE(tc.IsSystraceEnabled()); - EXPECT_FALSE(tc.IsArgumentFilterEnabled()); - EXPECT_STREQ("", tc.ToCategoryFilterString().c_str()); - CheckDefaultTraceConfigBehavior(tc); - - // If the config string a dictionary formatted as a JSON string, it will - // initialize TraceConfig with best effort. - tc = TraceConfig("{}"); - EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode()); - EXPECT_FALSE(tc.IsSystraceEnabled()); - EXPECT_FALSE(tc.IsArgumentFilterEnabled()); - EXPECT_STREQ("", tc.ToCategoryFilterString().c_str()); - CheckDefaultTraceConfigBehavior(tc); - - tc = TraceConfig("{\"arbitrary-key\":\"arbitrary-value\"}"); - EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode()); - EXPECT_FALSE(tc.IsSystraceEnabled()); - EXPECT_FALSE(tc.IsArgumentFilterEnabled()); - EXPECT_STREQ("", tc.ToCategoryFilterString().c_str()); - CheckDefaultTraceConfigBehavior(tc); - - const char invalid_config_string[] = - "{" - "\"enable_systrace\":1," - "\"excluded_categories\":[\"excluded\"]," - "\"included_categories\":\"not a list\"," - "\"record_mode\":\"arbitrary-mode\"" - "}"; - tc = TraceConfig(invalid_config_string); - EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode()); - EXPECT_FALSE(tc.IsSystraceEnabled()); - EXPECT_FALSE(tc.IsArgumentFilterEnabled()); - - const char invalid_config_string_2[] = - "{" - "\"included_categories\":[\"category\",\"disabled-by-default-pattern\"]," - "\"excluded_categories\":[\"category\",\"disabled-by-default-pattern\"]" - "}"; - tc = TraceConfig(invalid_config_string_2); - EXPECT_TRUE(tc.category_filter().IsCategoryEnabled("category")); - EXPECT_TRUE( - tc.category_filter().IsCategoryEnabled("disabled-by-default-pattern")); - EXPECT_TRUE(tc.IsCategoryGroupEnabled("category")); - EXPECT_TRUE(tc.IsCategoryGroupEnabled("disabled-by-default-pattern")); -} - -TEST(TraceConfigTest, MergingTraceConfigs) { - // Merge - TraceConfig tc; - TraceConfig tc2("included,-excluded,inc_pattern*,-exc_pattern*", ""); - tc.Merge(tc2); - EXPECT_STREQ("{" - "\"enable_argument_filter\":false," - "\"enable_systrace\":false," - "\"excluded_categories\":[\"excluded\",\"exc_pattern*\"]," - "\"record_mode\":\"record-until-full\"" - "}", - tc.ToString().c_str()); -} - -TEST(TraceConfigTest, IsCategoryGroupEnabled) { - // Enabling a disabled- category does not require all categories to be traced - // to be included. - TraceConfig tc("disabled-by-default-cc,-excluded", ""); - EXPECT_STREQ("disabled-by-default-cc,-excluded", - tc.ToCategoryFilterString().c_str()); - EXPECT_TRUE(tc.IsCategoryGroupEnabled("disabled-by-default-cc")); - EXPECT_TRUE(tc.IsCategoryGroupEnabled("some_other_group")); - EXPECT_FALSE(tc.IsCategoryGroupEnabled("excluded")); - - // Enabled a disabled- category and also including makes all categories to - // be traced require including. - tc = TraceConfig("disabled-by-default-cc,included", ""); - EXPECT_STREQ("included,disabled-by-default-cc", - tc.ToCategoryFilterString().c_str()); - EXPECT_TRUE(tc.IsCategoryGroupEnabled("disabled-by-default-cc")); - EXPECT_TRUE(tc.IsCategoryGroupEnabled("included")); - EXPECT_FALSE(tc.IsCategoryGroupEnabled("other_included")); - - // Excluding categories won't enable disabled-by-default ones with the - // excluded category is also present in the group. - tc = TraceConfig("-excluded", ""); - EXPECT_STREQ("-excluded", tc.ToCategoryFilterString().c_str()); - EXPECT_FALSE(tc.IsCategoryGroupEnabled("excluded,disabled-by-default-cc")); -} - -TEST(TraceConfigTest, IsCategoryNameAllowed) { - // Test that IsCategoryNameAllowed actually catches categories that are - // explicitly forbidden. This method is called in a DCHECK to assert that we - // don't have these types of strings as categories. - EXPECT_FALSE( - TraceConfigCategoryFilter::IsCategoryNameAllowed(" bad_category ")); - EXPECT_FALSE( - TraceConfigCategoryFilter::IsCategoryNameAllowed(" bad_category")); - EXPECT_FALSE( - TraceConfigCategoryFilter::IsCategoryNameAllowed("bad_category ")); - EXPECT_FALSE( - TraceConfigCategoryFilter::IsCategoryNameAllowed(" bad_category")); - EXPECT_FALSE( - TraceConfigCategoryFilter::IsCategoryNameAllowed("bad_category ")); - EXPECT_FALSE( - TraceConfigCategoryFilter::IsCategoryNameAllowed(" bad_category ")); - EXPECT_FALSE(TraceConfigCategoryFilter::IsCategoryNameAllowed("")); - EXPECT_TRUE( - TraceConfigCategoryFilter::IsCategoryNameAllowed("good_category")); -} - -TEST(TraceConfigTest, SetTraceOptionValues) { - TraceConfig tc; - EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode()); - EXPECT_FALSE(tc.IsSystraceEnabled()); - - tc.SetTraceRecordMode(RECORD_AS_MUCH_AS_POSSIBLE); - EXPECT_EQ(RECORD_AS_MUCH_AS_POSSIBLE, tc.GetTraceRecordMode()); - - tc.EnableSystrace(); - EXPECT_TRUE(tc.IsSystraceEnabled()); -} - -TEST(TraceConfigTest, TraceConfigFromMemoryConfigString) { - std::string tc_str1 = - TraceConfigMemoryTestUtil::GetTraceConfig_PeriodicTriggers(200, 2000); - TraceConfig tc1(tc_str1); - EXPECT_EQ(tc_str1, tc1.ToString()); - TraceConfig tc2( - TraceConfigMemoryTestUtil::GetTraceConfig_LegacyPeriodicTriggers(200, - 2000)); - EXPECT_EQ(tc_str1, tc2.ToString()); - - EXPECT_TRUE(tc1.IsCategoryGroupEnabled(MemoryDumpManager::kTraceCategory)); - ASSERT_EQ(2u, tc1.memory_dump_config().triggers.size()); - - EXPECT_EQ(200u, - tc1.memory_dump_config().triggers[0].min_time_between_dumps_ms); - EXPECT_EQ(MemoryDumpLevelOfDetail::LIGHT, - tc1.memory_dump_config().triggers[0].level_of_detail); - - EXPECT_EQ(2000u, - tc1.memory_dump_config().triggers[1].min_time_between_dumps_ms); - EXPECT_EQ(MemoryDumpLevelOfDetail::DETAILED, - tc1.memory_dump_config().triggers[1].level_of_detail); - EXPECT_EQ( - 2048u, - tc1.memory_dump_config().heap_profiler_options.breakdown_threshold_bytes); - - std::string tc_str3 = - TraceConfigMemoryTestUtil::GetTraceConfig_BackgroundTrigger( - 1 /* period_ms */); - TraceConfig tc3(tc_str3); - EXPECT_EQ(tc_str3, tc3.ToString()); - EXPECT_TRUE(tc3.IsCategoryGroupEnabled(MemoryDumpManager::kTraceCategory)); - ASSERT_EQ(1u, tc3.memory_dump_config().triggers.size()); - EXPECT_EQ(1u, tc3.memory_dump_config().triggers[0].min_time_between_dumps_ms); - EXPECT_EQ(MemoryDumpLevelOfDetail::BACKGROUND, - tc3.memory_dump_config().triggers[0].level_of_detail); - - std::string tc_str4 = - TraceConfigMemoryTestUtil::GetTraceConfig_PeakDetectionTrigger( - 1 /*heavy_period */); - TraceConfig tc4(tc_str4); - EXPECT_EQ(tc_str4, tc4.ToString()); - ASSERT_EQ(1u, tc4.memory_dump_config().triggers.size()); - EXPECT_EQ(1u, tc4.memory_dump_config().triggers[0].min_time_between_dumps_ms); - EXPECT_EQ(MemoryDumpLevelOfDetail::DETAILED, - tc4.memory_dump_config().triggers[0].level_of_detail); -} - -TEST(TraceConfigTest, EmptyMemoryDumpConfigTest) { - // Empty trigger list should also be specified when converting back to string. - TraceConfig tc(TraceConfigMemoryTestUtil::GetTraceConfig_EmptyTriggers()); - EXPECT_EQ(TraceConfigMemoryTestUtil::GetTraceConfig_EmptyTriggers(), - tc.ToString()); - EXPECT_EQ(0u, tc.memory_dump_config().triggers.size()); - EXPECT_EQ( - static_cast<uint32_t>(TraceConfig::MemoryDumpConfig::HeapProfiler:: - kDefaultBreakdownThresholdBytes), - tc.memory_dump_config().heap_profiler_options.breakdown_threshold_bytes); -} - -TEST(TraceConfigTest, LegacyStringToMemoryDumpConfig) { - TraceConfig tc(MemoryDumpManager::kTraceCategory, ""); - EXPECT_TRUE(tc.IsCategoryGroupEnabled(MemoryDumpManager::kTraceCategory)); - EXPECT_NE(std::string::npos, tc.ToString().find("memory_dump_config")); - EXPECT_EQ(0u, tc.memory_dump_config().triggers.size()); - EXPECT_EQ( - static_cast<uint32_t>(TraceConfig::MemoryDumpConfig::HeapProfiler:: - kDefaultBreakdownThresholdBytes), - tc.memory_dump_config().heap_profiler_options.breakdown_threshold_bytes); -} - -} // namespace trace_event -} // namespace base
diff --git a/base/trace_event/trace_event_android_unittest.cc b/base/trace_event/trace_event_android_unittest.cc deleted file mode 100644 index 58bd77e..0000000 --- a/base/trace_event/trace_event_android_unittest.cc +++ /dev/null
@@ -1,22 +0,0 @@ -// Copyright (c) 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/trace_event/trace_event.h" - -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace trace_event { - -TEST(TraceEventAndroidTest, WriteToATrace) { - // Just a smoke test to ensure no crash. - TraceLog* trace_log = TraceLog::GetInstance(); - trace_log->StartATrace(); - TRACE_EVENT0("test", "test-event"); - trace_log->StopATrace(); - trace_log->AddClockSyncMetadataEvent(); -} - -} // namespace trace_event -} // namespace base
diff --git a/base/trace_event/trace_event_argument_unittest.cc b/base/trace_event/trace_event_argument_unittest.cc deleted file mode 100644 index 448b2d5..0000000 --- a/base/trace_event/trace_event_argument_unittest.cc +++ /dev/null
@@ -1,165 +0,0 @@ -// 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/trace_event/trace_event_argument.h" - -#include <stddef.h> - -#include <utility> - -#include "base/memory/ptr_util.h" -#include "base/values.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace trace_event { - -TEST(TraceEventArgumentTest, FlatDictionary) { - std::unique_ptr<TracedValue> value(new TracedValue()); - value->SetBoolean("bool", true); - value->SetDouble("double", 0.0); - value->SetInteger("int", 2014); - value->SetString("string", "string"); - std::string json = "PREFIX"; - value->AppendAsTraceFormat(&json); - EXPECT_EQ( - "PREFIX{\"bool\":true,\"double\":0.0,\"int\":2014,\"string\":\"string\"}", - json); -} - -TEST(TraceEventArgumentTest, NoDotPathExpansion) { - std::unique_ptr<TracedValue> value(new TracedValue()); - value->SetBoolean("bo.ol", true); - value->SetDouble("doub.le", 0.0); - value->SetInteger("in.t", 2014); - value->SetString("str.ing", "str.ing"); - std::string json; - value->AppendAsTraceFormat(&json); - EXPECT_EQ( - "{\"bo.ol\":true,\"doub.le\":0.0,\"in.t\":2014,\"str.ing\":\"str.ing\"}", - json); -} - -TEST(TraceEventArgumentTest, Hierarchy) { - std::unique_ptr<TracedValue> value(new TracedValue()); - value->BeginArray("a1"); - value->AppendInteger(1); - value->AppendBoolean(true); - value->BeginDictionary(); - value->SetInteger("i2", 3); - value->EndDictionary(); - value->EndArray(); - value->SetBoolean("b0", true); - value->SetDouble("d0", 0.0); - value->BeginDictionary("dict1"); - value->BeginDictionary("dict2"); - value->SetBoolean("b2", false); - value->EndDictionary(); - value->SetInteger("i1", 2014); - value->SetString("s1", "foo"); - value->EndDictionary(); - value->SetInteger("i0", 2014); - value->SetString("s0", "foo"); - std::string json; - value->AppendAsTraceFormat(&json); - EXPECT_EQ( - "{\"a1\":[1,true,{\"i2\":3}],\"b0\":true,\"d0\":0.0,\"dict1\":{\"dict2\":" - "{\"b2\":false},\"i1\":2014,\"s1\":\"foo\"},\"i0\":2014,\"s0\":" - "\"foo\"}", - json); -} - -TEST(TraceEventArgumentTest, LongStrings) { - std::string kLongString = "supercalifragilisticexpialidocious"; - std::string kLongString2 = "0123456789012345678901234567890123456789"; - char kLongString3[4096]; - for (size_t i = 0; i < sizeof(kLongString3); ++i) - kLongString3[i] = 'a' + (i % 25); - kLongString3[sizeof(kLongString3) - 1] = '\0'; - - std::unique_ptr<TracedValue> value(new TracedValue()); - value->SetString("a", "short"); - value->SetString("b", kLongString); - value->BeginArray("c"); - value->AppendString(kLongString2); - value->AppendString(""); - value->BeginDictionary(); - value->SetString("a", kLongString3); - value->EndDictionary(); - value->EndArray(); - - std::string json; - value->AppendAsTraceFormat(&json); - EXPECT_EQ("{\"a\":\"short\",\"b\":\"" + kLongString + "\",\"c\":[\"" + - kLongString2 + "\",\"\",{\"a\":\"" + kLongString3 + "\"}]}", - json); -} - -TEST(TraceEventArgumentTest, PassBaseValue) { - Value int_value(42); - Value bool_value(true); - Value double_value(42.0f); - - auto dict_value = WrapUnique(new DictionaryValue); - dict_value->SetBoolean("bool", true); - dict_value->SetInteger("int", 42); - dict_value->SetDouble("double", 42.0f); - dict_value->SetString("string", std::string("a") + "b"); - dict_value->SetString("string", std::string("a") + "b"); - - auto list_value = WrapUnique(new ListValue); - list_value->AppendBoolean(false); - list_value->AppendInteger(1); - list_value->AppendString("in_list"); - list_value->Append(std::move(dict_value)); - - std::unique_ptr<TracedValue> value(new TracedValue()); - value->BeginDictionary("outer_dict"); - value->SetValue("inner_list", std::move(list_value)); - value->EndDictionary(); - - dict_value.reset(); - list_value.reset(); - - std::string json; - value->AppendAsTraceFormat(&json); - EXPECT_EQ( - "{\"outer_dict\":{\"inner_list\":[false,1,\"in_list\",{\"bool\":true," - "\"double\":42.0,\"int\":42,\"string\":\"ab\"}]}}", - json); -} - -TEST(TraceEventArgumentTest, PassTracedValue) { - auto dict_value = std::make_unique<TracedValue>(); - dict_value->SetInteger("a", 1); - - auto nested_dict_value = std::make_unique<TracedValue>(); - nested_dict_value->SetInteger("b", 2); - nested_dict_value->BeginArray("c"); - nested_dict_value->AppendString("foo"); - nested_dict_value->EndArray(); - - dict_value->SetValue("e", *nested_dict_value); - - // Check the merged result. - std::string json; - dict_value->AppendAsTraceFormat(&json); - EXPECT_EQ("{\"a\":1,\"e\":{\"b\":2,\"c\":[\"foo\"]}}", json); - - // Check that the passed nestd dict was left unouthced. - json = ""; - nested_dict_value->AppendAsTraceFormat(&json); - EXPECT_EQ("{\"b\":2,\"c\":[\"foo\"]}", json); - - // And that it is still usable. - nested_dict_value->SetInteger("f", 3); - nested_dict_value->BeginDictionary("g"); - nested_dict_value->EndDictionary(); - json = ""; - nested_dict_value->AppendAsTraceFormat(&json); - EXPECT_EQ("{\"b\":2,\"c\":[\"foo\"],\"f\":3,\"g\":{}}", json); -} - -} // namespace trace_event -} // namespace base
diff --git a/base/trace_event/trace_event_system_stats_monitor_unittest.cc b/base/trace_event/trace_event_system_stats_monitor_unittest.cc deleted file mode 100644 index 978746d..0000000 --- a/base/trace_event/trace_event_system_stats_monitor_unittest.cc +++ /dev/null
@@ -1,68 +0,0 @@ -// 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/trace_event/trace_event_system_stats_monitor.h" - -#include <sstream> -#include <string> - -#include "base/macros.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "base/trace_event/trace_event_impl.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace trace_event { - -#if !defined(OS_IOS) -// Tests for the system stats monitor. -// Exists as a class so it can be a friend of TraceEventSystemStatsMonitor. -class TraceSystemStatsMonitorTest : public testing::Test { - public: - TraceSystemStatsMonitorTest() = default; - ~TraceSystemStatsMonitorTest() override = default; - - private: - DISALLOW_COPY_AND_ASSIGN(TraceSystemStatsMonitorTest); -}; - -////////////////////////////////////////////////////////////////////////////// - -TEST_F(TraceSystemStatsMonitorTest, TraceEventSystemStatsMonitor) { - MessageLoop message_loop; - - // Start with no observers of the TraceLog. - EXPECT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest()); - - // Creating a system stats monitor adds it to the TraceLog observer list. - std::unique_ptr<TraceEventSystemStatsMonitor> system_stats_monitor( - new TraceEventSystemStatsMonitor(message_loop.task_runner())); - EXPECT_EQ(1u, TraceLog::GetInstance()->GetObserverCountForTest()); - EXPECT_TRUE( - TraceLog::GetInstance()->HasEnabledStateObserver( - system_stats_monitor.get())); - - // By default the observer isn't dumping memory profiles. - EXPECT_FALSE(system_stats_monitor->IsTimerRunningForTest()); - - // Simulate enabling tracing. - system_stats_monitor->StartProfiling(); - RunLoop().RunUntilIdle(); - EXPECT_TRUE(system_stats_monitor->IsTimerRunningForTest()); - - // Simulate disabling tracing. - system_stats_monitor->StopProfiling(); - RunLoop().RunUntilIdle(); - EXPECT_FALSE(system_stats_monitor->IsTimerRunningForTest()); - - // Deleting the observer removes it from the TraceLog observer list. - system_stats_monitor.reset(); - EXPECT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest()); -} -#endif // !defined(OS_IOS) - -} // namespace trace_event -} // namespace base
diff --git a/base/trace_event/trace_event_unittest.cc b/base/trace_event/trace_event_unittest.cc deleted file mode 100644 index a413ee5..0000000 --- a/base/trace_event/trace_event_unittest.cc +++ /dev/null
@@ -1,3169 +0,0 @@ -// 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/trace_event/trace_event.h" - -#include <math.h> -#include <stddef.h> -#include <stdint.h> - -#include <cstdlib> -#include <memory> -#include <utility> - -#include "base/bind.h" -#include "base/command_line.h" -#include "base/json/json_reader.h" -#include "base/json/json_writer.h" -#include "base/location.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/memory/ref_counted_memory.h" -#include "base/memory/singleton.h" -#include "base/process/process_handle.h" -#include "base/single_thread_task_runner.h" -#include "base/stl_util.h" -#include "base/strings/pattern.h" -#include "base/strings/stringprintf.h" -#include "base/synchronization/waitable_event.h" -#include "base/threading/platform_thread.h" -#include "base/threading/thread.h" -#include "base/time/time.h" -#include "base/trace_event/event_name_filter.h" -#include "base/trace_event/heap_profiler_event_filter.h" -#include "base/trace_event/trace_buffer.h" -#include "base/trace_event/trace_event.h" -#include "base/trace_event/trace_event_filter.h" -#include "base/trace_event/trace_event_filter_test_utils.h" -#include "base/values.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace trace_event { - -namespace { - -enum CompareOp { - IS_EQUAL, - IS_NOT_EQUAL, -}; - -struct JsonKeyValue { - const char* key; - const char* value; - CompareOp op; -}; - -const int kThreadId = 42; -const int kAsyncId = 5; -const char kAsyncIdStr[] = "0x5"; -const int kAsyncId2 = 6; -const char kAsyncId2Str[] = "0x6"; -const int kFlowId = 7; -const char kFlowIdStr[] = "0x7"; - -const char kRecordAllCategoryFilter[] = "*"; - -class TraceEventTestFixture : public testing::Test { - public: - void OnTraceDataCollected( - WaitableEvent* flush_complete_event, - const scoped_refptr<base::RefCountedString>& events_str, - bool has_more_events); - DictionaryValue* FindMatchingTraceEntry(const JsonKeyValue* key_values); - DictionaryValue* FindNamePhase(const char* name, const char* phase); - DictionaryValue* FindNamePhaseKeyValue(const char* name, - const char* phase, - const char* key, - const char* value); - void DropTracedMetadataRecords(); - bool FindMatchingValue(const char* key, - const char* value); - bool FindNonMatchingValue(const char* key, - const char* value); - void Clear() { - trace_parsed_.Clear(); - json_output_.json_output.clear(); - } - - void BeginTrace() { - BeginSpecificTrace("*"); - } - - void BeginSpecificTrace(const std::string& filter) { - TraceLog::GetInstance()->SetEnabled(TraceConfig(filter, ""), - TraceLog::RECORDING_MODE); - } - - void CancelTrace() { - WaitableEvent flush_complete_event( - WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - CancelTraceAsync(&flush_complete_event); - flush_complete_event.Wait(); - } - - void EndTraceAndFlush() { - num_flush_callbacks_ = 0; - WaitableEvent flush_complete_event( - WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - EndTraceAndFlushAsync(&flush_complete_event); - flush_complete_event.Wait(); - } - - // Used when testing thread-local buffers which requires the thread initiating - // flush to have a message loop. - void EndTraceAndFlushInThreadWithMessageLoop() { - WaitableEvent flush_complete_event( - WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - Thread flush_thread("flush"); - flush_thread.Start(); - flush_thread.task_runner()->PostTask( - FROM_HERE, - base::BindOnce(&TraceEventTestFixture::EndTraceAndFlushAsync, - base::Unretained(this), &flush_complete_event)); - flush_complete_event.Wait(); - } - - void CancelTraceAsync(WaitableEvent* flush_complete_event) { - TraceLog::GetInstance()->CancelTracing( - base::Bind(&TraceEventTestFixture::OnTraceDataCollected, - base::Unretained(static_cast<TraceEventTestFixture*>(this)), - base::Unretained(flush_complete_event))); - } - - void EndTraceAndFlushAsync(WaitableEvent* flush_complete_event) { - TraceLog::GetInstance()->SetDisabled(TraceLog::RECORDING_MODE | - TraceLog::FILTERING_MODE); - TraceLog::GetInstance()->Flush( - base::Bind(&TraceEventTestFixture::OnTraceDataCollected, - base::Unretained(static_cast<TraceEventTestFixture*>(this)), - base::Unretained(flush_complete_event))); - } - - void SetUp() override { - const char* name = PlatformThread::GetName(); - old_thread_name_ = name ? strdup(name) : nullptr; - - TraceLog::ResetForTesting(); - TraceLog* tracelog = TraceLog::GetInstance(); - ASSERT_TRUE(tracelog); - ASSERT_FALSE(tracelog->IsEnabled()); - trace_buffer_.SetOutputCallback(json_output_.GetCallback()); - num_flush_callbacks_ = 0; - } - void TearDown() override { - if (TraceLog::GetInstance()) - EXPECT_FALSE(TraceLog::GetInstance()->IsEnabled()); - PlatformThread::SetName(old_thread_name_ ? old_thread_name_ : ""); - free(old_thread_name_); - old_thread_name_ = nullptr; - // We want our singleton torn down after each test. - TraceLog::ResetForTesting(); - } - - char* old_thread_name_; - ListValue trace_parsed_; - TraceResultBuffer trace_buffer_; - TraceResultBuffer::SimpleOutput json_output_; - size_t num_flush_callbacks_; - - private: - // We want our singleton torn down after each test. - ShadowingAtExitManager at_exit_manager_; - Lock lock_; -}; - -void TraceEventTestFixture::OnTraceDataCollected( - WaitableEvent* flush_complete_event, - const scoped_refptr<base::RefCountedString>& events_str, - bool has_more_events) { - num_flush_callbacks_++; - if (num_flush_callbacks_ > 1) { - EXPECT_FALSE(events_str->data().empty()); - } - AutoLock lock(lock_); - json_output_.json_output.clear(); - trace_buffer_.Start(); - trace_buffer_.AddFragment(events_str->data()); - trace_buffer_.Finish(); - - std::unique_ptr<Value> root = - base::JSONReader::Read(json_output_.json_output, JSON_PARSE_RFC); - - if (!root.get()) { - LOG(ERROR) << json_output_.json_output; - } - - ListValue* root_list = nullptr; - ASSERT_TRUE(root.get()); - ASSERT_TRUE(root->GetAsList(&root_list)); - - // Move items into our aggregate collection - while (root_list->GetSize()) { - std::unique_ptr<Value> item; - root_list->Remove(0, &item); - trace_parsed_.Append(std::move(item)); - } - - if (!has_more_events) - flush_complete_event->Signal(); -} - -static bool CompareJsonValues(const std::string& lhs, - const std::string& rhs, - CompareOp op) { - switch (op) { - case IS_EQUAL: - return lhs == rhs; - case IS_NOT_EQUAL: - return lhs != rhs; - default: - CHECK(0); - } - return false; -} - -static bool IsKeyValueInDict(const JsonKeyValue* key_value, - DictionaryValue* dict) { - Value* value = nullptr; - std::string value_str; - if (dict->Get(key_value->key, &value) && - value->GetAsString(&value_str) && - CompareJsonValues(value_str, key_value->value, key_value->op)) - return true; - - // Recurse to test arguments - DictionaryValue* args_dict = nullptr; - dict->GetDictionary("args", &args_dict); - if (args_dict) - return IsKeyValueInDict(key_value, args_dict); - - return false; -} - -static bool IsAllKeyValueInDict(const JsonKeyValue* key_values, - DictionaryValue* dict) { - // Scan all key_values, they must all be present and equal. - while (key_values && key_values->key) { - if (!IsKeyValueInDict(key_values, dict)) - return false; - ++key_values; - } - return true; -} - -DictionaryValue* TraceEventTestFixture::FindMatchingTraceEntry( - const JsonKeyValue* key_values) { - // Scan all items - size_t trace_parsed_count = trace_parsed_.GetSize(); - for (size_t i = 0; i < trace_parsed_count; i++) { - Value* value = nullptr; - trace_parsed_.Get(i, &value); - if (!value || value->type() != Value::Type::DICTIONARY) - continue; - DictionaryValue* dict = static_cast<DictionaryValue*>(value); - - if (IsAllKeyValueInDict(key_values, dict)) - return dict; - } - return nullptr; -} - -void TraceEventTestFixture::DropTracedMetadataRecords() { - std::unique_ptr<ListValue> old_trace_parsed(trace_parsed_.CreateDeepCopy()); - size_t old_trace_parsed_size = old_trace_parsed->GetSize(); - trace_parsed_.Clear(); - - for (size_t i = 0; i < old_trace_parsed_size; i++) { - Value* value = nullptr; - old_trace_parsed->Get(i, &value); - if (!value || value->type() != Value::Type::DICTIONARY) { - trace_parsed_.Append(value->CreateDeepCopy()); - continue; - } - DictionaryValue* dict = static_cast<DictionaryValue*>(value); - std::string tmp; - if (dict->GetString("ph", &tmp) && tmp == "M") - continue; - - trace_parsed_.Append(value->CreateDeepCopy()); - } -} - -DictionaryValue* TraceEventTestFixture::FindNamePhase(const char* name, - const char* phase) { - JsonKeyValue key_values[] = {{"name", name, IS_EQUAL}, - {"ph", phase, IS_EQUAL}, - {nullptr, nullptr, IS_EQUAL}}; - return FindMatchingTraceEntry(key_values); -} - -DictionaryValue* TraceEventTestFixture::FindNamePhaseKeyValue( - const char* name, - const char* phase, - const char* key, - const char* value) { - JsonKeyValue key_values[] = {{"name", name, IS_EQUAL}, - {"ph", phase, IS_EQUAL}, - {key, value, IS_EQUAL}, - {nullptr, nullptr, IS_EQUAL}}; - return FindMatchingTraceEntry(key_values); -} - -bool TraceEventTestFixture::FindMatchingValue(const char* key, - const char* value) { - JsonKeyValue key_values[] = {{key, value, IS_EQUAL}, - {nullptr, nullptr, IS_EQUAL}}; - return FindMatchingTraceEntry(key_values); -} - -bool TraceEventTestFixture::FindNonMatchingValue(const char* key, - const char* value) { - JsonKeyValue key_values[] = {{key, value, IS_NOT_EQUAL}, - {nullptr, nullptr, IS_EQUAL}}; - return FindMatchingTraceEntry(key_values); -} - -bool IsStringInDict(const char* string_to_match, const DictionaryValue* dict) { - for (DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) { - if (it.key().find(string_to_match) != std::string::npos) - return true; - - std::string value_str; - it.value().GetAsString(&value_str); - if (value_str.find(string_to_match) != std::string::npos) - return true; - } - - // Recurse to test arguments - const DictionaryValue* args_dict = nullptr; - dict->GetDictionary("args", &args_dict); - if (args_dict) - return IsStringInDict(string_to_match, args_dict); - - return false; -} - -const DictionaryValue* FindTraceEntry( - const ListValue& trace_parsed, - const char* string_to_match, - const DictionaryValue* match_after_this_item = nullptr) { - // Scan all items - size_t trace_parsed_count = trace_parsed.GetSize(); - for (size_t i = 0; i < trace_parsed_count; i++) { - const Value* value = nullptr; - trace_parsed.Get(i, &value); - if (match_after_this_item) { - if (value == match_after_this_item) - match_after_this_item = nullptr; - continue; - } - if (!value || value->type() != Value::Type::DICTIONARY) - continue; - const DictionaryValue* dict = static_cast<const DictionaryValue*>(value); - - if (IsStringInDict(string_to_match, dict)) - return dict; - } - return nullptr; -} - -std::vector<const DictionaryValue*> FindTraceEntries( - const ListValue& trace_parsed, - const char* string_to_match) { - std::vector<const DictionaryValue*> hits; - size_t trace_parsed_count = trace_parsed.GetSize(); - for (size_t i = 0; i < trace_parsed_count; i++) { - const Value* value = nullptr; - trace_parsed.Get(i, &value); - if (!value || value->type() != Value::Type::DICTIONARY) - continue; - const DictionaryValue* dict = static_cast<const DictionaryValue*>(value); - - if (IsStringInDict(string_to_match, dict)) - hits.push_back(dict); - } - return hits; -} - -const char kControlCharacters[] = "\001\002\003\n\r"; - -void TraceWithAllMacroVariants(WaitableEvent* task_complete_event) { - { - TRACE_EVENT0("all", "TRACE_EVENT0 call"); - TRACE_EVENT1("all", "TRACE_EVENT1 call", "name1", "value1"); - TRACE_EVENT2("all", "TRACE_EVENT2 call", - "name1", "\"value1\"", - "name2", "value\\2"); - - TRACE_EVENT_INSTANT0("all", "TRACE_EVENT_INSTANT0 call", - TRACE_EVENT_SCOPE_GLOBAL); - TRACE_EVENT_INSTANT1("all", "TRACE_EVENT_INSTANT1 call", - TRACE_EVENT_SCOPE_PROCESS, "name1", "value1"); - TRACE_EVENT_INSTANT2("all", "TRACE_EVENT_INSTANT2 call", - TRACE_EVENT_SCOPE_THREAD, - "name1", "value1", - "name2", "value2"); - - TRACE_EVENT_BEGIN0("all", "TRACE_EVENT_BEGIN0 call"); - TRACE_EVENT_BEGIN1("all", "TRACE_EVENT_BEGIN1 call", "name1", "value1"); - TRACE_EVENT_BEGIN2("all", "TRACE_EVENT_BEGIN2 call", - "name1", "value1", - "name2", "value2"); - - TRACE_EVENT_END0("all", "TRACE_EVENT_END0 call"); - TRACE_EVENT_END1("all", "TRACE_EVENT_END1 call", "name1", "value1"); - TRACE_EVENT_END2("all", "TRACE_EVENT_END2 call", - "name1", "value1", - "name2", "value2"); - - TRACE_EVENT_ASYNC_BEGIN0("all", "TRACE_EVENT_ASYNC_BEGIN0 call", kAsyncId); - TRACE_EVENT_ASYNC_BEGIN1("all", "TRACE_EVENT_ASYNC_BEGIN1 call", kAsyncId, - "name1", "value1"); - TRACE_EVENT_ASYNC_BEGIN2("all", "TRACE_EVENT_ASYNC_BEGIN2 call", kAsyncId, - "name1", "value1", - "name2", "value2"); - - TRACE_EVENT_ASYNC_STEP_INTO0("all", "TRACE_EVENT_ASYNC_STEP_INTO0 call", - kAsyncId, "step_begin1"); - TRACE_EVENT_ASYNC_STEP_INTO1("all", "TRACE_EVENT_ASYNC_STEP_INTO1 call", - kAsyncId, "step_begin2", "name1", "value1"); - - TRACE_EVENT_ASYNC_END0("all", "TRACE_EVENT_ASYNC_END0 call", kAsyncId); - TRACE_EVENT_ASYNC_END1("all", "TRACE_EVENT_ASYNC_END1 call", kAsyncId, - "name1", "value1"); - TRACE_EVENT_ASYNC_END2("all", "TRACE_EVENT_ASYNC_END2 call", kAsyncId, - "name1", "value1", - "name2", "value2"); - - TRACE_EVENT_FLOW_BEGIN0("all", "TRACE_EVENT_FLOW_BEGIN0 call", kFlowId); - TRACE_EVENT_FLOW_STEP0("all", "TRACE_EVENT_FLOW_STEP0 call", - kFlowId, "step1"); - TRACE_EVENT_FLOW_END_BIND_TO_ENCLOSING0("all", - "TRACE_EVENT_FLOW_END_BIND_TO_ENCLOSING0 call", kFlowId); - - TRACE_COUNTER1("all", "TRACE_COUNTER1 call", 31415); - TRACE_COUNTER2("all", "TRACE_COUNTER2 call", - "a", 30000, - "b", 1415); - - TRACE_COUNTER_WITH_TIMESTAMP1("all", "TRACE_COUNTER_WITH_TIMESTAMP1 call", - TimeTicks::FromInternalValue(42), 31415); - TRACE_COUNTER_WITH_TIMESTAMP2("all", "TRACE_COUNTER_WITH_TIMESTAMP2 call", - TimeTicks::FromInternalValue(42), - "a", 30000, "b", 1415); - - TRACE_COUNTER_ID1("all", "TRACE_COUNTER_ID1 call", 0x319009, 31415); - TRACE_COUNTER_ID2("all", "TRACE_COUNTER_ID2 call", 0x319009, - "a", 30000, "b", 1415); - - TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP0("all", - "TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP0 call", - kAsyncId, kThreadId, TimeTicks::FromInternalValue(12345)); - TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP0("all", - "TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP0 call", - kAsyncId, kThreadId, TimeTicks::FromInternalValue(23456)); - - TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0("all", - "TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0 call", - kAsyncId2, kThreadId, TimeTicks::FromInternalValue(34567)); - TRACE_EVENT_ASYNC_STEP_PAST0("all", "TRACE_EVENT_ASYNC_STEP_PAST0 call", - kAsyncId2, "step_end1"); - TRACE_EVENT_ASYNC_STEP_PAST1("all", "TRACE_EVENT_ASYNC_STEP_PAST1 call", - kAsyncId2, "step_end2", "name1", "value1"); - - TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0("all", - "TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0 call", - kAsyncId2, kThreadId, TimeTicks::FromInternalValue(45678)); - - TRACE_EVENT_OBJECT_CREATED_WITH_ID("all", "tracked object 1", 0x42); - TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( - "all", "tracked object 1", 0x42, "hello"); - TRACE_EVENT_OBJECT_DELETED_WITH_ID("all", "tracked object 1", 0x42); - - TraceScopedTrackableObject<int> trackable("all", "tracked object 2", - 0x2128506); - trackable.snapshot("world"); - - TRACE_EVENT_OBJECT_CREATED_WITH_ID( - "all", "tracked object 3", TRACE_ID_WITH_SCOPE("scope", 0x42)); - TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( - "all", "tracked object 3", TRACE_ID_WITH_SCOPE("scope", 0x42), "hello"); - TRACE_EVENT_OBJECT_DELETED_WITH_ID( - "all", "tracked object 3", TRACE_ID_WITH_SCOPE("scope", 0x42)); - - TRACE_EVENT1(kControlCharacters, kControlCharacters, - kControlCharacters, kControlCharacters); - - uint64_t context_id = 0x20151021; - - TRACE_EVENT_ENTER_CONTEXT("all", "TRACE_EVENT_ENTER_CONTEXT call", - TRACE_ID_WITH_SCOPE("scope", context_id)); - TRACE_EVENT_LEAVE_CONTEXT("all", "TRACE_EVENT_LEAVE_CONTEXT call", - TRACE_ID_WITH_SCOPE("scope", context_id)); - TRACE_EVENT_SCOPED_CONTEXT("disabled-by-default-cat", - "TRACE_EVENT_SCOPED_CONTEXT disabled call", - context_id); - TRACE_EVENT_SCOPED_CONTEXT("all", "TRACE_EVENT_SCOPED_CONTEXT call", - context_id); - - TRACE_LINK_IDS("all", "TRACE_LINK_IDS simple call", 0x1000, 0x2000); - TRACE_LINK_IDS("all", "TRACE_LINK_IDS scoped call", - TRACE_ID_WITH_SCOPE("scope 1", 0x1000), - TRACE_ID_WITH_SCOPE("scope 2", 0x2000)); - TRACE_LINK_IDS("all", "TRACE_LINK_IDS to a local ID", 0x1000, - TRACE_ID_LOCAL(0x2000)); - TRACE_LINK_IDS("all", "TRACE_LINK_IDS to a global ID", 0x1000, - TRACE_ID_GLOBAL(0x2000)); - TRACE_LINK_IDS("all", "TRACE_LINK_IDS to a composite ID", 0x1000, - TRACE_ID_WITH_SCOPE("scope 1", 0x2000, 0x3000)); - - TRACE_EVENT_ASYNC_BEGIN0("all", "async default process scope", 0x1000); - TRACE_EVENT_ASYNC_BEGIN0("all", "async local id", TRACE_ID_LOCAL(0x2000)); - TRACE_EVENT_ASYNC_BEGIN0("all", "async global id", TRACE_ID_GLOBAL(0x3000)); - TRACE_EVENT_ASYNC_BEGIN0("all", "async global id with scope string", - TRACE_ID_WITH_SCOPE("scope string", - TRACE_ID_GLOBAL(0x4000))); - } // Scope close causes TRACE_EVENT0 etc to send their END events. - - if (task_complete_event) - task_complete_event->Signal(); -} - -void ValidateAllTraceMacrosCreatedData(const ListValue& trace_parsed) { - const DictionaryValue* item = nullptr; - -#define EXPECT_FIND_(string) \ - item = FindTraceEntry(trace_parsed, string); \ - EXPECT_TRUE(item); -#define EXPECT_NOT_FIND_(string) \ - item = FindTraceEntry(trace_parsed, string); \ - EXPECT_FALSE(item); -#define EXPECT_SUB_FIND_(string) \ - if (item) \ - EXPECT_TRUE(IsStringInDict(string, item)); - - EXPECT_FIND_("TRACE_EVENT0 call"); - { - std::string ph; - std::string ph_end; - EXPECT_TRUE((item = FindTraceEntry(trace_parsed, "TRACE_EVENT0 call"))); - EXPECT_TRUE((item && item->GetString("ph", &ph))); - EXPECT_EQ("X", ph); - item = FindTraceEntry(trace_parsed, "TRACE_EVENT0 call", item); - EXPECT_FALSE(item); - } - EXPECT_FIND_("TRACE_EVENT1 call"); - EXPECT_SUB_FIND_("name1"); - EXPECT_SUB_FIND_("value1"); - EXPECT_FIND_("TRACE_EVENT2 call"); - EXPECT_SUB_FIND_("name1"); - EXPECT_SUB_FIND_("\"value1\""); - EXPECT_SUB_FIND_("name2"); - EXPECT_SUB_FIND_("value\\2"); - - EXPECT_FIND_("TRACE_EVENT_INSTANT0 call"); - { - std::string scope; - EXPECT_TRUE((item && item->GetString("s", &scope))); - EXPECT_EQ("g", scope); - } - EXPECT_FIND_("TRACE_EVENT_INSTANT1 call"); - { - std::string scope; - EXPECT_TRUE((item && item->GetString("s", &scope))); - EXPECT_EQ("p", scope); - } - EXPECT_SUB_FIND_("name1"); - EXPECT_SUB_FIND_("value1"); - EXPECT_FIND_("TRACE_EVENT_INSTANT2 call"); - { - std::string scope; - EXPECT_TRUE((item && item->GetString("s", &scope))); - EXPECT_EQ("t", scope); - } - EXPECT_SUB_FIND_("name1"); - EXPECT_SUB_FIND_("value1"); - EXPECT_SUB_FIND_("name2"); - EXPECT_SUB_FIND_("value2"); - - EXPECT_FIND_("TRACE_EVENT_BEGIN0 call"); - EXPECT_FIND_("TRACE_EVENT_BEGIN1 call"); - EXPECT_SUB_FIND_("name1"); - EXPECT_SUB_FIND_("value1"); - EXPECT_FIND_("TRACE_EVENT_BEGIN2 call"); - EXPECT_SUB_FIND_("name1"); - EXPECT_SUB_FIND_("value1"); - EXPECT_SUB_FIND_("name2"); - EXPECT_SUB_FIND_("value2"); - - EXPECT_FIND_("TRACE_EVENT_END0 call"); - EXPECT_FIND_("TRACE_EVENT_END1 call"); - EXPECT_SUB_FIND_("name1"); - EXPECT_SUB_FIND_("value1"); - EXPECT_FIND_("TRACE_EVENT_END2 call"); - EXPECT_SUB_FIND_("name1"); - EXPECT_SUB_FIND_("value1"); - EXPECT_SUB_FIND_("name2"); - EXPECT_SUB_FIND_("value2"); - - EXPECT_FIND_("TRACE_EVENT_ASYNC_BEGIN0 call"); - EXPECT_SUB_FIND_("id"); - EXPECT_SUB_FIND_(kAsyncIdStr); - EXPECT_FIND_("TRACE_EVENT_ASYNC_BEGIN1 call"); - EXPECT_SUB_FIND_("id"); - EXPECT_SUB_FIND_(kAsyncIdStr); - EXPECT_SUB_FIND_("name1"); - EXPECT_SUB_FIND_("value1"); - EXPECT_FIND_("TRACE_EVENT_ASYNC_BEGIN2 call"); - EXPECT_SUB_FIND_("id"); - EXPECT_SUB_FIND_(kAsyncIdStr); - EXPECT_SUB_FIND_("name1"); - EXPECT_SUB_FIND_("value1"); - EXPECT_SUB_FIND_("name2"); - EXPECT_SUB_FIND_("value2"); - - EXPECT_FIND_("TRACE_EVENT_ASYNC_STEP_INTO0 call"); - EXPECT_SUB_FIND_("id"); - EXPECT_SUB_FIND_(kAsyncIdStr); - EXPECT_SUB_FIND_("step_begin1"); - EXPECT_FIND_("TRACE_EVENT_ASYNC_STEP_INTO1 call"); - EXPECT_SUB_FIND_("id"); - EXPECT_SUB_FIND_(kAsyncIdStr); - EXPECT_SUB_FIND_("step_begin2"); - EXPECT_SUB_FIND_("name1"); - EXPECT_SUB_FIND_("value1"); - - EXPECT_FIND_("TRACE_EVENT_ASYNC_END0 call"); - EXPECT_SUB_FIND_("id"); - EXPECT_SUB_FIND_(kAsyncIdStr); - EXPECT_FIND_("TRACE_EVENT_ASYNC_END1 call"); - EXPECT_SUB_FIND_("id"); - EXPECT_SUB_FIND_(kAsyncIdStr); - EXPECT_SUB_FIND_("name1"); - EXPECT_SUB_FIND_("value1"); - EXPECT_FIND_("TRACE_EVENT_ASYNC_END2 call"); - EXPECT_SUB_FIND_("id"); - EXPECT_SUB_FIND_(kAsyncIdStr); - EXPECT_SUB_FIND_("name1"); - EXPECT_SUB_FIND_("value1"); - EXPECT_SUB_FIND_("name2"); - EXPECT_SUB_FIND_("value2"); - - EXPECT_FIND_("TRACE_EVENT_FLOW_BEGIN0 call"); - EXPECT_SUB_FIND_("id"); - EXPECT_SUB_FIND_(kFlowIdStr); - EXPECT_FIND_("TRACE_EVENT_FLOW_STEP0 call"); - EXPECT_SUB_FIND_("id"); - EXPECT_SUB_FIND_(kFlowIdStr); - EXPECT_SUB_FIND_("step1"); - EXPECT_FIND_("TRACE_EVENT_FLOW_END_BIND_TO_ENCLOSING0 call"); - EXPECT_SUB_FIND_("id"); - EXPECT_SUB_FIND_(kFlowIdStr); - - EXPECT_FIND_("TRACE_COUNTER1 call"); - { - std::string ph; - EXPECT_TRUE((item && item->GetString("ph", &ph))); - EXPECT_EQ("C", ph); - - int value; - EXPECT_TRUE((item && item->GetInteger("args.value", &value))); - EXPECT_EQ(31415, value); - } - - EXPECT_FIND_("TRACE_COUNTER2 call"); - { - std::string ph; - EXPECT_TRUE((item && item->GetString("ph", &ph))); - EXPECT_EQ("C", ph); - - int value; - EXPECT_TRUE((item && item->GetInteger("args.a", &value))); - EXPECT_EQ(30000, value); - - EXPECT_TRUE((item && item->GetInteger("args.b", &value))); - EXPECT_EQ(1415, value); - } - - EXPECT_FIND_("TRACE_COUNTER_WITH_TIMESTAMP1 call"); - { - std::string ph; - EXPECT_TRUE((item && item->GetString("ph", &ph))); - EXPECT_EQ("C", ph); - - int value; - EXPECT_TRUE((item && item->GetInteger("args.value", &value))); - EXPECT_EQ(31415, value); - - int ts; - EXPECT_TRUE((item && item->GetInteger("ts", &ts))); - EXPECT_EQ(42, ts); - } - - EXPECT_FIND_("TRACE_COUNTER_WITH_TIMESTAMP2 call"); - { - std::string ph; - EXPECT_TRUE((item && item->GetString("ph", &ph))); - EXPECT_EQ("C", ph); - - int value; - EXPECT_TRUE((item && item->GetInteger("args.a", &value))); - EXPECT_EQ(30000, value); - - EXPECT_TRUE((item && item->GetInteger("args.b", &value))); - EXPECT_EQ(1415, value); - - int ts; - EXPECT_TRUE((item && item->GetInteger("ts", &ts))); - EXPECT_EQ(42, ts); - } - - EXPECT_FIND_("TRACE_COUNTER_ID1 call"); - { - std::string id; - EXPECT_TRUE((item && item->GetString("id", &id))); - EXPECT_EQ("0x319009", id); - - std::string ph; - EXPECT_TRUE((item && item->GetString("ph", &ph))); - EXPECT_EQ("C", ph); - - int value; - EXPECT_TRUE((item && item->GetInteger("args.value", &value))); - EXPECT_EQ(31415, value); - } - - EXPECT_FIND_("TRACE_COUNTER_ID2 call"); - { - std::string id; - EXPECT_TRUE((item && item->GetString("id", &id))); - EXPECT_EQ("0x319009", id); - - std::string ph; - EXPECT_TRUE((item && item->GetString("ph", &ph))); - EXPECT_EQ("C", ph); - - int value; - EXPECT_TRUE((item && item->GetInteger("args.a", &value))); - EXPECT_EQ(30000, value); - - EXPECT_TRUE((item && item->GetInteger("args.b", &value))); - EXPECT_EQ(1415, value); - } - - EXPECT_FIND_("TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP0 call"); - { - int val; - EXPECT_TRUE((item && item->GetInteger("ts", &val))); - EXPECT_EQ(12345, val); - EXPECT_TRUE((item && item->GetInteger("tid", &val))); - EXPECT_EQ(kThreadId, val); - std::string id; - EXPECT_TRUE((item && item->GetString("id", &id))); - EXPECT_EQ(kAsyncIdStr, id); - } - - EXPECT_FIND_("TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP0 call"); - { - int val; - EXPECT_TRUE((item && item->GetInteger("ts", &val))); - EXPECT_EQ(23456, val); - EXPECT_TRUE((item && item->GetInteger("tid", &val))); - EXPECT_EQ(kThreadId, val); - std::string id; - EXPECT_TRUE((item && item->GetString("id", &id))); - EXPECT_EQ(kAsyncIdStr, id); - } - - EXPECT_FIND_("TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0 call"); - { - int val; - EXPECT_TRUE((item && item->GetInteger("ts", &val))); - EXPECT_EQ(34567, val); - EXPECT_TRUE((item && item->GetInteger("tid", &val))); - EXPECT_EQ(kThreadId, val); - std::string id; - EXPECT_TRUE((item && item->GetString("id", &id))); - EXPECT_EQ(kAsyncId2Str, id); - } - - EXPECT_FIND_("TRACE_EVENT_ASYNC_STEP_PAST0 call"); - { - EXPECT_SUB_FIND_("id"); - EXPECT_SUB_FIND_(kAsyncId2Str); - EXPECT_SUB_FIND_("step_end1"); - EXPECT_FIND_("TRACE_EVENT_ASYNC_STEP_PAST1 call"); - EXPECT_SUB_FIND_("id"); - EXPECT_SUB_FIND_(kAsyncId2Str); - EXPECT_SUB_FIND_("step_end2"); - EXPECT_SUB_FIND_("name1"); - EXPECT_SUB_FIND_("value1"); - } - - EXPECT_FIND_("TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0 call"); - { - int val; - EXPECT_TRUE((item && item->GetInteger("ts", &val))); - EXPECT_EQ(45678, val); - EXPECT_TRUE((item && item->GetInteger("tid", &val))); - EXPECT_EQ(kThreadId, val); - std::string id; - EXPECT_TRUE((item && item->GetString("id", &id))); - EXPECT_EQ(kAsyncId2Str, id); - } - - EXPECT_FIND_("tracked object 1"); - { - std::string phase; - std::string id; - std::string snapshot; - - EXPECT_TRUE((item && item->GetString("ph", &phase))); - EXPECT_EQ("N", phase); - EXPECT_FALSE((item && item->HasKey("scope"))); - EXPECT_TRUE((item && item->GetString("id", &id))); - EXPECT_EQ("0x42", id); - - item = FindTraceEntry(trace_parsed, "tracked object 1", item); - EXPECT_TRUE(item); - EXPECT_TRUE(item && item->GetString("ph", &phase)); - EXPECT_EQ("O", phase); - EXPECT_FALSE((item && item->HasKey("scope"))); - EXPECT_TRUE(item && item->GetString("id", &id)); - EXPECT_EQ("0x42", id); - EXPECT_TRUE(item && item->GetString("args.snapshot", &snapshot)); - EXPECT_EQ("hello", snapshot); - - item = FindTraceEntry(trace_parsed, "tracked object 1", item); - EXPECT_TRUE(item); - EXPECT_TRUE(item && item->GetString("ph", &phase)); - EXPECT_EQ("D", phase); - EXPECT_FALSE((item && item->HasKey("scope"))); - EXPECT_TRUE(item && item->GetString("id", &id)); - EXPECT_EQ("0x42", id); - } - - EXPECT_FIND_("tracked object 2"); - { - std::string phase; - std::string id; - std::string snapshot; - - EXPECT_TRUE(item && item->GetString("ph", &phase)); - EXPECT_EQ("N", phase); - EXPECT_TRUE(item && item->GetString("id", &id)); - EXPECT_EQ("0x2128506", id); - - item = FindTraceEntry(trace_parsed, "tracked object 2", item); - EXPECT_TRUE(item); - EXPECT_TRUE(item && item->GetString("ph", &phase)); - EXPECT_EQ("O", phase); - EXPECT_TRUE(item && item->GetString("id", &id)); - EXPECT_EQ("0x2128506", id); - EXPECT_TRUE(item && item->GetString("args.snapshot", &snapshot)); - EXPECT_EQ("world", snapshot); - - item = FindTraceEntry(trace_parsed, "tracked object 2", item); - EXPECT_TRUE(item); - EXPECT_TRUE(item && item->GetString("ph", &phase)); - EXPECT_EQ("D", phase); - EXPECT_TRUE(item && item->GetString("id", &id)); - EXPECT_EQ("0x2128506", id); - } - - EXPECT_FIND_("tracked object 3"); - { - std::string phase; - std::string scope; - std::string id; - std::string snapshot; - - EXPECT_TRUE((item && item->GetString("ph", &phase))); - EXPECT_EQ("N", phase); - EXPECT_TRUE((item && item->GetString("scope", &scope))); - EXPECT_EQ("scope", scope); - EXPECT_TRUE((item && item->GetString("id", &id))); - EXPECT_EQ("0x42", id); - - item = FindTraceEntry(trace_parsed, "tracked object 3", item); - EXPECT_TRUE(item); - EXPECT_TRUE(item && item->GetString("ph", &phase)); - EXPECT_EQ("O", phase); - EXPECT_TRUE((item && item->GetString("scope", &scope))); - EXPECT_EQ("scope", scope); - EXPECT_TRUE(item && item->GetString("id", &id)); - EXPECT_EQ("0x42", id); - EXPECT_TRUE(item && item->GetString("args.snapshot", &snapshot)); - EXPECT_EQ("hello", snapshot); - - item = FindTraceEntry(trace_parsed, "tracked object 3", item); - EXPECT_TRUE(item); - EXPECT_TRUE(item && item->GetString("ph", &phase)); - EXPECT_EQ("D", phase); - EXPECT_TRUE((item && item->GetString("scope", &scope))); - EXPECT_EQ("scope", scope); - EXPECT_TRUE(item && item->GetString("id", &id)); - EXPECT_EQ("0x42", id); - } - - EXPECT_FIND_(kControlCharacters); - EXPECT_SUB_FIND_(kControlCharacters); - - EXPECT_FIND_("TRACE_EVENT_ENTER_CONTEXT call"); - { - std::string ph; - EXPECT_TRUE((item && item->GetString("ph", &ph))); - EXPECT_EQ("(", ph); - - std::string scope; - std::string id; - EXPECT_TRUE((item && item->GetString("scope", &scope))); - EXPECT_EQ("scope", scope); - EXPECT_TRUE((item && item->GetString("id", &id))); - EXPECT_EQ("0x20151021", id); - } - - EXPECT_FIND_("TRACE_EVENT_LEAVE_CONTEXT call"); - { - std::string ph; - EXPECT_TRUE((item && item->GetString("ph", &ph))); - EXPECT_EQ(")", ph); - - std::string scope; - std::string id; - EXPECT_TRUE((item && item->GetString("scope", &scope))); - EXPECT_EQ("scope", scope); - EXPECT_TRUE((item && item->GetString("id", &id))); - EXPECT_EQ("0x20151021", id); - } - - std::vector<const DictionaryValue*> scoped_context_calls = - FindTraceEntries(trace_parsed, "TRACE_EVENT_SCOPED_CONTEXT call"); - EXPECT_EQ(2u, scoped_context_calls.size()); - { - item = scoped_context_calls[0]; - std::string ph; - EXPECT_TRUE((item && item->GetString("ph", &ph))); - EXPECT_EQ("(", ph); - - std::string id; - EXPECT_FALSE((item && item->HasKey("scope"))); - EXPECT_TRUE((item && item->GetString("id", &id))); - EXPECT_EQ("0x20151021", id); - } - - { - item = scoped_context_calls[1]; - std::string ph; - EXPECT_TRUE((item && item->GetString("ph", &ph))); - EXPECT_EQ(")", ph); - - std::string id; - EXPECT_FALSE((item && item->HasKey("scope"))); - EXPECT_TRUE((item && item->GetString("id", &id))); - EXPECT_EQ("0x20151021", id); - } - - EXPECT_FIND_("TRACE_LINK_IDS simple call"); - { - std::string ph; - EXPECT_TRUE((item && item->GetString("ph", &ph))); - EXPECT_EQ("=", ph); - - EXPECT_FALSE((item && item->HasKey("scope"))); - std::string id1; - EXPECT_TRUE((item && item->GetString("id", &id1))); - EXPECT_EQ("0x1000", id1); - - EXPECT_FALSE((item && item->HasKey("args.linked_id.scope"))); - std::string id2; - EXPECT_TRUE((item && item->GetString("args.linked_id.id", &id2))); - EXPECT_EQ("0x2000", id2); - } - - EXPECT_FIND_("TRACE_LINK_IDS scoped call"); - { - std::string ph; - EXPECT_TRUE((item && item->GetString("ph", &ph))); - EXPECT_EQ("=", ph); - - std::string scope1; - EXPECT_TRUE((item && item->GetString("scope", &scope1))); - EXPECT_EQ("scope 1", scope1); - std::string id1; - EXPECT_TRUE((item && item->GetString("id", &id1))); - EXPECT_EQ("0x1000", id1); - - std::string scope2; - EXPECT_TRUE((item && item->GetString("args.linked_id.scope", &scope2))); - EXPECT_EQ("scope 2", scope2); - std::string id2; - EXPECT_TRUE((item && item->GetString("args.linked_id.id", &id2))); - EXPECT_EQ("0x2000", id2); - } - - EXPECT_FIND_("TRACE_LINK_IDS to a local ID"); - { - std::string ph; - EXPECT_TRUE((item && item->GetString("ph", &ph))); - EXPECT_EQ("=", ph); - - EXPECT_FALSE((item && item->HasKey("scope"))); - std::string id1; - EXPECT_TRUE((item && item->GetString("id", &id1))); - EXPECT_EQ("0x1000", id1); - - EXPECT_FALSE((item && item->HasKey("args.linked_id.scope"))); - std::string id2; - EXPECT_TRUE((item && item->GetString("args.linked_id.id2.local", &id2))); - EXPECT_EQ("0x2000", id2); - } - - EXPECT_FIND_("TRACE_LINK_IDS to a global ID"); - { - std::string ph; - EXPECT_TRUE((item && item->GetString("ph", &ph))); - EXPECT_EQ("=", ph); - - EXPECT_FALSE((item && item->HasKey("scope"))); - std::string id1; - EXPECT_TRUE((item && item->GetString("id", &id1))); - EXPECT_EQ("0x1000", id1); - - EXPECT_FALSE((item && item->HasKey("args.linked_id.scope"))); - std::string id2; - EXPECT_TRUE((item && item->GetString("args.linked_id.id2.global", &id2))); - EXPECT_EQ("0x2000", id2); - } - - EXPECT_FIND_("TRACE_LINK_IDS to a composite ID"); - { - std::string ph; - EXPECT_TRUE((item && item->GetString("ph", &ph))); - EXPECT_EQ("=", ph); - - EXPECT_FALSE(item->HasKey("scope")); - std::string id1; - EXPECT_TRUE(item->GetString("id", &id1)); - EXPECT_EQ("0x1000", id1); - - std::string scope; - EXPECT_TRUE(item->GetString("args.linked_id.scope", &scope)); - EXPECT_EQ("scope 1", scope); - std::string id2; - EXPECT_TRUE(item->GetString("args.linked_id.id", &id2)); - EXPECT_EQ(id2, "0x2000/0x3000"); - } - - EXPECT_FIND_("async default process scope"); - { - std::string ph; - EXPECT_TRUE((item && item->GetString("ph", &ph))); - EXPECT_EQ("S", ph); - - std::string id; - EXPECT_TRUE((item && item->GetString("id", &id))); - EXPECT_EQ("0x1000", id); - } - - EXPECT_FIND_("async local id"); - { - std::string ph; - EXPECT_TRUE((item && item->GetString("ph", &ph))); - EXPECT_EQ("S", ph); - - std::string id; - EXPECT_TRUE((item && item->GetString("id2.local", &id))); - EXPECT_EQ("0x2000", id); - } - - EXPECT_FIND_("async global id"); - { - std::string ph; - EXPECT_TRUE((item && item->GetString("ph", &ph))); - EXPECT_EQ("S", ph); - - std::string id; - EXPECT_TRUE((item && item->GetString("id2.global", &id))); - EXPECT_EQ("0x3000", id); - } - - EXPECT_FIND_("async global id with scope string"); - { - std::string ph; - EXPECT_TRUE((item && item->GetString("ph", &ph))); - EXPECT_EQ("S", ph); - - std::string id; - EXPECT_TRUE((item && item->GetString("id2.global", &id))); - EXPECT_EQ("0x4000", id); - std::string scope; - EXPECT_TRUE((item && item->GetString("scope", &scope))); - EXPECT_EQ("scope string", scope); - } -} - -void TraceManyInstantEvents(int thread_id, int num_events, - WaitableEvent* task_complete_event) { - for (int i = 0; i < num_events; i++) { - TRACE_EVENT_INSTANT2("all", "multi thread event", - TRACE_EVENT_SCOPE_THREAD, - "thread", thread_id, - "event", i); - } - - if (task_complete_event) - task_complete_event->Signal(); -} - -void ValidateInstantEventPresentOnEveryThread(const ListValue& trace_parsed, - int num_threads, - int num_events) { - std::map<int, std::map<int, bool> > results; - - size_t trace_parsed_count = trace_parsed.GetSize(); - for (size_t i = 0; i < trace_parsed_count; i++) { - const Value* value = nullptr; - trace_parsed.Get(i, &value); - if (!value || value->type() != Value::Type::DICTIONARY) - continue; - const DictionaryValue* dict = static_cast<const DictionaryValue*>(value); - std::string name; - dict->GetString("name", &name); - if (name != "multi thread event") - continue; - - int thread = 0; - int event = 0; - EXPECT_TRUE(dict->GetInteger("args.thread", &thread)); - EXPECT_TRUE(dict->GetInteger("args.event", &event)); - results[thread][event] = true; - } - - EXPECT_FALSE(results[-1][-1]); - for (int thread = 0; thread < num_threads; thread++) { - for (int event = 0; event < num_events; event++) { - EXPECT_TRUE(results[thread][event]); - } - } -} - -void CheckTraceDefaultCategoryFilters(const TraceLog& trace_log) { - // Default enables all category filters except the disabled-by-default-* ones. - EXPECT_TRUE(*trace_log.GetCategoryGroupEnabled("foo")); - EXPECT_TRUE(*trace_log.GetCategoryGroupEnabled("bar")); - EXPECT_TRUE(*trace_log.GetCategoryGroupEnabled("foo,bar")); - EXPECT_TRUE(*trace_log.GetCategoryGroupEnabled( - "foo,disabled-by-default-foo")); - EXPECT_FALSE(*trace_log.GetCategoryGroupEnabled( - "disabled-by-default-foo,disabled-by-default-bar")); -} - -} // namespace - -// Simple Test for emitting data and validating it was received. -TEST_F(TraceEventTestFixture, DataCaptured) { - TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""), - TraceLog::RECORDING_MODE); - - TraceWithAllMacroVariants(nullptr); - - EndTraceAndFlush(); - - ValidateAllTraceMacrosCreatedData(trace_parsed_); -} - -// Emit some events and validate that only empty strings are received -// if we tell Flush() to discard events. -TEST_F(TraceEventTestFixture, DataDiscarded) { - TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""), - TraceLog::RECORDING_MODE); - - TraceWithAllMacroVariants(nullptr); - - CancelTrace(); - - EXPECT_TRUE(trace_parsed_.empty()); -} - -class MockEnabledStateChangedObserver : - public TraceLog::EnabledStateObserver { - public: - MOCK_METHOD0(OnTraceLogEnabled, void()); - MOCK_METHOD0(OnTraceLogDisabled, void()); -}; - -TEST_F(TraceEventTestFixture, EnabledObserverFiresOnEnable) { - MockEnabledStateChangedObserver observer; - TraceLog::GetInstance()->AddEnabledStateObserver(&observer); - - EXPECT_CALL(observer, OnTraceLogEnabled()) - .Times(1); - TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""), - TraceLog::RECORDING_MODE); - testing::Mock::VerifyAndClear(&observer); - EXPECT_TRUE(TraceLog::GetInstance()->IsEnabled()); - - // Cleanup. - TraceLog::GetInstance()->RemoveEnabledStateObserver(&observer); - TraceLog::GetInstance()->SetDisabled(); -} - -TEST_F(TraceEventTestFixture, EnabledObserverDoesntFireOnSecondEnable) { - TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""), - TraceLog::RECORDING_MODE); - - testing::StrictMock<MockEnabledStateChangedObserver> observer; - TraceLog::GetInstance()->AddEnabledStateObserver(&observer); - - EXPECT_CALL(observer, OnTraceLogEnabled()) - .Times(0); - EXPECT_CALL(observer, OnTraceLogDisabled()) - .Times(0); - TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""), - TraceLog::RECORDING_MODE); - testing::Mock::VerifyAndClear(&observer); - EXPECT_TRUE(TraceLog::GetInstance()->IsEnabled()); - - // Cleanup. - TraceLog::GetInstance()->RemoveEnabledStateObserver(&observer); - TraceLog::GetInstance()->SetDisabled(); - TraceLog::GetInstance()->SetDisabled(); -} - -TEST_F(TraceEventTestFixture, EnabledObserverFiresOnFirstDisable) { - TraceConfig tc_inc_all("*", ""); - TraceLog::GetInstance()->SetEnabled(tc_inc_all, TraceLog::RECORDING_MODE); - TraceLog::GetInstance()->SetEnabled(tc_inc_all, TraceLog::RECORDING_MODE); - - testing::StrictMock<MockEnabledStateChangedObserver> observer; - TraceLog::GetInstance()->AddEnabledStateObserver(&observer); - - EXPECT_CALL(observer, OnTraceLogEnabled()) - .Times(0); - EXPECT_CALL(observer, OnTraceLogDisabled()) - .Times(1); - TraceLog::GetInstance()->SetDisabled(); - testing::Mock::VerifyAndClear(&observer); - - // Cleanup. - TraceLog::GetInstance()->RemoveEnabledStateObserver(&observer); - TraceLog::GetInstance()->SetDisabled(); -} - -TEST_F(TraceEventTestFixture, EnabledObserverFiresOnDisable) { - TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""), - TraceLog::RECORDING_MODE); - - MockEnabledStateChangedObserver observer; - TraceLog::GetInstance()->AddEnabledStateObserver(&observer); - - EXPECT_CALL(observer, OnTraceLogDisabled()) - .Times(1); - TraceLog::GetInstance()->SetDisabled(); - testing::Mock::VerifyAndClear(&observer); - - // Cleanup. - TraceLog::GetInstance()->RemoveEnabledStateObserver(&observer); -} - -// Tests the IsEnabled() state of TraceLog changes before callbacks. -class AfterStateChangeEnabledStateObserver - : public TraceLog::EnabledStateObserver { - public: - AfterStateChangeEnabledStateObserver() = default; - ~AfterStateChangeEnabledStateObserver() override = default; - - // TraceLog::EnabledStateObserver overrides: - void OnTraceLogEnabled() override { - EXPECT_TRUE(TraceLog::GetInstance()->IsEnabled()); - } - - void OnTraceLogDisabled() override { - EXPECT_FALSE(TraceLog::GetInstance()->IsEnabled()); - } -}; - -TEST_F(TraceEventTestFixture, ObserversFireAfterStateChange) { - AfterStateChangeEnabledStateObserver observer; - TraceLog::GetInstance()->AddEnabledStateObserver(&observer); - - TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""), - TraceLog::RECORDING_MODE); - EXPECT_TRUE(TraceLog::GetInstance()->IsEnabled()); - - TraceLog::GetInstance()->SetDisabled(); - EXPECT_FALSE(TraceLog::GetInstance()->IsEnabled()); - - TraceLog::GetInstance()->RemoveEnabledStateObserver(&observer); -} - -// Tests that a state observer can remove itself during a callback. -class SelfRemovingEnabledStateObserver - : public TraceLog::EnabledStateObserver { - public: - SelfRemovingEnabledStateObserver() = default; - ~SelfRemovingEnabledStateObserver() override = default; - - // TraceLog::EnabledStateObserver overrides: - void OnTraceLogEnabled() override {} - - void OnTraceLogDisabled() override { - TraceLog::GetInstance()->RemoveEnabledStateObserver(this); - } -}; - -TEST_F(TraceEventTestFixture, SelfRemovingObserver) { - ASSERT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest()); - - SelfRemovingEnabledStateObserver observer; - TraceLog::GetInstance()->AddEnabledStateObserver(&observer); - EXPECT_EQ(1u, TraceLog::GetInstance()->GetObserverCountForTest()); - - TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""), - TraceLog::RECORDING_MODE); - TraceLog::GetInstance()->SetDisabled(); - // The observer removed itself on disable. - EXPECT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest()); -} - -bool IsNewTrace() { - bool is_new_trace; - TRACE_EVENT_IS_NEW_TRACE(&is_new_trace); - return is_new_trace; -} - -TEST_F(TraceEventTestFixture, NewTraceRecording) { - ASSERT_FALSE(IsNewTrace()); - TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""), - TraceLog::RECORDING_MODE); - // First call to IsNewTrace() should succeed. But, the second shouldn't. - ASSERT_TRUE(IsNewTrace()); - ASSERT_FALSE(IsNewTrace()); - EndTraceAndFlush(); - - // IsNewTrace() should definitely be false now. - ASSERT_FALSE(IsNewTrace()); - - // Start another trace. IsNewTrace() should become true again, briefly, as - // before. - TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""), - TraceLog::RECORDING_MODE); - ASSERT_TRUE(IsNewTrace()); - ASSERT_FALSE(IsNewTrace()); - - // Cleanup. - EndTraceAndFlush(); -} - -TEST_F(TraceEventTestFixture, TestTraceFlush) { - size_t min_traces = 1; - size_t max_traces = 1; - do { - max_traces *= 2; - TraceLog::GetInstance()->SetEnabled(TraceConfig(), - TraceLog::RECORDING_MODE); - for (size_t i = 0; i < max_traces; i++) { - TRACE_EVENT_INSTANT0("x", "y", TRACE_EVENT_SCOPE_THREAD); - } - EndTraceAndFlush(); - } while (num_flush_callbacks_ < 2); - - while (min_traces + 50 < max_traces) { - size_t traces = (min_traces + max_traces) / 2; - TraceLog::GetInstance()->SetEnabled(TraceConfig(), - TraceLog::RECORDING_MODE); - for (size_t i = 0; i < traces; i++) { - TRACE_EVENT_INSTANT0("x", "y", TRACE_EVENT_SCOPE_THREAD); - } - EndTraceAndFlush(); - if (num_flush_callbacks_ < 2) { - min_traces = traces - 10; - } else { - max_traces = traces + 10; - } - } - - for (size_t traces = min_traces; traces < max_traces; traces++) { - TraceLog::GetInstance()->SetEnabled(TraceConfig(), - TraceLog::RECORDING_MODE); - for (size_t i = 0; i < traces; i++) { - TRACE_EVENT_INSTANT0("x", "y", TRACE_EVENT_SCOPE_THREAD); - } - EndTraceAndFlush(); - } -} - -TEST_F(TraceEventTestFixture, AddMetadataEvent) { - int num_calls = 0; - - class Convertable : public ConvertableToTraceFormat { - public: - explicit Convertable(int* num_calls) : num_calls_(num_calls) {} - ~Convertable() override = default; - void AppendAsTraceFormat(std::string* out) const override { - (*num_calls_)++; - out->append("\"metadata_value\""); - } - - private: - int* num_calls_; - }; - - std::unique_ptr<ConvertableToTraceFormat> conv1(new Convertable(&num_calls)); - std::unique_ptr<Convertable> conv2(new Convertable(&num_calls)); - - BeginTrace(); - TRACE_EVENT_API_ADD_METADATA_EVENT( - TraceLog::GetCategoryGroupEnabled("__metadata"), "metadata_event_1", - "metadata_arg_name", std::move(conv1)); - TRACE_EVENT_API_ADD_METADATA_EVENT( - TraceLog::GetCategoryGroupEnabled("__metadata"), "metadata_event_2", - "metadata_arg_name", std::move(conv2)); - // |AppendAsTraceFormat| should only be called on flush, not when the event - // is added. - ASSERT_EQ(0, num_calls); - EndTraceAndFlush(); - ASSERT_EQ(2, num_calls); - EXPECT_TRUE(FindNamePhaseKeyValue("metadata_event_1", "M", - "metadata_arg_name", "metadata_value")); - EXPECT_TRUE(FindNamePhaseKeyValue("metadata_event_2", "M", - "metadata_arg_name", "metadata_value")); - - // The metadata event should only be adde to the current trace. In this new - // trace, the event should not appear. - BeginTrace(); - EndTraceAndFlush(); - ASSERT_EQ(2, num_calls); -} - -// Test that categories work. -TEST_F(TraceEventTestFixture, Categories) { - // Test that categories that are used can be retrieved whether trace was - // enabled or disabled when the trace event was encountered. - TRACE_EVENT_INSTANT0("c1", "name", TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("c2", "name", TRACE_EVENT_SCOPE_THREAD); - BeginTrace(); - TRACE_EVENT_INSTANT0("c3", "name", TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("c4", "name", TRACE_EVENT_SCOPE_THREAD); - // Category groups containing more than one category. - TRACE_EVENT_INSTANT0("c5,c6", "name", TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("c7,c8", "name", TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("c9"), "name", - TRACE_EVENT_SCOPE_THREAD); - - EndTraceAndFlush(); - std::vector<std::string> cat_groups; - TraceLog::GetInstance()->GetKnownCategoryGroups(&cat_groups); - EXPECT_TRUE(ContainsValue(cat_groups, "c1")); - EXPECT_TRUE(ContainsValue(cat_groups, "c2")); - EXPECT_TRUE(ContainsValue(cat_groups, "c3")); - EXPECT_TRUE(ContainsValue(cat_groups, "c4")); - EXPECT_TRUE(ContainsValue(cat_groups, "c5,c6")); - EXPECT_TRUE(ContainsValue(cat_groups, "c7,c8")); - EXPECT_TRUE(ContainsValue(cat_groups, "disabled-by-default-c9")); - // Make sure metadata isn't returned. - EXPECT_FALSE(ContainsValue(cat_groups, "__metadata")); - - const std::vector<std::string> empty_categories; - std::vector<std::string> included_categories; - std::vector<std::string> excluded_categories; - - // Test that category filtering works. - - // Include nonexistent category -> no events - Clear(); - included_categories.clear(); - TraceLog::GetInstance()->SetEnabled(TraceConfig("not_found823564786", ""), - TraceLog::RECORDING_MODE); - TRACE_EVENT_INSTANT0("cat1", "name", TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("cat2", "name", TRACE_EVENT_SCOPE_THREAD); - EndTraceAndFlush(); - DropTracedMetadataRecords(); - EXPECT_TRUE(trace_parsed_.empty()); - - // Include existent category -> only events of that category - Clear(); - included_categories.clear(); - TraceLog::GetInstance()->SetEnabled(TraceConfig("inc", ""), - TraceLog::RECORDING_MODE); - TRACE_EVENT_INSTANT0("inc", "name", TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("inc2", "name", TRACE_EVENT_SCOPE_THREAD); - EndTraceAndFlush(); - DropTracedMetadataRecords(); - EXPECT_TRUE(FindMatchingValue("cat", "inc")); - EXPECT_FALSE(FindNonMatchingValue("cat", "inc")); - - // Include existent wildcard -> all categories matching wildcard - Clear(); - included_categories.clear(); - TraceLog::GetInstance()->SetEnabled( - TraceConfig("inc_wildcard_*,inc_wildchar_?_end", ""), - TraceLog::RECORDING_MODE); - TRACE_EVENT_INSTANT0("inc_wildcard_abc", "included", - TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("inc_wildcard_", "included", TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("inc_wildchar_x_end", "included", - TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("inc_wildchar_bla_end", "not_inc", - TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("cat1", "not_inc", TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("cat2", "not_inc", TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("inc_wildcard_category,other_category", "included", - TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0( - "non_included_category,inc_wildcard_category", "included", - TRACE_EVENT_SCOPE_THREAD); - EndTraceAndFlush(); - EXPECT_TRUE(FindMatchingValue("cat", "inc_wildcard_abc")); - EXPECT_TRUE(FindMatchingValue("cat", "inc_wildcard_")); - EXPECT_TRUE(FindMatchingValue("cat", "inc_wildchar_x_end")); - EXPECT_FALSE(FindMatchingValue("name", "not_inc")); - EXPECT_TRUE(FindMatchingValue("cat", "inc_wildcard_category,other_category")); - EXPECT_TRUE(FindMatchingValue("cat", - "non_included_category,inc_wildcard_category")); - - included_categories.clear(); - - // Exclude nonexistent category -> all events - Clear(); - TraceLog::GetInstance()->SetEnabled(TraceConfig("-not_found823564786", ""), - TraceLog::RECORDING_MODE); - TRACE_EVENT_INSTANT0("cat1", "name", TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("cat2", "name", TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("category1,category2", "name", TRACE_EVENT_SCOPE_THREAD); - EndTraceAndFlush(); - EXPECT_TRUE(FindMatchingValue("cat", "cat1")); - EXPECT_TRUE(FindMatchingValue("cat", "cat2")); - EXPECT_TRUE(FindMatchingValue("cat", "category1,category2")); - - // Exclude existent category -> only events of other categories - Clear(); - TraceLog::GetInstance()->SetEnabled(TraceConfig("-inc", ""), - TraceLog::RECORDING_MODE); - TRACE_EVENT_INSTANT0("inc", "name", TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("inc2", "name", TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("inc2,inc", "name", TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("inc,inc2", "name", TRACE_EVENT_SCOPE_THREAD); - EndTraceAndFlush(); - EXPECT_TRUE(FindMatchingValue("cat", "inc2")); - EXPECT_FALSE(FindMatchingValue("cat", "inc")); - EXPECT_TRUE(FindMatchingValue("cat", "inc2,inc")); - EXPECT_TRUE(FindMatchingValue("cat", "inc,inc2")); - - // Exclude existent wildcard -> all categories not matching wildcard - Clear(); - TraceLog::GetInstance()->SetEnabled( - TraceConfig("-inc_wildcard_*,-inc_wildchar_?_end", ""), - TraceLog::RECORDING_MODE); - TRACE_EVENT_INSTANT0("inc_wildcard_abc", "not_inc", - TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("inc_wildcard_", "not_inc", - TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("inc_wildchar_x_end", "not_inc", - TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("inc_wildchar_bla_end", "included", - TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("cat1", "included", TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("cat2", "included", TRACE_EVENT_SCOPE_THREAD); - EndTraceAndFlush(); - EXPECT_TRUE(FindMatchingValue("cat", "inc_wildchar_bla_end")); - EXPECT_TRUE(FindMatchingValue("cat", "cat1")); - EXPECT_TRUE(FindMatchingValue("cat", "cat2")); - EXPECT_FALSE(FindMatchingValue("name", "not_inc")); -} - - -// Test ASYNC_BEGIN/END events -TEST_F(TraceEventTestFixture, AsyncBeginEndEvents) { - BeginTrace(); - - unsigned long long id = 0xfeedbeeffeedbeefull; - TRACE_EVENT_ASYNC_BEGIN0("cat", "name1", id); - TRACE_EVENT_ASYNC_STEP_INTO0("cat", "name1", id, "step1"); - TRACE_EVENT_ASYNC_END0("cat", "name1", id); - TRACE_EVENT_BEGIN0("cat", "name2"); - TRACE_EVENT_ASYNC_BEGIN0("cat", "name3", 0); - TRACE_EVENT_ASYNC_STEP_PAST0("cat", "name3", 0, "step2"); - - EndTraceAndFlush(); - - EXPECT_TRUE(FindNamePhase("name1", "S")); - EXPECT_TRUE(FindNamePhase("name1", "T")); - EXPECT_TRUE(FindNamePhase("name1", "F")); - - std::string id_str; - StringAppendF(&id_str, "0x%llx", id); - - EXPECT_TRUE(FindNamePhaseKeyValue("name1", "S", "id", id_str.c_str())); - EXPECT_TRUE(FindNamePhaseKeyValue("name1", "T", "id", id_str.c_str())); - EXPECT_TRUE(FindNamePhaseKeyValue("name1", "F", "id", id_str.c_str())); - EXPECT_TRUE(FindNamePhaseKeyValue("name3", "S", "id", "0x0")); - EXPECT_TRUE(FindNamePhaseKeyValue("name3", "p", "id", "0x0")); - - // BEGIN events should not have id - EXPECT_FALSE(FindNamePhaseKeyValue("name2", "B", "id", "0")); -} - -// Test ASYNC_BEGIN/END events -TEST_F(TraceEventTestFixture, AsyncBeginEndPointerMangling) { - void* ptr = this; - - TraceLog::GetInstance()->SetProcessID(100); - BeginTrace(); - TRACE_EVENT_ASYNC_BEGIN0("cat", "name1", ptr); - TRACE_EVENT_ASYNC_BEGIN0("cat", "name2", ptr); - EndTraceAndFlush(); - - TraceLog::GetInstance()->SetProcessID(200); - BeginTrace(); - TRACE_EVENT_ASYNC_END0("cat", "name1", ptr); - EndTraceAndFlush(); - - DictionaryValue* async_begin = FindNamePhase("name1", "S"); - DictionaryValue* async_begin2 = FindNamePhase("name2", "S"); - DictionaryValue* async_end = FindNamePhase("name1", "F"); - EXPECT_TRUE(async_begin); - EXPECT_TRUE(async_begin2); - EXPECT_TRUE(async_end); - - Value* value = nullptr; - std::string async_begin_id_str; - std::string async_begin2_id_str; - std::string async_end_id_str; - ASSERT_TRUE(async_begin->Get("id", &value)); - ASSERT_TRUE(value->GetAsString(&async_begin_id_str)); - ASSERT_TRUE(async_begin2->Get("id", &value)); - ASSERT_TRUE(value->GetAsString(&async_begin2_id_str)); - ASSERT_TRUE(async_end->Get("id", &value)); - ASSERT_TRUE(value->GetAsString(&async_end_id_str)); - - EXPECT_STREQ(async_begin_id_str.c_str(), async_begin2_id_str.c_str()); - EXPECT_STRNE(async_begin_id_str.c_str(), async_end_id_str.c_str()); -} - -// Test that static strings are not copied. -TEST_F(TraceEventTestFixture, StaticStringVsString) { - TraceLog* tracer = TraceLog::GetInstance(); - // Make sure old events are flushed: - EXPECT_EQ(0u, tracer->GetStatus().event_count); - const unsigned char* category_group_enabled = - TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED("cat"); - - { - BeginTrace(); - // Test that string arguments are copied. - TraceEventHandle handle1 = - trace_event_internal::AddTraceEvent( - TRACE_EVENT_PHASE_INSTANT, category_group_enabled, "name1", - trace_event_internal::kGlobalScope, trace_event_internal::kNoId, - 0, trace_event_internal::kNoId, - "arg1", std::string("argval"), "arg2", std::string("argval")); - // Test that static TRACE_STR_COPY string arguments are copied. - TraceEventHandle handle2 = - trace_event_internal::AddTraceEvent( - TRACE_EVENT_PHASE_INSTANT, category_group_enabled, "name2", - trace_event_internal::kGlobalScope, trace_event_internal::kNoId, - 0, trace_event_internal::kNoId, - "arg1", TRACE_STR_COPY("argval"), - "arg2", TRACE_STR_COPY("argval")); - EXPECT_GT(tracer->GetStatus().event_count, 1u); - const TraceEvent* event1 = tracer->GetEventByHandle(handle1); - const TraceEvent* event2 = tracer->GetEventByHandle(handle2); - ASSERT_TRUE(event1); - ASSERT_TRUE(event2); - EXPECT_STREQ("name1", event1->name()); - EXPECT_STREQ("name2", event2->name()); - EXPECT_TRUE(event1->parameter_copy_storage() != nullptr); - EXPECT_TRUE(event2->parameter_copy_storage() != nullptr); - EXPECT_GT(event1->parameter_copy_storage()->size(), 0u); - EXPECT_GT(event2->parameter_copy_storage()->size(), 0u); - EndTraceAndFlush(); - } - - { - BeginTrace(); - // Test that static literal string arguments are not copied. - TraceEventHandle handle1 = - trace_event_internal::AddTraceEvent( - TRACE_EVENT_PHASE_INSTANT, category_group_enabled, "name1", - trace_event_internal::kGlobalScope, trace_event_internal::kNoId, - 0, trace_event_internal::kNoId, - "arg1", "argval", "arg2", "argval"); - // Test that static TRACE_STR_COPY NULL string arguments are not copied. - const char* str1 = nullptr; - const char* str2 = nullptr; - TraceEventHandle handle2 = - trace_event_internal::AddTraceEvent( - TRACE_EVENT_PHASE_INSTANT, category_group_enabled, "name2", - trace_event_internal::kGlobalScope, trace_event_internal::kNoId, - 0, trace_event_internal::kNoId, - "arg1", TRACE_STR_COPY(str1), - "arg2", TRACE_STR_COPY(str2)); - EXPECT_GT(tracer->GetStatus().event_count, 1u); - const TraceEvent* event1 = tracer->GetEventByHandle(handle1); - const TraceEvent* event2 = tracer->GetEventByHandle(handle2); - ASSERT_TRUE(event1); - ASSERT_TRUE(event2); - EXPECT_STREQ("name1", event1->name()); - EXPECT_STREQ("name2", event2->name()); - EXPECT_TRUE(event1->parameter_copy_storage() == nullptr); - EXPECT_TRUE(event2->parameter_copy_storage() == nullptr); - EndTraceAndFlush(); - } -} - -// Test that data sent from other threads is gathered -TEST_F(TraceEventTestFixture, DataCapturedOnThread) { - BeginTrace(); - - Thread thread("1"); - WaitableEvent task_complete_event(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - thread.Start(); - - thread.task_runner()->PostTask( - FROM_HERE, - base::BindOnce(&TraceWithAllMacroVariants, &task_complete_event)); - task_complete_event.Wait(); - thread.Stop(); - - EndTraceAndFlush(); - ValidateAllTraceMacrosCreatedData(trace_parsed_); -} - -// Test that data sent from multiple threads is gathered -TEST_F(TraceEventTestFixture, DataCapturedManyThreads) { - BeginTrace(); - - const int num_threads = 4; - const int num_events = 4000; - Thread* threads[num_threads]; - WaitableEvent* task_complete_events[num_threads]; - for (int i = 0; i < num_threads; i++) { - threads[i] = new Thread(StringPrintf("Thread %d", i)); - task_complete_events[i] = - new WaitableEvent(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - threads[i]->Start(); - threads[i]->task_runner()->PostTask( - FROM_HERE, base::BindOnce(&TraceManyInstantEvents, i, num_events, - task_complete_events[i])); - } - - for (int i = 0; i < num_threads; i++) { - task_complete_events[i]->Wait(); - } - - // Let half of the threads end before flush. - for (int i = 0; i < num_threads / 2; i++) { - threads[i]->Stop(); - delete threads[i]; - delete task_complete_events[i]; - } - - EndTraceAndFlushInThreadWithMessageLoop(); - ValidateInstantEventPresentOnEveryThread(trace_parsed_, - num_threads, num_events); - - // Let the other half of the threads end after flush. - for (int i = num_threads / 2; i < num_threads; i++) { - threads[i]->Stop(); - delete threads[i]; - delete task_complete_events[i]; - } -} - -// Test that thread and process names show up in the trace -TEST_F(TraceEventTestFixture, ThreadNames) { - // Create threads before we enable tracing to make sure - // that tracelog still captures them. - const int kNumThreads = 4; - const int kNumEvents = 10; - Thread* threads[kNumThreads]; - PlatformThreadId thread_ids[kNumThreads]; - for (int i = 0; i < kNumThreads; i++) - threads[i] = new Thread(StringPrintf("Thread %d", i)); - - // Enable tracing. - BeginTrace(); - - // Now run some trace code on these threads. - WaitableEvent* task_complete_events[kNumThreads]; - for (int i = 0; i < kNumThreads; i++) { - task_complete_events[i] = - new WaitableEvent(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - threads[i]->Start(); - thread_ids[i] = threads[i]->GetThreadId(); - threads[i]->task_runner()->PostTask( - FROM_HERE, base::BindOnce(&TraceManyInstantEvents, i, kNumEvents, - task_complete_events[i])); - } - for (int i = 0; i < kNumThreads; i++) { - task_complete_events[i]->Wait(); - } - - // Shut things down. - for (int i = 0; i < kNumThreads; i++) { - threads[i]->Stop(); - delete threads[i]; - delete task_complete_events[i]; - } - - EndTraceAndFlush(); - - std::string tmp; - int tmp_int; - const DictionaryValue* item; - - // Make sure we get thread name metadata. - // Note, the test suite may have created a ton of threads. - // So, we'll have thread names for threads we didn't create. - std::vector<const DictionaryValue*> items = - FindTraceEntries(trace_parsed_, "thread_name"); - for (int i = 0; i < static_cast<int>(items.size()); i++) { - item = items[i]; - ASSERT_TRUE(item); - EXPECT_TRUE(item->GetInteger("tid", &tmp_int)); - - // See if this thread name is one of the threads we just created - for (int j = 0; j < kNumThreads; j++) { - if (static_cast<int>(thread_ids[j]) != tmp_int) - continue; - - std::string expected_name = StringPrintf("Thread %d", j); - EXPECT_TRUE(item->GetString("ph", &tmp) && tmp == "M"); - EXPECT_TRUE(item->GetInteger("pid", &tmp_int) && - tmp_int == static_cast<int>(base::GetCurrentProcId())); - // If the thread name changes or the tid gets reused, the name will be - // a comma-separated list of thread names, so look for a substring. - EXPECT_TRUE(item->GetString("args.name", &tmp) && - tmp.find(expected_name) != std::string::npos); - } - } -} - -TEST_F(TraceEventTestFixture, ThreadNameChanges) { - BeginTrace(); - - PlatformThread::SetName(""); - TRACE_EVENT_INSTANT0("drink", "water", TRACE_EVENT_SCOPE_THREAD); - - PlatformThread::SetName("cafe"); - TRACE_EVENT_INSTANT0("drink", "coffee", TRACE_EVENT_SCOPE_THREAD); - - PlatformThread::SetName("shop"); - // No event here, so won't appear in combined name. - - PlatformThread::SetName("pub"); - TRACE_EVENT_INSTANT0("drink", "beer", TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("drink", "wine", TRACE_EVENT_SCOPE_THREAD); - - PlatformThread::SetName(" bar"); - TRACE_EVENT_INSTANT0("drink", "whisky", TRACE_EVENT_SCOPE_THREAD); - - EndTraceAndFlush(); - - std::vector<const DictionaryValue*> items = - FindTraceEntries(trace_parsed_, "thread_name"); - EXPECT_EQ(1u, items.size()); - ASSERT_GT(items.size(), 0u); - const DictionaryValue* item = items[0]; - ASSERT_TRUE(item); - int tid; - EXPECT_TRUE(item->GetInteger("tid", &tid)); - EXPECT_EQ(PlatformThread::CurrentId(), static_cast<PlatformThreadId>(tid)); - - std::string expected_name = "cafe,pub, bar"; - std::string tmp; - EXPECT_TRUE(item->GetString("args.name", &tmp)); - EXPECT_EQ(expected_name, tmp); -} - -// Test that the disabled trace categories are included/excluded from the -// trace output correctly. -TEST_F(TraceEventTestFixture, DisabledCategories) { - BeginTrace(); - TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("cc"), "first", - TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("included", "first", TRACE_EVENT_SCOPE_THREAD); - EndTraceAndFlush(); - { - const DictionaryValue* item = nullptr; - ListValue& trace_parsed = trace_parsed_; - EXPECT_NOT_FIND_("disabled-by-default-cc"); - EXPECT_FIND_("included"); - } - Clear(); - - BeginSpecificTrace("disabled-by-default-cc"); - TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("cc"), "second", - TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("other_included", "second", TRACE_EVENT_SCOPE_THREAD); - EndTraceAndFlush(); - - { - const DictionaryValue* item = nullptr; - ListValue& trace_parsed = trace_parsed_; - EXPECT_FIND_("disabled-by-default-cc"); - EXPECT_FIND_("other_included"); - } - - Clear(); - - BeginSpecificTrace("other_included"); - TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("cc") ",other_included", - "first", TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("other_included," TRACE_DISABLED_BY_DEFAULT("cc"), - "second", TRACE_EVENT_SCOPE_THREAD); - EndTraceAndFlush(); - - { - const DictionaryValue* item = nullptr; - ListValue& trace_parsed = trace_parsed_; - EXPECT_FIND_("disabled-by-default-cc,other_included"); - EXPECT_FIND_("other_included,disabled-by-default-cc"); - } -} - -TEST_F(TraceEventTestFixture, NormallyNoDeepCopy) { - // Test that the TRACE_EVENT macros do not deep-copy their string. If they - // do so it may indicate a performance regression, but more-over it would - // make the DEEP_COPY overloads redundant. - std::string name_string("event name"); - - BeginTrace(); - TRACE_EVENT_INSTANT0("category", name_string.c_str(), - TRACE_EVENT_SCOPE_THREAD); - - // Modify the string in place (a wholesale reassignment may leave the old - // string intact on the heap). - name_string[0] = '@'; - - EndTraceAndFlush(); - - EXPECT_FALSE(FindTraceEntry(trace_parsed_, "event name")); - EXPECT_TRUE(FindTraceEntry(trace_parsed_, name_string.c_str())); -} - -TEST_F(TraceEventTestFixture, DeepCopy) { - static const char kOriginalName1[] = "name1"; - static const char kOriginalName2[] = "name2"; - static const char kOriginalName3[] = "name3"; - std::string name1(kOriginalName1); - std::string name2(kOriginalName2); - std::string name3(kOriginalName3); - std::string arg1("arg1"); - std::string arg2("arg2"); - std::string val1("val1"); - std::string val2("val2"); - - BeginTrace(); - TRACE_EVENT_COPY_INSTANT0("category", name1.c_str(), - TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_COPY_BEGIN1("category", name2.c_str(), - arg1.c_str(), 5); - TRACE_EVENT_COPY_END2("category", name3.c_str(), - arg1.c_str(), val1, - arg2.c_str(), val2); - - // As per NormallyNoDeepCopy, modify the strings in place. - name1[0] = name2[0] = name3[0] = arg1[0] = arg2[0] = val1[0] = val2[0] = '@'; - - EndTraceAndFlush(); - - EXPECT_FALSE(FindTraceEntry(trace_parsed_, name1.c_str())); - EXPECT_FALSE(FindTraceEntry(trace_parsed_, name2.c_str())); - EXPECT_FALSE(FindTraceEntry(trace_parsed_, name3.c_str())); - - const DictionaryValue* entry1 = FindTraceEntry(trace_parsed_, kOriginalName1); - const DictionaryValue* entry2 = FindTraceEntry(trace_parsed_, kOriginalName2); - const DictionaryValue* entry3 = FindTraceEntry(trace_parsed_, kOriginalName3); - ASSERT_TRUE(entry1); - ASSERT_TRUE(entry2); - ASSERT_TRUE(entry3); - - int i; - EXPECT_FALSE(entry2->GetInteger("args.@rg1", &i)); - EXPECT_TRUE(entry2->GetInteger("args.arg1", &i)); - EXPECT_EQ(5, i); - - std::string s; - EXPECT_TRUE(entry3->GetString("args.arg1", &s)); - EXPECT_EQ("val1", s); - EXPECT_TRUE(entry3->GetString("args.arg2", &s)); - EXPECT_EQ("val2", s); -} - -// Test that TraceResultBuffer outputs the correct result whether it is added -// in chunks or added all at once. -TEST_F(TraceEventTestFixture, TraceResultBuffer) { - Clear(); - - trace_buffer_.Start(); - trace_buffer_.AddFragment("bla1"); - trace_buffer_.AddFragment("bla2"); - trace_buffer_.AddFragment("bla3,bla4"); - trace_buffer_.Finish(); - EXPECT_STREQ(json_output_.json_output.c_str(), "[bla1,bla2,bla3,bla4]"); - - Clear(); - - trace_buffer_.Start(); - trace_buffer_.AddFragment("bla1,bla2,bla3,bla4"); - trace_buffer_.Finish(); - EXPECT_STREQ(json_output_.json_output.c_str(), "[bla1,bla2,bla3,bla4]"); -} - -// Test that trace_event parameters are not evaluated if the tracing -// system is disabled. -TEST_F(TraceEventTestFixture, TracingIsLazy) { - BeginTrace(); - - int a = 0; - TRACE_EVENT_INSTANT1("category", "test", TRACE_EVENT_SCOPE_THREAD, "a", a++); - EXPECT_EQ(1, a); - - TraceLog::GetInstance()->SetDisabled(); - - TRACE_EVENT_INSTANT1("category", "test", TRACE_EVENT_SCOPE_THREAD, "a", a++); - EXPECT_EQ(1, a); - - EndTraceAndFlush(); -} - -TEST_F(TraceEventTestFixture, TraceEnableDisable) { - TraceLog* trace_log = TraceLog::GetInstance(); - TraceConfig tc_inc_all("*", ""); - trace_log->SetEnabled(tc_inc_all, TraceLog::RECORDING_MODE); - EXPECT_TRUE(trace_log->IsEnabled()); - trace_log->SetDisabled(); - EXPECT_FALSE(trace_log->IsEnabled()); - - trace_log->SetEnabled(tc_inc_all, TraceLog::RECORDING_MODE); - EXPECT_TRUE(trace_log->IsEnabled()); - const std::vector<std::string> empty; - trace_log->SetEnabled(TraceConfig(), TraceLog::RECORDING_MODE); - EXPECT_TRUE(trace_log->IsEnabled()); - trace_log->SetDisabled(); - EXPECT_FALSE(trace_log->IsEnabled()); - trace_log->SetDisabled(); - EXPECT_FALSE(trace_log->IsEnabled()); -} - -TEST_F(TraceEventTestFixture, TraceCategoriesAfterNestedEnable) { - TraceLog* trace_log = TraceLog::GetInstance(); - trace_log->SetEnabled(TraceConfig("foo,bar", ""), TraceLog::RECORDING_MODE); - EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("foo")); - EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("bar")); - EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("baz")); - trace_log->SetEnabled(TraceConfig("foo2", ""), TraceLog::RECORDING_MODE); - EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("foo2")); - EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("baz")); - // The "" becomes the default catergory set when applied. - trace_log->SetEnabled(TraceConfig(), TraceLog::RECORDING_MODE); - EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("foo")); - EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("baz")); - EXPECT_STREQ( - "", - trace_log->GetCurrentTraceConfig().ToCategoryFilterString().c_str()); - trace_log->SetDisabled(); - trace_log->SetDisabled(); - trace_log->SetDisabled(); - EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("foo")); - EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("baz")); - - trace_log->SetEnabled(TraceConfig("-foo,-bar", ""), TraceLog::RECORDING_MODE); - EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("foo")); - EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("baz")); - trace_log->SetEnabled(TraceConfig("moo", ""), TraceLog::RECORDING_MODE); - EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("baz")); - EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("moo")); - EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("foo")); - EXPECT_STREQ( - "-foo,-bar", - trace_log->GetCurrentTraceConfig().ToCategoryFilterString().c_str()); - trace_log->SetDisabled(); - trace_log->SetDisabled(); - - // Make sure disabled categories aren't cleared if we set in the second. - trace_log->SetEnabled(TraceConfig("disabled-by-default-cc,foo", ""), - TraceLog::RECORDING_MODE); - EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("bar")); - trace_log->SetEnabled(TraceConfig("disabled-by-default-gpu", ""), - TraceLog::RECORDING_MODE); - EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("disabled-by-default-cc")); - EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("disabled-by-default-gpu")); - EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("bar")); - EXPECT_STREQ( - "disabled-by-default-cc,disabled-by-default-gpu", - trace_log->GetCurrentTraceConfig().ToCategoryFilterString().c_str()); - trace_log->SetDisabled(); - trace_log->SetDisabled(); -} - -TEST_F(TraceEventTestFixture, TraceWithDefaultCategoryFilters) { - TraceLog* trace_log = TraceLog::GetInstance(); - - trace_log->SetEnabled(TraceConfig(), TraceLog::RECORDING_MODE); - CheckTraceDefaultCategoryFilters(*trace_log); - trace_log->SetDisabled(); - - trace_log->SetEnabled(TraceConfig("", ""), TraceLog::RECORDING_MODE); - CheckTraceDefaultCategoryFilters(*trace_log); - trace_log->SetDisabled(); - - trace_log->SetEnabled(TraceConfig("*", ""), TraceLog::RECORDING_MODE); - CheckTraceDefaultCategoryFilters(*trace_log); - trace_log->SetDisabled(); - - trace_log->SetEnabled(TraceConfig(""), TraceLog::RECORDING_MODE); - CheckTraceDefaultCategoryFilters(*trace_log); - trace_log->SetDisabled(); -} - -TEST_F(TraceEventTestFixture, TraceWithDisabledByDefaultCategoryFilters) { - TraceLog* trace_log = TraceLog::GetInstance(); - - trace_log->SetEnabled(TraceConfig("foo,disabled-by-default-foo", ""), - TraceLog::RECORDING_MODE); - EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("foo")); - EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("disabled-by-default-foo")); - EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("bar")); - EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("disabled-by-default-bar")); - trace_log->SetDisabled(); - - // Enabling only the disabled-by-default-* category means the default ones - // are also enabled. - trace_log->SetEnabled(TraceConfig("disabled-by-default-foo", ""), - TraceLog::RECORDING_MODE); - EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("disabled-by-default-foo")); - EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("foo")); - EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("bar")); - EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("disabled-by-default-bar")); - trace_log->SetDisabled(); -} - -class MyData : public ConvertableToTraceFormat { - public: - MyData() = default; - ~MyData() override = default; - - void AppendAsTraceFormat(std::string* out) const override { - out->append("{\"foo\":1}"); - } - - private: - DISALLOW_COPY_AND_ASSIGN(MyData); -}; - -TEST_F(TraceEventTestFixture, ConvertableTypes) { - TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""), - TraceLog::RECORDING_MODE); - - std::unique_ptr<ConvertableToTraceFormat> data(new MyData()); - std::unique_ptr<ConvertableToTraceFormat> data1(new MyData()); - std::unique_ptr<ConvertableToTraceFormat> data2(new MyData()); - TRACE_EVENT1("foo", "bar", "data", std::move(data)); - TRACE_EVENT2("foo", "baz", "data1", std::move(data1), "data2", - std::move(data2)); - - // Check that std::unique_ptr<DerivedClassOfConvertable> are properly treated - // as - // convertable and not accidentally casted to bool. - std::unique_ptr<MyData> convertData1(new MyData()); - std::unique_ptr<MyData> convertData2(new MyData()); - std::unique_ptr<MyData> convertData3(new MyData()); - std::unique_ptr<MyData> convertData4(new MyData()); - TRACE_EVENT2("foo", "string_first", "str", "string value 1", "convert", - std::move(convertData1)); - TRACE_EVENT2("foo", "string_second", "convert", std::move(convertData2), - "str", "string value 2"); - TRACE_EVENT2("foo", "both_conv", "convert1", std::move(convertData3), - "convert2", std::move(convertData4)); - EndTraceAndFlush(); - - // One arg version. - DictionaryValue* dict = FindNamePhase("bar", "X"); - ASSERT_TRUE(dict); - - const DictionaryValue* args_dict = nullptr; - dict->GetDictionary("args", &args_dict); - ASSERT_TRUE(args_dict); - - const Value* value = nullptr; - const DictionaryValue* convertable_dict = nullptr; - EXPECT_TRUE(args_dict->Get("data", &value)); - ASSERT_TRUE(value->GetAsDictionary(&convertable_dict)); - - int foo_val; - EXPECT_TRUE(convertable_dict->GetInteger("foo", &foo_val)); - EXPECT_EQ(1, foo_val); - - // Two arg version. - dict = FindNamePhase("baz", "X"); - ASSERT_TRUE(dict); - - args_dict = nullptr; - dict->GetDictionary("args", &args_dict); - ASSERT_TRUE(args_dict); - - value = nullptr; - convertable_dict = nullptr; - EXPECT_TRUE(args_dict->Get("data1", &value)); - ASSERT_TRUE(value->GetAsDictionary(&convertable_dict)); - - value = nullptr; - convertable_dict = nullptr; - EXPECT_TRUE(args_dict->Get("data2", &value)); - ASSERT_TRUE(value->GetAsDictionary(&convertable_dict)); - - // Convertable with other types. - dict = FindNamePhase("string_first", "X"); - ASSERT_TRUE(dict); - - args_dict = nullptr; - dict->GetDictionary("args", &args_dict); - ASSERT_TRUE(args_dict); - - std::string str_value; - EXPECT_TRUE(args_dict->GetString("str", &str_value)); - EXPECT_STREQ("string value 1", str_value.c_str()); - - value = nullptr; - convertable_dict = nullptr; - foo_val = 0; - EXPECT_TRUE(args_dict->Get("convert", &value)); - ASSERT_TRUE(value->GetAsDictionary(&convertable_dict)); - EXPECT_TRUE(convertable_dict->GetInteger("foo", &foo_val)); - EXPECT_EQ(1, foo_val); - - dict = FindNamePhase("string_second", "X"); - ASSERT_TRUE(dict); - - args_dict = nullptr; - dict->GetDictionary("args", &args_dict); - ASSERT_TRUE(args_dict); - - EXPECT_TRUE(args_dict->GetString("str", &str_value)); - EXPECT_STREQ("string value 2", str_value.c_str()); - - value = nullptr; - convertable_dict = nullptr; - foo_val = 0; - EXPECT_TRUE(args_dict->Get("convert", &value)); - ASSERT_TRUE(value->GetAsDictionary(&convertable_dict)); - EXPECT_TRUE(convertable_dict->GetInteger("foo", &foo_val)); - EXPECT_EQ(1, foo_val); - - dict = FindNamePhase("both_conv", "X"); - ASSERT_TRUE(dict); - - args_dict = nullptr; - dict->GetDictionary("args", &args_dict); - ASSERT_TRUE(args_dict); - - value = nullptr; - convertable_dict = nullptr; - foo_val = 0; - EXPECT_TRUE(args_dict->Get("convert1", &value)); - ASSERT_TRUE(value->GetAsDictionary(&convertable_dict)); - EXPECT_TRUE(args_dict->Get("convert2", &value)); - ASSERT_TRUE(value->GetAsDictionary(&convertable_dict)); -} - -TEST_F(TraceEventTestFixture, PrimitiveArgs) { - TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""), - TraceLog::RECORDING_MODE); - - TRACE_EVENT1("foo", "event1", "int_one", 1); - TRACE_EVENT1("foo", "event2", "int_neg_ten", -10); - TRACE_EVENT1("foo", "event3", "float_one", 1.0f); - TRACE_EVENT1("foo", "event4", "float_half", .5f); - TRACE_EVENT1("foo", "event5", "float_neghalf", -.5f); - TRACE_EVENT1("foo", "event6", "float_infinity", - std::numeric_limits<float>::infinity()); - TRACE_EVENT1("foo", "event6b", "float_neg_infinity", - -std::numeric_limits<float>::infinity()); - TRACE_EVENT1("foo", "event7", "double_nan", - std::numeric_limits<double>::quiet_NaN()); - void* p = nullptr; - TRACE_EVENT1("foo", "event8", "pointer_null", p); - p = reinterpret_cast<void*>(0xbadf00d); - TRACE_EVENT1("foo", "event9", "pointer_badf00d", p); - TRACE_EVENT1("foo", "event10", "bool_true", true); - TRACE_EVENT1("foo", "event11", "bool_false", false); - TRACE_EVENT1("foo", "event12", "time_null", - base::Time()); - TRACE_EVENT1("foo", "event13", "time_one", - base::Time::FromInternalValue(1)); - TRACE_EVENT1("foo", "event14", "timeticks_null", - base::TimeTicks()); - TRACE_EVENT1("foo", "event15", "timeticks_one", - base::TimeTicks::FromInternalValue(1)); - EndTraceAndFlush(); - - const DictionaryValue* args_dict = nullptr; - DictionaryValue* dict = nullptr; - const Value* value = nullptr; - std::string str_value; - int int_value; - double double_value; - bool bool_value; - - dict = FindNamePhase("event1", "X"); - ASSERT_TRUE(dict); - dict->GetDictionary("args", &args_dict); - ASSERT_TRUE(args_dict); - EXPECT_TRUE(args_dict->GetInteger("int_one", &int_value)); - EXPECT_EQ(1, int_value); - - dict = FindNamePhase("event2", "X"); - ASSERT_TRUE(dict); - dict->GetDictionary("args", &args_dict); - ASSERT_TRUE(args_dict); - EXPECT_TRUE(args_dict->GetInteger("int_neg_ten", &int_value)); - EXPECT_EQ(-10, int_value); - - // 1f must be serlized to JSON as "1.0" in order to be a double, not an int. - dict = FindNamePhase("event3", "X"); - ASSERT_TRUE(dict); - dict->GetDictionary("args", &args_dict); - ASSERT_TRUE(args_dict); - EXPECT_TRUE(args_dict->Get("float_one", &value)); - EXPECT_TRUE(value->is_double()); - EXPECT_TRUE(value->GetAsDouble(&double_value)); - EXPECT_EQ(1, double_value); - - // .5f must be serlized to JSON as "0.5". - dict = FindNamePhase("event4", "X"); - ASSERT_TRUE(dict); - dict->GetDictionary("args", &args_dict); - ASSERT_TRUE(args_dict); - EXPECT_TRUE(args_dict->Get("float_half", &value)); - EXPECT_TRUE(value->is_double()); - EXPECT_TRUE(value->GetAsDouble(&double_value)); - EXPECT_EQ(0.5, double_value); - - // -.5f must be serlized to JSON as "-0.5". - dict = FindNamePhase("event5", "X"); - ASSERT_TRUE(dict); - dict->GetDictionary("args", &args_dict); - ASSERT_TRUE(args_dict); - EXPECT_TRUE(args_dict->Get("float_neghalf", &value)); - EXPECT_TRUE(value->is_double()); - EXPECT_TRUE(value->GetAsDouble(&double_value)); - EXPECT_EQ(-0.5, double_value); - - // Infinity is serialized to JSON as a string. - dict = FindNamePhase("event6", "X"); - ASSERT_TRUE(dict); - dict->GetDictionary("args", &args_dict); - ASSERT_TRUE(args_dict); - EXPECT_TRUE(args_dict->GetString("float_infinity", &str_value)); - EXPECT_STREQ("Infinity", str_value.c_str()); - dict = FindNamePhase("event6b", "X"); - ASSERT_TRUE(dict); - dict->GetDictionary("args", &args_dict); - ASSERT_TRUE(args_dict); - EXPECT_TRUE(args_dict->GetString("float_neg_infinity", &str_value)); - EXPECT_STREQ("-Infinity", str_value.c_str()); - - // NaN is serialized to JSON as a string. - dict = FindNamePhase("event7", "X"); - ASSERT_TRUE(dict); - dict->GetDictionary("args", &args_dict); - ASSERT_TRUE(args_dict); - EXPECT_TRUE(args_dict->GetString("double_nan", &str_value)); - EXPECT_STREQ("NaN", str_value.c_str()); - - // NULL pointers should be serialized as "0x0". - dict = FindNamePhase("event8", "X"); - ASSERT_TRUE(dict); - dict->GetDictionary("args", &args_dict); - ASSERT_TRUE(args_dict); - EXPECT_TRUE(args_dict->GetString("pointer_null", &str_value)); - EXPECT_STREQ("0x0", str_value.c_str()); - - // Other pointers should be serlized as a hex string. - dict = FindNamePhase("event9", "X"); - ASSERT_TRUE(dict); - dict->GetDictionary("args", &args_dict); - ASSERT_TRUE(args_dict); - EXPECT_TRUE(args_dict->GetString("pointer_badf00d", &str_value)); - EXPECT_STREQ("0xbadf00d", str_value.c_str()); - - dict = FindNamePhase("event10", "X"); - ASSERT_TRUE(dict); - dict->GetDictionary("args", &args_dict); - ASSERT_TRUE(args_dict); - EXPECT_TRUE(args_dict->GetBoolean("bool_true", &bool_value)); - EXPECT_TRUE(bool_value); - - dict = FindNamePhase("event11", "X"); - ASSERT_TRUE(dict); - dict->GetDictionary("args", &args_dict); - ASSERT_TRUE(args_dict); - EXPECT_TRUE(args_dict->GetBoolean("bool_false", &bool_value)); - EXPECT_FALSE(bool_value); - - dict = FindNamePhase("event12", "X"); - ASSERT_TRUE(dict); - dict->GetDictionary("args", &args_dict); - ASSERT_TRUE(args_dict); - EXPECT_TRUE(args_dict->GetInteger("time_null", &int_value)); - EXPECT_EQ(0, int_value); - - dict = FindNamePhase("event13", "X"); - ASSERT_TRUE(dict); - dict->GetDictionary("args", &args_dict); - ASSERT_TRUE(args_dict); - EXPECT_TRUE(args_dict->GetInteger("time_one", &int_value)); - EXPECT_EQ(1, int_value); - - dict = FindNamePhase("event14", "X"); - ASSERT_TRUE(dict); - dict->GetDictionary("args", &args_dict); - ASSERT_TRUE(args_dict); - EXPECT_TRUE(args_dict->GetInteger("timeticks_null", &int_value)); - EXPECT_EQ(0, int_value); - - dict = FindNamePhase("event15", "X"); - ASSERT_TRUE(dict); - dict->GetDictionary("args", &args_dict); - ASSERT_TRUE(args_dict); - EXPECT_TRUE(args_dict->GetInteger("timeticks_one", &int_value)); - EXPECT_EQ(1, int_value); -} - -TEST_F(TraceEventTestFixture, NameIsEscaped) { - TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""), - TraceLog::RECORDING_MODE); - TRACE_EVENT0("category", "name\\with\\backspaces"); - EndTraceAndFlush(); - - EXPECT_TRUE(FindMatchingValue("cat", "category")); - EXPECT_TRUE(FindMatchingValue("name", "name\\with\\backspaces")); -} - -namespace { - -bool IsArgNameWhitelisted(const char* arg_name) { - return base::MatchPattern(arg_name, "granular_arg_whitelisted"); -} - -bool IsTraceEventArgsWhitelisted(const char* category_group_name, - const char* event_name, - ArgumentNameFilterPredicate* arg_filter) { - if (base::MatchPattern(category_group_name, "toplevel") && - base::MatchPattern(event_name, "*")) { - return true; - } - - if (base::MatchPattern(category_group_name, "benchmark") && - base::MatchPattern(event_name, "granularly_whitelisted")) { - *arg_filter = base::Bind(&IsArgNameWhitelisted); - return true; - } - - return false; -} - -} // namespace - -TEST_F(TraceEventTestFixture, ArgsWhitelisting) { - TraceLog::GetInstance()->SetArgumentFilterPredicate( - base::Bind(&IsTraceEventArgsWhitelisted)); - - TraceLog::GetInstance()->SetEnabled( - TraceConfig(kRecordAllCategoryFilter, "enable-argument-filter"), - TraceLog::RECORDING_MODE); - - TRACE_EVENT1("toplevel", "event1", "int_one", 1); - TRACE_EVENT1("whitewashed", "event2", "int_two", 1); - - TRACE_EVENT2("benchmark", "granularly_whitelisted", - "granular_arg_whitelisted", "whitelisted_value", - "granular_arg_blacklisted", "blacklisted_value"); - - EndTraceAndFlush(); - - const DictionaryValue* args_dict = nullptr; - DictionaryValue* dict = nullptr; - int int_value; - - dict = FindNamePhase("event1", "X"); - ASSERT_TRUE(dict); - dict->GetDictionary("args", &args_dict); - ASSERT_TRUE(args_dict); - EXPECT_TRUE(args_dict->GetInteger("int_one", &int_value)); - EXPECT_EQ(1, int_value); - - dict = FindNamePhase("event2", "X"); - ASSERT_TRUE(dict); - dict->GetDictionary("args", &args_dict); - ASSERT_TRUE(args_dict); - EXPECT_FALSE(args_dict->GetInteger("int_two", &int_value)); - - std::string args_string; - EXPECT_TRUE(dict->GetString("args", &args_string)); - EXPECT_EQ(args_string, "__stripped__"); - - dict = FindNamePhase("granularly_whitelisted", "X"); - ASSERT_TRUE(dict); - dict->GetDictionary("args", &args_dict); - ASSERT_TRUE(args_dict); - - EXPECT_TRUE(args_dict->GetString("granular_arg_whitelisted", &args_string)); - EXPECT_EQ(args_string, "whitelisted_value"); - - EXPECT_TRUE(args_dict->GetString("granular_arg_blacklisted", &args_string)); - EXPECT_EQ(args_string, "__stripped__"); -} - -TEST_F(TraceEventTestFixture, TraceBufferVectorReportFull) { - TraceLog* trace_log = TraceLog::GetInstance(); - trace_log->SetEnabled( - TraceConfig(kRecordAllCategoryFilter, ""), TraceLog::RECORDING_MODE); - trace_log->logged_events_.reset( - TraceBuffer::CreateTraceBufferVectorOfSize(100)); - do { - TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0( - "all", "with_timestamp", 0, 0, TimeTicks::Now()); - TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0( - "all", "with_timestamp", 0, 0, TimeTicks::Now()); - } while (!trace_log->BufferIsFull()); - - EndTraceAndFlush(); - - const DictionaryValue* trace_full_metadata = nullptr; - - trace_full_metadata = FindTraceEntry(trace_parsed_, - "overflowed_at_ts"); - std::string phase; - double buffer_limit_reached_timestamp = 0; - - EXPECT_TRUE(trace_full_metadata); - EXPECT_TRUE(trace_full_metadata->GetString("ph", &phase)); - EXPECT_EQ("M", phase); - EXPECT_TRUE(trace_full_metadata->GetDouble( - "args.overflowed_at_ts", &buffer_limit_reached_timestamp)); - EXPECT_DOUBLE_EQ( - static_cast<double>( - trace_log->buffer_limit_reached_timestamp_.ToInternalValue()), - buffer_limit_reached_timestamp); - - // Test that buffer_limit_reached_timestamp's value is between the timestamp - // of the last trace event and current time. - DropTracedMetadataRecords(); - const DictionaryValue* last_trace_event = nullptr; - double last_trace_event_timestamp = 0; - EXPECT_TRUE(trace_parsed_.GetDictionary(trace_parsed_.GetSize() - 1, - &last_trace_event)); - EXPECT_TRUE(last_trace_event->GetDouble("ts", &last_trace_event_timestamp)); - EXPECT_LE(last_trace_event_timestamp, buffer_limit_reached_timestamp); - EXPECT_LE(buffer_limit_reached_timestamp, - trace_log->OffsetNow().ToInternalValue()); -} - -TEST_F(TraceEventTestFixture, TraceBufferRingBufferGetReturnChunk) { - TraceLog::GetInstance()->SetEnabled( - TraceConfig(kRecordAllCategoryFilter, RECORD_CONTINUOUSLY), - TraceLog::RECORDING_MODE); - TraceBuffer* buffer = TraceLog::GetInstance()->trace_buffer(); - size_t capacity = buffer->Capacity(); - size_t num_chunks = capacity / TraceBufferChunk::kTraceBufferChunkSize; - uint32_t last_seq = 0; - size_t chunk_index; - EXPECT_EQ(0u, buffer->Size()); - - std::unique_ptr<TraceBufferChunk* []> chunks( - new TraceBufferChunk*[num_chunks]); - for (size_t i = 0; i < num_chunks; ++i) { - chunks[i] = buffer->GetChunk(&chunk_index).release(); - EXPECT_TRUE(chunks[i]); - EXPECT_EQ(i, chunk_index); - EXPECT_GT(chunks[i]->seq(), last_seq); - EXPECT_EQ((i + 1) * TraceBufferChunk::kTraceBufferChunkSize, - buffer->Size()); - last_seq = chunks[i]->seq(); - } - - // Ring buffer is never full. - EXPECT_FALSE(buffer->IsFull()); - - // Return all chunks in original order. - for (size_t i = 0; i < num_chunks; ++i) - buffer->ReturnChunk(i, std::unique_ptr<TraceBufferChunk>(chunks[i])); - - // Should recycle the chunks in the returned order. - for (size_t i = 0; i < num_chunks; ++i) { - chunks[i] = buffer->GetChunk(&chunk_index).release(); - EXPECT_TRUE(chunks[i]); - EXPECT_EQ(i, chunk_index); - EXPECT_GT(chunks[i]->seq(), last_seq); - last_seq = chunks[i]->seq(); - } - - // Return all chunks in reverse order. - for (size_t i = 0; i < num_chunks; ++i) { - buffer->ReturnChunk(num_chunks - i - 1, std::unique_ptr<TraceBufferChunk>( - chunks[num_chunks - i - 1])); - } - - // Should recycle the chunks in the returned order. - for (size_t i = 0; i < num_chunks; ++i) { - chunks[i] = buffer->GetChunk(&chunk_index).release(); - EXPECT_TRUE(chunks[i]); - EXPECT_EQ(num_chunks - i - 1, chunk_index); - EXPECT_GT(chunks[i]->seq(), last_seq); - last_seq = chunks[i]->seq(); - } - - for (size_t i = 0; i < num_chunks; ++i) - buffer->ReturnChunk(i, std::unique_ptr<TraceBufferChunk>(chunks[i])); - - TraceLog::GetInstance()->SetDisabled(); -} - -TEST_F(TraceEventTestFixture, TraceBufferRingBufferHalfIteration) { - TraceLog::GetInstance()->SetEnabled( - TraceConfig(kRecordAllCategoryFilter, RECORD_CONTINUOUSLY), - TraceLog::RECORDING_MODE); - TraceBuffer* buffer = TraceLog::GetInstance()->trace_buffer(); - size_t capacity = buffer->Capacity(); - size_t num_chunks = capacity / TraceBufferChunk::kTraceBufferChunkSize; - size_t chunk_index; - EXPECT_EQ(0u, buffer->Size()); - EXPECT_FALSE(buffer->NextChunk()); - - size_t half_chunks = num_chunks / 2; - std::unique_ptr<TraceBufferChunk* []> chunks( - new TraceBufferChunk*[half_chunks]); - - for (size_t i = 0; i < half_chunks; ++i) { - chunks[i] = buffer->GetChunk(&chunk_index).release(); - EXPECT_TRUE(chunks[i]); - EXPECT_EQ(i, chunk_index); - } - for (size_t i = 0; i < half_chunks; ++i) - buffer->ReturnChunk(i, std::unique_ptr<TraceBufferChunk>(chunks[i])); - - for (size_t i = 0; i < half_chunks; ++i) - EXPECT_EQ(chunks[i], buffer->NextChunk()); - EXPECT_FALSE(buffer->NextChunk()); - TraceLog::GetInstance()->SetDisabled(); -} - -TEST_F(TraceEventTestFixture, TraceBufferRingBufferFullIteration) { - TraceLog::GetInstance()->SetEnabled( - TraceConfig(kRecordAllCategoryFilter, RECORD_CONTINUOUSLY), - TraceLog::RECORDING_MODE); - TraceBuffer* buffer = TraceLog::GetInstance()->trace_buffer(); - size_t capacity = buffer->Capacity(); - size_t num_chunks = capacity / TraceBufferChunk::kTraceBufferChunkSize; - size_t chunk_index; - EXPECT_EQ(0u, buffer->Size()); - EXPECT_FALSE(buffer->NextChunk()); - - std::unique_ptr<TraceBufferChunk* []> chunks( - new TraceBufferChunk*[num_chunks]); - - for (size_t i = 0; i < num_chunks; ++i) { - chunks[i] = buffer->GetChunk(&chunk_index).release(); - EXPECT_TRUE(chunks[i]); - EXPECT_EQ(i, chunk_index); - } - for (size_t i = 0; i < num_chunks; ++i) - buffer->ReturnChunk(i, std::unique_ptr<TraceBufferChunk>(chunks[i])); - - for (size_t i = 0; i < num_chunks; ++i) - EXPECT_TRUE(chunks[i] == buffer->NextChunk()); - EXPECT_FALSE(buffer->NextChunk()); - TraceLog::GetInstance()->SetDisabled(); -} - -TEST_F(TraceEventTestFixture, TraceRecordAsMuchAsPossibleMode) { - TraceLog::GetInstance()->SetEnabled( - TraceConfig(kRecordAllCategoryFilter, RECORD_AS_MUCH_AS_POSSIBLE), - TraceLog::RECORDING_MODE); - TraceBuffer* buffer = TraceLog::GetInstance()->trace_buffer(); - EXPECT_EQ(512000000UL, buffer->Capacity()); - TraceLog::GetInstance()->SetDisabled(); -} - -void BlockUntilStopped(WaitableEvent* task_start_event, - WaitableEvent* task_stop_event) { - task_start_event->Signal(); - task_stop_event->Wait(); -} - -TEST_F(TraceEventTestFixture, SetCurrentThreadBlocksMessageLoopBeforeTracing) { - BeginTrace(); - - Thread thread("1"); - WaitableEvent task_complete_event(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - thread.Start(); - thread.task_runner()->PostTask( - FROM_HERE, BindOnce(&TraceLog::SetCurrentThreadBlocksMessageLoop, - Unretained(TraceLog::GetInstance()))); - - thread.task_runner()->PostTask( - FROM_HERE, BindOnce(&TraceWithAllMacroVariants, &task_complete_event)); - task_complete_event.Wait(); - - WaitableEvent task_start_event(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - WaitableEvent task_stop_event(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - thread.task_runner()->PostTask( - FROM_HERE, - BindOnce(&BlockUntilStopped, &task_start_event, &task_stop_event)); - task_start_event.Wait(); - - EndTraceAndFlush(); - ValidateAllTraceMacrosCreatedData(trace_parsed_); - - task_stop_event.Signal(); - thread.Stop(); -} - -TEST_F(TraceEventTestFixture, ConvertTraceConfigToInternalOptions) { - TraceLog* trace_log = TraceLog::GetInstance(); - EXPECT_EQ(TraceLog::kInternalRecordUntilFull, - trace_log->GetInternalOptionsFromTraceConfig( - TraceConfig(kRecordAllCategoryFilter, RECORD_UNTIL_FULL))); - - EXPECT_EQ(TraceLog::kInternalRecordContinuously, - trace_log->GetInternalOptionsFromTraceConfig( - TraceConfig(kRecordAllCategoryFilter, RECORD_CONTINUOUSLY))); - - EXPECT_EQ(TraceLog::kInternalEchoToConsole, - trace_log->GetInternalOptionsFromTraceConfig( - TraceConfig(kRecordAllCategoryFilter, ECHO_TO_CONSOLE))); - - EXPECT_EQ(TraceLog::kInternalEchoToConsole, - trace_log->GetInternalOptionsFromTraceConfig( - TraceConfig("*", "trace-to-console,enable-systrace"))); -} - -void SetBlockingFlagAndBlockUntilStopped(WaitableEvent* task_start_event, - WaitableEvent* task_stop_event) { - TraceLog::GetInstance()->SetCurrentThreadBlocksMessageLoop(); - BlockUntilStopped(task_start_event, task_stop_event); -} - -TEST_F(TraceEventTestFixture, SetCurrentThreadBlocksMessageLoopAfterTracing) { - BeginTrace(); - - Thread thread("1"); - WaitableEvent task_complete_event(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - thread.Start(); - - thread.task_runner()->PostTask( - FROM_HERE, BindOnce(&TraceWithAllMacroVariants, &task_complete_event)); - task_complete_event.Wait(); - - WaitableEvent task_start_event(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - WaitableEvent task_stop_event(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - thread.task_runner()->PostTask(FROM_HERE, - BindOnce(&SetBlockingFlagAndBlockUntilStopped, - &task_start_event, &task_stop_event)); - task_start_event.Wait(); - - EndTraceAndFlush(); - ValidateAllTraceMacrosCreatedData(trace_parsed_); - - task_stop_event.Signal(); - thread.Stop(); -} - -TEST_F(TraceEventTestFixture, ThreadOnceBlocking) { - BeginTrace(); - - Thread thread("1"); - WaitableEvent task_complete_event(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - thread.Start(); - - thread.task_runner()->PostTask( - FROM_HERE, BindOnce(&TraceWithAllMacroVariants, &task_complete_event)); - task_complete_event.Wait(); - - WaitableEvent task_start_event(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - WaitableEvent task_stop_event(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - thread.task_runner()->PostTask( - FROM_HERE, - BindOnce(&BlockUntilStopped, &task_start_event, &task_stop_event)); - task_start_event.Wait(); - - // The thread will timeout in this flush. - EndTraceAndFlushInThreadWithMessageLoop(); - Clear(); - - // Let the thread's message loop continue to spin. - task_stop_event.Signal(); - - // The following sequence ensures that the FlushCurrentThread task has been - // executed in the thread before continuing. - thread.task_runner()->PostTask( - FROM_HERE, - BindOnce(&BlockUntilStopped, &task_start_event, &task_stop_event)); - task_start_event.Wait(); - task_stop_event.Signal(); - Clear(); - - // TraceLog should discover the generation mismatch and recover the thread - // local buffer for the thread without any error. - BeginTrace(); - thread.task_runner()->PostTask( - FROM_HERE, BindOnce(&TraceWithAllMacroVariants, &task_complete_event)); - task_complete_event.Wait(); - EndTraceAndFlushInThreadWithMessageLoop(); - ValidateAllTraceMacrosCreatedData(trace_parsed_); -} - -std::string* g_log_buffer = nullptr; -bool MockLogMessageHandler(int, const char*, int, size_t, - const std::string& str) { - if (!g_log_buffer) - g_log_buffer = new std::string(); - g_log_buffer->append(str); - return false; -} - -TEST_F(TraceEventTestFixture, EchoToConsole) { - logging::LogMessageHandlerFunction old_log_message_handler = - logging::GetLogMessageHandler(); - logging::SetLogMessageHandler(MockLogMessageHandler); - - TraceLog::GetInstance()->SetEnabled( - TraceConfig(kRecordAllCategoryFilter, ECHO_TO_CONSOLE), - TraceLog::RECORDING_MODE); - TRACE_EVENT_BEGIN0("a", "begin_end"); - { - TRACE_EVENT0("b", "duration"); - TRACE_EVENT0("b1", "duration1"); - } - TRACE_EVENT_INSTANT0("c", "instant", TRACE_EVENT_SCOPE_GLOBAL); - TRACE_EVENT_END0("a", "begin_end"); - - EXPECT_NE(std::string::npos, g_log_buffer->find("begin_end[a]\x1b")); - EXPECT_NE(std::string::npos, g_log_buffer->find("| duration[b]\x1b")); - EXPECT_NE(std::string::npos, g_log_buffer->find("| | duration1[b1]\x1b")); - EXPECT_NE(std::string::npos, g_log_buffer->find("| | duration1[b1] (")); - EXPECT_NE(std::string::npos, g_log_buffer->find("| duration[b] (")); - EXPECT_NE(std::string::npos, g_log_buffer->find("| instant[c]\x1b")); - EXPECT_NE(std::string::npos, g_log_buffer->find("begin_end[a] (")); - - EndTraceAndFlush(); - delete g_log_buffer; - logging::SetLogMessageHandler(old_log_message_handler); - g_log_buffer = nullptr; -} - -bool LogMessageHandlerWithTraceEvent(int, const char*, int, size_t, - const std::string&) { - TRACE_EVENT0("log", "trace_event"); - return false; -} - -TEST_F(TraceEventTestFixture, EchoToConsoleTraceEventRecursion) { - logging::LogMessageHandlerFunction old_log_message_handler = - logging::GetLogMessageHandler(); - logging::SetLogMessageHandler(LogMessageHandlerWithTraceEvent); - - TraceLog::GetInstance()->SetEnabled( - TraceConfig(kRecordAllCategoryFilter, ECHO_TO_CONSOLE), - TraceLog::RECORDING_MODE); - { - // This should not cause deadlock or infinite recursion. - TRACE_EVENT0("b", "duration"); - } - - EndTraceAndFlush(); - logging::SetLogMessageHandler(old_log_message_handler); -} - -TEST_F(TraceEventTestFixture, TimeOffset) { - BeginTrace(); - // Let TraceLog timer start from 0. - TimeDelta time_offset = TimeTicks::Now() - TimeTicks(); - TraceLog::GetInstance()->SetTimeOffset(time_offset); - - { - TRACE_EVENT0("all", "duration1"); - TRACE_EVENT0("all", "duration2"); - } - TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0( - "all", "with_timestamp", 0, 0, TimeTicks::Now()); - TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0( - "all", "with_timestamp", 0, 0, TimeTicks::Now()); - - EndTraceAndFlush(); - DropTracedMetadataRecords(); - - double end_time = static_cast<double>( - (TimeTicks::Now() - time_offset).ToInternalValue()); - double last_timestamp = 0; - for (size_t i = 0; i < trace_parsed_.GetSize(); ++i) { - const DictionaryValue* item; - EXPECT_TRUE(trace_parsed_.GetDictionary(i, &item)); - double timestamp; - EXPECT_TRUE(item->GetDouble("ts", ×tamp)); - EXPECT_GE(timestamp, last_timestamp); - EXPECT_LE(timestamp, end_time); - last_timestamp = timestamp; - } -} - -TEST_F(TraceEventTestFixture, TraceFilteringMode) { - const char config_json[] = - "{" - " \"event_filters\": [" - " {" - " \"filter_predicate\": \"testing_predicate\", " - " \"included_categories\": [\"*\"]" - " }" - " ]" - "}"; - - // Run RECORDING_MODE within FILTERING_MODE: - TestEventFilter::HitsCounter filter_hits_counter; - TestEventFilter::set_filter_return_value(true); - TraceLog::GetInstance()->SetFilterFactoryForTesting(TestEventFilter::Factory); - - // Only filtering mode is enabled with test filters. - TraceLog::GetInstance()->SetEnabled(TraceConfig(config_json), - TraceLog::FILTERING_MODE); - EXPECT_EQ(TraceLog::FILTERING_MODE, TraceLog::GetInstance()->enabled_modes()); - { - void* ptr = this; - TRACE_EVENT0("c0", "name0"); - TRACE_EVENT_ASYNC_BEGIN0("c1", "name1", ptr); - TRACE_EVENT_INSTANT0("c0", "name0", TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_ASYNC_END0("c1", "name1", ptr); - } - - // Recording mode is enabled when filtering mode is turned on. - TraceLog::GetInstance()->SetEnabled(TraceConfig("", ""), - TraceLog::RECORDING_MODE); - EXPECT_EQ(TraceLog::RECORDING_MODE | TraceLog::FILTERING_MODE, - TraceLog::GetInstance()->enabled_modes()); - { - TRACE_EVENT0("c2", "name2"); - } - // Only recording mode is disabled and filtering mode will continue to run. - TraceLog::GetInstance()->SetDisabled(TraceLog::RECORDING_MODE); - EXPECT_EQ(TraceLog::FILTERING_MODE, TraceLog::GetInstance()->enabled_modes()); - - { - TRACE_EVENT0("c0", "name0"); - } - // Filtering mode is disabled and no tracing mode should be enabled. - TraceLog::GetInstance()->SetDisabled(TraceLog::FILTERING_MODE); - EXPECT_EQ(0, TraceLog::GetInstance()->enabled_modes()); - - EndTraceAndFlush(); - EXPECT_FALSE(FindMatchingValue("cat", "c0")); - EXPECT_FALSE(FindMatchingValue("cat", "c1")); - EXPECT_FALSE(FindMatchingValue("name", "name0")); - EXPECT_FALSE(FindMatchingValue("name", "name1")); - EXPECT_TRUE(FindMatchingValue("cat", "c2")); - EXPECT_TRUE(FindMatchingValue("name", "name2")); - EXPECT_EQ(6u, filter_hits_counter.filter_trace_event_hit_count); - EXPECT_EQ(3u, filter_hits_counter.end_event_hit_count); - Clear(); - filter_hits_counter.Reset(); - - // Run FILTERING_MODE within RECORDING_MODE: - // Only recording mode is enabled and all events must be recorded. - TraceLog::GetInstance()->SetEnabled(TraceConfig("", ""), - TraceLog::RECORDING_MODE); - EXPECT_EQ(TraceLog::RECORDING_MODE, TraceLog::GetInstance()->enabled_modes()); - { - TRACE_EVENT0("c0", "name0"); - } - - // Filtering mode is also enabled and all events must be filtered-out. - TestEventFilter::set_filter_return_value(false); - TraceLog::GetInstance()->SetEnabled(TraceConfig(config_json), - TraceLog::FILTERING_MODE); - EXPECT_EQ(TraceLog::RECORDING_MODE | TraceLog::FILTERING_MODE, - TraceLog::GetInstance()->enabled_modes()); - { - TRACE_EVENT0("c1", "name1"); - } - // Only filtering mode is disabled and recording mode should continue to run - // with all events being recorded. - TraceLog::GetInstance()->SetDisabled(TraceLog::FILTERING_MODE); - EXPECT_EQ(TraceLog::RECORDING_MODE, TraceLog::GetInstance()->enabled_modes()); - - { - TRACE_EVENT0("c2", "name2"); - } - // Recording mode is disabled and no tracing mode should be enabled. - TraceLog::GetInstance()->SetDisabled(TraceLog::RECORDING_MODE); - EXPECT_EQ(0, TraceLog::GetInstance()->enabled_modes()); - - EndTraceAndFlush(); - EXPECT_TRUE(FindMatchingValue("cat", "c0")); - EXPECT_TRUE(FindMatchingValue("cat", "c2")); - EXPECT_TRUE(FindMatchingValue("name", "name0")); - EXPECT_TRUE(FindMatchingValue("name", "name2")); - EXPECT_FALSE(FindMatchingValue("cat", "c1")); - EXPECT_FALSE(FindMatchingValue("name", "name1")); - EXPECT_EQ(1u, filter_hits_counter.filter_trace_event_hit_count); - EXPECT_EQ(1u, filter_hits_counter.end_event_hit_count); - Clear(); -} - -TEST_F(TraceEventTestFixture, EventFiltering) { - const char config_json[] = - "{" - " \"included_categories\": [" - " \"filtered_cat\"," - " \"unfiltered_cat\"," - " \"" TRACE_DISABLED_BY_DEFAULT("filtered_cat") "\"," - " \"" TRACE_DISABLED_BY_DEFAULT("unfiltered_cat") "\"]," - " \"event_filters\": [" - " {" - " \"filter_predicate\": \"testing_predicate\", " - " \"included_categories\": [" - " \"filtered_cat\"," - " \"" TRACE_DISABLED_BY_DEFAULT("filtered_cat") "\"]" - " }" - " " - " ]" - "}"; - - TestEventFilter::HitsCounter filter_hits_counter; - TestEventFilter::set_filter_return_value(true); - TraceLog::GetInstance()->SetFilterFactoryForTesting(TestEventFilter::Factory); - - TraceConfig trace_config(config_json); - TraceLog::GetInstance()->SetEnabled( - trace_config, TraceLog::RECORDING_MODE | TraceLog::FILTERING_MODE); - ASSERT_TRUE(TraceLog::GetInstance()->IsEnabled()); - - TRACE_EVENT0("filtered_cat", "a snake"); - TRACE_EVENT0("filtered_cat", "a mushroom"); - TRACE_EVENT0("unfiltered_cat", "a horse"); - - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("filtered_cat"), "a dog"); - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("unfiltered_cat"), "a pony"); - - // This is scoped so we can test the end event being filtered. - { TRACE_EVENT0("filtered_cat", "another cat whoa"); } - - EndTraceAndFlush(); - - EXPECT_EQ(4u, filter_hits_counter.filter_trace_event_hit_count); - EXPECT_EQ(1u, filter_hits_counter.end_event_hit_count); -} - -TEST_F(TraceEventTestFixture, EventWhitelistFiltering) { - std::string config_json = StringPrintf( - "{" - " \"included_categories\": [" - " \"filtered_cat\"," - " \"unfiltered_cat\"," - " \"" TRACE_DISABLED_BY_DEFAULT("filtered_cat") "\"]," - " \"event_filters\": [" - " {" - " \"filter_predicate\": \"%s\", " - " \"included_categories\": [" - " \"filtered_cat\"," - " \"" TRACE_DISABLED_BY_DEFAULT("*") "\"], " - " \"filter_args\": {" - " \"event_name_whitelist\": [\"a snake\", \"a dog\"]" - " }" - " }" - " " - " ]" - "}", - EventNameFilter::kName); - - TraceConfig trace_config(config_json); - TraceLog::GetInstance()->SetEnabled( - trace_config, TraceLog::RECORDING_MODE | TraceLog::FILTERING_MODE); - EXPECT_TRUE(TraceLog::GetInstance()->IsEnabled()); - - TRACE_EVENT0("filtered_cat", "a snake"); - TRACE_EVENT0("filtered_cat", "a mushroom"); - TRACE_EVENT0("unfiltered_cat", "a cat"); - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("filtered_cat"), "a dog"); - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("filtered_cat"), "a pony"); - - EndTraceAndFlush(); - - EXPECT_TRUE(FindMatchingValue("name", "a snake")); - EXPECT_FALSE(FindMatchingValue("name", "a mushroom")); - EXPECT_TRUE(FindMatchingValue("name", "a cat")); - EXPECT_TRUE(FindMatchingValue("name", "a dog")); - EXPECT_FALSE(FindMatchingValue("name", "a pony")); -} - -TEST_F(TraceEventTestFixture, HeapProfilerFiltering) { - std::string config_json = StringPrintf( - "{" - " \"included_categories\": [" - " \"filtered_cat\"," - " \"unfiltered_cat\"," - " \"" TRACE_DISABLED_BY_DEFAULT("filtered_cat") "\"," - " \"" TRACE_DISABLED_BY_DEFAULT("unfiltered_cat") "\"]," - " \"excluded_categories\": [\"excluded_cat\"]," - " \"event_filters\": [" - " {" - " \"filter_predicate\": \"%s\", " - " \"included_categories\": [" - " \"*\"," - " \"" TRACE_DISABLED_BY_DEFAULT("filtered_cat") "\"]" - " }" - " ]" - "}", - HeapProfilerEventFilter::kName); - - TraceConfig trace_config(config_json); - TraceLog::GetInstance()->SetEnabled( - trace_config, TraceLog::RECORDING_MODE | TraceLog::FILTERING_MODE); - EXPECT_TRUE(TraceLog::GetInstance()->IsEnabled()); - - TRACE_EVENT0("filtered_cat", "a snake"); - TRACE_EVENT0("excluded_cat", "a mushroom"); - TRACE_EVENT0("unfiltered_cat", "a cat"); - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("filtered_cat"), "a dog"); - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("unfiltered_cat"), "a pony"); - - EndTraceAndFlush(); - - // The predicate should not change behavior of the trace events. - EXPECT_TRUE(FindMatchingValue("name", "a snake")); - EXPECT_FALSE(FindMatchingValue("name", "a mushroom")); - EXPECT_TRUE(FindMatchingValue("name", "a cat")); - EXPECT_TRUE(FindMatchingValue("name", "a dog")); - EXPECT_TRUE(FindMatchingValue("name", "a pony")); -} - -TEST_F(TraceEventTestFixture, ClockSyncEventsAreAlwaysAddedToTrace) { - BeginSpecificTrace("-*"); - TRACE_EVENT_CLOCK_SYNC_RECEIVER(1); - EndTraceAndFlush(); - EXPECT_TRUE(FindNamePhase("clock_sync", "c")); -} - -} // namespace trace_event -} // namespace base
diff --git a/base/tuple_unittest.cc b/base/tuple_unittest.cc deleted file mode 100644 index 4b38797..0000000 --- a/base/tuple_unittest.cc +++ /dev/null
@@ -1,118 +0,0 @@ -// Copyright (c) 2006-2008 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/tuple.h" - -#include "base/compiler_specific.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -void DoAdd(int a, int b, int c, int* res) { - *res = a + b + c; -} - -struct Addy { - Addy() = default; - void DoAdd(int a, int b, int c, int d, int* res) { - *res = a + b + c + d; - } -}; - -struct Addz { - Addz() = default; - void DoAdd(int a, int b, int c, int d, int e, int* res) { - *res = a + b + c + d + e; - } -}; - -} // namespace - -TEST(TupleTest, Basic) { - std::tuple<> t0 = std::make_tuple(); - ALLOW_UNUSED_LOCAL(t0); - std::tuple<int> t1(1); - std::tuple<int, const char*> t2 = - std::make_tuple(1, static_cast<const char*>("wee")); - ALLOW_UNUSED_LOCAL(t2); - std::tuple<int, int, int> t3(1, 2, 3); - ALLOW_UNUSED_LOCAL(t3); - std::tuple<int, int, int, int*> t4(1, 2, 3, &std::get<0>(t1)); - std::tuple<int, int, int, int, int*> t5(1, 2, 3, 4, &std::get<0>(t4)); - std::tuple<int, int, int, int, int, int*> t6(1, 2, 3, 4, 5, &std::get<0>(t4)); - - EXPECT_EQ(1, std::get<0>(t1)); - DispatchToFunction(&DoAdd, t4); - EXPECT_EQ(6, std::get<0>(t1)); - - int res = 0; - DispatchToFunction(&DoAdd, std::make_tuple(9, 8, 7, &res)); - EXPECT_EQ(24, res); - - Addy addy; - EXPECT_EQ(1, std::get<0>(t4)); - DispatchToMethod(&addy, &Addy::DoAdd, t5); - EXPECT_EQ(10, std::get<0>(t4)); - - Addz addz; - EXPECT_EQ(10, std::get<0>(t4)); - DispatchToMethod(&addz, &Addz::DoAdd, t6); - EXPECT_EQ(15, std::get<0>(t4)); -} - -namespace { - -struct CopyLogger { - CopyLogger() { ++TimesConstructed; } - CopyLogger(const CopyLogger& tocopy) { ++TimesConstructed; ++TimesCopied; } - ~CopyLogger() = default; - - static int TimesCopied; - static int TimesConstructed; -}; - -void SomeLoggerMethRef(const CopyLogger& logy, const CopyLogger* ptr, bool* b) { - *b = &logy == ptr; -} - -void SomeLoggerMethCopy(CopyLogger logy, const CopyLogger* ptr, bool* b) { - *b = &logy == ptr; -} - -int CopyLogger::TimesCopied = 0; -int CopyLogger::TimesConstructed = 0; - -} // namespace - -TEST(TupleTest, Copying) { - CopyLogger logger; - EXPECT_EQ(0, CopyLogger::TimesCopied); - EXPECT_EQ(1, CopyLogger::TimesConstructed); - - bool res = false; - - // Creating the tuple should copy the class to store internally in the tuple. - std::tuple<CopyLogger, CopyLogger*, bool*> tuple(logger, &logger, &res); - std::get<CopyLogger*>(tuple) = &std::get<CopyLogger>(tuple); - EXPECT_EQ(2, CopyLogger::TimesConstructed); - EXPECT_EQ(1, CopyLogger::TimesCopied); - - // Our internal Logger and the one passed to the function should be the same. - res = false; - DispatchToFunction(&SomeLoggerMethRef, tuple); - EXPECT_TRUE(res); - EXPECT_EQ(2, CopyLogger::TimesConstructed); - EXPECT_EQ(1, CopyLogger::TimesCopied); - - // Now they should be different, since the function call will make a copy. - res = false; - DispatchToFunction(&SomeLoggerMethCopy, tuple); - EXPECT_FALSE(res); - EXPECT_EQ(3, CopyLogger::TimesConstructed); - EXPECT_EQ(2, CopyLogger::TimesCopied); -} - -} // namespace base
diff --git a/base/unguessable_token_unittest.cc b/base/unguessable_token_unittest.cc deleted file mode 100644 index b70cc72..0000000 --- a/base/unguessable_token_unittest.cc +++ /dev/null
@@ -1,155 +0,0 @@ -// Copyright (c) 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/unguessable_token.h" - -#include <memory> -#include <sstream> -#include <type_traits> - -#include "base/value_conversions.h" -#include "base/values.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -void TestSmallerThanOperator(const UnguessableToken& a, - const UnguessableToken& b) { - EXPECT_TRUE(a < b); - EXPECT_FALSE(b < a); -} - -TEST(UnguessableTokenTest, VerifyEqualityOperators) { - // Deserialize is used for testing purposes. - // Use UnguessableToken::Create() in production code instead. - UnguessableToken token = UnguessableToken::Deserialize(1, 2); - UnguessableToken same_token = UnguessableToken::Deserialize(1, 2); - UnguessableToken diff_token = UnguessableToken::Deserialize(1, 3); - - EXPECT_TRUE(token == token); - EXPECT_FALSE(token != token); - - EXPECT_TRUE(token == same_token); - EXPECT_FALSE(token != same_token); - - EXPECT_FALSE(token == diff_token); - EXPECT_FALSE(diff_token == token); - EXPECT_TRUE(token != diff_token); - EXPECT_TRUE(diff_token != token); -} - -TEST(UnguessableTokenTest, VerifyConstructors) { - UnguessableToken token = UnguessableToken::Create(); - EXPECT_FALSE(token.is_empty()); - EXPECT_TRUE(token); - - UnguessableToken copied_token(token); - EXPECT_TRUE(copied_token); - EXPECT_EQ(token, copied_token); - - UnguessableToken uninitialized; - EXPECT_TRUE(uninitialized.is_empty()); - EXPECT_FALSE(uninitialized); - - EXPECT_TRUE(UnguessableToken().is_empty()); - EXPECT_FALSE(UnguessableToken()); -} - -TEST(UnguessableTokenTest, VerifySerialization) { - UnguessableToken token = UnguessableToken::Create(); - - uint64_t high = token.GetHighForSerialization(); - uint64_t low = token.GetLowForSerialization(); - - EXPECT_TRUE(high); - EXPECT_TRUE(low); - - UnguessableToken Deserialized = UnguessableToken::Deserialize(high, low); - EXPECT_EQ(token, Deserialized); -} - -TEST(UnguessableTokenTest, VerifyValueSerialization) { - UnguessableToken token = UnguessableToken::Create(); - std::unique_ptr<Value> value = CreateUnguessableTokenValue(token); - - UnguessableToken deserialized; - EXPECT_TRUE(GetValueAsUnguessableToken(*value, &deserialized)); - EXPECT_EQ(token, deserialized); -} - -// Common case (~88% of the time) - no leading zeroes in high_ nor low_. -TEST(UnguessableTokenTest, VerifyToString1) { - UnguessableToken token = - UnguessableToken::Deserialize(0x1234567890ABCDEF, 0xFEDCBA0987654321); - std::string expected = "1234567890ABCDEFFEDCBA0987654321"; - - EXPECT_EQ(expected, token.ToString()); - - std::string expected_stream = "(1234567890ABCDEFFEDCBA0987654321)"; - std::stringstream stream; - stream << token; - EXPECT_EQ(expected_stream, stream.str()); -} - -// Less common case - leading zeroes in high_ or low_ (testing with both). -TEST(UnguessableTokenTest, VerifyToString2) { - UnguessableToken token = UnguessableToken::Deserialize(0x123, 0xABC); - std::string expected = "00000000000001230000000000000ABC"; - - EXPECT_EQ(expected, token.ToString()); - - std::string expected_stream = "(00000000000001230000000000000ABC)"; - std::stringstream stream; - stream << token; - EXPECT_EQ(expected_stream, stream.str()); -} - -TEST(UnguessableTokenTest, VerifyToStringUniqueness) { - const UnguessableToken token1 = - UnguessableToken::Deserialize(0x0000000012345678, 0x0000000123456789); - const UnguessableToken token2 = - UnguessableToken::Deserialize(0x0000000123456781, 0x0000000023456789); - EXPECT_NE(token1.ToString(), token2.ToString()); -} - -TEST(UnguessableTokenTest, VerifySmallerThanOperator) { - // Deserialize is used for testing purposes. - // Use UnguessableToken::Create() in production code instead. - { - SCOPED_TRACE("a.low < b.low and a.high == b.high."); - TestSmallerThanOperator(UnguessableToken::Deserialize(0, 1), - UnguessableToken::Deserialize(0, 5)); - } - { - SCOPED_TRACE("a.low == b.low and a.high < b.high."); - TestSmallerThanOperator(UnguessableToken::Deserialize(1, 0), - UnguessableToken::Deserialize(5, 0)); - } - { - SCOPED_TRACE("a.low < b.low and a.high < b.high."); - TestSmallerThanOperator(UnguessableToken::Deserialize(1, 1), - UnguessableToken::Deserialize(5, 5)); - } - { - SCOPED_TRACE("a.low > b.low and a.high < b.high."); - TestSmallerThanOperator(UnguessableToken::Deserialize(1, 10), - UnguessableToken::Deserialize(10, 1)); - } -} - -TEST(UnguessableTokenTest, VerifyHash) { - UnguessableToken token = UnguessableToken::Create(); - - EXPECT_EQ(base::HashInts64(token.GetHighForSerialization(), - token.GetLowForSerialization()), - UnguessableTokenHash()(token)); -} - -TEST(UnguessableTokenTest, VerifyBasicUniqueness) { - EXPECT_NE(UnguessableToken::Create(), UnguessableToken::Create()); - - UnguessableToken token = UnguessableToken::Create(); - EXPECT_NE(token.GetHighForSerialization(), token.GetLowForSerialization()); -} -}
diff --git a/base/value_iterators_unittest.cc b/base/value_iterators_unittest.cc deleted file mode 100644 index ed86182..0000000 --- a/base/value_iterators_unittest.cc +++ /dev/null
@@ -1,335 +0,0 @@ -// 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/value_iterators.h" - -#include <type_traits> - -#include "base/memory/ptr_util.h" -#include "base/values.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace detail { - -namespace { - -// Implementation of std::equal variant that is missing in C++11. -template <class BinaryPredicate, class InputIterator1, class InputIterator2> -bool are_equal(InputIterator1 first1, - InputIterator1 last1, - InputIterator2 first2, - InputIterator2 last2, - BinaryPredicate pred) { - for (; first1 != last1 && first2 != last2; ++first1, ++first2) { - if (!pred(*first1, *first2)) - return false; - } - return first1 == last1 && first2 == last2; -} - -} // namespace - -TEST(ValueIteratorsTest, SameDictStorage) { - static_assert(std::is_same<Value::DictStorage, DictStorage>::value, - "DictStorage differs between Value and Value Iterators."); -} - -TEST(ValueIteratorsTest, IsAssignable) { - static_assert( - !std::is_assignable<dict_iterator::reference::first_type, std::string>(), - "Can assign strings to dict_iterator"); - - static_assert( - std::is_assignable<dict_iterator::reference::second_type, Value>(), - "Can't assign Values to dict_iterator"); - - static_assert(!std::is_assignable<const_dict_iterator::reference::first_type, - std::string>(), - "Can assign strings to const_dict_iterator"); - - static_assert( - !std::is_assignable<const_dict_iterator::reference::second_type, Value>(), - "Can assign Values to const_dict_iterator"); -} - -TEST(ValueIteratorsTest, DictIteratorOperatorStar) { - DictStorage storage; - storage.emplace("0", std::make_unique<Value>(0)); - - using iterator = dict_iterator; - iterator iter(storage.begin()); - EXPECT_EQ("0", (*iter).first); - EXPECT_EQ(Value(0), (*iter).second); - - (*iter).second = Value(1); - EXPECT_EQ(Value(1), *storage["0"]); -} - -TEST(ValueIteratorsTest, DictIteratorOperatorArrow) { - DictStorage storage; - storage.emplace("0", std::make_unique<Value>(0)); - - using iterator = dict_iterator; - iterator iter(storage.begin()); - EXPECT_EQ("0", iter->first); - EXPECT_EQ(Value(0), iter->second); - - iter->second = Value(1); - EXPECT_EQ(Value(1), *storage["0"]); -} - -TEST(ValueIteratorsTest, DictIteratorPreIncrement) { - DictStorage storage; - storage.emplace("0", std::make_unique<Value>(0)); - storage.emplace("1", std::make_unique<Value>(1)); - - using iterator = dict_iterator; - iterator iter(storage.begin()); - EXPECT_EQ("0", iter->first); - EXPECT_EQ(Value(0), iter->second); - - iterator& iter_ref = ++iter; - EXPECT_EQ(&iter, &iter_ref); - - EXPECT_EQ("1", iter_ref->first); - EXPECT_EQ(Value(1), iter_ref->second); -} - -TEST(ValueIteratorsTest, DictIteratorPostIncrement) { - DictStorage storage; - storage.emplace("0", std::make_unique<Value>(0)); - storage.emplace("1", std::make_unique<Value>(1)); - - using iterator = dict_iterator; - iterator iter(storage.begin()); - iterator iter_old = iter++; - - EXPECT_EQ("0", iter_old->first); - EXPECT_EQ(Value(0), iter_old->second); - - EXPECT_EQ("1", iter->first); - EXPECT_EQ(Value(1), iter->second); -} - -TEST(ValueIteratorsTest, DictIteratorPreDecrement) { - DictStorage storage; - storage.emplace("0", std::make_unique<Value>(0)); - storage.emplace("1", std::make_unique<Value>(1)); - - using iterator = dict_iterator; - iterator iter(++storage.begin()); - EXPECT_EQ("1", iter->first); - EXPECT_EQ(Value(1), iter->second); - - iterator& iter_ref = --iter; - EXPECT_EQ(&iter, &iter_ref); - - EXPECT_EQ("0", iter_ref->first); - EXPECT_EQ(Value(0), iter_ref->second); -} - -TEST(ValueIteratorsTest, DictIteratorPostDecrement) { - DictStorage storage; - storage.emplace("0", std::make_unique<Value>(0)); - storage.emplace("1", std::make_unique<Value>(1)); - - using iterator = dict_iterator; - iterator iter(++storage.begin()); - iterator iter_old = iter--; - - EXPECT_EQ("1", iter_old->first); - EXPECT_EQ(Value(1), iter_old->second); - - EXPECT_EQ("0", iter->first); - EXPECT_EQ(Value(0), iter->second); -} - -TEST(ValueIteratorsTest, DictIteratorOperatorEQ) { - DictStorage storage; - using iterator = dict_iterator; - EXPECT_EQ(iterator(storage.begin()), iterator(storage.begin())); - EXPECT_EQ(iterator(storage.end()), iterator(storage.end())); -} - -TEST(ValueIteratorsTest, DictIteratorOperatorNE) { - DictStorage storage; - storage.emplace("0", std::make_unique<Value>(0)); - - using iterator = dict_iterator; - EXPECT_NE(iterator(storage.begin()), iterator(storage.end())); -} - -TEST(ValueIteratorsTest, ConstDictIteratorOperatorStar) { - DictStorage storage; - storage.emplace("0", std::make_unique<Value>(0)); - - using iterator = const_dict_iterator; - iterator iter(storage.begin()); - EXPECT_EQ("0", (*iter).first); - EXPECT_EQ(Value(0), (*iter).second); -} - -TEST(ValueIteratorsTest, ConstDictIteratorOperatorArrow) { - DictStorage storage; - storage.emplace("0", std::make_unique<Value>(0)); - - using iterator = const_dict_iterator; - iterator iter(storage.begin()); - EXPECT_EQ("0", iter->first); - EXPECT_EQ(Value(0), iter->second); -} - -TEST(ValueIteratorsTest, ConstDictIteratorPreIncrement) { - DictStorage storage; - storage.emplace("0", std::make_unique<Value>(0)); - storage.emplace("1", std::make_unique<Value>(1)); - - using iterator = const_dict_iterator; - iterator iter(storage.begin()); - EXPECT_EQ("0", iter->first); - EXPECT_EQ(Value(0), iter->second); - - iterator& iter_ref = ++iter; - EXPECT_EQ(&iter, &iter_ref); - - EXPECT_EQ("1", iter_ref->first); - EXPECT_EQ(Value(1), iter_ref->second); -} - -TEST(ValueIteratorsTest, ConstDictIteratorPostIncrement) { - DictStorage storage; - storage.emplace("0", std::make_unique<Value>(0)); - storage.emplace("1", std::make_unique<Value>(1)); - - using iterator = const_dict_iterator; - iterator iter(storage.begin()); - iterator iter_old = iter++; - - EXPECT_EQ("0", iter_old->first); - EXPECT_EQ(Value(0), iter_old->second); - - EXPECT_EQ("1", iter->first); - EXPECT_EQ(Value(1), iter->second); -} - -TEST(ValueIteratorsTest, ConstDictIteratorPreDecrement) { - DictStorage storage; - storage.emplace("0", std::make_unique<Value>(0)); - storage.emplace("1", std::make_unique<Value>(1)); - - using iterator = const_dict_iterator; - iterator iter(++storage.begin()); - EXPECT_EQ("1", iter->first); - EXPECT_EQ(Value(1), iter->second); - - iterator& iter_ref = --iter; - EXPECT_EQ(&iter, &iter_ref); - - EXPECT_EQ("0", iter_ref->first); - EXPECT_EQ(Value(0), iter_ref->second); -} - -TEST(ValueIteratorsTest, ConstDictIteratorPostDecrement) { - DictStorage storage; - storage.emplace("0", std::make_unique<Value>(0)); - storage.emplace("1", std::make_unique<Value>(1)); - - using iterator = const_dict_iterator; - iterator iter(++storage.begin()); - iterator iter_old = iter--; - - EXPECT_EQ("1", iter_old->first); - EXPECT_EQ(Value(1), iter_old->second); - - EXPECT_EQ("0", iter->first); - EXPECT_EQ(Value(0), iter->second); -} - -TEST(ValueIteratorsTest, ConstDictIteratorOperatorEQ) { - DictStorage storage; - using iterator = const_dict_iterator; - EXPECT_EQ(iterator(storage.begin()), iterator(storage.begin())); - EXPECT_EQ(iterator(storage.end()), iterator(storage.end())); -} - -TEST(ValueIteratorsTest, ConstDictIteratorOperatorNE) { - DictStorage storage; - storage.emplace("0", std::make_unique<Value>(0)); - - using iterator = const_dict_iterator; - EXPECT_NE(iterator(storage.begin()), iterator(storage.end())); -} - -TEST(ValueIteratorsTest, DictIteratorProxy) { - DictStorage storage; - storage.emplace("null", std::make_unique<Value>(Value::Type::NONE)); - storage.emplace("bool", std::make_unique<Value>(Value::Type::BOOLEAN)); - storage.emplace("int", std::make_unique<Value>(Value::Type::INTEGER)); - storage.emplace("double", std::make_unique<Value>(Value::Type::DOUBLE)); - storage.emplace("string", std::make_unique<Value>(Value::Type::STRING)); - storage.emplace("blob", std::make_unique<Value>(Value::Type::BINARY)); - storage.emplace("dict", std::make_unique<Value>(Value::Type::DICTIONARY)); - storage.emplace("list", std::make_unique<Value>(Value::Type::LIST)); - - using iterator = const_dict_iterator; - using iterator_proxy = dict_iterator_proxy; - iterator_proxy proxy(&storage); - - auto equal_to = [](const DictStorage::value_type& lhs, - const iterator::reference& rhs) { - return std::tie(lhs.first, *lhs.second) == std::tie(rhs.first, rhs.second); - }; - - EXPECT_TRUE(are_equal(storage.begin(), storage.end(), proxy.begin(), - proxy.end(), equal_to)); - - EXPECT_TRUE(are_equal(storage.rbegin(), storage.rend(), proxy.rbegin(), - proxy.rend(), equal_to)); - - EXPECT_TRUE(are_equal(storage.cbegin(), storage.cend(), proxy.cbegin(), - proxy.cend(), equal_to)); - - EXPECT_TRUE(are_equal(storage.crbegin(), storage.crend(), proxy.crbegin(), - proxy.crend(), equal_to)); -} - -TEST(ValueIteratorsTest, ConstDictIteratorProxy) { - DictStorage storage; - storage.emplace("null", std::make_unique<Value>(Value::Type::NONE)); - storage.emplace("bool", std::make_unique<Value>(Value::Type::BOOLEAN)); - storage.emplace("int", std::make_unique<Value>(Value::Type::INTEGER)); - storage.emplace("double", std::make_unique<Value>(Value::Type::DOUBLE)); - storage.emplace("string", std::make_unique<Value>(Value::Type::STRING)); - storage.emplace("blob", std::make_unique<Value>(Value::Type::BINARY)); - storage.emplace("dict", std::make_unique<Value>(Value::Type::DICTIONARY)); - storage.emplace("list", std::make_unique<Value>(Value::Type::LIST)); - - using iterator = const_dict_iterator; - using iterator_proxy = const_dict_iterator_proxy; - iterator_proxy proxy(&storage); - - auto equal_to = [](const DictStorage::value_type& lhs, - const iterator::reference& rhs) { - return std::tie(lhs.first, *lhs.second) == std::tie(rhs.first, rhs.second); - }; - - EXPECT_TRUE(are_equal(storage.begin(), storage.end(), proxy.begin(), - proxy.end(), equal_to)); - - EXPECT_TRUE(are_equal(storage.rbegin(), storage.rend(), proxy.rbegin(), - proxy.rend(), equal_to)); - - EXPECT_TRUE(are_equal(storage.cbegin(), storage.cend(), proxy.cbegin(), - proxy.cend(), equal_to)); - - EXPECT_TRUE(are_equal(storage.crbegin(), storage.crend(), proxy.crbegin(), - proxy.crend(), equal_to)); -} - -} // namespace detail - -} // namespace base
diff --git a/base/values_unittest.cc b/base/values_unittest.cc deleted file mode 100644 index b8efac7..0000000 --- a/base/values_unittest.cc +++ /dev/null
@@ -1,1922 +0,0 @@ -// 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/values.h" - -#include <stddef.h> - -#include <functional> -#include <limits> -#include <memory> -#include <string> -#include <type_traits> -#include <utility> -#include <vector> - -#include "base/containers/adapters.h" -#include "base/memory/ptr_util.h" -#include "base/strings/string16.h" -#include "base/strings/string_piece.h" -#include "base/strings/utf_string_conversions.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(ValuesTest, TestNothrow) { - static_assert(std::is_nothrow_move_constructible<Value>::value, - "IsNothrowMoveConstructible"); - static_assert(std::is_nothrow_default_constructible<Value>::value, - "IsNothrowDefaultConstructible"); - static_assert(std::is_nothrow_constructible<Value, std::string&&>::value, - "IsNothrowMoveConstructibleFromString"); - static_assert( - std::is_nothrow_constructible<Value, Value::BlobStorage&&>::value, - "IsNothrowMoveConstructibleFromBlob"); - static_assert( - std::is_nothrow_constructible<Value, Value::ListStorage&&>::value, - "IsNothrowMoveConstructibleFromList"); - static_assert(std::is_nothrow_move_assignable<Value>::value, - "IsNothrowMoveAssignable"); - static_assert( - std::is_nothrow_constructible<ListValue, Value::ListStorage&&>::value, - "ListIsNothrowMoveConstructibleFromList"); -} - -// Group of tests for the value constructors. -TEST(ValuesTest, ConstructBool) { - Value true_value(true); - EXPECT_EQ(Value::Type::BOOLEAN, true_value.type()); - EXPECT_TRUE(true_value.GetBool()); - - Value false_value(false); - EXPECT_EQ(Value::Type::BOOLEAN, false_value.type()); - EXPECT_FALSE(false_value.GetBool()); -} - -TEST(ValuesTest, ConstructInt) { - Value value(-37); - EXPECT_EQ(Value::Type::INTEGER, value.type()); - EXPECT_EQ(-37, value.GetInt()); -} - -TEST(ValuesTest, ConstructDouble) { - Value value(-4.655); - EXPECT_EQ(Value::Type::DOUBLE, value.type()); - EXPECT_EQ(-4.655, value.GetDouble()); -} - -TEST(ValuesTest, ConstructStringFromConstCharPtr) { - const char* str = "foobar"; - Value value(str); - EXPECT_EQ(Value::Type::STRING, value.type()); - EXPECT_EQ("foobar", value.GetString()); -} - -TEST(ValuesTest, ConstructStringFromStringPiece) { - std::string str = "foobar"; - Value value{StringPiece(str)}; - EXPECT_EQ(Value::Type::STRING, value.type()); - EXPECT_EQ("foobar", value.GetString()); -} - -TEST(ValuesTest, ConstructStringFromStdStringRRef) { - std::string str = "foobar"; - Value value(std::move(str)); - EXPECT_EQ(Value::Type::STRING, value.type()); - EXPECT_EQ("foobar", value.GetString()); -} - -TEST(ValuesTest, ConstructStringFromConstChar16Ptr) { - string16 str = ASCIIToUTF16("foobar"); - Value value(str.c_str()); - EXPECT_EQ(Value::Type::STRING, value.type()); - EXPECT_EQ("foobar", value.GetString()); -} - -TEST(ValuesTest, ConstructStringFromStringPiece16) { - string16 str = ASCIIToUTF16("foobar"); - Value value{StringPiece16(str)}; - EXPECT_EQ(Value::Type::STRING, value.type()); - EXPECT_EQ("foobar", value.GetString()); -} - -TEST(ValuesTest, ConstructBinary) { - Value value(Value::BlobStorage({0xF, 0x0, 0x0, 0xB, 0xA, 0x2})); - EXPECT_EQ(Value::Type::BINARY, value.type()); - EXPECT_EQ(Value::BlobStorage({0xF, 0x0, 0x0, 0xB, 0xA, 0x2}), - value.GetBlob()); -} - -TEST(ValuesTest, ConstructDict) { - DictionaryValue value; - EXPECT_EQ(Value::Type::DICTIONARY, value.type()); -} - -TEST(ValuesTest, ConstructDictFromStorage) { - Value::DictStorage storage; - storage.emplace("foo", std::make_unique<Value>("bar")); - { - DictionaryValue value(storage); - EXPECT_EQ(Value::Type::DICTIONARY, value.type()); - EXPECT_EQ(Value::Type::STRING, value.FindKey("foo")->type()); - EXPECT_EQ("bar", value.FindKey("foo")->GetString()); - } - - *storage["foo"] = base::Value("baz"); - { - DictionaryValue value(std::move(storage)); - EXPECT_EQ(Value::Type::DICTIONARY, value.type()); - EXPECT_EQ(Value::Type::STRING, value.FindKey("foo")->type()); - EXPECT_EQ("baz", value.FindKey("foo")->GetString()); - } -} - -TEST(ValuesTest, ConstructList) { - ListValue value; - EXPECT_EQ(Value::Type::LIST, value.type()); -} - -TEST(ValuesTest, ConstructListFromStorage) { - Value::ListStorage storage; - storage.emplace_back("foo"); - { - ListValue value(storage); - EXPECT_EQ(Value::Type::LIST, value.type()); - EXPECT_EQ(1u, value.GetList().size()); - EXPECT_EQ(Value::Type::STRING, value.GetList()[0].type()); - EXPECT_EQ("foo", value.GetList()[0].GetString()); - } - - storage.back() = base::Value("bar"); - { - ListValue value(std::move(storage)); - EXPECT_EQ(Value::Type::LIST, value.type()); - EXPECT_EQ(1u, value.GetList().size()); - EXPECT_EQ(Value::Type::STRING, value.GetList()[0].type()); - EXPECT_EQ("bar", value.GetList()[0].GetString()); - } -} - -// Group of tests for the copy constructors and copy-assigmnent. For equality -// checks comparisons of the interesting fields are done instead of relying on -// Equals being correct. -TEST(ValuesTest, CopyBool) { - Value true_value(true); - Value copied_true_value(true_value.Clone()); - EXPECT_EQ(true_value.type(), copied_true_value.type()); - EXPECT_EQ(true_value.GetBool(), copied_true_value.GetBool()); - - Value false_value(false); - Value copied_false_value(false_value.Clone()); - EXPECT_EQ(false_value.type(), copied_false_value.type()); - EXPECT_EQ(false_value.GetBool(), copied_false_value.GetBool()); - - Value blank; - - blank = true_value.Clone(); - EXPECT_EQ(true_value.type(), blank.type()); - EXPECT_EQ(true_value.GetBool(), blank.GetBool()); - - blank = false_value.Clone(); - EXPECT_EQ(false_value.type(), blank.type()); - EXPECT_EQ(false_value.GetBool(), blank.GetBool()); -} - -TEST(ValuesTest, CopyInt) { - Value value(74); - Value copied_value(value.Clone()); - EXPECT_EQ(value.type(), copied_value.type()); - EXPECT_EQ(value.GetInt(), copied_value.GetInt()); - - Value blank; - - blank = value.Clone(); - EXPECT_EQ(value.type(), blank.type()); - EXPECT_EQ(value.GetInt(), blank.GetInt()); -} - -TEST(ValuesTest, CopyDouble) { - Value value(74.896); - Value copied_value(value.Clone()); - EXPECT_EQ(value.type(), copied_value.type()); - EXPECT_EQ(value.GetDouble(), copied_value.GetDouble()); - - Value blank; - - blank = value.Clone(); - EXPECT_EQ(value.type(), blank.type()); - EXPECT_EQ(value.GetDouble(), blank.GetDouble()); -} - -TEST(ValuesTest, CopyString) { - Value value("foobar"); - Value copied_value(value.Clone()); - EXPECT_EQ(value.type(), copied_value.type()); - EXPECT_EQ(value.GetString(), copied_value.GetString()); - - Value blank; - - blank = value.Clone(); - EXPECT_EQ(value.type(), blank.type()); - EXPECT_EQ(value.GetString(), blank.GetString()); -} - -TEST(ValuesTest, CopyBinary) { - Value value(Value::BlobStorage({0xF, 0x0, 0x0, 0xB, 0xA, 0x2})); - Value copied_value(value.Clone()); - EXPECT_EQ(value.type(), copied_value.type()); - EXPECT_EQ(value.GetBlob(), copied_value.GetBlob()); - - Value blank; - - blank = value.Clone(); - EXPECT_EQ(value.type(), blank.type()); - EXPECT_EQ(value.GetBlob(), blank.GetBlob()); -} - -TEST(ValuesTest, CopyDictionary) { - Value::DictStorage storage; - storage.emplace("Int", std::make_unique<Value>(123)); - Value value(std::move(storage)); - - Value copied_value(value.Clone()); - EXPECT_EQ(value, copied_value); - - Value blank; - blank = value.Clone(); - EXPECT_EQ(value, blank); -} - -TEST(ValuesTest, CopyList) { - Value::ListStorage storage; - storage.emplace_back(123); - Value value(std::move(storage)); - - Value copied_value(value.Clone()); - EXPECT_EQ(value, copied_value); - - Value blank; - blank = value.Clone(); - EXPECT_EQ(value, blank); -} - -// Group of tests for the move constructors and move-assigmnent. -TEST(ValuesTest, MoveBool) { - Value true_value(true); - Value moved_true_value(std::move(true_value)); - EXPECT_EQ(Value::Type::BOOLEAN, moved_true_value.type()); - EXPECT_TRUE(moved_true_value.GetBool()); - - Value false_value(false); - Value moved_false_value(std::move(false_value)); - EXPECT_EQ(Value::Type::BOOLEAN, moved_false_value.type()); - EXPECT_FALSE(moved_false_value.GetBool()); - - Value blank; - - blank = Value(true); - EXPECT_EQ(Value::Type::BOOLEAN, blank.type()); - EXPECT_TRUE(blank.GetBool()); - - blank = Value(false); - EXPECT_EQ(Value::Type::BOOLEAN, blank.type()); - EXPECT_FALSE(blank.GetBool()); -} - -TEST(ValuesTest, MoveInt) { - Value value(74); - Value moved_value(std::move(value)); - EXPECT_EQ(Value::Type::INTEGER, moved_value.type()); - EXPECT_EQ(74, moved_value.GetInt()); - - Value blank; - - blank = Value(47); - EXPECT_EQ(Value::Type::INTEGER, blank.type()); - EXPECT_EQ(47, blank.GetInt()); -} - -TEST(ValuesTest, MoveDouble) { - Value value(74.896); - Value moved_value(std::move(value)); - EXPECT_EQ(Value::Type::DOUBLE, moved_value.type()); - EXPECT_EQ(74.896, moved_value.GetDouble()); - - Value blank; - - blank = Value(654.38); - EXPECT_EQ(Value::Type::DOUBLE, blank.type()); - EXPECT_EQ(654.38, blank.GetDouble()); -} - -TEST(ValuesTest, MoveString) { - Value value("foobar"); - Value moved_value(std::move(value)); - EXPECT_EQ(Value::Type::STRING, moved_value.type()); - EXPECT_EQ("foobar", moved_value.GetString()); - - Value blank; - - blank = Value("foobar"); - EXPECT_EQ(Value::Type::STRING, blank.type()); - EXPECT_EQ("foobar", blank.GetString()); -} - -TEST(ValuesTest, MoveBinary) { - const Value::BlobStorage buffer = {0xF, 0x0, 0x0, 0xB, 0xA, 0x2}; - Value value(buffer); - Value moved_value(std::move(value)); - EXPECT_EQ(Value::Type::BINARY, moved_value.type()); - EXPECT_EQ(buffer, moved_value.GetBlob()); - - Value blank; - - blank = Value(buffer); - EXPECT_EQ(Value::Type::BINARY, blank.type()); - EXPECT_EQ(buffer, blank.GetBlob()); -} - -TEST(ValuesTest, MoveConstructDictionary) { - Value::DictStorage storage; - storage.emplace("Int", std::make_unique<Value>(123)); - - Value value(std::move(storage)); - Value moved_value(std::move(value)); - EXPECT_EQ(Value::Type::DICTIONARY, moved_value.type()); - EXPECT_EQ(123, moved_value.FindKey("Int")->GetInt()); -} - -TEST(ValuesTest, MoveAssignDictionary) { - Value::DictStorage storage; - storage.emplace("Int", std::make_unique<Value>(123)); - - Value blank; - blank = Value(std::move(storage)); - EXPECT_EQ(Value::Type::DICTIONARY, blank.type()); - EXPECT_EQ(123, blank.FindKey("Int")->GetInt()); -} - -TEST(ValuesTest, MoveList) { - Value::ListStorage storage; - storage.emplace_back(123); - Value value(storage); - Value moved_value(std::move(value)); - EXPECT_EQ(Value::Type::LIST, moved_value.type()); - EXPECT_EQ(123, moved_value.GetList().back().GetInt()); - - Value blank; - blank = Value(std::move(storage)); - EXPECT_EQ(Value::Type::LIST, blank.type()); - EXPECT_EQ(123, blank.GetList().back().GetInt()); -} - -TEST(ValuesTest, FindKey) { - Value::DictStorage storage; - storage.emplace("foo", std::make_unique<Value>("bar")); - Value dict(std::move(storage)); - EXPECT_NE(nullptr, dict.FindKey("foo")); - EXPECT_EQ(nullptr, dict.FindKey("baz")); - - // Single not found key. - bool found = dict.FindKey("notfound"); - EXPECT_FALSE(found); -} - -TEST(ValuesTest, FindKeyChangeValue) { - Value::DictStorage storage; - storage.emplace("foo", std::make_unique<Value>("bar")); - Value dict(std::move(storage)); - Value* found = dict.FindKey("foo"); - EXPECT_NE(nullptr, found); - EXPECT_EQ("bar", found->GetString()); - - *found = Value(123); - EXPECT_EQ(123, dict.FindKey("foo")->GetInt()); -} - -TEST(ValuesTest, FindKeyConst) { - Value::DictStorage storage; - storage.emplace("foo", std::make_unique<Value>("bar")); - const Value dict(std::move(storage)); - EXPECT_NE(nullptr, dict.FindKey("foo")); - EXPECT_EQ(nullptr, dict.FindKey("baz")); -} - -TEST(ValuesTest, FindKeyOfType) { - Value::DictStorage storage; - storage.emplace("null", std::make_unique<Value>(Value::Type::NONE)); - storage.emplace("bool", std::make_unique<Value>(Value::Type::BOOLEAN)); - storage.emplace("int", std::make_unique<Value>(Value::Type::INTEGER)); - storage.emplace("double", std::make_unique<Value>(Value::Type::DOUBLE)); - storage.emplace("string", std::make_unique<Value>(Value::Type::STRING)); - storage.emplace("blob", std::make_unique<Value>(Value::Type::BINARY)); - storage.emplace("list", std::make_unique<Value>(Value::Type::LIST)); - storage.emplace("dict", std::make_unique<Value>(Value::Type::DICTIONARY)); - - Value dict(std::move(storage)); - EXPECT_NE(nullptr, dict.FindKeyOfType("null", Value::Type::NONE)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("null", Value::Type::BOOLEAN)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("null", Value::Type::INTEGER)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("null", Value::Type::DOUBLE)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("null", Value::Type::STRING)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("null", Value::Type::BINARY)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("null", Value::Type::LIST)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("null", Value::Type::DICTIONARY)); - - EXPECT_EQ(nullptr, dict.FindKeyOfType("bool", Value::Type::NONE)); - EXPECT_NE(nullptr, dict.FindKeyOfType("bool", Value::Type::BOOLEAN)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("bool", Value::Type::INTEGER)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("bool", Value::Type::DOUBLE)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("bool", Value::Type::STRING)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("bool", Value::Type::BINARY)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("bool", Value::Type::LIST)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("bool", Value::Type::DICTIONARY)); - - EXPECT_EQ(nullptr, dict.FindKeyOfType("int", Value::Type::NONE)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("int", Value::Type::BOOLEAN)); - EXPECT_NE(nullptr, dict.FindKeyOfType("int", Value::Type::INTEGER)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("int", Value::Type::DOUBLE)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("int", Value::Type::STRING)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("int", Value::Type::BINARY)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("int", Value::Type::LIST)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("int", Value::Type::DICTIONARY)); - - EXPECT_EQ(nullptr, dict.FindKeyOfType("double", Value::Type::NONE)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("double", Value::Type::BOOLEAN)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("double", Value::Type::INTEGER)); - EXPECT_NE(nullptr, dict.FindKeyOfType("double", Value::Type::DOUBLE)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("double", Value::Type::STRING)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("double", Value::Type::BINARY)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("double", Value::Type::LIST)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("double", Value::Type::DICTIONARY)); - - EXPECT_EQ(nullptr, dict.FindKeyOfType("string", Value::Type::NONE)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("string", Value::Type::BOOLEAN)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("string", Value::Type::INTEGER)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("string", Value::Type::DOUBLE)); - EXPECT_NE(nullptr, dict.FindKeyOfType("string", Value::Type::STRING)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("string", Value::Type::BINARY)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("string", Value::Type::LIST)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("string", Value::Type::DICTIONARY)); - - EXPECT_EQ(nullptr, dict.FindKeyOfType("blob", Value::Type::NONE)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("blob", Value::Type::BOOLEAN)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("blob", Value::Type::INTEGER)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("blob", Value::Type::DOUBLE)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("blob", Value::Type::STRING)); - EXPECT_NE(nullptr, dict.FindKeyOfType("blob", Value::Type::BINARY)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("blob", Value::Type::LIST)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("blob", Value::Type::DICTIONARY)); - - EXPECT_EQ(nullptr, dict.FindKeyOfType("list", Value::Type::NONE)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("list", Value::Type::BOOLEAN)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("list", Value::Type::INTEGER)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("list", Value::Type::DOUBLE)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("list", Value::Type::STRING)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("list", Value::Type::BINARY)); - EXPECT_NE(nullptr, dict.FindKeyOfType("list", Value::Type::LIST)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("list", Value::Type::DICTIONARY)); - - EXPECT_EQ(nullptr, dict.FindKeyOfType("dict", Value::Type::NONE)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("dict", Value::Type::BOOLEAN)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("dict", Value::Type::INTEGER)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("dict", Value::Type::DOUBLE)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("dict", Value::Type::STRING)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("dict", Value::Type::BINARY)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("dict", Value::Type::LIST)); - EXPECT_NE(nullptr, dict.FindKeyOfType("dict", Value::Type::DICTIONARY)); -} - -TEST(ValuesTest, FindKeyOfTypeConst) { - Value::DictStorage storage; - storage.emplace("null", std::make_unique<Value>(Value::Type::NONE)); - storage.emplace("bool", std::make_unique<Value>(Value::Type::BOOLEAN)); - storage.emplace("int", std::make_unique<Value>(Value::Type::INTEGER)); - storage.emplace("double", std::make_unique<Value>(Value::Type::DOUBLE)); - storage.emplace("string", std::make_unique<Value>(Value::Type::STRING)); - storage.emplace("blob", std::make_unique<Value>(Value::Type::BINARY)); - storage.emplace("list", std::make_unique<Value>(Value::Type::LIST)); - storage.emplace("dict", std::make_unique<Value>(Value::Type::DICTIONARY)); - - const Value dict(std::move(storage)); - EXPECT_NE(nullptr, dict.FindKeyOfType("null", Value::Type::NONE)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("null", Value::Type::BOOLEAN)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("null", Value::Type::INTEGER)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("null", Value::Type::DOUBLE)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("null", Value::Type::STRING)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("null", Value::Type::BINARY)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("null", Value::Type::LIST)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("null", Value::Type::DICTIONARY)); - - EXPECT_EQ(nullptr, dict.FindKeyOfType("bool", Value::Type::NONE)); - EXPECT_NE(nullptr, dict.FindKeyOfType("bool", Value::Type::BOOLEAN)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("bool", Value::Type::INTEGER)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("bool", Value::Type::DOUBLE)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("bool", Value::Type::STRING)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("bool", Value::Type::BINARY)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("bool", Value::Type::LIST)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("bool", Value::Type::DICTIONARY)); - - EXPECT_EQ(nullptr, dict.FindKeyOfType("int", Value::Type::NONE)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("int", Value::Type::BOOLEAN)); - EXPECT_NE(nullptr, dict.FindKeyOfType("int", Value::Type::INTEGER)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("int", Value::Type::DOUBLE)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("int", Value::Type::STRING)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("int", Value::Type::BINARY)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("int", Value::Type::LIST)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("int", Value::Type::DICTIONARY)); - - EXPECT_EQ(nullptr, dict.FindKeyOfType("double", Value::Type::NONE)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("double", Value::Type::BOOLEAN)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("double", Value::Type::INTEGER)); - EXPECT_NE(nullptr, dict.FindKeyOfType("double", Value::Type::DOUBLE)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("double", Value::Type::STRING)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("double", Value::Type::BINARY)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("double", Value::Type::LIST)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("double", Value::Type::DICTIONARY)); - - EXPECT_EQ(nullptr, dict.FindKeyOfType("string", Value::Type::NONE)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("string", Value::Type::BOOLEAN)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("string", Value::Type::INTEGER)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("string", Value::Type::DOUBLE)); - EXPECT_NE(nullptr, dict.FindKeyOfType("string", Value::Type::STRING)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("string", Value::Type::BINARY)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("string", Value::Type::LIST)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("string", Value::Type::DICTIONARY)); - - EXPECT_EQ(nullptr, dict.FindKeyOfType("blob", Value::Type::NONE)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("blob", Value::Type::BOOLEAN)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("blob", Value::Type::INTEGER)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("blob", Value::Type::DOUBLE)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("blob", Value::Type::STRING)); - EXPECT_NE(nullptr, dict.FindKeyOfType("blob", Value::Type::BINARY)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("blob", Value::Type::LIST)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("blob", Value::Type::DICTIONARY)); - - EXPECT_EQ(nullptr, dict.FindKeyOfType("list", Value::Type::NONE)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("list", Value::Type::BOOLEAN)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("list", Value::Type::INTEGER)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("list", Value::Type::DOUBLE)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("list", Value::Type::STRING)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("list", Value::Type::BINARY)); - EXPECT_NE(nullptr, dict.FindKeyOfType("list", Value::Type::LIST)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("list", Value::Type::DICTIONARY)); - - EXPECT_EQ(nullptr, dict.FindKeyOfType("dict", Value::Type::NONE)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("dict", Value::Type::BOOLEAN)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("dict", Value::Type::INTEGER)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("dict", Value::Type::DOUBLE)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("dict", Value::Type::STRING)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("dict", Value::Type::BINARY)); - EXPECT_EQ(nullptr, dict.FindKeyOfType("dict", Value::Type::LIST)); - EXPECT_NE(nullptr, dict.FindKeyOfType("dict", Value::Type::DICTIONARY)); -} - -TEST(ValuesTest, SetKey) { - Value::DictStorage storage; - storage.emplace("null", std::make_unique<Value>(Value::Type::NONE)); - storage.emplace("bool", std::make_unique<Value>(Value::Type::BOOLEAN)); - storage.emplace("int", std::make_unique<Value>(Value::Type::INTEGER)); - storage.emplace("double", std::make_unique<Value>(Value::Type::DOUBLE)); - storage.emplace("string", std::make_unique<Value>(Value::Type::STRING)); - storage.emplace("blob", std::make_unique<Value>(Value::Type::BINARY)); - storage.emplace("list", std::make_unique<Value>(Value::Type::LIST)); - storage.emplace("dict", std::make_unique<Value>(Value::Type::DICTIONARY)); - - Value dict(Value::Type::DICTIONARY); - dict.SetKey(StringPiece("null"), Value(Value::Type::NONE)); - dict.SetKey(StringPiece("bool"), Value(Value::Type::BOOLEAN)); - dict.SetKey(std::string("int"), Value(Value::Type::INTEGER)); - dict.SetKey(std::string("double"), Value(Value::Type::DOUBLE)); - dict.SetKey(std::string("string"), Value(Value::Type::STRING)); - dict.SetKey("blob", Value(Value::Type::BINARY)); - dict.SetKey("list", Value(Value::Type::LIST)); - dict.SetKey("dict", Value(Value::Type::DICTIONARY)); - - EXPECT_EQ(Value(std::move(storage)), dict); -} - -TEST(ValuesTest, FindPath) { - // Construct a dictionary path {root}.foo.bar = 123 - Value foo(Value::Type::DICTIONARY); - foo.SetKey("bar", Value(123)); - - Value root(Value::Type::DICTIONARY); - root.SetKey("foo", std::move(foo)); - - // No key (stupid but well-defined and takes work to prevent). - Value* found = root.FindPath(std::vector<StringPiece>{}); - EXPECT_EQ(&root, found); - - // Double key, second not found. - found = root.FindPath(std::vector<StringPiece>{"foo", "notfound"}); - EXPECT_FALSE(found); - - // Double key, found. - found = root.FindPath(std::vector<StringPiece>{"foo", "bar"}); - EXPECT_TRUE(found); - EXPECT_TRUE(found->is_int()); - EXPECT_EQ(123, found->GetInt()); -} - -TEST(ValuesTest, SetPath) { - Value root(Value::Type::DICTIONARY); - - Value* inserted = root.SetPath({"one", "two"}, Value(123)); - Value* found = root.FindPathOfType({"one", "two"}, Value::Type::INTEGER); - ASSERT_TRUE(found); - EXPECT_EQ(inserted, found); - EXPECT_EQ(123, found->GetInt()); - - inserted = root.SetPath(std::vector<StringPiece>{"foo", "bar"}, Value(123)); - found = root.FindPathOfType({"foo", "bar"}, Value::Type::INTEGER); - ASSERT_TRUE(found); - EXPECT_EQ(inserted, found); - EXPECT_EQ(123, found->GetInt()); - - // Overwrite with a different value. - root.SetPath({"foo", "bar"}, Value("hello")); - found = root.FindPathOfType(std::vector<StringPiece>{"foo", "bar"}, - Value::Type::STRING); - ASSERT_TRUE(found); - EXPECT_EQ("hello", found->GetString()); - - // Can't change existing non-dictionary keys to dictionaries. - found = - root.SetPath(std::vector<StringPiece>{"foo", "bar", "baz"}, Value(123)); - EXPECT_FALSE(found); -} - -TEST(ValuesTest, RemoveKey) { - Value root(Value::Type::DICTIONARY); - root.SetKey("one", Value(123)); - - // Removal of missing key should fail. - EXPECT_FALSE(root.RemoveKey("two")); - - // Removal of existing key should succeed. - EXPECT_TRUE(root.RemoveKey("one")); - - // Second removal of previously existing key should fail. - EXPECT_FALSE(root.RemoveKey("one")); -} - -TEST(ValuesTest, RemovePath) { - Value root(Value::Type::DICTIONARY); - root.SetPath({"one", "two", "three"}, Value(123)); - - // Removal of missing key should fail. - EXPECT_FALSE(root.RemovePath({"one", "two", "four"})); - - // Removal of existing key should succeed. - EXPECT_TRUE(root.RemovePath({"one", "two", "three"})); - - // Second removal of previously existing key should fail. - EXPECT_FALSE(root.RemovePath({"one", "two", "three"})); - - // Intermediate empty dictionaries should be cleared. - EXPECT_FALSE(root.FindKey("one")); - - root.SetPath({"one", "two", "three"}, Value(123)); - root.SetPath({"one", "two", "four"}, Value(124)); - - EXPECT_TRUE(root.RemovePath(std::vector<StringPiece>{"one", "two", "three"})); - // Intermediate non-empty dictionaries should be kept. - EXPECT_TRUE(root.FindKey("one")); - EXPECT_TRUE(root.FindPath({"one", "two"})); - EXPECT_TRUE(root.FindPath({"one", "two", "four"})); -} - -TEST(ValuesTest, Basic) { - // Test basic dictionary getting/setting - DictionaryValue settings; - std::string homepage = "http://google.com"; - ASSERT_FALSE(settings.GetString("global.homepage", &homepage)); - ASSERT_EQ(std::string("http://google.com"), homepage); - - ASSERT_FALSE(settings.Get("global", nullptr)); - settings.SetBoolean("global", true); - ASSERT_TRUE(settings.Get("global", nullptr)); - settings.SetString("global.homepage", "http://scurvy.com"); - ASSERT_TRUE(settings.Get("global", nullptr)); - homepage = "http://google.com"; - ASSERT_TRUE(settings.GetString("global.homepage", &homepage)); - ASSERT_EQ(std::string("http://scurvy.com"), homepage); - - // Test storing a dictionary in a list. - ListValue* toolbar_bookmarks; - ASSERT_FALSE( - settings.GetList("global.toolbar.bookmarks", &toolbar_bookmarks)); - - std::unique_ptr<ListValue> new_toolbar_bookmarks(new ListValue); - settings.Set("global.toolbar.bookmarks", std::move(new_toolbar_bookmarks)); - ASSERT_TRUE(settings.GetList("global.toolbar.bookmarks", &toolbar_bookmarks)); - - std::unique_ptr<DictionaryValue> new_bookmark(new DictionaryValue); - new_bookmark->SetString("name", "Froogle"); - new_bookmark->SetString("url", "http://froogle.com"); - toolbar_bookmarks->Append(std::move(new_bookmark)); - - ListValue* bookmark_list; - ASSERT_TRUE(settings.GetList("global.toolbar.bookmarks", &bookmark_list)); - DictionaryValue* bookmark; - ASSERT_EQ(1U, bookmark_list->GetSize()); - ASSERT_TRUE(bookmark_list->GetDictionary(0, &bookmark)); - std::string bookmark_name = "Unnamed"; - ASSERT_TRUE(bookmark->GetString("name", &bookmark_name)); - ASSERT_EQ(std::string("Froogle"), bookmark_name); - std::string bookmark_url; - ASSERT_TRUE(bookmark->GetString("url", &bookmark_url)); - ASSERT_EQ(std::string("http://froogle.com"), bookmark_url); -} - -TEST(ValuesTest, List) { - std::unique_ptr<ListValue> mixed_list(new ListValue()); - mixed_list->Set(0, std::make_unique<Value>(true)); - mixed_list->Set(1, std::make_unique<Value>(42)); - mixed_list->Set(2, std::make_unique<Value>(88.8)); - mixed_list->Set(3, std::make_unique<Value>("foo")); - ASSERT_EQ(4u, mixed_list->GetSize()); - - Value* value = nullptr; - bool bool_value = false; - int int_value = 0; - double double_value = 0.0; - std::string string_value; - - ASSERT_FALSE(mixed_list->Get(4, &value)); - - ASSERT_FALSE(mixed_list->GetInteger(0, &int_value)); - ASSERT_EQ(0, int_value); - ASSERT_FALSE(mixed_list->GetBoolean(1, &bool_value)); - ASSERT_FALSE(bool_value); - ASSERT_FALSE(mixed_list->GetString(2, &string_value)); - ASSERT_EQ("", string_value); - ASSERT_FALSE(mixed_list->GetInteger(2, &int_value)); - ASSERT_EQ(0, int_value); - ASSERT_FALSE(mixed_list->GetBoolean(3, &bool_value)); - ASSERT_FALSE(bool_value); - - ASSERT_TRUE(mixed_list->GetBoolean(0, &bool_value)); - ASSERT_TRUE(bool_value); - ASSERT_TRUE(mixed_list->GetInteger(1, &int_value)); - ASSERT_EQ(42, int_value); - // implicit conversion from Integer to Double should be possible. - ASSERT_TRUE(mixed_list->GetDouble(1, &double_value)); - ASSERT_EQ(42, double_value); - ASSERT_TRUE(mixed_list->GetDouble(2, &double_value)); - ASSERT_EQ(88.8, double_value); - ASSERT_TRUE(mixed_list->GetString(3, &string_value)); - ASSERT_EQ("foo", string_value); - - // Try searching in the mixed list. - base::Value sought_value(42); - base::Value not_found_value(false); - - ASSERT_NE(mixed_list->end(), mixed_list->Find(sought_value)); - ASSERT_TRUE((*mixed_list->Find(sought_value)).GetAsInteger(&int_value)); - ASSERT_EQ(42, int_value); - ASSERT_EQ(mixed_list->end(), mixed_list->Find(not_found_value)); -} - -TEST(ValuesTest, BinaryValue) { - // Default constructor creates a BinaryValue with a buffer of size 0. - auto binary = std::make_unique<Value>(Value::Type::BINARY); - ASSERT_TRUE(binary.get()); - ASSERT_TRUE(binary->GetBlob().empty()); - - // Test the common case of a non-empty buffer - Value::BlobStorage buffer(15); - char* original_buffer = buffer.data(); - binary.reset(new Value(std::move(buffer))); - ASSERT_TRUE(binary.get()); - ASSERT_TRUE(binary->GetBlob().data()); - ASSERT_EQ(original_buffer, binary->GetBlob().data()); - ASSERT_EQ(15U, binary->GetBlob().size()); - - char stack_buffer[42]; - memset(stack_buffer, '!', 42); - binary = Value::CreateWithCopiedBuffer(stack_buffer, 42); - ASSERT_TRUE(binary.get()); - ASSERT_TRUE(binary->GetBlob().data()); - ASSERT_NE(stack_buffer, binary->GetBlob().data()); - ASSERT_EQ(42U, binary->GetBlob().size()); - ASSERT_EQ(0, memcmp(stack_buffer, binary->GetBlob().data(), - binary->GetBlob().size())); -} - -TEST(ValuesTest, StringValue) { - // Test overloaded StringValue constructor. - std::unique_ptr<Value> narrow_value(new Value("narrow")); - ASSERT_TRUE(narrow_value.get()); - ASSERT_TRUE(narrow_value->is_string()); - std::unique_ptr<Value> utf16_value(new Value(ASCIIToUTF16("utf16"))); - ASSERT_TRUE(utf16_value.get()); - ASSERT_TRUE(utf16_value->is_string()); - - // Test overloaded GetAsString. - std::string narrow = "http://google.com"; - string16 utf16 = ASCIIToUTF16("http://google.com"); - const Value* string_value = nullptr; - ASSERT_TRUE(narrow_value->GetAsString(&narrow)); - ASSERT_TRUE(narrow_value->GetAsString(&utf16)); - ASSERT_TRUE(narrow_value->GetAsString(&string_value)); - ASSERT_EQ(std::string("narrow"), narrow); - ASSERT_EQ(ASCIIToUTF16("narrow"), utf16); - ASSERT_EQ(string_value->GetString(), narrow); - - ASSERT_TRUE(utf16_value->GetAsString(&narrow)); - ASSERT_TRUE(utf16_value->GetAsString(&utf16)); - ASSERT_TRUE(utf16_value->GetAsString(&string_value)); - ASSERT_EQ(std::string("utf16"), narrow); - ASSERT_EQ(ASCIIToUTF16("utf16"), utf16); - ASSERT_EQ(string_value->GetString(), narrow); - - // Don't choke on NULL values. - ASSERT_TRUE(narrow_value->GetAsString(static_cast<string16*>(nullptr))); - ASSERT_TRUE(narrow_value->GetAsString(static_cast<std::string*>(nullptr))); - ASSERT_TRUE(narrow_value->GetAsString(static_cast<const Value**>(nullptr))); -} - -TEST(ValuesTest, ListDeletion) { - ListValue list; - list.Append(std::make_unique<Value>()); - EXPECT_FALSE(list.empty()); - list.Clear(); - EXPECT_TRUE(list.empty()); -} - -TEST(ValuesTest, ListRemoval) { - std::unique_ptr<Value> removed_item; - - { - ListValue list; - list.Append(std::make_unique<Value>()); - EXPECT_EQ(1U, list.GetSize()); - EXPECT_FALSE(list.Remove(std::numeric_limits<size_t>::max(), - &removed_item)); - EXPECT_FALSE(list.Remove(1, &removed_item)); - EXPECT_TRUE(list.Remove(0, &removed_item)); - ASSERT_TRUE(removed_item); - EXPECT_EQ(0U, list.GetSize()); - } - removed_item.reset(); - - { - ListValue list; - list.Append(std::make_unique<Value>()); - EXPECT_TRUE(list.Remove(0, nullptr)); - EXPECT_EQ(0U, list.GetSize()); - } - - { - ListValue list; - auto value = std::make_unique<Value>(); - Value original_value = value->Clone(); - list.Append(std::move(value)); - size_t index = 0; - list.Remove(original_value, &index); - EXPECT_EQ(0U, index); - EXPECT_EQ(0U, list.GetSize()); - } -} - -TEST(ValuesTest, DictionaryDeletion) { - std::string key = "test"; - DictionaryValue dict; - dict.Set(key, std::make_unique<Value>()); - EXPECT_FALSE(dict.empty()); - EXPECT_FALSE(dict.DictEmpty()); - EXPECT_EQ(1U, dict.DictSize()); - dict.Clear(); - EXPECT_TRUE(dict.empty()); - EXPECT_TRUE(dict.DictEmpty()); - EXPECT_EQ(0U, dict.DictSize()); -} - -TEST(ValuesTest, DictionarySetReturnsPointer) { - { - DictionaryValue dict; - Value* blank_ptr = dict.Set("foo.bar", std::make_unique<base::Value>()); - EXPECT_EQ(Value::Type::NONE, blank_ptr->type()); - } - - { - DictionaryValue dict; - Value* blank_ptr = dict.SetWithoutPathExpansion( - "foo.bar", std::make_unique<base::Value>()); - EXPECT_EQ(Value::Type::NONE, blank_ptr->type()); - } - - { - DictionaryValue dict; - Value* int_ptr = dict.SetInteger("foo.bar", 42); - EXPECT_EQ(Value::Type::INTEGER, int_ptr->type()); - EXPECT_EQ(42, int_ptr->GetInt()); - } - - { - DictionaryValue dict; - Value* double_ptr = dict.SetDouble("foo.bar", 3.142); - EXPECT_EQ(Value::Type::DOUBLE, double_ptr->type()); - EXPECT_EQ(3.142, double_ptr->GetDouble()); - } - - { - DictionaryValue dict; - Value* string_ptr = dict.SetString("foo.bar", "foo"); - EXPECT_EQ(Value::Type::STRING, string_ptr->type()); - EXPECT_EQ("foo", string_ptr->GetString()); - } - - { - DictionaryValue dict; - Value* string16_ptr = dict.SetString("foo.bar", ASCIIToUTF16("baz")); - EXPECT_EQ(Value::Type::STRING, string16_ptr->type()); - EXPECT_EQ("baz", string16_ptr->GetString()); - } - - { - DictionaryValue dict; - DictionaryValue* dict_ptr = dict.SetDictionary( - "foo.bar", std::make_unique<base::DictionaryValue>()); - EXPECT_EQ(Value::Type::DICTIONARY, dict_ptr->type()); - } - - { - DictionaryValue dict; - ListValue* list_ptr = - dict.SetList("foo.bar", std::make_unique<base::ListValue>()); - EXPECT_EQ(Value::Type::LIST, list_ptr->type()); - } -} - -TEST(ValuesTest, DictionaryRemoval) { - std::string key = "test"; - std::unique_ptr<Value> removed_item; - - { - DictionaryValue dict; - EXPECT_EQ(0U, dict.DictSize()); - EXPECT_TRUE(dict.DictEmpty()); - dict.Set(key, std::make_unique<Value>()); - EXPECT_TRUE(dict.HasKey(key)); - EXPECT_FALSE(dict.Remove("absent key", &removed_item)); - EXPECT_EQ(1U, dict.DictSize()); - EXPECT_FALSE(dict.DictEmpty()); - - EXPECT_TRUE(dict.Remove(key, &removed_item)); - EXPECT_FALSE(dict.HasKey(key)); - ASSERT_TRUE(removed_item); - EXPECT_EQ(0U, dict.DictSize()); - EXPECT_TRUE(dict.DictEmpty()); - } - - { - DictionaryValue dict; - dict.Set(key, std::make_unique<Value>()); - EXPECT_TRUE(dict.HasKey(key)); - EXPECT_TRUE(dict.Remove(key, nullptr)); - EXPECT_FALSE(dict.HasKey(key)); - } -} - -TEST(ValuesTest, DictionaryWithoutPathExpansion) { - DictionaryValue dict; - dict.Set("this.is.expanded", std::make_unique<Value>()); - dict.SetWithoutPathExpansion("this.isnt.expanded", std::make_unique<Value>()); - - EXPECT_FALSE(dict.HasKey("this.is.expanded")); - EXPECT_TRUE(dict.HasKey("this")); - Value* value1; - EXPECT_TRUE(dict.Get("this", &value1)); - DictionaryValue* value2; - ASSERT_TRUE(dict.GetDictionaryWithoutPathExpansion("this", &value2)); - EXPECT_EQ(value1, value2); - EXPECT_EQ(1U, value2->size()); - - EXPECT_TRUE(dict.HasKey("this.isnt.expanded")); - Value* value3; - EXPECT_FALSE(dict.Get("this.isnt.expanded", &value3)); - Value* value4; - ASSERT_TRUE(dict.GetWithoutPathExpansion("this.isnt.expanded", &value4)); - EXPECT_EQ(Value::Type::NONE, value4->type()); -} - -// Tests the deprecated version of SetWithoutPathExpansion. -// TODO(estade): remove. -TEST(ValuesTest, DictionaryWithoutPathExpansionDeprecated) { - DictionaryValue dict; - dict.Set("this.is.expanded", std::make_unique<Value>()); - dict.SetWithoutPathExpansion("this.isnt.expanded", std::make_unique<Value>()); - - EXPECT_FALSE(dict.HasKey("this.is.expanded")); - EXPECT_TRUE(dict.HasKey("this")); - Value* value1; - EXPECT_TRUE(dict.Get("this", &value1)); - DictionaryValue* value2; - ASSERT_TRUE(dict.GetDictionaryWithoutPathExpansion("this", &value2)); - EXPECT_EQ(value1, value2); - EXPECT_EQ(1U, value2->size()); - - EXPECT_TRUE(dict.HasKey("this.isnt.expanded")); - Value* value3; - EXPECT_FALSE(dict.Get("this.isnt.expanded", &value3)); - Value* value4; - ASSERT_TRUE(dict.GetWithoutPathExpansion("this.isnt.expanded", &value4)); - EXPECT_EQ(Value::Type::NONE, value4->type()); -} - -TEST(ValuesTest, DictionaryRemovePath) { - DictionaryValue dict; - dict.SetInteger("a.long.way.down", 1); - dict.SetBoolean("a.long.key.path", true); - - std::unique_ptr<Value> removed_item; - EXPECT_TRUE(dict.RemovePath("a.long.way.down", &removed_item)); - ASSERT_TRUE(removed_item); - EXPECT_TRUE(removed_item->is_int()); - EXPECT_FALSE(dict.HasKey("a.long.way.down")); - EXPECT_FALSE(dict.HasKey("a.long.way")); - EXPECT_TRUE(dict.Get("a.long.key.path", nullptr)); - - removed_item.reset(); - EXPECT_FALSE(dict.RemovePath("a.long.way.down", &removed_item)); - EXPECT_FALSE(removed_item); - EXPECT_TRUE(dict.Get("a.long.key.path", nullptr)); - - removed_item.reset(); - EXPECT_TRUE(dict.RemovePath("a.long.key.path", &removed_item)); - ASSERT_TRUE(removed_item); - EXPECT_TRUE(removed_item->is_bool()); - EXPECT_TRUE(dict.empty()); -} - -TEST(ValuesTest, DeepCopy) { - DictionaryValue original_dict; - Value* null_weak = original_dict.Set("null", std::make_unique<Value>()); - Value* bool_weak = original_dict.Set("bool", std::make_unique<Value>(true)); - Value* int_weak = original_dict.Set("int", std::make_unique<Value>(42)); - Value* double_weak = - original_dict.Set("double", std::make_unique<Value>(3.14)); - Value* string_weak = - original_dict.Set("string", std::make_unique<Value>("hello")); - Value* string16_weak = original_dict.Set( - "string16", std::make_unique<Value>(ASCIIToUTF16("hello16"))); - - Value* binary_weak = original_dict.Set( - "binary", std::make_unique<Value>(Value::BlobStorage(42, '!'))); - - Value::ListStorage storage; - storage.emplace_back(0); - storage.emplace_back(1); - Value* list_weak = - original_dict.Set("list", std::make_unique<Value>(std::move(storage))); - Value* list_element_0_weak = &list_weak->GetList()[0]; - Value* list_element_1_weak = &list_weak->GetList()[1]; - - DictionaryValue* dict_weak = original_dict.SetDictionary( - "dictionary", std::make_unique<DictionaryValue>()); - dict_weak->SetString("key", "value"); - - auto copy_dict = original_dict.CreateDeepCopy(); - ASSERT_TRUE(copy_dict.get()); - ASSERT_NE(copy_dict.get(), &original_dict); - - Value* copy_null = nullptr; - ASSERT_TRUE(copy_dict->Get("null", ©_null)); - ASSERT_TRUE(copy_null); - ASSERT_NE(copy_null, null_weak); - ASSERT_TRUE(copy_null->is_none()); - - Value* copy_bool = nullptr; - ASSERT_TRUE(copy_dict->Get("bool", ©_bool)); - ASSERT_TRUE(copy_bool); - ASSERT_NE(copy_bool, bool_weak); - ASSERT_TRUE(copy_bool->is_bool()); - bool copy_bool_value = false; - ASSERT_TRUE(copy_bool->GetAsBoolean(©_bool_value)); - ASSERT_TRUE(copy_bool_value); - - Value* copy_int = nullptr; - ASSERT_TRUE(copy_dict->Get("int", ©_int)); - ASSERT_TRUE(copy_int); - ASSERT_NE(copy_int, int_weak); - ASSERT_TRUE(copy_int->is_int()); - int copy_int_value = 0; - ASSERT_TRUE(copy_int->GetAsInteger(©_int_value)); - ASSERT_EQ(42, copy_int_value); - - Value* copy_double = nullptr; - ASSERT_TRUE(copy_dict->Get("double", ©_double)); - ASSERT_TRUE(copy_double); - ASSERT_NE(copy_double, double_weak); - ASSERT_TRUE(copy_double->is_double()); - double copy_double_value = 0; - ASSERT_TRUE(copy_double->GetAsDouble(©_double_value)); - ASSERT_EQ(3.14, copy_double_value); - - Value* copy_string = nullptr; - ASSERT_TRUE(copy_dict->Get("string", ©_string)); - ASSERT_TRUE(copy_string); - ASSERT_NE(copy_string, string_weak); - ASSERT_TRUE(copy_string->is_string()); - std::string copy_string_value; - string16 copy_string16_value; - ASSERT_TRUE(copy_string->GetAsString(©_string_value)); - ASSERT_TRUE(copy_string->GetAsString(©_string16_value)); - ASSERT_EQ(std::string("hello"), copy_string_value); - ASSERT_EQ(ASCIIToUTF16("hello"), copy_string16_value); - - Value* copy_string16 = nullptr; - ASSERT_TRUE(copy_dict->Get("string16", ©_string16)); - ASSERT_TRUE(copy_string16); - ASSERT_NE(copy_string16, string16_weak); - ASSERT_TRUE(copy_string16->is_string()); - ASSERT_TRUE(copy_string16->GetAsString(©_string_value)); - ASSERT_TRUE(copy_string16->GetAsString(©_string16_value)); - ASSERT_EQ(std::string("hello16"), copy_string_value); - ASSERT_EQ(ASCIIToUTF16("hello16"), copy_string16_value); - - Value* copy_binary = nullptr; - ASSERT_TRUE(copy_dict->Get("binary", ©_binary)); - ASSERT_TRUE(copy_binary); - ASSERT_NE(copy_binary, binary_weak); - ASSERT_TRUE(copy_binary->is_blob()); - ASSERT_NE(binary_weak->GetBlob().data(), copy_binary->GetBlob().data()); - ASSERT_EQ(binary_weak->GetBlob(), copy_binary->GetBlob()); - - Value* copy_value = nullptr; - ASSERT_TRUE(copy_dict->Get("list", ©_value)); - ASSERT_TRUE(copy_value); - ASSERT_NE(copy_value, list_weak); - ASSERT_TRUE(copy_value->is_list()); - ListValue* copy_list = nullptr; - ASSERT_TRUE(copy_value->GetAsList(©_list)); - ASSERT_TRUE(copy_list); - ASSERT_EQ(2U, copy_list->GetSize()); - - Value* copy_list_element_0; - ASSERT_TRUE(copy_list->Get(0, ©_list_element_0)); - ASSERT_TRUE(copy_list_element_0); - ASSERT_NE(copy_list_element_0, list_element_0_weak); - int copy_list_element_0_value; - ASSERT_TRUE(copy_list_element_0->GetAsInteger(©_list_element_0_value)); - ASSERT_EQ(0, copy_list_element_0_value); - - Value* copy_list_element_1; - ASSERT_TRUE(copy_list->Get(1, ©_list_element_1)); - ASSERT_TRUE(copy_list_element_1); - ASSERT_NE(copy_list_element_1, list_element_1_weak); - int copy_list_element_1_value; - ASSERT_TRUE(copy_list_element_1->GetAsInteger(©_list_element_1_value)); - ASSERT_EQ(1, copy_list_element_1_value); - - copy_value = nullptr; - ASSERT_TRUE(copy_dict->Get("dictionary", ©_value)); - ASSERT_TRUE(copy_value); - ASSERT_NE(copy_value, dict_weak); - ASSERT_TRUE(copy_value->is_dict()); - DictionaryValue* copy_nested_dictionary = nullptr; - ASSERT_TRUE(copy_value->GetAsDictionary(©_nested_dictionary)); - ASSERT_TRUE(copy_nested_dictionary); - EXPECT_TRUE(copy_nested_dictionary->HasKey("key")); -} - -TEST(ValuesTest, Equals) { - auto null1 = std::make_unique<Value>(); - auto null2 = std::make_unique<Value>(); - EXPECT_NE(null1.get(), null2.get()); - EXPECT_EQ(*null1, *null2); - - Value boolean(false); - EXPECT_NE(*null1, boolean); - - DictionaryValue dv; - dv.SetBoolean("a", false); - dv.SetInteger("b", 2); - dv.SetDouble("c", 2.5); - dv.SetString("d1", "string"); - dv.SetString("d2", ASCIIToUTF16("http://google.com")); - dv.Set("e", std::make_unique<Value>()); - - auto copy = dv.CreateDeepCopy(); - EXPECT_EQ(dv, *copy); - - std::unique_ptr<ListValue> list(new ListValue); - list->Append(std::make_unique<Value>()); - list->Append(WrapUnique(new DictionaryValue)); - auto list_copy = std::make_unique<Value>(list->Clone()); - - ListValue* list_weak = dv.SetList("f", std::move(list)); - EXPECT_NE(dv, *copy); - copy->Set("f", std::move(list_copy)); - EXPECT_EQ(dv, *copy); - - list_weak->Append(std::make_unique<Value>(true)); - EXPECT_NE(dv, *copy); - - // Check if Equals detects differences in only the keys. - copy = dv.CreateDeepCopy(); - EXPECT_EQ(dv, *copy); - copy->Remove("a", nullptr); - copy->SetBoolean("aa", false); - EXPECT_NE(dv, *copy); -} - -TEST(ValuesTest, Comparisons) { - // Test None Values. - Value null1; - Value null2; - EXPECT_EQ(null1, null2); - EXPECT_FALSE(null1 != null2); - EXPECT_FALSE(null1 < null2); - EXPECT_FALSE(null1 > null2); - EXPECT_LE(null1, null2); - EXPECT_GE(null1, null2); - - // Test Bool Values. - Value bool1(false); - Value bool2(true); - EXPECT_FALSE(bool1 == bool2); - EXPECT_NE(bool1, bool2); - EXPECT_LT(bool1, bool2); - EXPECT_FALSE(bool1 > bool2); - EXPECT_LE(bool1, bool2); - EXPECT_FALSE(bool1 >= bool2); - - // Test Int Values. - Value int1(1); - Value int2(2); - EXPECT_FALSE(int1 == int2); - EXPECT_NE(int1, int2); - EXPECT_LT(int1, int2); - EXPECT_FALSE(int1 > int2); - EXPECT_LE(int1, int2); - EXPECT_FALSE(int1 >= int2); - - // Test Double Values. - Value double1(1.0); - Value double2(2.0); - EXPECT_FALSE(double1 == double2); - EXPECT_NE(double1, double2); - EXPECT_LT(double1, double2); - EXPECT_FALSE(double1 > double2); - EXPECT_LE(double1, double2); - EXPECT_FALSE(double1 >= double2); - - // Test String Values. - Value string1("1"); - Value string2("2"); - EXPECT_FALSE(string1 == string2); - EXPECT_NE(string1, string2); - EXPECT_LT(string1, string2); - EXPECT_FALSE(string1 > string2); - EXPECT_LE(string1, string2); - EXPECT_FALSE(string1 >= string2); - - // Test Binary Values. - Value binary1(Value::BlobStorage{0x01}); - Value binary2(Value::BlobStorage{0x02}); - EXPECT_FALSE(binary1 == binary2); - EXPECT_NE(binary1, binary2); - EXPECT_LT(binary1, binary2); - EXPECT_FALSE(binary1 > binary2); - EXPECT_LE(binary1, binary2); - EXPECT_FALSE(binary1 >= binary2); - - // Test Empty List Values. - ListValue null_list1; - ListValue null_list2; - EXPECT_EQ(null_list1, null_list2); - EXPECT_FALSE(null_list1 != null_list2); - EXPECT_FALSE(null_list1 < null_list2); - EXPECT_FALSE(null_list1 > null_list2); - EXPECT_LE(null_list1, null_list2); - EXPECT_GE(null_list1, null_list2); - - // Test Non Empty List Values. - ListValue int_list1; - ListValue int_list2; - int_list1.AppendInteger(1); - int_list2.AppendInteger(2); - EXPECT_FALSE(int_list1 == int_list2); - EXPECT_NE(int_list1, int_list2); - EXPECT_LT(int_list1, int_list2); - EXPECT_FALSE(int_list1 > int_list2); - EXPECT_LE(int_list1, int_list2); - EXPECT_FALSE(int_list1 >= int_list2); - - // Test Empty Dict Values. - DictionaryValue null_dict1; - DictionaryValue null_dict2; - EXPECT_EQ(null_dict1, null_dict2); - EXPECT_FALSE(null_dict1 != null_dict2); - EXPECT_FALSE(null_dict1 < null_dict2); - EXPECT_FALSE(null_dict1 > null_dict2); - EXPECT_LE(null_dict1, null_dict2); - EXPECT_GE(null_dict1, null_dict2); - - // Test Non Empty Dict Values. - DictionaryValue int_dict1; - DictionaryValue int_dict2; - int_dict1.SetInteger("key", 1); - int_dict2.SetInteger("key", 2); - EXPECT_FALSE(int_dict1 == int_dict2); - EXPECT_NE(int_dict1, int_dict2); - EXPECT_LT(int_dict1, int_dict2); - EXPECT_FALSE(int_dict1 > int_dict2); - EXPECT_LE(int_dict1, int_dict2); - EXPECT_FALSE(int_dict1 >= int_dict2); - - // Test Values of different types. - std::vector<Value> values; - values.emplace_back(std::move(null1)); - values.emplace_back(std::move(bool1)); - values.emplace_back(std::move(int1)); - values.emplace_back(std::move(double1)); - values.emplace_back(std::move(string1)); - values.emplace_back(std::move(binary1)); - values.emplace_back(std::move(int_dict1)); - values.emplace_back(std::move(int_list1)); - for (size_t i = 0; i < values.size(); ++i) { - for (size_t j = i + 1; j < values.size(); ++j) { - EXPECT_FALSE(values[i] == values[j]); - EXPECT_NE(values[i], values[j]); - EXPECT_LT(values[i], values[j]); - EXPECT_FALSE(values[i] > values[j]); - EXPECT_LE(values[i], values[j]); - EXPECT_FALSE(values[i] >= values[j]); - } - } -} - -TEST(ValuesTest, DeepCopyCovariantReturnTypes) { - DictionaryValue original_dict; - Value* null_weak = original_dict.SetKey("null", Value()); - Value* bool_weak = original_dict.SetKey("bool", Value(true)); - Value* int_weak = original_dict.SetKey("int", Value(42)); - Value* double_weak = original_dict.SetKey("double", Value(3.14)); - Value* string_weak = original_dict.SetKey("string", Value("hello")); - Value* string16_weak = - original_dict.SetKey("string16", Value(ASCIIToUTF16("hello16"))); - Value* binary_weak = - original_dict.SetKey("binary", Value(Value::BlobStorage(42, '!'))); - - Value::ListStorage storage; - storage.emplace_back(0); - storage.emplace_back(1); - Value* list_weak = original_dict.SetKey("list", Value(std::move(storage))); - - auto copy_dict = std::make_unique<Value>(original_dict.Clone()); - auto copy_null = std::make_unique<Value>(null_weak->Clone()); - auto copy_bool = std::make_unique<Value>(bool_weak->Clone()); - auto copy_int = std::make_unique<Value>(int_weak->Clone()); - auto copy_double = std::make_unique<Value>(double_weak->Clone()); - auto copy_string = std::make_unique<Value>(string_weak->Clone()); - auto copy_string16 = std::make_unique<Value>(string16_weak->Clone()); - auto copy_binary = std::make_unique<Value>(binary_weak->Clone()); - auto copy_list = std::make_unique<Value>(list_weak->Clone()); - - EXPECT_EQ(original_dict, *copy_dict); - EXPECT_EQ(*null_weak, *copy_null); - EXPECT_EQ(*bool_weak, *copy_bool); - EXPECT_EQ(*int_weak, *copy_int); - EXPECT_EQ(*double_weak, *copy_double); - EXPECT_EQ(*string_weak, *copy_string); - EXPECT_EQ(*string16_weak, *copy_string16); - EXPECT_EQ(*binary_weak, *copy_binary); - EXPECT_EQ(*list_weak, *copy_list); -} - -TEST(ValuesTest, RemoveEmptyChildren) { - auto root = std::make_unique<DictionaryValue>(); - // Remove empty lists and dictionaries. - root->Set("empty_dict", std::make_unique<DictionaryValue>()); - root->Set("empty_list", std::make_unique<ListValue>()); - root->SetWithoutPathExpansion("a.b.c.d.e", - std::make_unique<DictionaryValue>()); - root = root->DeepCopyWithoutEmptyChildren(); - EXPECT_TRUE(root->empty()); - - // Make sure we don't prune too much. - root->SetBoolean("bool", true); - root->Set("empty_dict", std::make_unique<DictionaryValue>()); - root->SetString("empty_string", std::string()); - root = root->DeepCopyWithoutEmptyChildren(); - EXPECT_EQ(2U, root->size()); - - // Should do nothing. - root = root->DeepCopyWithoutEmptyChildren(); - EXPECT_EQ(2U, root->size()); - - // Nested test cases. These should all reduce back to the bool and string - // set above. - { - root->Set("a.b.c.d.e", std::make_unique<DictionaryValue>()); - root = root->DeepCopyWithoutEmptyChildren(); - EXPECT_EQ(2U, root->size()); - } - { - auto inner = std::make_unique<DictionaryValue>(); - inner->Set("empty_dict", std::make_unique<DictionaryValue>()); - inner->Set("empty_list", std::make_unique<ListValue>()); - root->Set("dict_with_empty_children", std::move(inner)); - root = root->DeepCopyWithoutEmptyChildren(); - EXPECT_EQ(2U, root->size()); - } - { - auto inner = std::make_unique<ListValue>(); - inner->Append(std::make_unique<DictionaryValue>()); - inner->Append(std::make_unique<ListValue>()); - root->Set("list_with_empty_children", std::move(inner)); - root = root->DeepCopyWithoutEmptyChildren(); - EXPECT_EQ(2U, root->size()); - } - - // Nested with siblings. - { - auto inner = std::make_unique<ListValue>(); - inner->Append(std::make_unique<DictionaryValue>()); - inner->Append(std::make_unique<ListValue>()); - root->Set("list_with_empty_children", std::move(inner)); - auto inner2 = std::make_unique<DictionaryValue>(); - inner2->Set("empty_dict", std::make_unique<DictionaryValue>()); - inner2->Set("empty_list", std::make_unique<ListValue>()); - root->Set("dict_with_empty_children", std::move(inner2)); - root = root->DeepCopyWithoutEmptyChildren(); - EXPECT_EQ(2U, root->size()); - } - - // Make sure nested values don't get pruned. - { - auto inner = std::make_unique<ListValue>(); - auto inner2 = std::make_unique<ListValue>(); - inner2->Append(std::make_unique<Value>("hello")); - inner->Append(std::make_unique<DictionaryValue>()); - inner->Append(std::move(inner2)); - root->Set("list_with_empty_children", std::move(inner)); - root = root->DeepCopyWithoutEmptyChildren(); - EXPECT_EQ(3U, root->size()); - - ListValue* inner_value, *inner_value2; - EXPECT_TRUE(root->GetList("list_with_empty_children", &inner_value)); - EXPECT_EQ(1U, inner_value->GetSize()); // Dictionary was pruned. - EXPECT_TRUE(inner_value->GetList(0, &inner_value2)); - EXPECT_EQ(1U, inner_value2->GetSize()); - } -} - -TEST(ValuesTest, MergeDictionary) { - std::unique_ptr<DictionaryValue> base(new DictionaryValue); - base->SetString("base_key", "base_key_value_base"); - base->SetString("collide_key", "collide_key_value_base"); - std::unique_ptr<DictionaryValue> base_sub_dict(new DictionaryValue); - base_sub_dict->SetString("sub_base_key", "sub_base_key_value_base"); - base_sub_dict->SetString("sub_collide_key", "sub_collide_key_value_base"); - base->Set("sub_dict_key", std::move(base_sub_dict)); - - std::unique_ptr<DictionaryValue> merge(new DictionaryValue); - merge->SetString("merge_key", "merge_key_value_merge"); - merge->SetString("collide_key", "collide_key_value_merge"); - std::unique_ptr<DictionaryValue> merge_sub_dict(new DictionaryValue); - merge_sub_dict->SetString("sub_merge_key", "sub_merge_key_value_merge"); - merge_sub_dict->SetString("sub_collide_key", "sub_collide_key_value_merge"); - merge->Set("sub_dict_key", std::move(merge_sub_dict)); - - base->MergeDictionary(merge.get()); - - EXPECT_EQ(4U, base->size()); - std::string base_key_value; - EXPECT_TRUE(base->GetString("base_key", &base_key_value)); - EXPECT_EQ("base_key_value_base", base_key_value); // Base value preserved. - std::string collide_key_value; - EXPECT_TRUE(base->GetString("collide_key", &collide_key_value)); - EXPECT_EQ("collide_key_value_merge", collide_key_value); // Replaced. - std::string merge_key_value; - EXPECT_TRUE(base->GetString("merge_key", &merge_key_value)); - EXPECT_EQ("merge_key_value_merge", merge_key_value); // Merged in. - - DictionaryValue* res_sub_dict; - EXPECT_TRUE(base->GetDictionary("sub_dict_key", &res_sub_dict)); - EXPECT_EQ(3U, res_sub_dict->size()); - std::string sub_base_key_value; - EXPECT_TRUE(res_sub_dict->GetString("sub_base_key", &sub_base_key_value)); - EXPECT_EQ("sub_base_key_value_base", sub_base_key_value); // Preserved. - std::string sub_collide_key_value; - EXPECT_TRUE(res_sub_dict->GetString("sub_collide_key", - &sub_collide_key_value)); - EXPECT_EQ("sub_collide_key_value_merge", sub_collide_key_value); // Replaced. - std::string sub_merge_key_value; - EXPECT_TRUE(res_sub_dict->GetString("sub_merge_key", &sub_merge_key_value)); - EXPECT_EQ("sub_merge_key_value_merge", sub_merge_key_value); // Merged in. -} - -TEST(ValuesTest, MergeDictionaryDeepCopy) { - std::unique_ptr<DictionaryValue> child(new DictionaryValue); - DictionaryValue* original_child = child.get(); - child->SetString("test", "value"); - EXPECT_EQ(1U, child->size()); - - std::string value; - EXPECT_TRUE(child->GetString("test", &value)); - EXPECT_EQ("value", value); - - std::unique_ptr<DictionaryValue> base(new DictionaryValue); - base->Set("dict", std::move(child)); - EXPECT_EQ(1U, base->size()); - - DictionaryValue* ptr; - EXPECT_TRUE(base->GetDictionary("dict", &ptr)); - EXPECT_EQ(original_child, ptr); - - std::unique_ptr<DictionaryValue> merged(new DictionaryValue); - merged->MergeDictionary(base.get()); - EXPECT_EQ(1U, merged->size()); - EXPECT_TRUE(merged->GetDictionary("dict", &ptr)); - EXPECT_NE(original_child, ptr); - EXPECT_TRUE(ptr->GetString("test", &value)); - EXPECT_EQ("value", value); - - original_child->SetString("test", "overwrite"); - base.reset(); - EXPECT_TRUE(ptr->GetString("test", &value)); - EXPECT_EQ("value", value); -} - -TEST(ValuesTest, DictionaryIterator) { - DictionaryValue dict; - for (DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) { - ADD_FAILURE(); - } - - Value value1("value1"); - dict.SetKey("key1", value1.Clone()); - bool seen1 = false; - for (DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) { - EXPECT_FALSE(seen1); - EXPECT_EQ("key1", it.key()); - EXPECT_EQ(value1, it.value()); - seen1 = true; - } - EXPECT_TRUE(seen1); - - Value value2("value2"); - dict.SetKey("key2", value2.Clone()); - bool seen2 = seen1 = false; - for (DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) { - if (it.key() == "key1") { - EXPECT_FALSE(seen1); - EXPECT_EQ(value1, it.value()); - seen1 = true; - } else if (it.key() == "key2") { - EXPECT_FALSE(seen2); - EXPECT_EQ(value2, it.value()); - seen2 = true; - } else { - ADD_FAILURE(); - } - } - EXPECT_TRUE(seen1); - EXPECT_TRUE(seen2); -} - -TEST(ValuesTest, StdDictionaryIterator) { - DictionaryValue dict; - for (auto it = dict.begin(); it != dict.end(); ++it) { - ADD_FAILURE(); - } - - Value value1("value1"); - dict.SetKey("key1", value1.Clone()); - bool seen1 = false; - for (const auto& it : dict) { - EXPECT_FALSE(seen1); - EXPECT_EQ("key1", it.first); - EXPECT_EQ(value1, *it.second); - seen1 = true; - } - EXPECT_TRUE(seen1); - - Value value2("value2"); - dict.SetKey("key2", value2.Clone()); - bool seen2 = seen1 = false; - for (const auto& it : dict) { - if (it.first == "key1") { - EXPECT_FALSE(seen1); - EXPECT_EQ(value1, *it.second); - seen1 = true; - } else if (it.first == "key2") { - EXPECT_FALSE(seen2); - EXPECT_EQ(value2, *it.second); - seen2 = true; - } else { - ADD_FAILURE(); - } - } - EXPECT_TRUE(seen1); - EXPECT_TRUE(seen2); -} - -// DictionaryValue/ListValue's Get*() methods should accept NULL as an out-value -// and still return true/false based on success. -TEST(ValuesTest, GetWithNullOutValue) { - DictionaryValue main_dict; - ListValue main_list; - - Value bool_value(false); - Value int_value(1234); - Value double_value(12.34567); - Value string_value("foo"); - Value binary_value(Value::Type::BINARY); - DictionaryValue dict_value; - ListValue list_value; - - main_dict.SetKey("bool", bool_value.Clone()); - main_dict.SetKey("int", int_value.Clone()); - main_dict.SetKey("double", double_value.Clone()); - main_dict.SetKey("string", string_value.Clone()); - main_dict.SetKey("binary", binary_value.Clone()); - main_dict.SetKey("dict", dict_value.Clone()); - main_dict.SetKey("list", list_value.Clone()); - - main_list.Append(std::make_unique<Value>(bool_value.Clone())); - main_list.Append(std::make_unique<Value>(int_value.Clone())); - main_list.Append(std::make_unique<Value>(double_value.Clone())); - main_list.Append(std::make_unique<Value>(string_value.Clone())); - main_list.Append(std::make_unique<Value>(binary_value.Clone())); - main_list.Append(std::make_unique<Value>(dict_value.Clone())); - main_list.Append(std::make_unique<Value>(list_value.Clone())); - - EXPECT_TRUE(main_dict.Get("bool", nullptr)); - EXPECT_TRUE(main_dict.Get("int", nullptr)); - EXPECT_TRUE(main_dict.Get("double", nullptr)); - EXPECT_TRUE(main_dict.Get("string", nullptr)); - EXPECT_TRUE(main_dict.Get("binary", nullptr)); - EXPECT_TRUE(main_dict.Get("dict", nullptr)); - EXPECT_TRUE(main_dict.Get("list", nullptr)); - EXPECT_FALSE(main_dict.Get("DNE", nullptr)); - - EXPECT_TRUE(main_dict.GetBoolean("bool", nullptr)); - EXPECT_FALSE(main_dict.GetBoolean("int", nullptr)); - EXPECT_FALSE(main_dict.GetBoolean("double", nullptr)); - EXPECT_FALSE(main_dict.GetBoolean("string", nullptr)); - EXPECT_FALSE(main_dict.GetBoolean("binary", nullptr)); - EXPECT_FALSE(main_dict.GetBoolean("dict", nullptr)); - EXPECT_FALSE(main_dict.GetBoolean("list", nullptr)); - EXPECT_FALSE(main_dict.GetBoolean("DNE", nullptr)); - - EXPECT_FALSE(main_dict.GetInteger("bool", nullptr)); - EXPECT_TRUE(main_dict.GetInteger("int", nullptr)); - EXPECT_FALSE(main_dict.GetInteger("double", nullptr)); - EXPECT_FALSE(main_dict.GetInteger("string", nullptr)); - EXPECT_FALSE(main_dict.GetInteger("binary", nullptr)); - EXPECT_FALSE(main_dict.GetInteger("dict", nullptr)); - EXPECT_FALSE(main_dict.GetInteger("list", nullptr)); - EXPECT_FALSE(main_dict.GetInteger("DNE", nullptr)); - - // Both int and double values can be obtained from GetDouble. - EXPECT_FALSE(main_dict.GetDouble("bool", nullptr)); - EXPECT_TRUE(main_dict.GetDouble("int", nullptr)); - EXPECT_TRUE(main_dict.GetDouble("double", nullptr)); - EXPECT_FALSE(main_dict.GetDouble("string", nullptr)); - EXPECT_FALSE(main_dict.GetDouble("binary", nullptr)); - EXPECT_FALSE(main_dict.GetDouble("dict", nullptr)); - EXPECT_FALSE(main_dict.GetDouble("list", nullptr)); - EXPECT_FALSE(main_dict.GetDouble("DNE", nullptr)); - - EXPECT_FALSE(main_dict.GetString("bool", static_cast<std::string*>(nullptr))); - EXPECT_FALSE(main_dict.GetString("int", static_cast<std::string*>(nullptr))); - EXPECT_FALSE( - main_dict.GetString("double", static_cast<std::string*>(nullptr))); - EXPECT_TRUE( - main_dict.GetString("string", static_cast<std::string*>(nullptr))); - EXPECT_FALSE( - main_dict.GetString("binary", static_cast<std::string*>(nullptr))); - EXPECT_FALSE(main_dict.GetString("dict", static_cast<std::string*>(nullptr))); - EXPECT_FALSE(main_dict.GetString("list", static_cast<std::string*>(nullptr))); - EXPECT_FALSE(main_dict.GetString("DNE", static_cast<std::string*>(nullptr))); - - EXPECT_FALSE(main_dict.GetString("bool", static_cast<string16*>(nullptr))); - EXPECT_FALSE(main_dict.GetString("int", static_cast<string16*>(nullptr))); - EXPECT_FALSE(main_dict.GetString("double", static_cast<string16*>(nullptr))); - EXPECT_TRUE(main_dict.GetString("string", static_cast<string16*>(nullptr))); - EXPECT_FALSE(main_dict.GetString("binary", static_cast<string16*>(nullptr))); - EXPECT_FALSE(main_dict.GetString("dict", static_cast<string16*>(nullptr))); - EXPECT_FALSE(main_dict.GetString("list", static_cast<string16*>(nullptr))); - EXPECT_FALSE(main_dict.GetString("DNE", static_cast<string16*>(nullptr))); - - EXPECT_FALSE(main_dict.GetBinary("bool", nullptr)); - EXPECT_FALSE(main_dict.GetBinary("int", nullptr)); - EXPECT_FALSE(main_dict.GetBinary("double", nullptr)); - EXPECT_FALSE(main_dict.GetBinary("string", nullptr)); - EXPECT_TRUE(main_dict.GetBinary("binary", nullptr)); - EXPECT_FALSE(main_dict.GetBinary("dict", nullptr)); - EXPECT_FALSE(main_dict.GetBinary("list", nullptr)); - EXPECT_FALSE(main_dict.GetBinary("DNE", nullptr)); - - EXPECT_FALSE(main_dict.GetDictionary("bool", nullptr)); - EXPECT_FALSE(main_dict.GetDictionary("int", nullptr)); - EXPECT_FALSE(main_dict.GetDictionary("double", nullptr)); - EXPECT_FALSE(main_dict.GetDictionary("string", nullptr)); - EXPECT_FALSE(main_dict.GetDictionary("binary", nullptr)); - EXPECT_TRUE(main_dict.GetDictionary("dict", nullptr)); - EXPECT_FALSE(main_dict.GetDictionary("list", nullptr)); - EXPECT_FALSE(main_dict.GetDictionary("DNE", nullptr)); - - EXPECT_FALSE(main_dict.GetList("bool", nullptr)); - EXPECT_FALSE(main_dict.GetList("int", nullptr)); - EXPECT_FALSE(main_dict.GetList("double", nullptr)); - EXPECT_FALSE(main_dict.GetList("string", nullptr)); - EXPECT_FALSE(main_dict.GetList("binary", nullptr)); - EXPECT_FALSE(main_dict.GetList("dict", nullptr)); - EXPECT_TRUE(main_dict.GetList("list", nullptr)); - EXPECT_FALSE(main_dict.GetList("DNE", nullptr)); - - EXPECT_TRUE(main_dict.GetWithoutPathExpansion("bool", nullptr)); - EXPECT_TRUE(main_dict.GetWithoutPathExpansion("int", nullptr)); - EXPECT_TRUE(main_dict.GetWithoutPathExpansion("double", nullptr)); - EXPECT_TRUE(main_dict.GetWithoutPathExpansion("string", nullptr)); - EXPECT_TRUE(main_dict.GetWithoutPathExpansion("binary", nullptr)); - EXPECT_TRUE(main_dict.GetWithoutPathExpansion("dict", nullptr)); - EXPECT_TRUE(main_dict.GetWithoutPathExpansion("list", nullptr)); - EXPECT_FALSE(main_dict.GetWithoutPathExpansion("DNE", nullptr)); - - EXPECT_TRUE(main_dict.GetBooleanWithoutPathExpansion("bool", nullptr)); - EXPECT_FALSE(main_dict.GetBooleanWithoutPathExpansion("int", nullptr)); - EXPECT_FALSE(main_dict.GetBooleanWithoutPathExpansion("double", nullptr)); - EXPECT_FALSE(main_dict.GetBooleanWithoutPathExpansion("string", nullptr)); - EXPECT_FALSE(main_dict.GetBooleanWithoutPathExpansion("binary", nullptr)); - EXPECT_FALSE(main_dict.GetBooleanWithoutPathExpansion("dict", nullptr)); - EXPECT_FALSE(main_dict.GetBooleanWithoutPathExpansion("list", nullptr)); - EXPECT_FALSE(main_dict.GetBooleanWithoutPathExpansion("DNE", nullptr)); - - EXPECT_FALSE(main_dict.GetIntegerWithoutPathExpansion("bool", nullptr)); - EXPECT_TRUE(main_dict.GetIntegerWithoutPathExpansion("int", nullptr)); - EXPECT_FALSE(main_dict.GetIntegerWithoutPathExpansion("double", nullptr)); - EXPECT_FALSE(main_dict.GetIntegerWithoutPathExpansion("string", nullptr)); - EXPECT_FALSE(main_dict.GetIntegerWithoutPathExpansion("binary", nullptr)); - EXPECT_FALSE(main_dict.GetIntegerWithoutPathExpansion("dict", nullptr)); - EXPECT_FALSE(main_dict.GetIntegerWithoutPathExpansion("list", nullptr)); - EXPECT_FALSE(main_dict.GetIntegerWithoutPathExpansion("DNE", nullptr)); - - EXPECT_FALSE(main_dict.GetDoubleWithoutPathExpansion("bool", nullptr)); - EXPECT_TRUE(main_dict.GetDoubleWithoutPathExpansion("int", nullptr)); - EXPECT_TRUE(main_dict.GetDoubleWithoutPathExpansion("double", nullptr)); - EXPECT_FALSE(main_dict.GetDoubleWithoutPathExpansion("string", nullptr)); - EXPECT_FALSE(main_dict.GetDoubleWithoutPathExpansion("binary", nullptr)); - EXPECT_FALSE(main_dict.GetDoubleWithoutPathExpansion("dict", nullptr)); - EXPECT_FALSE(main_dict.GetDoubleWithoutPathExpansion("list", nullptr)); - EXPECT_FALSE(main_dict.GetDoubleWithoutPathExpansion("DNE", nullptr)); - - EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion( - "bool", static_cast<std::string*>(nullptr))); - EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion( - "int", static_cast<std::string*>(nullptr))); - EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion( - "double", static_cast<std::string*>(nullptr))); - EXPECT_TRUE(main_dict.GetStringWithoutPathExpansion( - "string", static_cast<std::string*>(nullptr))); - EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion( - "binary", static_cast<std::string*>(nullptr))); - EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion( - "dict", static_cast<std::string*>(nullptr))); - EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion( - "list", static_cast<std::string*>(nullptr))); - EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion( - "DNE", static_cast<std::string*>(nullptr))); - - EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion( - "bool", static_cast<string16*>(nullptr))); - EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion( - "int", static_cast<string16*>(nullptr))); - EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion( - "double", static_cast<string16*>(nullptr))); - EXPECT_TRUE(main_dict.GetStringWithoutPathExpansion( - "string", static_cast<string16*>(nullptr))); - EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion( - "binary", static_cast<string16*>(nullptr))); - EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion( - "dict", static_cast<string16*>(nullptr))); - EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion( - "list", static_cast<string16*>(nullptr))); - EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion( - "DNE", static_cast<string16*>(nullptr))); - - // There is no GetBinaryWithoutPathExpansion for some reason, but if there - // were it should be tested here... - - EXPECT_FALSE(main_dict.GetDictionaryWithoutPathExpansion("bool", nullptr)); - EXPECT_FALSE(main_dict.GetDictionaryWithoutPathExpansion("int", nullptr)); - EXPECT_FALSE(main_dict.GetDictionaryWithoutPathExpansion("double", nullptr)); - EXPECT_FALSE(main_dict.GetDictionaryWithoutPathExpansion("string", nullptr)); - EXPECT_FALSE(main_dict.GetDictionaryWithoutPathExpansion("binary", nullptr)); - EXPECT_TRUE(main_dict.GetDictionaryWithoutPathExpansion("dict", nullptr)); - EXPECT_FALSE(main_dict.GetDictionaryWithoutPathExpansion("list", nullptr)); - EXPECT_FALSE(main_dict.GetDictionaryWithoutPathExpansion("DNE", nullptr)); - - EXPECT_FALSE(main_dict.GetListWithoutPathExpansion("bool", nullptr)); - EXPECT_FALSE(main_dict.GetListWithoutPathExpansion("int", nullptr)); - EXPECT_FALSE(main_dict.GetListWithoutPathExpansion("double", nullptr)); - EXPECT_FALSE(main_dict.GetListWithoutPathExpansion("string", nullptr)); - EXPECT_FALSE(main_dict.GetListWithoutPathExpansion("binary", nullptr)); - EXPECT_FALSE(main_dict.GetListWithoutPathExpansion("dict", nullptr)); - EXPECT_TRUE(main_dict.GetListWithoutPathExpansion("list", nullptr)); - EXPECT_FALSE(main_dict.GetListWithoutPathExpansion("DNE", nullptr)); - - EXPECT_TRUE(main_list.Get(0, nullptr)); - EXPECT_TRUE(main_list.Get(1, nullptr)); - EXPECT_TRUE(main_list.Get(2, nullptr)); - EXPECT_TRUE(main_list.Get(3, nullptr)); - EXPECT_TRUE(main_list.Get(4, nullptr)); - EXPECT_TRUE(main_list.Get(5, nullptr)); - EXPECT_TRUE(main_list.Get(6, nullptr)); - EXPECT_FALSE(main_list.Get(7, nullptr)); - - EXPECT_TRUE(main_list.GetBoolean(0, nullptr)); - EXPECT_FALSE(main_list.GetBoolean(1, nullptr)); - EXPECT_FALSE(main_list.GetBoolean(2, nullptr)); - EXPECT_FALSE(main_list.GetBoolean(3, nullptr)); - EXPECT_FALSE(main_list.GetBoolean(4, nullptr)); - EXPECT_FALSE(main_list.GetBoolean(5, nullptr)); - EXPECT_FALSE(main_list.GetBoolean(6, nullptr)); - EXPECT_FALSE(main_list.GetBoolean(7, nullptr)); - - EXPECT_FALSE(main_list.GetInteger(0, nullptr)); - EXPECT_TRUE(main_list.GetInteger(1, nullptr)); - EXPECT_FALSE(main_list.GetInteger(2, nullptr)); - EXPECT_FALSE(main_list.GetInteger(3, nullptr)); - EXPECT_FALSE(main_list.GetInteger(4, nullptr)); - EXPECT_FALSE(main_list.GetInteger(5, nullptr)); - EXPECT_FALSE(main_list.GetInteger(6, nullptr)); - EXPECT_FALSE(main_list.GetInteger(7, nullptr)); - - EXPECT_FALSE(main_list.GetDouble(0, nullptr)); - EXPECT_TRUE(main_list.GetDouble(1, nullptr)); - EXPECT_TRUE(main_list.GetDouble(2, nullptr)); - EXPECT_FALSE(main_list.GetDouble(3, nullptr)); - EXPECT_FALSE(main_list.GetDouble(4, nullptr)); - EXPECT_FALSE(main_list.GetDouble(5, nullptr)); - EXPECT_FALSE(main_list.GetDouble(6, nullptr)); - EXPECT_FALSE(main_list.GetDouble(7, nullptr)); - - EXPECT_FALSE(main_list.GetString(0, static_cast<std::string*>(nullptr))); - EXPECT_FALSE(main_list.GetString(1, static_cast<std::string*>(nullptr))); - EXPECT_FALSE(main_list.GetString(2, static_cast<std::string*>(nullptr))); - EXPECT_TRUE(main_list.GetString(3, static_cast<std::string*>(nullptr))); - EXPECT_FALSE(main_list.GetString(4, static_cast<std::string*>(nullptr))); - EXPECT_FALSE(main_list.GetString(5, static_cast<std::string*>(nullptr))); - EXPECT_FALSE(main_list.GetString(6, static_cast<std::string*>(nullptr))); - EXPECT_FALSE(main_list.GetString(7, static_cast<std::string*>(nullptr))); - - EXPECT_FALSE(main_list.GetString(0, static_cast<string16*>(nullptr))); - EXPECT_FALSE(main_list.GetString(1, static_cast<string16*>(nullptr))); - EXPECT_FALSE(main_list.GetString(2, static_cast<string16*>(nullptr))); - EXPECT_TRUE(main_list.GetString(3, static_cast<string16*>(nullptr))); - EXPECT_FALSE(main_list.GetString(4, static_cast<string16*>(nullptr))); - EXPECT_FALSE(main_list.GetString(5, static_cast<string16*>(nullptr))); - EXPECT_FALSE(main_list.GetString(6, static_cast<string16*>(nullptr))); - EXPECT_FALSE(main_list.GetString(7, static_cast<string16*>(nullptr))); - - EXPECT_FALSE(main_list.GetDictionary(0, nullptr)); - EXPECT_FALSE(main_list.GetDictionary(1, nullptr)); - EXPECT_FALSE(main_list.GetDictionary(2, nullptr)); - EXPECT_FALSE(main_list.GetDictionary(3, nullptr)); - EXPECT_FALSE(main_list.GetDictionary(4, nullptr)); - EXPECT_TRUE(main_list.GetDictionary(5, nullptr)); - EXPECT_FALSE(main_list.GetDictionary(6, nullptr)); - EXPECT_FALSE(main_list.GetDictionary(7, nullptr)); - - EXPECT_FALSE(main_list.GetList(0, nullptr)); - EXPECT_FALSE(main_list.GetList(1, nullptr)); - EXPECT_FALSE(main_list.GetList(2, nullptr)); - EXPECT_FALSE(main_list.GetList(3, nullptr)); - EXPECT_FALSE(main_list.GetList(4, nullptr)); - EXPECT_FALSE(main_list.GetList(5, nullptr)); - EXPECT_TRUE(main_list.GetList(6, nullptr)); - EXPECT_FALSE(main_list.GetList(7, nullptr)); -} - -TEST(ValuesTest, SelfSwap) { - base::Value test(1); - std::swap(test, test); - EXPECT_EQ(1, test.GetInt()); -} - -TEST(ValuesTest, FromToUniquePtrValue) { - std::unique_ptr<DictionaryValue> dict = std::make_unique<DictionaryValue>(); - dict->SetString("name", "Froogle"); - dict->SetString("url", "http://froogle.com"); - Value dict_copy = dict->Clone(); - - Value dict_converted = Value::FromUniquePtrValue(std::move(dict)); - EXPECT_EQ(dict_copy, dict_converted); - - std::unique_ptr<Value> val = - Value::ToUniquePtrValue(std::move(dict_converted)); - EXPECT_EQ(dict_copy, *val); -} - -} // namespace base
diff --git a/base/version_unittest.cc b/base/version_unittest.cc deleted file mode 100644 index 285ca9c..0000000 --- a/base/version_unittest.cc +++ /dev/null
@@ -1,200 +0,0 @@ -// 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/version.h" - -#include <stddef.h> -#include <stdint.h> -#include <utility> - -#include "base/macros.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -TEST(VersionTest, DefaultConstructor) { - base::Version v; - EXPECT_FALSE(v.IsValid()); -} - -TEST(VersionTest, ValueSemantics) { - base::Version v1("1.2.3.4"); - EXPECT_TRUE(v1.IsValid()); - base::Version v3; - EXPECT_FALSE(v3.IsValid()); - { - base::Version v2(v1); - v3 = v2; - EXPECT_TRUE(v2.IsValid()); - EXPECT_EQ(v1, v2); - } - EXPECT_EQ(v3, v1); -} - -TEST(VersionTest, MoveSemantics) { - const std::vector<uint32_t> components = {1, 2, 3, 4}; - base::Version v1(std::move(components)); - EXPECT_TRUE(v1.IsValid()); - base::Version v2("1.2.3.4"); - EXPECT_EQ(v1, v2); -} - -TEST(VersionTest, GetVersionFromString) { - static const struct version_string { - const char* input; - size_t parts; - uint32_t firstpart; - bool success; - } cases[] = { - {"", 0, 0, false}, - {" ", 0, 0, false}, - {"\t", 0, 0, false}, - {"\n", 0, 0, false}, - {" ", 0, 0, false}, - {".", 0, 0, false}, - {" . ", 0, 0, false}, - {"0", 1, 0, true}, - {"0.", 0, 0, false}, - {"0.0", 2, 0, true}, - {"4294967295.0", 2, 4294967295, true}, - {"4294967296.0", 0, 0, false}, - {"-1.0", 0, 0, false}, - {"1.-1.0", 0, 0, false}, - {"1,--1.0", 0, 0, false}, - {"+1.0", 0, 0, false}, - {"1.+1.0", 0, 0, false}, - {"1+1.0", 0, 0, false}, - {"++1.0", 0, 0, false}, - {"1.0a", 0, 0, false}, - {"1.2.3.4.5.6.7.8.9.0", 10, 1, true}, - {"02.1", 0, 0, false}, - {"0.01", 2, 0, true}, - {"f.1", 0, 0, false}, - {"15.007.20011", 3, 15, true}, - {"15.5.28.130162", 4, 15, true}, - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - base::Version version(cases[i].input); - EXPECT_EQ(cases[i].success, version.IsValid()); - if (cases[i].success) { - EXPECT_EQ(cases[i].parts, version.components().size()); - EXPECT_EQ(cases[i].firstpart, version.components()[0]); - } - } -} - -TEST(VersionTest, Compare) { - static const struct version_compare { - const char* lhs; - const char* rhs; - int expected; - } cases[] = { - {"1.0", "1.0", 0}, - {"1.0", "0.0", 1}, - {"1.0", "2.0", -1}, - {"1.0", "1.1", -1}, - {"1.1", "1.0", 1}, - {"1.0", "1.0.1", -1}, - {"1.1", "1.0.1", 1}, - {"1.1", "1.0.1", 1}, - {"1.0.0", "1.0", 0}, - {"1.0.3", "1.0.20", -1}, - {"11.0.10", "15.007.20011", -1}, - {"11.0.10", "15.5.28.130162", -1}, - {"15.5.28.130162", "15.5.28.130162", 0}, - }; - for (size_t i = 0; i < arraysize(cases); ++i) { - base::Version lhs(cases[i].lhs); - base::Version rhs(cases[i].rhs); - EXPECT_EQ(lhs.CompareTo(rhs), cases[i].expected) << - cases[i].lhs << " ? " << cases[i].rhs; - // CompareToWildcardString() should have same behavior as CompareTo() when - // no wildcards are present. - EXPECT_EQ(lhs.CompareToWildcardString(cases[i].rhs), cases[i].expected) - << cases[i].lhs << " ? " << cases[i].rhs; - EXPECT_EQ(rhs.CompareToWildcardString(cases[i].lhs), -cases[i].expected) - << cases[i].lhs << " ? " << cases[i].rhs; - - // Test comparison operators - switch (cases[i].expected) { - case -1: - EXPECT_LT(lhs, rhs); - EXPECT_LE(lhs, rhs); - EXPECT_NE(lhs, rhs); - EXPECT_FALSE(lhs == rhs); - EXPECT_FALSE(lhs >= rhs); - EXPECT_FALSE(lhs > rhs); - break; - case 0: - EXPECT_FALSE(lhs < rhs); - EXPECT_LE(lhs, rhs); - EXPECT_FALSE(lhs != rhs); - EXPECT_EQ(lhs, rhs); - EXPECT_GE(lhs, rhs); - EXPECT_FALSE(lhs > rhs); - break; - case 1: - EXPECT_FALSE(lhs < rhs); - EXPECT_FALSE(lhs <= rhs); - EXPECT_NE(lhs, rhs); - EXPECT_FALSE(lhs == rhs); - EXPECT_GE(lhs, rhs); - EXPECT_GT(lhs, rhs); - break; - } - } -} - -TEST(VersionTest, CompareToWildcardString) { - static const struct version_compare { - const char* lhs; - const char* rhs; - int expected; - } cases[] = { - {"1.0", "1.*", 0}, - {"1.0", "0.*", 1}, - {"1.0", "2.*", -1}, - {"1.2.3", "1.2.3.*", 0}, - {"10.0", "1.0.*", 1}, - {"1.0", "3.0.*", -1}, - {"1.4", "1.3.0.*", 1}, - {"1.3.9", "1.3.*", 0}, - {"1.4.1", "1.3.*", 1}, - {"1.3", "1.4.5.*", -1}, - {"1.5", "1.4.5.*", 1}, - {"1.3.9", "1.3.*", 0}, - {"1.2.0.0.0.0", "1.2.*", 0}, - }; - for (size_t i = 0; i < arraysize(cases); ++i) { - const base::Version version(cases[i].lhs); - const int result = version.CompareToWildcardString(cases[i].rhs); - EXPECT_EQ(result, cases[i].expected) << cases[i].lhs << "?" << cases[i].rhs; - } -} - -TEST(VersionTest, IsValidWildcardString) { - static const struct version_compare { - const char* version; - bool expected; - } cases[] = { - {"1.0", true}, - {"", false}, - {"1.2.3.4.5.6", true}, - {"1.2.3.*", true}, - {"1.2.3.5*", false}, - {"1.2.3.56*", false}, - {"1.*.3", false}, - {"20.*", true}, - {"+2.*", false}, - {"*", false}, - {"*.2", false}, - }; - for (size_t i = 0; i < arraysize(cases); ++i) { - EXPECT_EQ(base::Version::IsValidWildcardString(cases[i].version), - cases[i].expected) << cases[i].version << "?" << cases[i].expected; - } -} - -} // namespace
diff --git a/base/vlog_unittest.cc b/base/vlog_unittest.cc deleted file mode 100644 index 3c3f49c..0000000 --- a/base/vlog_unittest.cc +++ /dev/null
@@ -1,124 +0,0 @@ -// 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/vlog.h" - -#include "base/logging.h" -#include "base/time/time.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace logging { - -namespace { - -TEST(VlogTest, NoVmodule) { - int min_log_level = 0; - EXPECT_EQ(0, - VlogInfo(std::string(), std::string(), &min_log_level) - .GetVlogLevel("test1")); - EXPECT_EQ(0, - VlogInfo("0", std::string(), &min_log_level).GetVlogLevel("test2")); - EXPECT_EQ( - 0, VlogInfo("blah", std::string(), &min_log_level).GetVlogLevel("test3")); - EXPECT_EQ( - 0, - VlogInfo("0blah1", std::string(), &min_log_level).GetVlogLevel("test4")); - EXPECT_EQ(1, - VlogInfo("1", std::string(), &min_log_level).GetVlogLevel("test5")); - EXPECT_EQ(5, - VlogInfo("5", std::string(), &min_log_level).GetVlogLevel("test6")); -} - -TEST(VlogTest, MatchVlogPattern) { - // Degenerate cases. - EXPECT_TRUE(MatchVlogPattern("", "")); - EXPECT_TRUE(MatchVlogPattern("", "****")); - EXPECT_FALSE(MatchVlogPattern("", "x")); - EXPECT_FALSE(MatchVlogPattern("x", "")); - - // Basic. - EXPECT_TRUE(MatchVlogPattern("blah", "blah")); - - // ? should match exactly one character. - EXPECT_TRUE(MatchVlogPattern("blah", "bl?h")); - EXPECT_FALSE(MatchVlogPattern("blh", "bl?h")); - EXPECT_FALSE(MatchVlogPattern("blaah", "bl?h")); - EXPECT_TRUE(MatchVlogPattern("blah", "?lah")); - EXPECT_FALSE(MatchVlogPattern("lah", "?lah")); - EXPECT_FALSE(MatchVlogPattern("bblah", "?lah")); - - // * can match any number (even 0) of characters. - EXPECT_TRUE(MatchVlogPattern("blah", "bl*h")); - EXPECT_TRUE(MatchVlogPattern("blabcdefh", "bl*h")); - EXPECT_TRUE(MatchVlogPattern("blh", "bl*h")); - EXPECT_TRUE(MatchVlogPattern("blah", "*blah")); - EXPECT_TRUE(MatchVlogPattern("ohblah", "*blah")); - EXPECT_TRUE(MatchVlogPattern("blah", "blah*")); - EXPECT_TRUE(MatchVlogPattern("blahhhh", "blah*")); - EXPECT_TRUE(MatchVlogPattern("blahhhh", "blah*")); - EXPECT_TRUE(MatchVlogPattern("blah", "*blah*")); - EXPECT_TRUE(MatchVlogPattern("blahhhh", "*blah*")); - EXPECT_TRUE(MatchVlogPattern("bbbblahhhh", "*blah*")); - - // Multiple *s should work fine. - EXPECT_TRUE(MatchVlogPattern("ballaah", "b*la*h")); - EXPECT_TRUE(MatchVlogPattern("blah", "b*la*h")); - EXPECT_TRUE(MatchVlogPattern("bbbblah", "b*la*h")); - EXPECT_TRUE(MatchVlogPattern("blaaah", "b*la*h")); - - // There should be no escaping going on. - EXPECT_TRUE(MatchVlogPattern("bl\\ah", "bl\\?h")); - EXPECT_FALSE(MatchVlogPattern("bl?h", "bl\\?h")); - EXPECT_TRUE(MatchVlogPattern("bl\\aaaah", "bl\\*h")); - EXPECT_FALSE(MatchVlogPattern("bl*h", "bl\\*h")); - - // Any slash matches any slash. - EXPECT_TRUE(MatchVlogPattern("/b\\lah", "/b\\lah")); - EXPECT_TRUE(MatchVlogPattern("\\b/lah", "/b\\lah")); -} - -TEST(VlogTest, VmoduleBasic) { - const char kVSwitch[] = "-1"; - const char kVModuleSwitch[] = - "foo=,bar=0,baz=blah,,qux=0blah1,quux=1,corge.ext=5"; - int min_log_level = 0; - VlogInfo vlog_info(kVSwitch, kVModuleSwitch, &min_log_level); - EXPECT_EQ(-1, vlog_info.GetVlogLevel("/path/to/grault.cc")); - EXPECT_EQ(0, vlog_info.GetVlogLevel("/path/to/foo.cc")); - EXPECT_EQ(0, vlog_info.GetVlogLevel("D:\\Path\\To\\bar-inl.mm")); - EXPECT_EQ(-1, vlog_info.GetVlogLevel("D:\\path\\to what/bar_unittest.m")); - EXPECT_EQ(0, vlog_info.GetVlogLevel("baz.h")); - EXPECT_EQ(0, vlog_info.GetVlogLevel("/another/path/to/qux.h")); - EXPECT_EQ(1, vlog_info.GetVlogLevel("/path/to/quux")); - EXPECT_EQ(5, vlog_info.GetVlogLevel("c:\\path/to/corge.ext.h")); -} - -TEST(VlogTest, VmoduleDirs) { - const char kVModuleSwitch[] = - "foo/bar.cc=1,baz\\*\\qux.cc=2,*quux/*=3,*/*-inl.h=4"; - int min_log_level = 0; - VlogInfo vlog_info(std::string(), kVModuleSwitch, &min_log_level); - EXPECT_EQ(0, vlog_info.GetVlogLevel("/foo/bar.cc")); - EXPECT_EQ(0, vlog_info.GetVlogLevel("bar.cc")); - EXPECT_EQ(1, vlog_info.GetVlogLevel("foo/bar.cc")); - - EXPECT_EQ(0, vlog_info.GetVlogLevel("baz/grault/qux.h")); - EXPECT_EQ(0, vlog_info.GetVlogLevel("/baz/grault/qux.cc")); - EXPECT_EQ(2, vlog_info.GetVlogLevel("baz/grault/qux.cc")); - EXPECT_EQ(2, vlog_info.GetVlogLevel("baz/grault/blah/qux.cc")); - EXPECT_EQ(2, vlog_info.GetVlogLevel("baz\\grault\\qux.cc")); - EXPECT_EQ(2, vlog_info.GetVlogLevel("baz\\grault//blah\\qux.cc")); - - EXPECT_EQ(0, vlog_info.GetVlogLevel("/foo/bar/baz/quux.cc")); - EXPECT_EQ(3, vlog_info.GetVlogLevel("/foo/bar/baz/quux/grault.cc")); - EXPECT_EQ(3, vlog_info.GetVlogLevel("/foo\\bar/baz\\quux/grault.cc")); - - EXPECT_EQ(0, vlog_info.GetVlogLevel("foo/bar/test-inl.cc")); - EXPECT_EQ(4, vlog_info.GetVlogLevel("foo/bar/test-inl.h")); - EXPECT_EQ(4, vlog_info.GetVlogLevel("foo/bar/baz/blah-inl.h")); -} - -} // namespace - -} // namespace logging
diff --git a/base/win/BUILD.gn b/base/win/BUILD.gn deleted file mode 100644 index 19c2982..0000000 --- a/base/win/BUILD.gn +++ /dev/null
@@ -1,32 +0,0 @@ -# Copyright (c) 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. - -import("//build/buildflag_header.gni") - -declare_args() { - # Indicates if the handle verifier should operate in a single module mode. By - # default a single instance gets shared by all the modules. - single_module_mode_handle_verifier = false -} - -# Ensure that the handle verifier is always used in a single module mode for the -# component builds. -if (is_component_build) { - single_module_mode_handle_verifier = true -} - -buildflag_header("base_win_buildflags") { - header = "base_win_buildflags.h" - header_dir = "base/win" - flags = [ - "SINGLE_MODULE_MODE_HANDLE_VERIFIER=$single_module_mode_handle_verifier", - ] -} - -static_library("pe_image") { - sources = [ - "pe_image.cc", - "pe_image.h", - ] -}
diff --git a/base/win/async_operation_unittest.cc b/base/win/async_operation_unittest.cc deleted file mode 100644 index b29e181..0000000 --- a/base/win/async_operation_unittest.cc +++ /dev/null
@@ -1,174 +0,0 @@ -// 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/win/async_operation.h" - -#include <utility> - -#include "base/test/gtest_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace WRL = Microsoft::WRL; - -using ABI::Windows::Foundation::IAsyncOperation; -using ABI::Windows::Foundation::IAsyncOperationCompletedHandler; - -// In order to exercise the interface logic of AsyncOperation we define an empty -// dummy interface, its implementation, and the necessary boilerplate to hook it -// up with IAsyncOperation and IAsyncOperationCompletedHandler. -namespace { - -// Chosen by fair `uuidgen` invocation. Also applies to the UUIDs below. -MIDL_INTERFACE("756358C7-8083-4D78-9D27-9278B76096d4") -IFooBar : public IInspectable{}; - -class FooBar - : public WRL::RuntimeClass< - WRL::RuntimeClassFlags<WRL::WinRt | WRL::InhibitRoOriginateError>, - IFooBar> {}; - -} // namespace - -namespace ABI { -namespace Windows { -namespace Foundation { - -// Provide the required template specializations to register -// IAsyncOperation<Foobar*> as an AggregateType. This is similar to how it is -// done for UWP classes. -template <> -struct DECLSPEC_UUID("124858e4-f97e-409c-86ae-418c4781144c") - IAsyncOperation<FooBar*> - : IAsyncOperation_impl<Internal::AggregateType<FooBar*, IFooBar*>> { - static const wchar_t* z_get_rc_name_impl() { - return L"Windows.Foundation.IAsyncOperation<FooBar>"; - } -}; - -template <> -struct DECLSPEC_UUID("9e49373c-200c-4715-abd7-4214ba669c81") - IAsyncOperationCompletedHandler<FooBar*> - : IAsyncOperationCompletedHandler_impl< - Internal::AggregateType<FooBar*, IFooBar*>> { - static const wchar_t* z_get_rc_name_impl() { - return L"Windows.Foundation.AsyncOperationCompletedHandler<FooBar>"; - } -}; - -} // namespace Foundation -} // namespace Windows -} // namespace ABI - -namespace base { -namespace win { - -namespace { - -// Utility method to add a completion callback to |async_op|. |*called_cb| will -// be set to true once the callback is invoked. -template <typename T> -void PutCallback(AsyncOperation<T>* async_op, bool* called_cb) { - async_op->put_Completed( - WRL::Callback<IAsyncOperationCompletedHandler<T>>( - [=](IAsyncOperation<T>* iasync_op, AsyncStatus status) { - EXPECT_EQ(async_op, iasync_op); - *called_cb = true; - return S_OK; - }) - .Get()); -} - -} // namespace - -TEST(AsyncOperationTest, TestInt) { - bool called_cb = false; - - auto int_op = WRL::Make<AsyncOperation<int>>(); - PutCallback(int_op.Get(), &called_cb); - - int results; - EXPECT_TRUE(FAILED(int_op->GetResults(&results))); - EXPECT_FALSE(called_cb); - int_op->callback().Run(123); - - EXPECT_TRUE(called_cb); - EXPECT_TRUE(SUCCEEDED(int_op->GetResults(&results))); - EXPECT_EQ(123, results); - - // GetResults should be idempotent. - EXPECT_TRUE(SUCCEEDED(int_op->GetResults(&results))); - EXPECT_EQ(123, results); -} - -TEST(AsyncOperationTest, TestBool) { - bool called_cb = false; - - auto bool_op = WRL::Make<AsyncOperation<bool>>(); - PutCallback(bool_op.Get(), &called_cb); - - // AsyncOperation<bool> is an aggregate of bool and boolean, and requires a - // pointer to the latter to get the results. - boolean results; - EXPECT_TRUE(FAILED(bool_op->GetResults(&results))); - EXPECT_FALSE(called_cb); - bool_op->callback().Run(true); - - EXPECT_TRUE(called_cb); - EXPECT_TRUE(SUCCEEDED(bool_op->GetResults(&results))); - EXPECT_TRUE(results); -} - -TEST(AsyncOperationTest, TestInterface) { - bool called_cb = false; - - auto foobar_op = WRL::Make<AsyncOperation<FooBar*>>(); - PutCallback(foobar_op.Get(), &called_cb); - - // AsyncOperation<FooBar*> is an aggregate of FooBar* and IFooBar*. - WRL::ComPtr<IFooBar> results; - EXPECT_TRUE(FAILED(foobar_op->GetResults(&results))); - EXPECT_FALSE(called_cb); - - auto foobar = WRL::Make<FooBar>(); - IFooBar* foobar_ptr = foobar.Get(); - foobar_op->callback().Run(std::move(foobar)); - - EXPECT_TRUE(called_cb); - EXPECT_TRUE(SUCCEEDED(foobar_op->GetResults(&results))); - EXPECT_EQ(foobar_ptr, results.Get()); -} - -TEST(AsyncOperationTest, TestIdempotence) { - bool called_cb = false; - - auto int_op = WRL::Make<AsyncOperation<int>>(); - PutCallback(int_op.Get(), &called_cb); - - int results; - EXPECT_TRUE(FAILED(int_op->GetResults(&results))); - EXPECT_FALSE(called_cb); - // Calling GetResults twice shouldn't change the result. - EXPECT_TRUE(FAILED(int_op->GetResults(&results))); - EXPECT_FALSE(called_cb); - - int_op->callback().Run(42); - - EXPECT_TRUE(called_cb); - EXPECT_TRUE(SUCCEEDED(int_op->GetResults(&results))); - EXPECT_EQ(42, results); - // Calling GetResults twice shouldn't change the result. - EXPECT_TRUE(SUCCEEDED(int_op->GetResults(&results))); - EXPECT_EQ(42, results); -} - -TEST(AsyncOperationTest, DoubleCallbackFails) { - auto int_op = WRL::Make<AsyncOperation<int>>(); - auto cb = int_op->callback(); - - // Obtaining another callback should result in a DCHECK failure. - EXPECT_DCHECK_DEATH(int_op->callback()); -} - -} // namespace win -} // namespace base
diff --git a/base/win/com_init_check_hook_unittest.cc b/base/win/com_init_check_hook_unittest.cc deleted file mode 100644 index 32aede4..0000000 --- a/base/win/com_init_check_hook_unittest.cc +++ /dev/null
@@ -1,134 +0,0 @@ -// 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/win/com_init_check_hook.h" - -#include <objbase.h> -#include <shlobj.h> -#include <wrl/client.h> - -#include "base/test/gtest_util.h" -#include "base/win/com_init_util.h" -#include "base/win/patch_util.h" -#include "base/win/scoped_com_initializer.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace win { - -using Microsoft::WRL::ComPtr; - -TEST(ComInitCheckHook, AssertNotInitialized) { - ComInitCheckHook com_check_hook; - AssertComApartmentType(ComApartmentType::NONE); - ComPtr<IUnknown> shell_link; -#if defined(COM_INIT_CHECK_HOOK_ENABLED) - EXPECT_DCHECK_DEATH(::CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_ALL, - IID_PPV_ARGS(&shell_link))); -#else - EXPECT_EQ(CO_E_NOTINITIALIZED, - ::CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_ALL, - IID_PPV_ARGS(&shell_link))); -#endif -} - -TEST(ComInitCheckHook, HookRemoval) { - AssertComApartmentType(ComApartmentType::NONE); - { ComInitCheckHook com_check_hook; } - ComPtr<IUnknown> shell_link; - EXPECT_EQ(CO_E_NOTINITIALIZED, - ::CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_ALL, - IID_PPV_ARGS(&shell_link))); -} - -TEST(ComInitCheckHook, NoAssertComInitialized) { - ComInitCheckHook com_check_hook; - ScopedCOMInitializer com_initializer; - ComPtr<IUnknown> shell_link; - EXPECT_TRUE(SUCCEEDED(::CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_ALL, - IID_PPV_ARGS(&shell_link)))); -} - -TEST(ComInitCheckHook, MultipleHooks) { - ComInitCheckHook com_check_hook_1; - ComInitCheckHook com_check_hook_2; - AssertComApartmentType(ComApartmentType::NONE); - ComPtr<IUnknown> shell_link; -#if defined(COM_INIT_CHECK_HOOK_ENABLED) - EXPECT_DCHECK_DEATH(::CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_ALL, - IID_PPV_ARGS(&shell_link))); -#else - EXPECT_EQ(CO_E_NOTINITIALIZED, - ::CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_ALL, - IID_PPV_ARGS(&shell_link))); -#endif -} - -TEST(ComInitCheckHook, UnexpectedHook) { -#if defined(COM_INIT_CHECK_HOOK_ENABLED) - HMODULE ole32_library = ::LoadLibrary(L"ole32.dll"); - ASSERT_TRUE(ole32_library); - - uint32_t co_create_instance_padded_address = - reinterpret_cast<uint32_t>( - GetProcAddress(ole32_library, "CoCreateInstance")) - 5; - const unsigned char* co_create_instance_bytes = - reinterpret_cast<const unsigned char*>(co_create_instance_padded_address); - const unsigned char original_byte = co_create_instance_bytes[0]; - const unsigned char unexpected_byte = 0xdb; - ASSERT_EQ(static_cast<DWORD>(NO_ERROR), - internal::ModifyCode( - reinterpret_cast<void*>(co_create_instance_padded_address), - reinterpret_cast<const void*>(&unexpected_byte), - sizeof(unexpected_byte))); - - EXPECT_DCHECK_DEATH({ ComInitCheckHook com_check_hook; }); - - // If this call fails, really bad things are going to happen to other tests - // so CHECK here. - CHECK_EQ(static_cast<DWORD>(NO_ERROR), - internal::ModifyCode( - reinterpret_cast<void*>(co_create_instance_padded_address), - reinterpret_cast<const void*>(&original_byte), - sizeof(original_byte))); - - ::FreeLibrary(ole32_library); - ole32_library = nullptr; -#endif -} - -TEST(ComInitCheckHook, ExternallyHooked) { -#if defined(COM_INIT_CHECK_HOOK_ENABLED) - HMODULE ole32_library = ::LoadLibrary(L"ole32.dll"); - ASSERT_TRUE(ole32_library); - - uint32_t co_create_instance_address = reinterpret_cast<uint32_t>( - GetProcAddress(ole32_library, "CoCreateInstance")); - const unsigned char* co_create_instance_bytes = - reinterpret_cast<const unsigned char*>(co_create_instance_address); - const unsigned char original_byte = co_create_instance_bytes[0]; - const unsigned char jmp_byte = 0xe9; - ASSERT_EQ(static_cast<DWORD>(NO_ERROR), - internal::ModifyCode( - reinterpret_cast<void*>(co_create_instance_address), - reinterpret_cast<const void*>(&jmp_byte), sizeof(jmp_byte))); - - // Externally patched instances should crash so we catch these cases on bots. - EXPECT_DCHECK_DEATH({ ComInitCheckHook com_check_hook; }); - - // If this call fails, really bad things are going to happen to other tests - // so CHECK here. - CHECK_EQ( - static_cast<DWORD>(NO_ERROR), - internal::ModifyCode(reinterpret_cast<void*>(co_create_instance_address), - reinterpret_cast<const void*>(&original_byte), - sizeof(original_byte))); - - ::FreeLibrary(ole32_library); - ole32_library = nullptr; -#endif -} - -} // namespace win -} // namespace base
diff --git a/base/win/com_init_util_unittest.cc b/base/win/com_init_util_unittest.cc deleted file mode 100644 index fb897dd..0000000 --- a/base/win/com_init_util_unittest.cc +++ /dev/null
@@ -1,75 +0,0 @@ -// 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/win/com_init_util.h" - -#include "base/test/gtest_util.h" -#include "base/win/scoped_com_initializer.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace win { - -TEST(ComInitUtil, AssertNotInitialized) { - EXPECT_DCHECK_DEATH(AssertComInitialized()); -} - -TEST(ComInitUtil, AssertUninitialized) { - // When COM is uninitialized, the TLS data will remain, but the apartment - // status will be updated. This covers that case. - { - ScopedCOMInitializer com_initializer; - ASSERT_TRUE(com_initializer.Succeeded()); - } - EXPECT_DCHECK_DEATH(AssertComInitialized()); -} - -TEST(ComInitUtil, AssertSTAInitialized) { - ScopedCOMInitializer com_initializer; - ASSERT_TRUE(com_initializer.Succeeded()); - - AssertComInitialized(); -} - -TEST(ComInitUtil, AssertMTAInitialized) { - ScopedCOMInitializer com_initializer(ScopedCOMInitializer::kMTA); - ASSERT_TRUE(com_initializer.Succeeded()); - - AssertComInitialized(); -} - -TEST(ComInitUtil, AssertNoneApartmentType) { - AssertComApartmentType(ComApartmentType::NONE); - EXPECT_DCHECK_DEATH(AssertComApartmentType(ComApartmentType::STA)); - EXPECT_DCHECK_DEATH(AssertComApartmentType(ComApartmentType::MTA)); -} - -TEST(ComInitUtil, AssertNoneApartmentTypeUninitialized) { - // When COM is uninitialized, the TLS data will remain, but the apartment - // status will be updated. This covers that case. - { - ScopedCOMInitializer com_initializer; - ASSERT_TRUE(com_initializer.Succeeded()); - } - AssertComApartmentType(ComApartmentType::NONE); - EXPECT_DCHECK_DEATH(AssertComApartmentType(ComApartmentType::STA)); - EXPECT_DCHECK_DEATH(AssertComApartmentType(ComApartmentType::MTA)); -} - -TEST(ComInitUtil, AssertSTAApartmentType) { - ScopedCOMInitializer com_initializer; - EXPECT_DCHECK_DEATH(AssertComApartmentType(ComApartmentType::NONE)); - AssertComApartmentType(ComApartmentType::STA); - EXPECT_DCHECK_DEATH(AssertComApartmentType(ComApartmentType::MTA)); -} - -TEST(ComInitUtil, AssertMTAApartmentType) { - ScopedCOMInitializer com_initializer(ScopedCOMInitializer::kMTA); - EXPECT_DCHECK_DEATH(AssertComApartmentType(ComApartmentType::NONE)); - EXPECT_DCHECK_DEATH(AssertComApartmentType(ComApartmentType::STA)); - AssertComApartmentType(ComApartmentType::MTA); -} - -} // namespace win -} // namespace base
diff --git a/base/win/core_winrt_util_unittest.cc b/base/win/core_winrt_util_unittest.cc deleted file mode 100644 index 11d08b8..0000000 --- a/base/win/core_winrt_util_unittest.cc +++ /dev/null
@@ -1,34 +0,0 @@ -// 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/win/core_winrt_util.h" - -#include "base/win/com_init_util.h" -#include "base/win/scoped_com_initializer.h" -#include "base/win/windows_version.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace win { - -TEST(CoreWinrtUtilTest, PreloadFunctions) { - if (GetVersion() < VERSION_WIN8) - EXPECT_FALSE(ResolveCoreWinRTDelayload()); - else - EXPECT_TRUE(ResolveCoreWinRTDelayload()); -} - -TEST(CoreWinrtUtilTest, RoInitializeAndUninitialize) { - if (GetVersion() < VERSION_WIN8) - return; - - ASSERT_TRUE(ResolveCoreWinRTDelayload()); - ASSERT_HRESULT_SUCCEEDED(base::win::RoInitialize(RO_INIT_MULTITHREADED)); - AssertComApartmentType(ComApartmentType::MTA); - base::win::RoUninitialize(); - AssertComApartmentType(ComApartmentType::NONE); -} - -} // namespace win -} // namespace base
diff --git a/base/win/enum_variant_unittest.cc b/base/win/enum_variant_unittest.cc deleted file mode 100644 index 288c97e..0000000 --- a/base/win/enum_variant_unittest.cc +++ /dev/null
@@ -1,118 +0,0 @@ -// 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/win/enum_variant.h" - -#include "base/win/scoped_com_initializer.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace win { - -TEST(EnumVariantTest, EmptyEnumVariant) { - ScopedCOMInitializer com_initializer; - - EnumVariant* ev = new EnumVariant(0); - ev->AddRef(); - - IUnknown* iunknown; - EXPECT_TRUE(SUCCEEDED( - ev->QueryInterface(IID_IUnknown, reinterpret_cast<void**>(&iunknown)))); - iunknown->Release(); - - IEnumVARIANT* ienumvariant; - EXPECT_TRUE(SUCCEEDED( - ev->QueryInterface(IID_IEnumVARIANT, - reinterpret_cast<void**>(&ienumvariant)))); - EXPECT_EQ(ev, ienumvariant); - ienumvariant->Release(); - - VARIANT out_element; - ULONG out_received = 0; - EXPECT_EQ(S_FALSE, ev->Next(1, &out_element, &out_received)); - EXPECT_EQ(0u, out_received); - - EXPECT_EQ(S_FALSE, ev->Skip(1)); - - EXPECT_EQ(S_OK, ev->Reset()); - - IEnumVARIANT* ev2 = NULL; - EXPECT_EQ(S_OK, ev->Clone(&ev2)); - - EXPECT_NE(static_cast<IEnumVARIANT*>(NULL), ev2); - EXPECT_NE(ev, ev2); - EXPECT_EQ(S_FALSE, ev2->Skip(1)); - EXPECT_EQ(S_OK, ev2->Reset()); - - ULONG ev2_finalrefcount = ev2->Release(); - EXPECT_EQ(0u, ev2_finalrefcount); - - ULONG ev_finalrefcount = ev->Release(); - EXPECT_EQ(0u, ev_finalrefcount); -} - -TEST(EnumVariantTest, SimpleEnumVariant) { - ScopedCOMInitializer com_initializer; - - EnumVariant* ev = new EnumVariant(3); - ev->AddRef(); - ev->ItemAt(0)->vt = VT_I4; - ev->ItemAt(0)->lVal = 10; - ev->ItemAt(1)->vt = VT_I4; - ev->ItemAt(1)->lVal = 20; - ev->ItemAt(2)->vt = VT_I4; - ev->ItemAt(2)->lVal = 30; - - // Get elements one at a time. - VARIANT out_element; - ULONG out_received = 0; - EXPECT_EQ(S_OK, ev->Next(1, &out_element, &out_received)); - EXPECT_EQ(1u, out_received); - EXPECT_EQ(VT_I4, out_element.vt); - EXPECT_EQ(10, out_element.lVal); - EXPECT_EQ(S_OK, ev->Skip(1)); - EXPECT_EQ(S_OK, ev->Next(1, &out_element, &out_received)); - EXPECT_EQ(1u, out_received); - EXPECT_EQ(VT_I4, out_element.vt); - EXPECT_EQ(30, out_element.lVal); - EXPECT_EQ(S_FALSE, ev->Next(1, &out_element, &out_received)); - - // Reset and get all elements at once. - VARIANT out_elements[3]; - EXPECT_EQ(S_OK, ev->Reset()); - EXPECT_EQ(S_OK, ev->Next(3, out_elements, &out_received)); - EXPECT_EQ(3u, out_received); - EXPECT_EQ(VT_I4, out_elements[0].vt); - EXPECT_EQ(10, out_elements[0].lVal); - EXPECT_EQ(VT_I4, out_elements[1].vt); - EXPECT_EQ(20, out_elements[1].lVal); - EXPECT_EQ(VT_I4, out_elements[2].vt); - EXPECT_EQ(30, out_elements[2].lVal); - EXPECT_EQ(S_FALSE, ev->Next(1, &out_element, &out_received)); - - // Clone it. - IEnumVARIANT* ev2 = NULL; - EXPECT_EQ(S_OK, ev->Clone(&ev2)); - EXPECT_TRUE(ev2 != NULL); - EXPECT_EQ(S_FALSE, ev->Next(1, &out_element, &out_received)); - EXPECT_EQ(S_OK, ev2->Reset()); - EXPECT_EQ(S_OK, ev2->Next(3, out_elements, &out_received)); - EXPECT_EQ(3u, out_received); - EXPECT_EQ(VT_I4, out_elements[0].vt); - EXPECT_EQ(10, out_elements[0].lVal); - EXPECT_EQ(VT_I4, out_elements[1].vt); - EXPECT_EQ(20, out_elements[1].lVal); - EXPECT_EQ(VT_I4, out_elements[2].vt); - EXPECT_EQ(30, out_elements[2].lVal); - EXPECT_EQ(S_FALSE, ev2->Next(1, &out_element, &out_received)); - - ULONG ev2_finalrefcount = ev2->Release(); - EXPECT_EQ(0u, ev2_finalrefcount); - - ULONG ev_finalrefcount = ev->Release(); - EXPECT_EQ(0u, ev_finalrefcount); -} - -} // namespace win -} // namespace base
diff --git a/base/win/event_trace_consumer_unittest.cc b/base/win/event_trace_consumer_unittest.cc deleted file mode 100644 index 9c4c242..0000000 --- a/base/win/event_trace_consumer_unittest.cc +++ /dev/null
@@ -1,367 +0,0 @@ -// 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. -// -// Unit tests for event trace consumer base class. -#include "base/win/event_trace_consumer.h" - -#include <list> - -#include <objbase.h> - -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/files/scoped_temp_dir.h" -#include "base/logging.h" -#include "base/macros.h" -#include "base/process/process_handle.h" -#include "base/strings/stringprintf.h" -#include "base/win/event_trace_controller.h" -#include "base/win/event_trace_provider.h" -#include "base/win/scoped_handle.h" -#include "testing/gtest/include/gtest/gtest.h" - -#include <initguid.h> // NOLINT - has to be last - -namespace base { -namespace win { - -namespace { - -typedef std::list<EVENT_TRACE> EventQueue; - -class TestConsumer: public EtwTraceConsumerBase<TestConsumer> { - public: - TestConsumer() { - sank_event_.Set(::CreateEvent(NULL, TRUE, FALSE, NULL)); - ClearQueue(); - } - - ~TestConsumer() { - ClearQueue(); - sank_event_.Close(); - } - - void ClearQueue() { - for (EventQueue::const_iterator it(events_.begin()), end(events_.end()); - it != end; ++it) { - delete[] reinterpret_cast<char*>(it->MofData); - } - - events_.clear(); - } - - static void EnqueueEvent(EVENT_TRACE* event) { - events_.push_back(*event); - EVENT_TRACE& back = events_.back(); - - if (event->MofData != NULL && event->MofLength != 0) { - back.MofData = new char[event->MofLength]; - memcpy(back.MofData, event->MofData, event->MofLength); - } - } - - static void ProcessEvent(EVENT_TRACE* event) { - EnqueueEvent(event); - ::SetEvent(sank_event_.Get()); - } - - static ScopedHandle sank_event_; - static EventQueue events_; - - private: - DISALLOW_COPY_AND_ASSIGN(TestConsumer); -}; - -ScopedHandle TestConsumer::sank_event_; -EventQueue TestConsumer::events_; - -class EtwTraceConsumerBaseTest: public testing::Test { - public: - EtwTraceConsumerBaseTest() - : session_name_(StringPrintf(L"TestSession-%d", GetCurrentProcId())) { - } - - void SetUp() override { - // Cleanup any potentially dangling sessions. - EtwTraceProperties ignore; - EtwTraceController::Stop(session_name_.c_str(), &ignore); - - // Allocate a new GUID for each provider test. - ASSERT_HRESULT_SUCCEEDED(::CoCreateGuid(&test_provider_)); - } - - void TearDown() override { - // Cleanup any potentially dangling sessions. - EtwTraceProperties ignore; - EtwTraceController::Stop(session_name_.c_str(), &ignore); - } - - protected: - GUID test_provider_; - std::wstring session_name_; -}; - -} // namespace - -TEST_F(EtwTraceConsumerBaseTest, Initialize) { - TestConsumer consumer_; -} - -TEST_F(EtwTraceConsumerBaseTest, OpenRealtimeSucceedsWhenNoSession) { - TestConsumer consumer_; - ASSERT_HRESULT_SUCCEEDED( - consumer_.OpenRealtimeSession(session_name_.c_str())); -} - -TEST_F(EtwTraceConsumerBaseTest, ConsumerImmediateFailureWhenNoSession) { - TestConsumer consumer_; - ASSERT_HRESULT_SUCCEEDED( - consumer_.OpenRealtimeSession(session_name_.c_str())); - ASSERT_HRESULT_FAILED(consumer_.Consume()); -} - -namespace { - -class EtwTraceConsumerRealtimeTest: public EtwTraceConsumerBaseTest { - public: - void SetUp() override { - EtwTraceConsumerBaseTest::SetUp(); - ASSERT_HRESULT_SUCCEEDED( - consumer_.OpenRealtimeSession(session_name_.c_str())); - } - - void TearDown() override { - consumer_.Close(); - EtwTraceConsumerBaseTest::TearDown(); - } - - DWORD ConsumerThread() { - ::SetEvent(consumer_ready_.Get()); - return consumer_.Consume(); - } - - static DWORD WINAPI ConsumerThreadMainProc(void* arg) { - return reinterpret_cast<EtwTraceConsumerRealtimeTest*>(arg)-> - ConsumerThread(); - } - - HRESULT StartConsumerThread() { - consumer_ready_.Set(::CreateEvent(NULL, TRUE, FALSE, NULL)); - EXPECT_TRUE(consumer_ready_.IsValid()); - consumer_thread_.Set(::CreateThread(NULL, 0, ConsumerThreadMainProc, this, - 0, NULL)); - if (consumer_thread_.Get() == NULL) - return HRESULT_FROM_WIN32(::GetLastError()); - - HANDLE events[] = { consumer_ready_.Get(), consumer_thread_.Get() }; - DWORD result = ::WaitForMultipleObjects(arraysize(events), events, - FALSE, INFINITE); - switch (result) { - case WAIT_OBJECT_0: - // The event was set, the consumer_ is ready. - return S_OK; - case WAIT_OBJECT_0 + 1: { - // The thread finished. This may race with the event, so check - // explicitly for the event here, before concluding there's trouble. - if (::WaitForSingleObject(consumer_ready_.Get(), 0) == WAIT_OBJECT_0) - return S_OK; - DWORD exit_code = 0; - if (::GetExitCodeThread(consumer_thread_.Get(), &exit_code)) - return exit_code; - return HRESULT_FROM_WIN32(::GetLastError()); - } - default: - return E_UNEXPECTED; - } - } - - // Waits for consumer_ thread to exit, and returns its exit code. - HRESULT JoinConsumerThread() { - if (::WaitForSingleObject(consumer_thread_.Get(), INFINITE) != - WAIT_OBJECT_0) { - return HRESULT_FROM_WIN32(::GetLastError()); - } - - DWORD exit_code = 0; - if (::GetExitCodeThread(consumer_thread_.Get(), &exit_code)) - return exit_code; - - return HRESULT_FROM_WIN32(::GetLastError()); - } - - TestConsumer consumer_; - ScopedHandle consumer_ready_; - ScopedHandle consumer_thread_; -}; - -} // namespace - -TEST_F(EtwTraceConsumerRealtimeTest, ConsumerReturnsWhenSessionClosed) { - EtwTraceController controller; - if (controller.StartRealtimeSession(session_name_.c_str(), 100 * 1024) == - E_ACCESSDENIED) { - VLOG(1) << "You must be an administrator to run this test on Vista"; - return; - } - - // Start the consumer_. - ASSERT_HRESULT_SUCCEEDED(StartConsumerThread()); - - // Wait around for the consumer_ thread a bit. - ASSERT_EQ(static_cast<DWORD>(WAIT_TIMEOUT), - ::WaitForSingleObject(consumer_thread_.Get(), 50)); - ASSERT_HRESULT_SUCCEEDED(controller.Stop(NULL)); - - // The consumer_ returns success on session stop. - ASSERT_HRESULT_SUCCEEDED(JoinConsumerThread()); -} - -namespace { - -// {57E47923-A549-476f-86CA-503D57F59E62} -DEFINE_GUID( - kTestEventType, - 0x57e47923, 0xa549, 0x476f, 0x86, 0xca, 0x50, 0x3d, 0x57, 0xf5, 0x9e, 0x62); - -} // namespace - -TEST_F(EtwTraceConsumerRealtimeTest, ConsumeEvent) { - EtwTraceController controller; - if (controller.StartRealtimeSession(session_name_.c_str(), 100 * 1024) == - E_ACCESSDENIED) { - VLOG(1) << "You must be an administrator to run this test on Vista"; - return; - } - - ASSERT_HRESULT_SUCCEEDED(controller.EnableProvider( - test_provider_, TRACE_LEVEL_VERBOSE, 0xFFFFFFFF)); - - EtwTraceProvider provider(test_provider_); - ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), provider.Register()); - - // Start the consumer_. - ASSERT_HRESULT_SUCCEEDED(StartConsumerThread()); - ASSERT_EQ(0u, TestConsumer::events_.size()); - - EtwMofEvent<1> event(kTestEventType, 1, TRACE_LEVEL_ERROR); - EXPECT_EQ(static_cast<DWORD>(ERROR_SUCCESS), provider.Log(&event.header)); - EXPECT_EQ(WAIT_OBJECT_0, - ::WaitForSingleObject(TestConsumer::sank_event_.Get(), INFINITE)); - ASSERT_HRESULT_SUCCEEDED(controller.Stop(NULL)); - ASSERT_HRESULT_SUCCEEDED(JoinConsumerThread()); - ASSERT_NE(0u, TestConsumer::events_.size()); -} - -namespace { - -// We run events through a file session to assert that -// the content comes through. -class EtwTraceConsumerDataTest: public EtwTraceConsumerBaseTest { - public: - EtwTraceConsumerDataTest() { - } - - void SetUp() override { - EtwTraceConsumerBaseTest::SetUp(); - - EtwTraceProperties prop; - EtwTraceController::Stop(session_name_.c_str(), &prop); - - // Create a temp dir for this test. - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - // Construct a temp file name in our dir. - temp_file_ = temp_dir_.GetPath().Append(L"test.etl"); - } - - void TearDown() override { - EXPECT_TRUE(base::DeleteFile(temp_file_, false)); - - EtwTraceConsumerBaseTest::TearDown(); - } - - HRESULT LogEventToTempSession(PEVENT_TRACE_HEADER header) { - EtwTraceController controller; - - // Set up a file session. - HRESULT hr = controller.StartFileSession(session_name_.c_str(), - temp_file_.value().c_str()); - if (FAILED(hr)) - return hr; - - // Enable our provider. - EXPECT_HRESULT_SUCCEEDED(controller.EnableProvider( - test_provider_, TRACE_LEVEL_VERBOSE, 0xFFFFFFFF)); - - EtwTraceProvider provider(test_provider_); - // Then register our provider, means we get a session handle immediately. - EXPECT_EQ(static_cast<DWORD>(ERROR_SUCCESS), provider.Register()); - // Trace the event, it goes to the temp file. - EXPECT_EQ(static_cast<DWORD>(ERROR_SUCCESS), provider.Log(header)); - EXPECT_HRESULT_SUCCEEDED(controller.DisableProvider(test_provider_)); - EXPECT_HRESULT_SUCCEEDED(provider.Unregister()); - EXPECT_HRESULT_SUCCEEDED(controller.Flush(NULL)); - EXPECT_HRESULT_SUCCEEDED(controller.Stop(NULL)); - - return S_OK; - } - - HRESULT ConsumeEventFromTempSession() { - // Now consume the event(s). - TestConsumer consumer_; - HRESULT hr = consumer_.OpenFileSession(temp_file_.value().c_str()); - if (SUCCEEDED(hr)) - hr = consumer_.Consume(); - consumer_.Close(); - // And nab the result. - events_.swap(TestConsumer::events_); - return hr; - } - - HRESULT RoundTripEvent(PEVENT_TRACE_HEADER header, PEVENT_TRACE* trace) { - base::DeleteFile(temp_file_, false); - - HRESULT hr = LogEventToTempSession(header); - if (SUCCEEDED(hr)) - hr = ConsumeEventFromTempSession(); - - if (FAILED(hr)) - return hr; - - // We should now have the event in the queue. - if (events_.empty()) - return E_FAIL; - - *trace = &events_.back(); - return S_OK; - } - - EventQueue events_; - ScopedTempDir temp_dir_; - FilePath temp_file_; -}; - -} // namespace - - -TEST_F(EtwTraceConsumerDataTest, RoundTrip) { - EtwMofEvent<1> event(kTestEventType, 1, TRACE_LEVEL_ERROR); - - static const char kData[] = "This is but test data"; - event.fields[0].DataPtr = reinterpret_cast<ULONG64>(kData); - event.fields[0].Length = sizeof(kData); - - PEVENT_TRACE trace = NULL; - HRESULT hr = RoundTripEvent(&event.header, &trace); - if (hr == E_ACCESSDENIED) { - VLOG(1) << "You must be an administrator to run this test on Vista"; - return; - } - ASSERT_HRESULT_SUCCEEDED(hr) << "RoundTripEvent failed"; - ASSERT_TRUE(trace != NULL); - ASSERT_EQ(sizeof(kData), trace->MofLength); - ASSERT_STREQ(kData, reinterpret_cast<const char*>(trace->MofData)); -} - -} // namespace win -} // namespace base
diff --git a/base/win/event_trace_controller_unittest.cc b/base/win/event_trace_controller_unittest.cc deleted file mode 100644 index f19ee31..0000000 --- a/base/win/event_trace_controller_unittest.cc +++ /dev/null
@@ -1,244 +0,0 @@ -// 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. -// -// Unit tests for event trace controller. - -#include <objbase.h> -#include <initguid.h> - -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/files/scoped_temp_dir.h" -#include "base/logging.h" -#include "base/macros.h" -#include "base/process/process_handle.h" -#include "base/strings/stringprintf.h" -#include "base/sys_info.h" -#include "base/win/event_trace_controller.h" -#include "base/win/event_trace_provider.h" -#include "base/win/scoped_handle.h" -#include "base/win/windows_version.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace win { - -namespace { - -DEFINE_GUID(kGuidNull, - 0x0000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0); - -const ULONG kTestProviderFlags = 0xCAFEBABE; - -class TestingProvider: public EtwTraceProvider { - public: - explicit TestingProvider(const GUID& provider_name) - : EtwTraceProvider(provider_name) { - callback_event_.Set(::CreateEvent(NULL, TRUE, FALSE, NULL)); - } - - void WaitForCallback() { - ::WaitForSingleObject(callback_event_.Get(), INFINITE); - ::ResetEvent(callback_event_.Get()); - } - - private: - void OnEventsEnabled() override { ::SetEvent(callback_event_.Get()); } - void PostEventsDisabled() override { ::SetEvent(callback_event_.Get()); } - - ScopedHandle callback_event_; - - DISALLOW_COPY_AND_ASSIGN(TestingProvider); -}; - -} // namespace - -TEST(EtwTracePropertiesTest, Initialization) { - EtwTraceProperties prop; - - EVENT_TRACE_PROPERTIES* p = prop.get(); - EXPECT_NE(0u, p->Wnode.BufferSize); - EXPECT_EQ(0u, p->Wnode.ProviderId); - EXPECT_EQ(0u, p->Wnode.HistoricalContext); - - EXPECT_TRUE(kGuidNull == p->Wnode.Guid); - EXPECT_EQ(0u, p->Wnode.ClientContext); - EXPECT_EQ(static_cast<ULONG>(WNODE_FLAG_TRACED_GUID), p->Wnode.Flags); - - EXPECT_EQ(0u, p->BufferSize); - EXPECT_EQ(0u, p->MinimumBuffers); - EXPECT_EQ(0u, p->MaximumBuffers); - EXPECT_EQ(0u, p->MaximumFileSize); - EXPECT_EQ(0u, p->LogFileMode); - EXPECT_EQ(0u, p->FlushTimer); - EXPECT_EQ(0u, p->EnableFlags); - EXPECT_EQ(0, p->AgeLimit); - - EXPECT_EQ(0u, p->NumberOfBuffers); - EXPECT_EQ(0u, p->FreeBuffers); - EXPECT_EQ(0u, p->EventsLost); - EXPECT_EQ(0u, p->BuffersWritten); - EXPECT_EQ(0u, p->LogBuffersLost); - EXPECT_EQ(0u, p->RealTimeBuffersLost); - EXPECT_EQ(0u, p->LoggerThreadId); - EXPECT_NE(0u, p->LogFileNameOffset); - EXPECT_NE(0u, p->LoggerNameOffset); -} - -TEST(EtwTracePropertiesTest, Strings) { - EtwTraceProperties prop; - - ASSERT_STREQ(L"", prop.GetLoggerFileName()); - ASSERT_STREQ(L"", prop.GetLoggerName()); - - std::wstring name(1023, L'A'); - ASSERT_HRESULT_SUCCEEDED(prop.SetLoggerFileName(name.c_str())); - ASSERT_HRESULT_SUCCEEDED(prop.SetLoggerName(name.c_str())); - ASSERT_STREQ(name.c_str(), prop.GetLoggerFileName()); - ASSERT_STREQ(name.c_str(), prop.GetLoggerName()); - - std::wstring name2(1024, L'A'); - ASSERT_HRESULT_FAILED(prop.SetLoggerFileName(name2.c_str())); - ASSERT_HRESULT_FAILED(prop.SetLoggerName(name2.c_str())); -} - -namespace { - -class EtwTraceControllerTest : public testing::Test { - public: - EtwTraceControllerTest() - : session_name_(StringPrintf(L"TestSession-%d", GetCurrentProcId())) { - } - - void SetUp() override { - EtwTraceProperties ignore; - EtwTraceController::Stop(session_name_.c_str(), &ignore); - - // Allocate a new provider name GUID for each test. - ASSERT_HRESULT_SUCCEEDED(::CoCreateGuid(&test_provider_)); - } - - void TearDown() override { - EtwTraceProperties prop; - EtwTraceController::Stop(session_name_.c_str(), &prop); - } - - protected: - GUID test_provider_; - std::wstring session_name_; -}; - -} // namespace - -TEST_F(EtwTraceControllerTest, Initialize) { - EtwTraceController controller; - - EXPECT_EQ(0u, controller.session()); - EXPECT_STREQ(L"", controller.session_name()); -} - - -TEST_F(EtwTraceControllerTest, StartRealTimeSession) { - EtwTraceController controller; - - HRESULT hr = controller.StartRealtimeSession(session_name_.c_str(), - 100 * 1024); - if (hr == E_ACCESSDENIED) { - VLOG(1) << "You must be an administrator to run this test on Vista"; - return; - } - - EXPECT_NE(0u, controller.session()); - EXPECT_STREQ(session_name_.c_str(), controller.session_name()); - - EXPECT_HRESULT_SUCCEEDED(controller.Stop(NULL)); - EXPECT_EQ(0u, controller.session()); - EXPECT_STREQ(L"", controller.session_name()); -} - -TEST_F(EtwTraceControllerTest, StartFileSession) { - ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - FilePath temp; - ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.GetPath(), &temp)); - - EtwTraceController controller; - HRESULT hr = controller.StartFileSession(session_name_.c_str(), - temp.value().c_str()); - if (hr == E_ACCESSDENIED) { - VLOG(1) << "You must be an administrator to run this test on Vista"; - base::DeleteFile(temp, false); - return; - } - - EXPECT_NE(0u, controller.session()); - EXPECT_STREQ(session_name_.c_str(), controller.session_name()); - - EXPECT_HRESULT_SUCCEEDED(controller.Stop(NULL)); - EXPECT_EQ(0u, controller.session()); - EXPECT_STREQ(L"", controller.session_name()); - base::DeleteFile(temp, false); -} - -// This test is flaky for unclear reasons. See bugs 525297 and 534184 -TEST_F(EtwTraceControllerTest, DISABLED_EnableDisable) { - TestingProvider provider(test_provider_); - - EXPECT_EQ(static_cast<DWORD>(ERROR_SUCCESS), provider.Register()); - EXPECT_EQ(0u, provider.session_handle()); - - EtwTraceController controller; - HRESULT hr = controller.StartRealtimeSession(session_name_.c_str(), - 100 * 1024); - if (hr == E_ACCESSDENIED) { - VLOG(1) << "You must be an administrator to run this test on Vista"; - return; - } - - EXPECT_HRESULT_SUCCEEDED(controller.EnableProvider(test_provider_, - TRACE_LEVEL_VERBOSE, kTestProviderFlags)); - - provider.WaitForCallback(); - - EXPECT_EQ(TRACE_LEVEL_VERBOSE, provider.enable_level()); - EXPECT_EQ(kTestProviderFlags, provider.enable_flags()); - - EXPECT_HRESULT_SUCCEEDED(controller.DisableProvider(test_provider_)); - - provider.WaitForCallback(); - - EXPECT_EQ(0, provider.enable_level()); - EXPECT_EQ(0u, provider.enable_flags()); - - EXPECT_EQ(static_cast<DWORD>(ERROR_SUCCESS), provider.Unregister()); - - // Enable the provider again, before registering. - EXPECT_HRESULT_SUCCEEDED(controller.EnableProvider(test_provider_, - TRACE_LEVEL_VERBOSE, kTestProviderFlags)); - - // Register the provider again, the settings above - // should take immediate effect. - EXPECT_EQ(static_cast<DWORD>(ERROR_SUCCESS), provider.Register()); - - EXPECT_EQ(TRACE_LEVEL_VERBOSE, provider.enable_level()); - EXPECT_EQ(kTestProviderFlags, provider.enable_flags()); - - // Consume the callback event of the previous controller.EnableProvider(). - provider.WaitForCallback(); - - EXPECT_HRESULT_SUCCEEDED(controller.Stop(NULL)); - - // Windows 7 does not call the callback when Stop() is called so we - // can't wait, and enable_level and enable_flags are not zeroed. - if (base::win::GetVersion() >= VERSION_WIN8) { - provider.WaitForCallback(); - - // Session should have wound down. - EXPECT_EQ(0, provider.enable_level()); - EXPECT_EQ(0u, provider.enable_flags()); - } -} - -} // namespace win -} // namespace base
diff --git a/base/win/event_trace_provider_unittest.cc b/base/win/event_trace_provider_unittest.cc deleted file mode 100644 index 7d57773..0000000 --- a/base/win/event_trace_provider_unittest.cc +++ /dev/null
@@ -1,110 +0,0 @@ -// 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. -// -// Unit tests for event trace provider. -#include "base/win/event_trace_provider.h" -#include <new> -#include "testing/gtest/include/gtest/gtest.h" -#include <initguid.h> // NOLINT - has to be last - -namespace { - -using base::win::EtwTraceProvider; -using base::win::EtwMofEvent; - -// {7F0FD37F-FA3C-4cd6-9242-DF60967A2CB2} -DEFINE_GUID(kTestProvider, - 0x7f0fd37f, 0xfa3c, 0x4cd6, 0x92, 0x42, 0xdf, 0x60, 0x96, 0x7a, 0x2c, 0xb2); - -// {7F0FD37F-FA3C-4cd6-9242-DF60967A2CB2} -DEFINE_GUID(kTestEventClass, - 0x7f0fd37f, 0xfa3c, 0x4cd6, 0x92, 0x42, 0xdf, 0x60, 0x96, 0x7a, 0x2c, 0xb2); - -} // namespace - -TEST(EtwTraceProviderTest, ToleratesPreCreateInvocations) { - // Because the trace provider is used in logging, it's important that - // it be possible to use static provider instances without regard to - // whether they've been constructed or destructed. - // The interface of the class is designed to tolerate this usage. - char buf[sizeof(EtwTraceProvider)] = {0}; - EtwTraceProvider& provider = reinterpret_cast<EtwTraceProvider&>(buf); - - EXPECT_EQ(0u, provider.registration_handle()); - EXPECT_EQ(0u, provider.session_handle()); - EXPECT_EQ(0u, provider.enable_flags()); - EXPECT_EQ(0u, provider.enable_level()); - - EXPECT_FALSE(provider.ShouldLog(TRACE_LEVEL_FATAL, 0xfffffff)); - - // We expect these not to crash. - provider.Log(kTestEventClass, 0, TRACE_LEVEL_FATAL, "foo"); - provider.Log(kTestEventClass, 0, TRACE_LEVEL_FATAL, L"foo"); - - EtwMofEvent<1> dummy(kTestEventClass, 0, TRACE_LEVEL_FATAL); - DWORD data = 0; - dummy.SetField(0, sizeof(data), &data); - provider.Log(dummy.get()); - - // Placement-new the provider into our buffer. - new (buf) EtwTraceProvider(kTestProvider); - - // Registration is now safe. - EXPECT_EQ(static_cast<ULONG>(ERROR_SUCCESS), provider.Register()); - - // Destruct the instance, this should unregister it. - provider.EtwTraceProvider::~EtwTraceProvider(); - - // And post-destruction, all of the above should still be safe. - EXPECT_EQ(0u, provider.registration_handle()); - EXPECT_EQ(0u, provider.session_handle()); - EXPECT_EQ(0u, provider.enable_flags()); - EXPECT_EQ(0u, provider.enable_level()); - - EXPECT_FALSE(provider.ShouldLog(TRACE_LEVEL_FATAL, 0xfffffff)); - - // We expect these not to crash. - provider.Log(kTestEventClass, 0, TRACE_LEVEL_FATAL, "foo"); - provider.Log(kTestEventClass, 0, TRACE_LEVEL_FATAL, L"foo"); - provider.Log(dummy.get()); -} - -TEST(EtwTraceProviderTest, Initialize) { - EtwTraceProvider provider(kTestProvider); - - EXPECT_EQ(0u, provider.registration_handle()); - EXPECT_EQ(0u, provider.session_handle()); - EXPECT_EQ(0u, provider.enable_flags()); - EXPECT_EQ(0u, provider.enable_level()); -} - -TEST(EtwTraceProviderTest, Register) { - EtwTraceProvider provider(kTestProvider); - - ASSERT_EQ(static_cast<ULONG>(ERROR_SUCCESS), provider.Register()); - EXPECT_NE(0u, provider.registration_handle()); - ASSERT_EQ(static_cast<ULONG>(ERROR_SUCCESS), provider.Unregister()); - EXPECT_EQ(0u, provider.registration_handle()); -} - -TEST(EtwTraceProviderTest, RegisterWithNoNameFails) { - EtwTraceProvider provider; - - EXPECT_TRUE(provider.Register() != ERROR_SUCCESS); -} - -TEST(EtwTraceProviderTest, Enable) { - EtwTraceProvider provider(kTestProvider); - - ASSERT_EQ(static_cast<ULONG>(ERROR_SUCCESS), provider.Register()); - EXPECT_NE(0u, provider.registration_handle()); - - // No session so far. - EXPECT_EQ(0u, provider.session_handle()); - EXPECT_EQ(0u, provider.enable_flags()); - EXPECT_EQ(0u, provider.enable_level()); - - ASSERT_EQ(static_cast<ULONG>(ERROR_SUCCESS), provider.Unregister()); - EXPECT_EQ(0u, provider.registration_handle()); -}
diff --git a/base/win/i18n_unittest.cc b/base/win/i18n_unittest.cc deleted file mode 100644 index 9af6dbf..0000000 --- a/base/win/i18n_unittest.cc +++ /dev/null
@@ -1,44 +0,0 @@ -// 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. - -// This file contains unit tests for Windows internationalization funcs. - -#include "testing/gtest/include/gtest/gtest.h" - -#include <stddef.h> - -#include "base/win/i18n.h" -#include "base/win/windows_version.h" - -namespace base { -namespace win { -namespace i18n { - -// Tests that at least one user preferred UI language can be obtained. -TEST(I18NTest, GetUserPreferredUILanguageList) { - std::vector<std::wstring> languages; - EXPECT_TRUE(GetUserPreferredUILanguageList(&languages)); - EXPECT_NE(static_cast<std::vector<std::wstring>::size_type>(0), - languages.size()); - for (std::vector<std::wstring>::const_iterator scan = languages.begin(), - end = languages.end(); scan != end; ++scan) { - EXPECT_FALSE((*scan).empty()); - } -} - -// Tests that at least one thread preferred UI language can be obtained. -TEST(I18NTest, GetThreadPreferredUILanguageList) { - std::vector<std::wstring> languages; - EXPECT_TRUE(GetThreadPreferredUILanguageList(&languages)); - EXPECT_NE(static_cast<std::vector<std::wstring>::size_type>(0), - languages.size()); - for (std::vector<std::wstring>::const_iterator scan = languages.begin(), - end = languages.end(); scan != end; ++scan) { - EXPECT_FALSE((*scan).empty()); - } -} - -} // namespace i18n -} // namespace win -} // namespace base
diff --git a/base/win/iunknown_impl_unittest.cc b/base/win/iunknown_impl_unittest.cc deleted file mode 100644 index c6c3539..0000000 --- a/base/win/iunknown_impl_unittest.cc +++ /dev/null
@@ -1,49 +0,0 @@ -// 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/win/iunknown_impl.h" - -#include "base/win/scoped_com_initializer.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace win { - -class TestIUnknownImplSubclass : public IUnknownImpl { - public: - TestIUnknownImplSubclass() { - ++instance_count; - } - ~TestIUnknownImplSubclass() override { --instance_count; } - static int instance_count; -}; - -// static -int TestIUnknownImplSubclass::instance_count = 0; - -TEST(IUnknownImplTest, IUnknownImpl) { - ScopedCOMInitializer com_initializer; - - EXPECT_EQ(0, TestIUnknownImplSubclass::instance_count); - IUnknown* u = new TestIUnknownImplSubclass(); - - EXPECT_EQ(1, TestIUnknownImplSubclass::instance_count); - - EXPECT_EQ(1u, u->AddRef()); - EXPECT_EQ(1u, u->AddRef()); - - IUnknown* other = NULL; - EXPECT_EQ(E_NOINTERFACE, u->QueryInterface( - IID_IDispatch, reinterpret_cast<void**>(&other))); - EXPECT_EQ(S_OK, u->QueryInterface( - IID_IUnknown, reinterpret_cast<void**>(&other))); - other->Release(); - - EXPECT_EQ(1u, u->Release()); - EXPECT_EQ(0u, u->Release()); - EXPECT_EQ(0, TestIUnknownImplSubclass::instance_count); -} - -} // namespace win -} // namespace base
diff --git a/base/win/message_window_unittest.cc b/base/win/message_window_unittest.cc deleted file mode 100644 index 00248bf..0000000 --- a/base/win/message_window_unittest.cc +++ /dev/null
@@ -1,61 +0,0 @@ -// 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/bind.h" -#include "base/guid.h" -#include "base/strings/utf_string_conversions.h" -#include "base/win/message_window.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -bool HandleMessage( - UINT message, WPARAM wparam, LPARAM lparam, LRESULT* result) { - // Return |wparam| as the result of WM_USER message. - if (message == WM_USER) { - *result = wparam; - return true; - } - - return false; -} - -} // namespace - -// Checks that a window can be created. -TEST(MessageWindowTest, Create) { - win::MessageWindow window; - EXPECT_TRUE(window.Create(base::Bind(&HandleMessage))); -} - -// Checks that a named window can be created. -TEST(MessageWindowTest, CreateNamed) { - win::MessageWindow window; - EXPECT_TRUE(window.CreateNamed(base::Bind(&HandleMessage), - UTF8ToUTF16("test_message_window"))); -} - -// Verifies that the created window can receive messages. -TEST(MessageWindowTest, SendMessage) { - win::MessageWindow window; - EXPECT_TRUE(window.Create(base::Bind(&HandleMessage))); - - EXPECT_EQ(SendMessage(window.hwnd(), WM_USER, 100, 0), 100); -} - -// Verifies that a named window can be found by name. -TEST(MessageWindowTest, FindWindow) { - string16 name = UTF8ToUTF16(base::GenerateGUID()); - win::MessageWindow window; - EXPECT_TRUE(window.CreateNamed(base::Bind(&HandleMessage), name)); - - HWND hwnd = win::MessageWindow::FindWindow(name); - EXPECT_TRUE(hwnd != NULL); - EXPECT_EQ(SendMessage(hwnd, WM_USER, 200, 0), 200); -} - -} // namespace base
diff --git a/base/win/object_watcher_unittest.cc b/base/win/object_watcher_unittest.cc deleted file mode 100644 index 5aa3891..0000000 --- a/base/win/object_watcher_unittest.cc +++ /dev/null
@@ -1,221 +0,0 @@ -// 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/win/object_watcher.h" - -#include <process.h> - -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace win { - -namespace { - -class QuitDelegate : public ObjectWatcher::Delegate { - public: - void OnObjectSignaled(HANDLE object) override { - RunLoop::QuitCurrentWhenIdleDeprecated(); - } -}; - -class DecrementCountDelegate : public ObjectWatcher::Delegate { - public: - explicit DecrementCountDelegate(int* counter) : counter_(counter) { - } - void OnObjectSignaled(HANDLE object) override { --(*counter_); } - - private: - int* counter_; -}; - -void RunTest_BasicSignal(MessageLoop::Type message_loop_type) { - MessageLoop message_loop(message_loop_type); - - ObjectWatcher watcher; - EXPECT_FALSE(watcher.IsWatching()); - - // A manual-reset event that is not yet signaled. - HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL); - - QuitDelegate delegate; - bool ok = watcher.StartWatchingOnce(event, &delegate); - EXPECT_TRUE(ok); - EXPECT_TRUE(watcher.IsWatching()); - EXPECT_EQ(event, watcher.GetWatchedObject()); - - SetEvent(event); - - RunLoop().Run(); - - EXPECT_FALSE(watcher.IsWatching()); - CloseHandle(event); -} - -void RunTest_BasicCancel(MessageLoop::Type message_loop_type) { - MessageLoop message_loop(message_loop_type); - - ObjectWatcher watcher; - - // A manual-reset event that is not yet signaled. - HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL); - - QuitDelegate delegate; - bool ok = watcher.StartWatchingOnce(event, &delegate); - EXPECT_TRUE(ok); - - watcher.StopWatching(); - - CloseHandle(event); -} - -void RunTest_CancelAfterSet(MessageLoop::Type message_loop_type) { - MessageLoop message_loop(message_loop_type); - - ObjectWatcher watcher; - - int counter = 1; - DecrementCountDelegate delegate(&counter); - - // A manual-reset event that is not yet signaled. - HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL); - - bool ok = watcher.StartWatchingOnce(event, &delegate); - EXPECT_TRUE(ok); - - SetEvent(event); - - // Let the background thread do its business - Sleep(30); - - watcher.StopWatching(); - - RunLoop().RunUntilIdle(); - - // Our delegate should not have fired. - EXPECT_EQ(1, counter); - - CloseHandle(event); -} - -void RunTest_SignalBeforeWatch(MessageLoop::Type message_loop_type) { - MessageLoop message_loop(message_loop_type); - - ObjectWatcher watcher; - - // A manual-reset event that is signaled before we begin watching. - HANDLE event = CreateEvent(NULL, TRUE, TRUE, NULL); - - QuitDelegate delegate; - bool ok = watcher.StartWatchingOnce(event, &delegate); - EXPECT_TRUE(ok); - - RunLoop().Run(); - - EXPECT_FALSE(watcher.IsWatching()); - CloseHandle(event); -} - -void RunTest_OutlivesMessageLoop(MessageLoop::Type message_loop_type) { - // Simulate a MessageLoop that dies before an ObjectWatcher. This ordinarily - // doesn't happen when people use the Thread class, but it can happen when - // people use the Singleton pattern or atexit. - HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL); // not signaled - { - ObjectWatcher watcher; - { - MessageLoop message_loop(message_loop_type); - - QuitDelegate delegate; - watcher.StartWatchingOnce(event, &delegate); - } - } - CloseHandle(event); -} - -class QuitAfterMultipleDelegate : public ObjectWatcher::Delegate { - public: - QuitAfterMultipleDelegate(HANDLE event, int iterations) - : event_(event), iterations_(iterations) {} - void OnObjectSignaled(HANDLE object) override { - if (--iterations_) { - SetEvent(event_); - } else { - RunLoop::QuitCurrentWhenIdleDeprecated(); - } - } - - private: - HANDLE event_; - int iterations_; -}; - -void RunTest_ExecuteMultipleTimes(MessageLoop::Type message_loop_type) { - MessageLoop message_loop(message_loop_type); - - ObjectWatcher watcher; - EXPECT_FALSE(watcher.IsWatching()); - - // An auto-reset event that is not yet signaled. - HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL); - - QuitAfterMultipleDelegate delegate(event, 2); - bool ok = watcher.StartWatchingMultipleTimes(event, &delegate); - EXPECT_TRUE(ok); - EXPECT_TRUE(watcher.IsWatching()); - EXPECT_EQ(event, watcher.GetWatchedObject()); - - SetEvent(event); - - RunLoop().Run(); - - EXPECT_TRUE(watcher.IsWatching()); - EXPECT_TRUE(watcher.StopWatching()); - CloseHandle(event); -} - -} // namespace - -//----------------------------------------------------------------------------- - -TEST(ObjectWatcherTest, BasicSignal) { - RunTest_BasicSignal(MessageLoop::TYPE_DEFAULT); - RunTest_BasicSignal(MessageLoop::TYPE_IO); - RunTest_BasicSignal(MessageLoop::TYPE_UI); -} - -TEST(ObjectWatcherTest, BasicCancel) { - RunTest_BasicCancel(MessageLoop::TYPE_DEFAULT); - RunTest_BasicCancel(MessageLoop::TYPE_IO); - RunTest_BasicCancel(MessageLoop::TYPE_UI); -} - -TEST(ObjectWatcherTest, CancelAfterSet) { - RunTest_CancelAfterSet(MessageLoop::TYPE_DEFAULT); - RunTest_CancelAfterSet(MessageLoop::TYPE_IO); - RunTest_CancelAfterSet(MessageLoop::TYPE_UI); -} - -TEST(ObjectWatcherTest, SignalBeforeWatch) { - RunTest_SignalBeforeWatch(MessageLoop::TYPE_DEFAULT); - RunTest_SignalBeforeWatch(MessageLoop::TYPE_IO); - RunTest_SignalBeforeWatch(MessageLoop::TYPE_UI); -} - -TEST(ObjectWatcherTest, OutlivesMessageLoop) { - RunTest_OutlivesMessageLoop(MessageLoop::TYPE_DEFAULT); - RunTest_OutlivesMessageLoop(MessageLoop::TYPE_IO); - RunTest_OutlivesMessageLoop(MessageLoop::TYPE_UI); -} - -TEST(ObjectWatcherTest, ExecuteMultipleTimes) { - RunTest_ExecuteMultipleTimes(MessageLoop::TYPE_DEFAULT); - RunTest_ExecuteMultipleTimes(MessageLoop::TYPE_IO); - RunTest_ExecuteMultipleTimes(MessageLoop::TYPE_UI); -} - -} // namespace win -} // namespace base
diff --git a/base/win/pe_image_unittest.cc b/base/win/pe_image_unittest.cc deleted file mode 100644 index 2216449..0000000 --- a/base/win/pe_image_unittest.cc +++ /dev/null
@@ -1,225 +0,0 @@ -// 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 contains unit tests for PEImage. -#include <algorithm> -#include <vector> - -#include "base/files/file_path.h" -#include "base/path_service.h" -#include "base/scoped_native_library.h" -#include "base/win/pe_image.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace win { - -namespace { - -// Just counts the number of invocations. -bool ImportsCallback(const PEImage& image, - LPCSTR module, - DWORD ordinal, - LPCSTR name, - DWORD hint, - PIMAGE_THUNK_DATA iat, - PVOID cookie) { - int* count = reinterpret_cast<int*>(cookie); - (*count)++; - return true; -} - -// Just counts the number of invocations. -bool SectionsCallback(const PEImage& image, - PIMAGE_SECTION_HEADER header, - PVOID section_start, - DWORD section_size, - PVOID cookie) { - int* count = reinterpret_cast<int*>(cookie); - (*count)++; - return true; -} - -// Just counts the number of invocations. -bool RelocsCallback(const PEImage& image, - WORD type, - PVOID address, - PVOID cookie) { - int* count = reinterpret_cast<int*>(cookie); - (*count)++; - return true; -} - -// Just counts the number of invocations. -bool ImportChunksCallback(const PEImage& image, - LPCSTR module, - PIMAGE_THUNK_DATA name_table, - PIMAGE_THUNK_DATA iat, - PVOID cookie) { - int* count = reinterpret_cast<int*>(cookie); - (*count)++; - return true; -} - -// Just counts the number of invocations. -bool DelayImportChunksCallback(const PEImage& image, - PImgDelayDescr delay_descriptor, - LPCSTR module, - PIMAGE_THUNK_DATA name_table, - PIMAGE_THUNK_DATA iat, - PVOID cookie) { - int* count = reinterpret_cast<int*>(cookie); - (*count)++; - return true; -} - -// Just counts the number of invocations. -bool ExportsCallback(const PEImage& image, - DWORD ordinal, - DWORD hint, - LPCSTR name, - PVOID function, - LPCSTR forward, - PVOID cookie) { - int* count = reinterpret_cast<int*>(cookie); - (*count)++; - return true; -} - -} // namespace - -// Tests that we are able to enumerate stuff from a PE file, and that -// the actual number of items found matches an expected value. -TEST(PEImageTest, EnumeratesPE) { - base::FilePath pe_image_test_path; - ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &pe_image_test_path)); - pe_image_test_path = pe_image_test_path.Append(FILE_PATH_LITERAL("pe_image")); - -#if defined(ARCH_CPU_64_BITS) - pe_image_test_path = - pe_image_test_path.Append(FILE_PATH_LITERAL("pe_image_test_64.dll")); - const int sections = 6; - const int imports_dlls = 2; - const int delay_dlls = 2; - const int exports = 3; - const int imports = 70; - const int delay_imports = 2; - const int relocs = 976; -#else - pe_image_test_path = - pe_image_test_path.Append(FILE_PATH_LITERAL("pe_image_test_32.dll")); - const int sections = 5; - const int imports_dlls = 2; - const int delay_dlls = 2; - const int exports = 3; - const int imports = 66; - const int delay_imports = 2; - const int relocs = 2114; -#endif - - ScopedNativeLibrary module(pe_image_test_path); - ASSERT_TRUE(module.is_valid()); - - PEImage pe(module.get()); - int count = 0; - EXPECT_TRUE(pe.VerifyMagic()); - - pe.EnumSections(SectionsCallback, &count); - EXPECT_EQ(sections, count); - - count = 0; - pe.EnumImportChunks(ImportChunksCallback, &count); - EXPECT_EQ(imports_dlls, count); - - count = 0; - pe.EnumDelayImportChunks(DelayImportChunksCallback, &count); - EXPECT_EQ(delay_dlls, count); - - count = 0; - pe.EnumExports(ExportsCallback, &count); - EXPECT_EQ(exports, count); - - count = 0; - pe.EnumAllImports(ImportsCallback, &count); - EXPECT_EQ(imports, count); - - count = 0; - pe.EnumAllDelayImports(ImportsCallback, &count); - EXPECT_EQ(delay_imports, count); - - count = 0; - pe.EnumRelocs(RelocsCallback, &count); - EXPECT_EQ(relocs, count); -} - -// Tests that we can locate an specific exported symbol, by name and by ordinal. -TEST(PEImageTest, RetrievesExports) { - ScopedNativeLibrary module(FilePath(L"advapi32.dll")); - ASSERT_TRUE(module.is_valid()); - - PEImage pe(module.get()); - WORD ordinal; - - EXPECT_TRUE(pe.GetProcOrdinal("RegEnumKeyExW", &ordinal)); - - FARPROC address1 = pe.GetProcAddress("RegEnumKeyExW"); - FARPROC address2 = pe.GetProcAddress(reinterpret_cast<char*>(ordinal)); - EXPECT_TRUE(address1 != NULL); - EXPECT_TRUE(address2 != NULL); - EXPECT_TRUE(address1 == address2); -} - -// Tests that we can locate a forwarded export. -TEST(PEImageTest, ForwardedExport) { - base::FilePath pe_image_test_path; - ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &pe_image_test_path)); - pe_image_test_path = pe_image_test_path.Append(FILE_PATH_LITERAL("pe_image")); - -#if defined(ARCH_CPU_64_BITS) - pe_image_test_path = - pe_image_test_path.Append(FILE_PATH_LITERAL("pe_image_test_64.dll")); -#else - pe_image_test_path = - pe_image_test_path.Append(FILE_PATH_LITERAL("pe_image_test_32.dll")); -#endif - - ScopedNativeLibrary module(pe_image_test_path); - - ASSERT_TRUE(module.is_valid()); - - PEImage pe(module.get()); - - FARPROC addr = pe.GetProcAddress("FwdExport"); - EXPECT_EQ(FARPROC(-1), addr); - - PDWORD export_entry = pe.GetExportEntry("FwdExport"); - EXPECT_NE(nullptr, export_entry); - PVOID fwd_addr = pe.RVAToAddr(*export_entry); - const char expected_fwd[] = "KERNEL32.CreateFileA"; - EXPECT_STREQ(expected_fwd, reinterpret_cast<char*>(fwd_addr)); -} - -// Test that we can get debug id out of a module. -TEST(PEImageTest, GetDebugId) { - ScopedNativeLibrary module(FilePath(L"advapi32.dll")); - ASSERT_TRUE(module.is_valid()); - - PEImage pe(module.get()); - GUID guid = {0}; - DWORD age = 0; - LPCSTR pdb_file = nullptr; - EXPECT_TRUE(pe.GetDebugId(&guid, &age, &pdb_file)); - EXPECT_STREQ("advapi32.pdb", pdb_file); - - // Should be valid to call without parameters. - EXPECT_TRUE(pe.GetDebugId(nullptr, nullptr, nullptr)); - - GUID empty_guid = {0}; - EXPECT_TRUE(!IsEqualGUID(empty_guid, guid)); - EXPECT_NE(0U, age); -} - -} // namespace win -} // namespace base
diff --git a/base/win/registry_unittest.cc b/base/win/registry_unittest.cc deleted file mode 100644 index 5a18ffa..0000000 --- a/base/win/registry_unittest.cc +++ /dev/null
@@ -1,423 +0,0 @@ -// 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/win/registry.h" - -#include <stdint.h> - -#include <cstring> -#include <vector> - -#include "base/bind.h" -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "base/stl_util.h" -#include "base/win/windows_version.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace win { - -namespace { - -class RegistryTest : public testing::Test { - protected: -#if defined(_WIN64) - static const REGSAM kNativeViewMask = KEY_WOW64_64KEY; - static const REGSAM kRedirectedViewMask = KEY_WOW64_32KEY; -#else - static const REGSAM kNativeViewMask = KEY_WOW64_32KEY; - static const REGSAM kRedirectedViewMask = KEY_WOW64_64KEY; -#endif // _WIN64 - - RegistryTest() {} - void SetUp() override { - // Create a temporary key. - RegKey key(HKEY_CURRENT_USER, L"", KEY_ALL_ACCESS); - key.DeleteKey(kRootKey); - ASSERT_NE(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_READ)); - ASSERT_EQ(ERROR_SUCCESS, key.Create(HKEY_CURRENT_USER, kRootKey, KEY_READ)); - foo_software_key_ = L"Software\\"; - foo_software_key_ += kRootKey; - foo_software_key_ += L"\\Foo"; - } - - void TearDown() override { - // Clean up the temporary key. - RegKey key(HKEY_CURRENT_USER, L"", KEY_SET_VALUE); - ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(kRootKey)); - ASSERT_NE(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_READ)); - } - - static bool IsRedirectorPresent() { -#if defined(_WIN64) - return true; -#else - return OSInfo::GetInstance()->wow64_status() == OSInfo::WOW64_ENABLED; -#endif - } - - const wchar_t* const kRootKey = L"Base_Registry_Unittest"; - std::wstring foo_software_key_; - - private: - DISALLOW_COPY_AND_ASSIGN(RegistryTest); -}; - -// static -const REGSAM RegistryTest::kNativeViewMask; -const REGSAM RegistryTest::kRedirectedViewMask; - -TEST_F(RegistryTest, ValueTest) { - RegKey key; - - std::wstring foo_key(kRootKey); - foo_key += L"\\Foo"; - ASSERT_EQ(ERROR_SUCCESS, key.Create(HKEY_CURRENT_USER, foo_key.c_str(), - KEY_READ)); - - { - ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, foo_key.c_str(), - KEY_READ | KEY_SET_VALUE)); - ASSERT_TRUE(key.Valid()); - - const wchar_t kStringValueName[] = L"StringValue"; - const wchar_t kDWORDValueName[] = L"DWORDValue"; - const wchar_t kInt64ValueName[] = L"Int64Value"; - const wchar_t kStringData[] = L"string data"; - const DWORD kDWORDData = 0xdeadbabe; - const int64_t kInt64Data = 0xdeadbabedeadbabeLL; - - // Test value creation - ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kStringValueName, kStringData)); - ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kDWORDValueName, kDWORDData)); - ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kInt64ValueName, &kInt64Data, - sizeof(kInt64Data), REG_QWORD)); - EXPECT_EQ(3U, key.GetValueCount()); - EXPECT_TRUE(key.HasValue(kStringValueName)); - EXPECT_TRUE(key.HasValue(kDWORDValueName)); - EXPECT_TRUE(key.HasValue(kInt64ValueName)); - - // Test Read - std::wstring string_value; - DWORD dword_value = 0; - int64_t int64_value = 0; - ASSERT_EQ(ERROR_SUCCESS, key.ReadValue(kStringValueName, &string_value)); - ASSERT_EQ(ERROR_SUCCESS, key.ReadValueDW(kDWORDValueName, &dword_value)); - ASSERT_EQ(ERROR_SUCCESS, key.ReadInt64(kInt64ValueName, &int64_value)); - EXPECT_STREQ(kStringData, string_value.c_str()); - EXPECT_EQ(kDWORDData, dword_value); - EXPECT_EQ(kInt64Data, int64_value); - - // Make sure out args are not touched if ReadValue fails - const wchar_t* kNonExistent = L"NonExistent"; - ASSERT_NE(ERROR_SUCCESS, key.ReadValue(kNonExistent, &string_value)); - ASSERT_NE(ERROR_SUCCESS, key.ReadValueDW(kNonExistent, &dword_value)); - ASSERT_NE(ERROR_SUCCESS, key.ReadInt64(kNonExistent, &int64_value)); - EXPECT_STREQ(kStringData, string_value.c_str()); - EXPECT_EQ(kDWORDData, dword_value); - EXPECT_EQ(kInt64Data, int64_value); - - // Test delete - ASSERT_EQ(ERROR_SUCCESS, key.DeleteValue(kStringValueName)); - ASSERT_EQ(ERROR_SUCCESS, key.DeleteValue(kDWORDValueName)); - ASSERT_EQ(ERROR_SUCCESS, key.DeleteValue(kInt64ValueName)); - EXPECT_EQ(0U, key.GetValueCount()); - EXPECT_FALSE(key.HasValue(kStringValueName)); - EXPECT_FALSE(key.HasValue(kDWORDValueName)); - EXPECT_FALSE(key.HasValue(kInt64ValueName)); - } -} - -TEST_F(RegistryTest, BigValueIteratorTest) { - RegKey key; - std::wstring foo_key(kRootKey); - foo_key += L"\\Foo"; - ASSERT_EQ(ERROR_SUCCESS, key.Create(HKEY_CURRENT_USER, foo_key.c_str(), - KEY_READ)); - ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, foo_key.c_str(), - KEY_READ | KEY_SET_VALUE)); - ASSERT_TRUE(key.Valid()); - - // Create a test value that is larger than MAX_PATH. - std::wstring data(MAX_PATH * 2, L'a'); - - ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(data.c_str(), data.c_str())); - - RegistryValueIterator iterator(HKEY_CURRENT_USER, foo_key.c_str()); - ASSERT_TRUE(iterator.Valid()); - EXPECT_STREQ(data.c_str(), iterator.Name()); - EXPECT_STREQ(data.c_str(), iterator.Value()); - // ValueSize() is in bytes, including NUL. - EXPECT_EQ((MAX_PATH * 2 + 1) * sizeof(wchar_t), iterator.ValueSize()); - ++iterator; - EXPECT_FALSE(iterator.Valid()); -} - -TEST_F(RegistryTest, TruncatedCharTest) { - RegKey key; - std::wstring foo_key(kRootKey); - foo_key += L"\\Foo"; - ASSERT_EQ(ERROR_SUCCESS, key.Create(HKEY_CURRENT_USER, foo_key.c_str(), - KEY_READ)); - ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, foo_key.c_str(), - KEY_READ | KEY_SET_VALUE)); - ASSERT_TRUE(key.Valid()); - - const wchar_t kName[] = L"name"; - // kData size is not a multiple of sizeof(wchar_t). - const uint8_t kData[] = {1, 2, 3, 4, 5}; - EXPECT_EQ(5u, arraysize(kData)); - ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kName, kData, - arraysize(kData), REG_BINARY)); - - RegistryValueIterator iterator(HKEY_CURRENT_USER, foo_key.c_str()); - ASSERT_TRUE(iterator.Valid()); - EXPECT_STREQ(kName, iterator.Name()); - // ValueSize() is in bytes. - ASSERT_EQ(arraysize(kData), iterator.ValueSize()); - // Value() is NUL terminated. - int end = (iterator.ValueSize() + sizeof(wchar_t) - 1) / sizeof(wchar_t); - EXPECT_NE(L'\0', iterator.Value()[end-1]); - EXPECT_EQ(L'\0', iterator.Value()[end]); - EXPECT_EQ(0, std::memcmp(kData, iterator.Value(), arraysize(kData))); - ++iterator; - EXPECT_FALSE(iterator.Valid()); -} - -TEST_F(RegistryTest, RecursiveDelete) { - RegKey key; - // Create kRootKey->Foo - // \->Bar (TestValue) - // \->Foo (TestValue) - // \->Bar - // \->Foo - // \->Moo - // \->Foo - // and delete kRootKey->Foo - std::wstring foo_key(kRootKey); - foo_key += L"\\Foo"; - ASSERT_EQ(ERROR_SUCCESS, - key.Create(HKEY_CURRENT_USER, foo_key.c_str(), KEY_WRITE)); - ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Bar", KEY_WRITE)); - ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(L"TestValue", L"TestData")); - ASSERT_EQ(ERROR_SUCCESS, - key.Create(HKEY_CURRENT_USER, foo_key.c_str(), KEY_WRITE)); - ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Moo", KEY_WRITE)); - ASSERT_EQ(ERROR_SUCCESS, - key.Create(HKEY_CURRENT_USER, foo_key.c_str(), KEY_WRITE)); - ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Foo", KEY_WRITE)); - foo_key += L"\\Bar"; - ASSERT_EQ(ERROR_SUCCESS, - key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_WRITE)); - foo_key += L"\\Foo"; - ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Foo", KEY_WRITE)); - ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(L"TestValue", L"TestData")); - ASSERT_EQ(ERROR_SUCCESS, - key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_READ)); - - ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_WRITE)); - ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(L"Bar")); - ASSERT_NE(ERROR_SUCCESS, key.DeleteEmptyKey(L"Foo")); - ASSERT_NE(ERROR_SUCCESS, key.DeleteEmptyKey(L"Foo\\Bar\\Foo")); - ASSERT_NE(ERROR_SUCCESS, key.DeleteEmptyKey(L"Foo\\Bar")); - ASSERT_EQ(ERROR_SUCCESS, key.DeleteEmptyKey(L"Foo\\Foo")); - - ASSERT_EQ(ERROR_SUCCESS, - key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_WRITE)); - ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Bar", KEY_WRITE)); - ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Foo", KEY_WRITE)); - ASSERT_EQ(ERROR_SUCCESS, - key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_WRITE)); - ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(L"")); - ASSERT_NE(ERROR_SUCCESS, - key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_READ)); - - ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_WRITE)); - ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(L"Foo")); - ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(L"Foo")); - ASSERT_NE(ERROR_SUCCESS, - key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_READ)); -} - -// This test requires running as an Administrator as it tests redirected -// registry writes to HKLM\Software -// http://msdn.microsoft.com/en-us/library/windows/desktop/aa384253.aspx -// TODO(wfh): flaky test on Vista. See http://crbug.com/377917 -TEST_F(RegistryTest, DISABLED_Wow64RedirectedFromNative) { - if (!IsRedirectorPresent()) - return; - - RegKey key; - - // Test redirected key access from non-redirected. - ASSERT_EQ(ERROR_SUCCESS, - key.Create(HKEY_LOCAL_MACHINE, - foo_software_key_.c_str(), - KEY_WRITE | kRedirectedViewMask)); - ASSERT_NE(ERROR_SUCCESS, - key.Open(HKEY_LOCAL_MACHINE, foo_software_key_.c_str(), KEY_READ)); - ASSERT_NE(ERROR_SUCCESS, - key.Open(HKEY_LOCAL_MACHINE, - foo_software_key_.c_str(), - KEY_READ | kNativeViewMask)); - - // Open the non-redirected view of the parent and try to delete the test key. - ASSERT_EQ(ERROR_SUCCESS, - key.Open(HKEY_LOCAL_MACHINE, L"Software", KEY_SET_VALUE)); - ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(kRootKey)); - ASSERT_EQ(ERROR_SUCCESS, - key.Open(HKEY_LOCAL_MACHINE, - L"Software", - KEY_SET_VALUE | kNativeViewMask)); - ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(kRootKey)); - - // Open the redirected view and delete the key created above. - ASSERT_EQ(ERROR_SUCCESS, - key.Open(HKEY_LOCAL_MACHINE, - L"Software", - KEY_SET_VALUE | kRedirectedViewMask)); - ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(kRootKey)); -} - -// Test for the issue found in http://crbug.com/384587 where OpenKey would call -// Close() and reset wow64_access_ flag to 0 and cause a NOTREACHED to hit on a -// subsequent OpenKey call. -TEST_F(RegistryTest, SameWowFlags) { - RegKey key; - - ASSERT_EQ(ERROR_SUCCESS, - key.Open(HKEY_LOCAL_MACHINE, - L"Software", - KEY_READ | KEY_WOW64_64KEY)); - ASSERT_EQ(ERROR_SUCCESS, - key.OpenKey(L"Microsoft", - KEY_READ | KEY_WOW64_64KEY)); - ASSERT_EQ(ERROR_SUCCESS, - key.OpenKey(L"Windows", - KEY_READ | KEY_WOW64_64KEY)); -} - -// TODO(wfh): flaky test on Vista. See http://crbug.com/377917 -TEST_F(RegistryTest, DISABLED_Wow64NativeFromRedirected) { - if (!IsRedirectorPresent()) - return; - RegKey key; - - // Test non-redirected key access from redirected. - ASSERT_EQ(ERROR_SUCCESS, - key.Create(HKEY_LOCAL_MACHINE, - foo_software_key_.c_str(), - KEY_WRITE | kNativeViewMask)); - ASSERT_EQ(ERROR_SUCCESS, - key.Open(HKEY_LOCAL_MACHINE, foo_software_key_.c_str(), KEY_READ)); - ASSERT_NE(ERROR_SUCCESS, - key.Open(HKEY_LOCAL_MACHINE, - foo_software_key_.c_str(), - KEY_READ | kRedirectedViewMask)); - - // Open the redirected view of the parent and try to delete the test key - // from the non-redirected view. - ASSERT_EQ(ERROR_SUCCESS, - key.Open(HKEY_LOCAL_MACHINE, - L"Software", - KEY_SET_VALUE | kRedirectedViewMask)); - ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(kRootKey)); - - ASSERT_EQ(ERROR_SUCCESS, - key.Open(HKEY_LOCAL_MACHINE, - L"Software", - KEY_SET_VALUE | kNativeViewMask)); - ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(kRootKey)); -} - -TEST_F(RegistryTest, OpenSubKey) { - RegKey key; - ASSERT_EQ(ERROR_SUCCESS, - key.Open(HKEY_CURRENT_USER, - kRootKey, - KEY_READ | KEY_CREATE_SUB_KEY)); - - ASSERT_NE(ERROR_SUCCESS, key.OpenKey(L"foo", KEY_READ)); - ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"foo", KEY_READ)); - ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_READ)); - ASSERT_EQ(ERROR_SUCCESS, key.OpenKey(L"foo", KEY_READ)); - - std::wstring foo_key(kRootKey); - foo_key += L"\\Foo"; - ASSERT_EQ(ERROR_SUCCESS, - key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_READ)); - - ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_WRITE)); - ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(L"foo")); -} - -class TestChangeDelegate { - public: - TestChangeDelegate() : called_(false) {} - ~TestChangeDelegate() {} - - void OnKeyChanged() { - RunLoop::QuitCurrentWhenIdleDeprecated(); - called_ = true; - } - - bool WasCalled() { - bool was_called = called_; - called_ = false; - return was_called; - } - - private: - bool called_; -}; - -TEST_F(RegistryTest, ChangeCallback) { - RegKey key; - TestChangeDelegate delegate; - MessageLoop message_loop; - - std::wstring foo_key(kRootKey); - foo_key += L"\\Foo"; - ASSERT_EQ(ERROR_SUCCESS, key.Create(HKEY_CURRENT_USER, foo_key.c_str(), - KEY_READ)); - - ASSERT_TRUE(key.StartWatching(Bind(&TestChangeDelegate::OnKeyChanged, - Unretained(&delegate)))); - EXPECT_FALSE(delegate.WasCalled()); - - // Make some change. - RegKey key2; - ASSERT_EQ(ERROR_SUCCESS, key2.Open(HKEY_CURRENT_USER, foo_key.c_str(), - KEY_READ | KEY_SET_VALUE)); - ASSERT_TRUE(key2.Valid()); - EXPECT_EQ(ERROR_SUCCESS, key2.WriteValue(L"name", L"data")); - - // Allow delivery of the notification. - EXPECT_FALSE(delegate.WasCalled()); - base::RunLoop().Run(); - - ASSERT_TRUE(delegate.WasCalled()); - EXPECT_FALSE(delegate.WasCalled()); - - ASSERT_TRUE(key.StartWatching(Bind(&TestChangeDelegate::OnKeyChanged, - Unretained(&delegate)))); - - // Change something else. - EXPECT_EQ(ERROR_SUCCESS, key2.WriteValue(L"name2", L"data2")); - base::RunLoop().Run(); - ASSERT_TRUE(delegate.WasCalled()); - - ASSERT_TRUE(key.StartWatching(Bind(&TestChangeDelegate::OnKeyChanged, - Unretained(&delegate)))); - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(delegate.WasCalled()); -} - -} // namespace - -} // namespace win -} // namespace base
diff --git a/base/win/scoped_bstr_unittest.cc b/base/win/scoped_bstr_unittest.cc deleted file mode 100644 index d305e5a..0000000 --- a/base/win/scoped_bstr_unittest.cc +++ /dev/null
@@ -1,80 +0,0 @@ -// 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 <stddef.h> - -#include "base/macros.h" -#include "base/win/scoped_bstr.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace win { - -namespace { - -static const wchar_t kTestString1[] = L"123"; -static const wchar_t kTestString2[] = L"456789"; -size_t test1_len = arraysize(kTestString1) - 1; -size_t test2_len = arraysize(kTestString2) - 1; - -void DumbBstrTests() { - ScopedBstr b; - EXPECT_TRUE(b == NULL); - EXPECT_EQ(0u, b.Length()); - EXPECT_EQ(0u, b.ByteLength()); - b.Reset(NULL); - EXPECT_TRUE(b == NULL); - EXPECT_TRUE(b.Release() == NULL); - ScopedBstr b2; - b.Swap(b2); - EXPECT_TRUE(b2 == NULL); -} - -void GiveMeABstr(BSTR* ret) { - *ret = SysAllocString(kTestString1); -} - -void BasicBstrTests() { - ScopedBstr b1(kTestString1); - EXPECT_EQ(test1_len, b1.Length()); - EXPECT_EQ(test1_len * sizeof(kTestString1[0]), b1.ByteLength()); - - ScopedBstr b2; - b1.Swap(b2); - EXPECT_EQ(test1_len, b2.Length()); - EXPECT_EQ(0u, b1.Length()); - EXPECT_EQ(0, lstrcmp(b2, kTestString1)); - BSTR tmp = b2.Release(); - EXPECT_TRUE(tmp != NULL); - EXPECT_EQ(0, lstrcmp(tmp, kTestString1)); - EXPECT_TRUE(b2 == NULL); - SysFreeString(tmp); - - GiveMeABstr(b2.Receive()); - EXPECT_TRUE(b2 != NULL); - b2.Reset(); - EXPECT_TRUE(b2.AllocateBytes(100) != NULL); - EXPECT_EQ(100u, b2.ByteLength()); - EXPECT_EQ(100 / sizeof(kTestString1[0]), b2.Length()); - lstrcpy(static_cast<BSTR>(b2), kTestString1); - EXPECT_EQ(test1_len, static_cast<size_t>(lstrlen(b2))); - EXPECT_EQ(100 / sizeof(kTestString1[0]), b2.Length()); - b2.SetByteLen(lstrlen(b2) * sizeof(kTestString2[0])); - EXPECT_EQ(b2.Length(), static_cast<size_t>(lstrlen(b2))); - - EXPECT_TRUE(b1.Allocate(kTestString2) != NULL); - EXPECT_EQ(test2_len, b1.Length()); - b1.SetByteLen((test2_len - 1) * sizeof(kTestString2[0])); - EXPECT_EQ(test2_len - 1, b1.Length()); -} - -} // namespace - -TEST(ScopedBstrTest, ScopedBstr) { - DumbBstrTests(); - BasicBstrTests(); -} - -} // namespace win -} // namespace base
diff --git a/base/win/scoped_handle_unittest.cc b/base/win/scoped_handle_unittest.cc deleted file mode 100644 index ca6fb45..0000000 --- a/base/win/scoped_handle_unittest.cc +++ /dev/null
@@ -1,142 +0,0 @@ -// 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 <windows.h> -#include <winternl.h> - -#include "base/base_switches.h" -#include "base/command_line.h" -#include "base/files/file_path.h" -#include "base/scoped_native_library.h" -#include "base/test/multiprocess_test.h" -#include "base/test/test_timeouts.h" -#include "base/win/scoped_handle.h" - -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/multiprocess_func_list.h" - -namespace base { -namespace win { - -namespace testing { -extern "C" bool __declspec(dllexport) RunTest(); -} // namespace testing - -TEST(ScopedHandleTest, ScopedHandle) { - // Any illegal error code will do. We just need to test that it is preserved - // by ScopedHandle to avoid bug 528394. - const DWORD magic_error = 0x12345678; - - HANDLE handle = ::CreateMutex(nullptr, false, nullptr); - // Call SetLastError after creating the handle. - ::SetLastError(magic_error); - base::win::ScopedHandle handle_holder(handle); - EXPECT_EQ(magic_error, ::GetLastError()); - - // Create a new handle and then set LastError again. - handle = ::CreateMutex(nullptr, false, nullptr); - ::SetLastError(magic_error); - handle_holder.Set(handle); - EXPECT_EQ(magic_error, ::GetLastError()); - - // Create a new handle and then set LastError again. - handle = ::CreateMutex(nullptr, false, nullptr); - base::win::ScopedHandle handle_source(handle); - ::SetLastError(magic_error); - handle_holder = std::move(handle_source); - EXPECT_EQ(magic_error, ::GetLastError()); -} - -TEST(ScopedHandleTest, ActiveVerifierTrackedHasBeenClosed) { - HANDLE handle = ::CreateMutex(nullptr, false, nullptr); - ASSERT_NE(HANDLE(nullptr), handle); - typedef NTSTATUS(WINAPI * NtCloseFunc)(HANDLE); - NtCloseFunc ntclose = reinterpret_cast<NtCloseFunc>( - GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtClose")); - ASSERT_NE(nullptr, ntclose); - - ASSERT_DEATH({ - base::win::ScopedHandle handle_holder(handle); - ntclose(handle); - // Destructing a ScopedHandle with an illegally closed handle should fail. - }, ""); -} - -TEST(ScopedHandleTest, ActiveVerifierDoubleTracking) { - HANDLE handle = ::CreateMutex(nullptr, false, nullptr); - ASSERT_NE(HANDLE(nullptr), handle); - - base::win::ScopedHandle handle_holder(handle); - - ASSERT_DEATH({ - base::win::ScopedHandle handle_holder2(handle); - }, ""); -} - -TEST(ScopedHandleTest, ActiveVerifierWrongOwner) { - HANDLE handle = ::CreateMutex(nullptr, false, nullptr); - ASSERT_NE(HANDLE(nullptr), handle); - - base::win::ScopedHandle handle_holder(handle); - ASSERT_DEATH({ - base::win::ScopedHandle handle_holder2; - handle_holder2.handle_ = handle; - }, ""); - ASSERT_TRUE(handle_holder.IsValid()); - handle_holder.Close(); -} - -TEST(ScopedHandleTest, ActiveVerifierUntrackedHandle) { - HANDLE handle = ::CreateMutex(nullptr, false, nullptr); - ASSERT_NE(HANDLE(nullptr), handle); - - ASSERT_DEATH({ - base::win::ScopedHandle handle_holder; - handle_holder.handle_ = handle; - }, ""); - - ASSERT_TRUE(::CloseHandle(handle)); -} - -// Under ASan, the multi-process test crashes during process shutdown for -// unknown reasons. Disable it for now. http://crbug.com/685262 -#if defined(ADDRESS_SANITIZER) -#define MAYBE_MultiProcess DISABLED_MultiProcess -#else -#define MAYBE_MultiProcess MultiProcess -#endif - -TEST(ScopedHandleTest, MAYBE_MultiProcess) { - // Initializing ICU in the child process causes a scoped handle to be created - // before the test gets a chance to test the race condition, so disable ICU - // for the child process here. - CommandLine command_line(base::GetMultiProcessTestChildBaseCommandLine()); - command_line.AppendSwitch(switches::kTestDoNotInitializeIcu); - - base::Process test_child_process = base::SpawnMultiProcessTestChild( - "ActiveVerifierChildProcess", command_line, LaunchOptions()); - - int rv = -1; - ASSERT_TRUE(test_child_process.WaitForExitWithTimeout( - TestTimeouts::action_timeout(), &rv)); - EXPECT_EQ(0, rv); -} - -MULTIPROCESS_TEST_MAIN(ActiveVerifierChildProcess) { - ScopedNativeLibrary module(FilePath(L"scoped_handle_test_dll.dll")); - - if (!module.is_valid()) - return 1; - auto run_test_function = reinterpret_cast<decltype(&testing::RunTest)>( - module.GetFunctionPointer("RunTest")); - if (!run_test_function) - return 1; - if (!run_test_function()) - return 1; - - return 0; -} - -} // namespace win -} // namespace base
diff --git a/base/win/scoped_hstring_unittest.cc b/base/win/scoped_hstring_unittest.cc deleted file mode 100644 index fdcf8ff..0000000 --- a/base/win/scoped_hstring_unittest.cc +++ /dev/null
@@ -1,55 +0,0 @@ -// 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/win/scoped_hstring.h" - -#include <winstring.h> - -#include "base/strings/utf_string_conversions.h" -#include "base/win/core_winrt_util.h" -#include "base/win/windows_version.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace win { - -namespace { - -constexpr wchar_t kTestString1[] = L"123"; -constexpr wchar_t kTestString2[] = L"456789"; - -} // namespace - -TEST(ScopedHStringTest, Init) { - // ScopedHString requires WinRT core functions, which are not available in - // older versions. - if (GetVersion() < VERSION_WIN8) { - EXPECT_FALSE(ScopedHString::ResolveCoreWinRTStringDelayload()); - return; - } - - EXPECT_TRUE(ScopedHString::ResolveCoreWinRTStringDelayload()); - - ScopedHString hstring = ScopedHString::Create(kTestString1); - std::string buffer = hstring.GetAsUTF8(); - EXPECT_EQ(kTestString1, base::UTF8ToWide(buffer)); - base::StringPiece16 contents = hstring.Get(); - EXPECT_EQ(kTestString1, contents); - - hstring.reset(); - EXPECT_TRUE(hstring == NULL); - EXPECT_EQ(NULL, hstring.get()); - - ScopedHString hstring2 = ScopedHString::Create(kTestString2); - hstring.swap(hstring2); - EXPECT_TRUE(hstring2 == NULL); - - buffer = hstring.GetAsUTF8(); - EXPECT_EQ(kTestString2, base::UTF8ToWide(buffer)); - contents = hstring.Get(); - EXPECT_EQ(kTestString2, contents); -} - -} // namespace win -} // namespace base
diff --git a/base/win/scoped_process_information_unittest.cc b/base/win/scoped_process_information_unittest.cc deleted file mode 100644 index 799b273..0000000 --- a/base/win/scoped_process_information_unittest.cc +++ /dev/null
@@ -1,166 +0,0 @@ -// 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 <windows.h> - -#include <string> - -#include "base/command_line.h" -#include "base/process/kill.h" -#include "base/process/process.h" -#include "base/test/multiprocess_test.h" -#include "base/win/scoped_process_information.h" -#include "testing/multiprocess_func_list.h" - -namespace { - -const DWORD kProcessId = 4321; -const DWORD kThreadId = 1234; -const HANDLE kProcessHandle = reinterpret_cast<HANDLE>(7651); -const HANDLE kThreadHandle = reinterpret_cast<HANDLE>(1567); - -void MockCreateProcess(base::win::ScopedProcessInformation* process_info) { - PROCESS_INFORMATION process_information = {}; - process_information.dwProcessId = kProcessId; - process_information.dwThreadId = kThreadId; - process_information.hProcess = kProcessHandle; - process_information.hThread = kThreadHandle; - process_info->Set(process_information); -} - -} // namespace - -class ScopedProcessInformationTest : public base::MultiProcessTest { - protected: - void DoCreateProcess(const std::string& main_id, - PROCESS_INFORMATION* process_handle); -}; - -MULTIPROCESS_TEST_MAIN(ReturnSeven) { - return 7; -} - -MULTIPROCESS_TEST_MAIN(ReturnNine) { - return 9; -} - -void ScopedProcessInformationTest::DoCreateProcess( - const std::string& main_id, PROCESS_INFORMATION* process_handle) { - std::wstring cmd_line = MakeCmdLine(main_id).GetCommandLineString(); - STARTUPINFO startup_info = {}; - startup_info.cb = sizeof(startup_info); - - EXPECT_TRUE(::CreateProcess(NULL, &cmd_line[0], - NULL, NULL, false, 0, NULL, NULL, - &startup_info, process_handle)); -} - -TEST_F(ScopedProcessInformationTest, InitiallyInvalid) { - base::win::ScopedProcessInformation process_info; - ASSERT_FALSE(process_info.IsValid()); -} - -TEST_F(ScopedProcessInformationTest, Receive) { - base::win::ScopedProcessInformation process_info; - MockCreateProcess(&process_info); - - EXPECT_TRUE(process_info.IsValid()); - EXPECT_EQ(kProcessId, process_info.process_id()); - EXPECT_EQ(kThreadId, process_info.thread_id()); - EXPECT_EQ(kProcessHandle, process_info.process_handle()); - EXPECT_EQ(kThreadHandle, process_info.thread_handle()); - process_info.Take(); -} - -TEST_F(ScopedProcessInformationTest, TakeProcess) { - base::win::ScopedProcessInformation process_info; - MockCreateProcess(&process_info); - - HANDLE process = process_info.TakeProcessHandle(); - EXPECT_EQ(kProcessHandle, process); - EXPECT_EQ(NULL, process_info.process_handle()); - EXPECT_EQ(0u, process_info.process_id()); - EXPECT_TRUE(process_info.IsValid()); - process_info.Take(); -} - -TEST_F(ScopedProcessInformationTest, TakeThread) { - base::win::ScopedProcessInformation process_info; - MockCreateProcess(&process_info); - - HANDLE thread = process_info.TakeThreadHandle(); - EXPECT_EQ(kThreadHandle, thread); - EXPECT_EQ(NULL, process_info.thread_handle()); - EXPECT_EQ(0u, process_info.thread_id()); - EXPECT_TRUE(process_info.IsValid()); - process_info.Take(); -} - -TEST_F(ScopedProcessInformationTest, TakeBoth) { - base::win::ScopedProcessInformation process_info; - MockCreateProcess(&process_info); - - process_info.TakeProcessHandle(); - process_info.TakeThreadHandle(); - EXPECT_FALSE(process_info.IsValid()); - process_info.Take(); -} - -TEST_F(ScopedProcessInformationTest, TakeWholeStruct) { - base::win::ScopedProcessInformation process_info; - MockCreateProcess(&process_info); - - PROCESS_INFORMATION to_discard = process_info.Take(); - EXPECT_EQ(kProcessId, to_discard.dwProcessId); - EXPECT_EQ(kThreadId, to_discard.dwThreadId); - EXPECT_EQ(kProcessHandle, to_discard.hProcess); - EXPECT_EQ(kThreadHandle, to_discard.hThread); - EXPECT_FALSE(process_info.IsValid()); -} - -TEST_F(ScopedProcessInformationTest, Duplicate) { - PROCESS_INFORMATION temp_process_information; - DoCreateProcess("ReturnSeven", &temp_process_information); - base::win::ScopedProcessInformation process_info; - process_info.Set(temp_process_information); - - base::win::ScopedProcessInformation duplicate; - duplicate.DuplicateFrom(process_info); - - ASSERT_TRUE(process_info.IsValid()); - ASSERT_NE(0u, process_info.process_id()); - ASSERT_EQ(duplicate.process_id(), process_info.process_id()); - ASSERT_NE(0u, process_info.thread_id()); - ASSERT_EQ(duplicate.thread_id(), process_info.thread_id()); - - // Validate that we have separate handles that are good. - int exit_code = 0; - base::Process process(process_info.TakeProcessHandle()); - ASSERT_TRUE(process.WaitForExit(&exit_code)); - ASSERT_EQ(7, exit_code); - - exit_code = 0; - base::Process dup_process(duplicate.TakeProcessHandle()); - ASSERT_TRUE(dup_process.WaitForExit(&exit_code)); - ASSERT_EQ(7, exit_code); - - ASSERT_TRUE(::CloseHandle(process_info.TakeThreadHandle())); - ASSERT_TRUE(::CloseHandle(duplicate.TakeThreadHandle())); -} - -TEST_F(ScopedProcessInformationTest, Set) { - base::win::ScopedProcessInformation base_process_info; - MockCreateProcess(&base_process_info); - - PROCESS_INFORMATION base_struct = base_process_info.Take(); - - base::win::ScopedProcessInformation process_info; - process_info.Set(base_struct); - - EXPECT_EQ(kProcessId, process_info.process_id()); - EXPECT_EQ(kThreadId, process_info.thread_id()); - EXPECT_EQ(kProcessHandle, process_info.process_handle()); - EXPECT_EQ(kThreadHandle, process_info.thread_handle()); - base_struct = process_info.Take(); -}
diff --git a/base/win/scoped_variant_unittest.cc b/base/win/scoped_variant_unittest.cc deleted file mode 100644 index 7d61e28..0000000 --- a/base/win/scoped_variant_unittest.cc +++ /dev/null
@@ -1,263 +0,0 @@ -// 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 <stdint.h> - -#include "base/win/scoped_variant.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace win { - -namespace { - -static const wchar_t kTestString1[] = L"Used to create BSTRs"; -static const wchar_t kTestString2[] = L"Also used to create BSTRs"; - -void GiveMeAVariant(VARIANT* ret) { - EXPECT_TRUE(ret != NULL); - ret->vt = VT_BSTR; - V_BSTR(ret) = ::SysAllocString(kTestString1); -} - -// A dummy IDispatch implementation (if you can call it that). -// The class does nothing intelligent really. Only increments a counter -// when AddRef is called and decrements it when Release is called. -class FakeComObject : public IDispatch { - public: - FakeComObject() : ref_(0) { - } - - STDMETHOD_(DWORD, AddRef)() override { - ref_++; - return ref_; - } - - STDMETHOD_(DWORD, Release)() override { - ref_--; - return ref_; - } - - STDMETHOD(QueryInterface)(REFIID, void**) override { return E_NOTIMPL; } - - STDMETHOD(GetTypeInfoCount)(UINT*) override { return E_NOTIMPL; } - - STDMETHOD(GetTypeInfo)(UINT, LCID, ITypeInfo**) override { return E_NOTIMPL; } - - STDMETHOD(GetIDsOfNames)(REFIID, LPOLESTR*, UINT, LCID, DISPID*) override { - return E_NOTIMPL; - } - - STDMETHOD(Invoke)(DISPID, - REFIID, - LCID, - WORD, - DISPPARAMS*, - VARIANT*, - EXCEPINFO*, - UINT*) override { - return E_NOTIMPL; - } - - // A way to check the internal reference count of the class. - int ref_count() const { - return ref_; - } - - protected: - int ref_; -}; - -} // namespace - -TEST(ScopedVariantTest, ScopedVariant) { - ScopedVariant var; - EXPECT_TRUE(var.type() == VT_EMPTY); - // V_BSTR(var.ptr()) = NULL; <- NOTE: Assignment like that is not supported. - - ScopedVariant var_bstr(L"VT_BSTR"); - EXPECT_EQ(VT_BSTR, V_VT(var_bstr.ptr())); - EXPECT_TRUE(V_BSTR(var_bstr.ptr()) != NULL); // can't use EXPECT_NE for BSTR - var_bstr.Reset(); - EXPECT_NE(VT_BSTR, V_VT(var_bstr.ptr())); - var_bstr.Set(kTestString2); - EXPECT_EQ(VT_BSTR, V_VT(var_bstr.ptr())); - - VARIANT tmp = var_bstr.Release(); - EXPECT_EQ(VT_EMPTY, V_VT(var_bstr.ptr())); - EXPECT_EQ(VT_BSTR, V_VT(&tmp)); - EXPECT_EQ(0, lstrcmp(V_BSTR(&tmp), kTestString2)); - - var.Reset(tmp); - EXPECT_EQ(VT_BSTR, V_VT(var.ptr())); - EXPECT_EQ(0, lstrcmpW(V_BSTR(var.ptr()), kTestString2)); - - var_bstr.Swap(var); - EXPECT_EQ(VT_EMPTY, V_VT(var.ptr())); - EXPECT_EQ(VT_BSTR, V_VT(var_bstr.ptr())); - EXPECT_EQ(0, lstrcmpW(V_BSTR(var_bstr.ptr()), kTestString2)); - var_bstr.Reset(); - - // Test the Compare and Copy routines. - GiveMeAVariant(var_bstr.Receive()); - ScopedVariant var_bstr2(V_BSTR(var_bstr.ptr())); - EXPECT_EQ(0, var_bstr.Compare(var_bstr2)); - var_bstr2.Reset(); - EXPECT_NE(0, var_bstr.Compare(var_bstr2)); - var_bstr2.Reset(var_bstr.Copy()); - EXPECT_EQ(0, var_bstr.Compare(var_bstr2)); - var_bstr2.Reset(); - var_bstr2.Set(V_BSTR(var_bstr.ptr())); - EXPECT_EQ(0, var_bstr.Compare(var_bstr2)); - var_bstr2.Reset(); - var_bstr.Reset(); - - // Test for the SetDate setter. - SYSTEMTIME sys_time; - ::GetSystemTime(&sys_time); - DATE date; - ::SystemTimeToVariantTime(&sys_time, &date); - var.Reset(); - var.SetDate(date); - EXPECT_EQ(VT_DATE, var.type()); - EXPECT_EQ(date, V_DATE(var.ptr())); - - // Simple setter tests. These do not require resetting the variant - // after each test since the variant type is not "leakable" (i.e. doesn't - // need to be freed explicitly). - - // We need static cast here since char defaults to int (!?). - var.Set(static_cast<int8_t>('v')); - EXPECT_EQ(VT_I1, var.type()); - EXPECT_EQ('v', V_I1(var.ptr())); - - var.Set(static_cast<short>(123)); - EXPECT_EQ(VT_I2, var.type()); - EXPECT_EQ(123, V_I2(var.ptr())); - - var.Set(static_cast<int32_t>(123)); - EXPECT_EQ(VT_I4, var.type()); - EXPECT_EQ(123, V_I4(var.ptr())); - - var.Set(static_cast<int64_t>(123)); - EXPECT_EQ(VT_I8, var.type()); - EXPECT_EQ(123, V_I8(var.ptr())); - - var.Set(static_cast<uint8_t>(123)); - EXPECT_EQ(VT_UI1, var.type()); - EXPECT_EQ(123u, V_UI1(var.ptr())); - - var.Set(static_cast<unsigned short>(123)); - EXPECT_EQ(VT_UI2, var.type()); - EXPECT_EQ(123u, V_UI2(var.ptr())); - - var.Set(static_cast<uint32_t>(123)); - EXPECT_EQ(VT_UI4, var.type()); - EXPECT_EQ(123u, V_UI4(var.ptr())); - - var.Set(static_cast<uint64_t>(123)); - EXPECT_EQ(VT_UI8, var.type()); - EXPECT_EQ(123u, V_UI8(var.ptr())); - - var.Set(123.123f); - EXPECT_EQ(VT_R4, var.type()); - EXPECT_EQ(123.123f, V_R4(var.ptr())); - - var.Set(static_cast<double>(123.123)); - EXPECT_EQ(VT_R8, var.type()); - EXPECT_EQ(123.123, V_R8(var.ptr())); - - var.Set(true); - EXPECT_EQ(VT_BOOL, var.type()); - EXPECT_EQ(VARIANT_TRUE, V_BOOL(var.ptr())); - var.Set(false); - EXPECT_EQ(VT_BOOL, var.type()); - EXPECT_EQ(VARIANT_FALSE, V_BOOL(var.ptr())); - - // Com interface tests - - var.Set(static_cast<IDispatch*>(NULL)); - EXPECT_EQ(VT_DISPATCH, var.type()); - EXPECT_EQ(NULL, V_DISPATCH(var.ptr())); - var.Reset(); - - var.Set(static_cast<IUnknown*>(NULL)); - EXPECT_EQ(VT_UNKNOWN, var.type()); - EXPECT_EQ(NULL, V_UNKNOWN(var.ptr())); - var.Reset(); - - FakeComObject faker; - EXPECT_EQ(0, faker.ref_count()); - var.Set(static_cast<IDispatch*>(&faker)); - EXPECT_EQ(VT_DISPATCH, var.type()); - EXPECT_EQ(&faker, V_DISPATCH(var.ptr())); - EXPECT_EQ(1, faker.ref_count()); - var.Reset(); - EXPECT_EQ(0, faker.ref_count()); - - var.Set(static_cast<IUnknown*>(&faker)); - EXPECT_EQ(VT_UNKNOWN, var.type()); - EXPECT_EQ(&faker, V_UNKNOWN(var.ptr())); - EXPECT_EQ(1, faker.ref_count()); - var.Reset(); - EXPECT_EQ(0, faker.ref_count()); - - { - ScopedVariant disp_var(&faker); - EXPECT_EQ(VT_DISPATCH, disp_var.type()); - EXPECT_EQ(&faker, V_DISPATCH(disp_var.ptr())); - EXPECT_EQ(1, faker.ref_count()); - } - EXPECT_EQ(0, faker.ref_count()); - - { - ScopedVariant ref1(&faker); - EXPECT_EQ(1, faker.ref_count()); - ScopedVariant ref2(static_cast<const VARIANT&>(ref1)); - EXPECT_EQ(2, faker.ref_count()); - ScopedVariant ref3; - ref3 = static_cast<const VARIANT&>(ref2); - EXPECT_EQ(3, faker.ref_count()); - } - EXPECT_EQ(0, faker.ref_count()); - - { - ScopedVariant unk_var(static_cast<IUnknown*>(&faker)); - EXPECT_EQ(VT_UNKNOWN, unk_var.type()); - EXPECT_EQ(&faker, V_UNKNOWN(unk_var.ptr())); - EXPECT_EQ(1, faker.ref_count()); - } - EXPECT_EQ(0, faker.ref_count()); - - VARIANT raw; - raw.vt = VT_UNKNOWN; - raw.punkVal = &faker; - EXPECT_EQ(0, faker.ref_count()); - var.Set(raw); - EXPECT_EQ(1, faker.ref_count()); - var.Reset(); - EXPECT_EQ(0, faker.ref_count()); - - { - ScopedVariant number(123); - EXPECT_EQ(VT_I4, number.type()); - EXPECT_EQ(123, V_I4(number.ptr())); - } - - // SAFEARRAY tests - var.Set(static_cast<SAFEARRAY*>(NULL)); - EXPECT_EQ(VT_EMPTY, var.type()); - - SAFEARRAY* sa = ::SafeArrayCreateVector(VT_UI1, 0, 100); - ASSERT_TRUE(sa != NULL); - - var.Set(sa); - EXPECT_TRUE(ScopedVariant::IsLeakableVarType(var.type())); - EXPECT_EQ(VT_ARRAY | VT_UI1, var.type()); - EXPECT_EQ(sa, V_ARRAY(var.ptr())); - // The array is destroyed in the destructor of var. -} - -} // namespace win -} // namespace base
diff --git a/base/win/scoped_winrt_initializer_unittest.cc b/base/win/scoped_winrt_initializer_unittest.cc deleted file mode 100644 index 9df1187..0000000 --- a/base/win/scoped_winrt_initializer_unittest.cc +++ /dev/null
@@ -1,47 +0,0 @@ -// 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/win/scoped_winrt_initializer.h" - -#include "base/test/gtest_util.h" -#include "base/win/com_init_util.h" -#include "base/win/scoped_com_initializer.h" -#include "base/win/windows_version.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace win { - -TEST(ScopedWinrtInitializer, BasicFunctionality) { - if (GetVersion() < VERSION_WIN8) - return; - - AssertComApartmentType(ComApartmentType::NONE); - { - ScopedWinrtInitializer scoped_winrt_initializer; - AssertComApartmentType(ComApartmentType::MTA); - } - AssertComApartmentType(ComApartmentType::NONE); -} - -TEST(ScopedWinrtInitializer, ApartmentChangeCheck) { - if (GetVersion() < VERSION_WIN8) - return; - - ScopedCOMInitializer com_initializer; - // ScopedCOMInitializer initialized an STA and the following should be a - // failed request for an MTA. - EXPECT_DCHECK_DEATH({ ScopedWinrtInitializer scoped_winrt_initializer; }); -} - -TEST(ScopedWinrtInitializer, VersionCheck) { - if (GetVersion() >= VERSION_WIN8) - return; - - // ScopedWinrtInitializer is unsupported on versions prior to Windows 8. - EXPECT_DCHECK_DEATH({ ScopedWinrtInitializer scoped_winrt_initializer; }); -} - -} // namespace win -} // namespace base
diff --git a/base/win/shortcut_unittest.cc b/base/win/shortcut_unittest.cc deleted file mode 100644 index 3c1c26f..0000000 --- a/base/win/shortcut_unittest.cc +++ /dev/null
@@ -1,330 +0,0 @@ -// 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/win/shortcut.h" - -#include <stdint.h> - -#include <string> - -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/files/scoped_temp_dir.h" -#include "base/macros.h" -#include "base/test/test_file_util.h" -#include "base/test/test_shortcut_win.h" -#include "base/win/scoped_com_initializer.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace win { - -namespace { - -static const char kFileContents[] = "This is a target."; -static const char kFileContents2[] = "This is another target."; - -class ShortcutTest : public testing::Test { - protected: - void SetUp() override { - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - ASSERT_TRUE(temp_dir_2_.CreateUniqueTempDir()); - - link_file_ = temp_dir_.GetPath().Append(L"My Link.lnk"); - - // Shortcut 1's properties - { - const FilePath target_file(temp_dir_.GetPath().Append(L"Target 1.txt")); - WriteFile(target_file, kFileContents, arraysize(kFileContents)); - - link_properties_.set_target(target_file); - link_properties_.set_working_dir(temp_dir_.GetPath()); - link_properties_.set_arguments(L"--magic --awesome"); - link_properties_.set_description(L"Chrome is awesome."); - link_properties_.set_icon(link_properties_.target, 4); - link_properties_.set_app_id(L"Chrome"); - link_properties_.set_dual_mode(false); - - // The CLSID below was randomly selected. - static constexpr CLSID toast_activator_clsid = { - 0x08d401c2, - 0x3f79, - 0x41d8, - {0x89, 0xd0, 0x99, 0x25, 0xee, 0x16, 0x28, 0x63}}; - link_properties_.set_toast_activator_clsid(toast_activator_clsid); - } - - // Shortcut 2's properties (all different from properties of shortcut 1). - { - const FilePath target_file_2(temp_dir_.GetPath().Append(L"Target 2.txt")); - WriteFile(target_file_2, kFileContents2, arraysize(kFileContents2)); - - FilePath icon_path_2; - CreateTemporaryFileInDir(temp_dir_.GetPath(), &icon_path_2); - - link_properties_2_.set_target(target_file_2); - link_properties_2_.set_working_dir(temp_dir_2_.GetPath()); - link_properties_2_.set_arguments(L"--super --crazy"); - link_properties_2_.set_description(L"The best in the west."); - link_properties_2_.set_icon(icon_path_2, 0); - link_properties_2_.set_app_id(L"Chrome.UserLevelCrazySuffix"); - link_properties_2_.set_dual_mode(true); - link_properties_2_.set_toast_activator_clsid(CLSID_NULL); - } - } - - ScopedCOMInitializer com_initializer_; - ScopedTempDir temp_dir_; - ScopedTempDir temp_dir_2_; - - // The link file to be created/updated in the shortcut tests below. - FilePath link_file_; - - // Properties for the created shortcut. - ShortcutProperties link_properties_; - - // Properties for the updated shortcut. - ShortcutProperties link_properties_2_; -}; - -} // namespace - -TEST_F(ShortcutTest, CreateAndResolveShortcutProperties) { - // Test all properties. - FilePath file_1(temp_dir_.GetPath().Append(L"Link1.lnk")); - ASSERT_TRUE(CreateOrUpdateShortcutLink( - file_1, link_properties_, SHORTCUT_CREATE_ALWAYS)); - - ShortcutProperties properties_read_1; - ASSERT_TRUE(ResolveShortcutProperties( - file_1, ShortcutProperties::PROPERTIES_ALL, &properties_read_1)); - EXPECT_EQ(static_cast<unsigned>(ShortcutProperties::PROPERTIES_ALL), - properties_read_1.options); - ValidatePathsAreEqual(link_properties_.target, properties_read_1.target); - ValidatePathsAreEqual(link_properties_.working_dir, - properties_read_1.working_dir); - EXPECT_EQ(link_properties_.arguments, properties_read_1.arguments); - EXPECT_EQ(link_properties_.description, properties_read_1.description); - ValidatePathsAreEqual(link_properties_.icon, properties_read_1.icon); - EXPECT_EQ(link_properties_.icon_index, properties_read_1.icon_index); - EXPECT_EQ(link_properties_.app_id, properties_read_1.app_id); - EXPECT_EQ(link_properties_.dual_mode, properties_read_1.dual_mode); - EXPECT_EQ(link_properties_.toast_activator_clsid, - properties_read_1.toast_activator_clsid); - - // Test simple shortcut with no special properties set. - FilePath file_2(temp_dir_.GetPath().Append(L"Link2.lnk")); - ShortcutProperties only_target_properties; - only_target_properties.set_target(link_properties_.target); - ASSERT_TRUE(CreateOrUpdateShortcutLink( - file_2, only_target_properties, SHORTCUT_CREATE_ALWAYS)); - - ShortcutProperties properties_read_2; - ASSERT_TRUE(ResolveShortcutProperties( - file_2, ShortcutProperties::PROPERTIES_ALL, &properties_read_2)); - EXPECT_EQ(static_cast<unsigned>(ShortcutProperties::PROPERTIES_ALL), - properties_read_2.options); - ValidatePathsAreEqual(only_target_properties.target, - properties_read_2.target); - ValidatePathsAreEqual(FilePath(), properties_read_2.working_dir); - EXPECT_EQ(L"", properties_read_2.arguments); - EXPECT_EQ(L"", properties_read_2.description); - ValidatePathsAreEqual(FilePath(), properties_read_2.icon); - EXPECT_EQ(0, properties_read_2.icon_index); - EXPECT_EQ(L"", properties_read_2.app_id); - EXPECT_FALSE(properties_read_2.dual_mode); - EXPECT_EQ(CLSID_NULL, properties_read_2.toast_activator_clsid); -} - -TEST_F(ShortcutTest, CreateAndResolveShortcut) { - ShortcutProperties only_target_properties; - only_target_properties.set_target(link_properties_.target); - - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, only_target_properties, SHORTCUT_CREATE_ALWAYS)); - - FilePath resolved_name; - EXPECT_TRUE(ResolveShortcut(link_file_, &resolved_name, NULL)); - - char read_contents[arraysize(kFileContents)]; - base::ReadFile(resolved_name, read_contents, arraysize(read_contents)); - EXPECT_STREQ(kFileContents, read_contents); -} - -TEST_F(ShortcutTest, ResolveShortcutWithArgs) { - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS)); - - FilePath resolved_name; - string16 args; - EXPECT_TRUE(ResolveShortcut(link_file_, &resolved_name, &args)); - - char read_contents[arraysize(kFileContents)]; - base::ReadFile(resolved_name, read_contents, arraysize(read_contents)); - EXPECT_STREQ(kFileContents, read_contents); - EXPECT_EQ(link_properties_.arguments, args); -} - -TEST_F(ShortcutTest, CreateShortcutWithOnlySomeProperties) { - ShortcutProperties target_and_args_properties; - target_and_args_properties.set_target(link_properties_.target); - target_and_args_properties.set_arguments(link_properties_.arguments); - - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, target_and_args_properties, - SHORTCUT_CREATE_ALWAYS)); - - ValidateShortcut(link_file_, target_and_args_properties); -} - -TEST_F(ShortcutTest, CreateShortcutVerifyProperties) { - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS)); - - ValidateShortcut(link_file_, link_properties_); -} - -TEST_F(ShortcutTest, UpdateShortcutVerifyProperties) { - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS)); - - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, link_properties_2_, SHORTCUT_UPDATE_EXISTING)); - - ValidateShortcut(link_file_, link_properties_2_); -} - -TEST_F(ShortcutTest, UpdateShortcutUpdateOnlyTargetAndResolve) { - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS)); - - ShortcutProperties update_only_target_properties; - update_only_target_properties.set_target(link_properties_2_.target); - - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, update_only_target_properties, - SHORTCUT_UPDATE_EXISTING)); - - ShortcutProperties expected_properties = link_properties_; - expected_properties.set_target(link_properties_2_.target); - ValidateShortcut(link_file_, expected_properties); - - FilePath resolved_name; - EXPECT_TRUE(ResolveShortcut(link_file_, &resolved_name, NULL)); - - char read_contents[arraysize(kFileContents2)]; - base::ReadFile(resolved_name, read_contents, arraysize(read_contents)); - EXPECT_STREQ(kFileContents2, read_contents); -} - -TEST_F(ShortcutTest, UpdateShortcutMakeDualMode) { - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS)); - - ShortcutProperties make_dual_mode_properties; - make_dual_mode_properties.set_dual_mode(true); - - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, make_dual_mode_properties, - SHORTCUT_UPDATE_EXISTING)); - - ShortcutProperties expected_properties = link_properties_; - expected_properties.set_dual_mode(true); - ValidateShortcut(link_file_, expected_properties); -} - -TEST_F(ShortcutTest, UpdateShortcutRemoveDualMode) { - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, link_properties_2_, SHORTCUT_CREATE_ALWAYS)); - - ShortcutProperties remove_dual_mode_properties; - remove_dual_mode_properties.set_dual_mode(false); - - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, remove_dual_mode_properties, - SHORTCUT_UPDATE_EXISTING)); - - ShortcutProperties expected_properties = link_properties_2_; - expected_properties.set_dual_mode(false); - ValidateShortcut(link_file_, expected_properties); -} - -TEST_F(ShortcutTest, UpdateShortcutClearArguments) { - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS)); - - ShortcutProperties clear_arguments_properties; - clear_arguments_properties.set_arguments(string16()); - - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, clear_arguments_properties, - SHORTCUT_UPDATE_EXISTING)); - - ShortcutProperties expected_properties = link_properties_; - expected_properties.set_arguments(string16()); - ValidateShortcut(link_file_, expected_properties); -} - -TEST_F(ShortcutTest, FailUpdateShortcutThatDoesNotExist) { - ASSERT_FALSE(CreateOrUpdateShortcutLink( - link_file_, link_properties_, SHORTCUT_UPDATE_EXISTING)); - ASSERT_FALSE(PathExists(link_file_)); -} - -TEST_F(ShortcutTest, ReplaceShortcutAllProperties) { - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS)); - - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, link_properties_2_, SHORTCUT_REPLACE_EXISTING)); - - ValidateShortcut(link_file_, link_properties_2_); -} - -TEST_F(ShortcutTest, ReplaceShortcutSomeProperties) { - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS)); - - ShortcutProperties new_properties; - new_properties.set_target(link_properties_2_.target); - new_properties.set_arguments(link_properties_2_.arguments); - new_properties.set_description(link_properties_2_.description); - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, new_properties, SHORTCUT_REPLACE_EXISTING)); - - // Expect only properties in |new_properties| to be set, all other properties - // should have been overwritten. - ShortcutProperties expected_properties(new_properties); - expected_properties.set_working_dir(FilePath()); - expected_properties.set_icon(FilePath(), 0); - expected_properties.set_app_id(string16()); - expected_properties.set_dual_mode(false); - ValidateShortcut(link_file_, expected_properties); -} - -TEST_F(ShortcutTest, FailReplaceShortcutThatDoesNotExist) { - ASSERT_FALSE(CreateOrUpdateShortcutLink( - link_file_, link_properties_, SHORTCUT_REPLACE_EXISTING)); - ASSERT_FALSE(PathExists(link_file_)); -} - -// Test that the old arguments remain on the replaced shortcut when not -// otherwise specified. -TEST_F(ShortcutTest, ReplaceShortcutKeepOldArguments) { - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS)); - - // Do not explicitly set the arguments. - link_properties_2_.options &= - ~ShortcutProperties::PROPERTIES_ARGUMENTS; - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, link_properties_2_, SHORTCUT_REPLACE_EXISTING)); - - ShortcutProperties expected_properties(link_properties_2_); - expected_properties.set_arguments(link_properties_.arguments); - ValidateShortcut(link_file_, expected_properties); -} - -} // namespace win -} // namespace base
diff --git a/base/win/startup_information_unittest.cc b/base/win/startup_information_unittest.cc deleted file mode 100644 index f5d1f37..0000000 --- a/base/win/startup_information_unittest.cc +++ /dev/null
@@ -1,75 +0,0 @@ -// 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 <windows.h> -#include <stddef.h> - -#include <string> - -#include "base/command_line.h" -#include "base/test/multiprocess_test.h" -#include "base/win/scoped_handle.h" -#include "base/win/scoped_process_information.h" -#include "base/win/startup_information.h" -#include "testing/multiprocess_func_list.h" - -const wchar_t kSectionName[] = L"EventTestSection"; -const size_t kSectionSize = 4096; - -MULTIPROCESS_TEST_MAIN(FireInheritedEvents) { - HANDLE section = ::OpenFileMappingW(PAGE_READWRITE, false, kSectionName); - HANDLE* events = reinterpret_cast<HANDLE*>(::MapViewOfFile(section, - PAGE_READWRITE, 0, 0, kSectionSize)); - // This event should not be valid because it wasn't explicitly inherited. - if (::SetEvent(events[1])) - return -1; - // This event should be valid because it was explicitly inherited. - if (!::SetEvent(events[0])) - return -1; - - return 0; -} - -class StartupInformationTest : public base::MultiProcessTest {}; - -// Verify that only the explicitly specified event is inherited. -TEST_F(StartupInformationTest, InheritStdOut) { - base::win::StartupInformation startup_info; - - HANDLE section = ::CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, - PAGE_READWRITE, 0, kSectionSize, - kSectionName); - ASSERT_TRUE(section); - - HANDLE* events = reinterpret_cast<HANDLE*>(::MapViewOfFile(section, - FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, kSectionSize)); - - // Make two inheritable events. - SECURITY_ATTRIBUTES security_attributes = { sizeof(security_attributes), - NULL, true }; - events[0] = ::CreateEvent(&security_attributes, false, false, NULL); - ASSERT_TRUE(events[0]); - events[1] = ::CreateEvent(&security_attributes, false, false, NULL); - ASSERT_TRUE(events[1]); - - ASSERT_TRUE(startup_info.InitializeProcThreadAttributeList(1)); - ASSERT_TRUE(startup_info.UpdateProcThreadAttribute( - PROC_THREAD_ATTRIBUTE_HANDLE_LIST, &events[0], - sizeof(events[0]))); - - std::wstring cmd_line = - MakeCmdLine("FireInheritedEvents").GetCommandLineString(); - - PROCESS_INFORMATION temp_process_info = {}; - ASSERT_TRUE(::CreateProcess(NULL, &cmd_line[0], - NULL, NULL, true, EXTENDED_STARTUPINFO_PRESENT, - NULL, NULL, startup_info.startup_info(), - &temp_process_info)) << ::GetLastError(); - base::win::ScopedProcessInformation process_info(temp_process_info); - - // Only the first event should be signalled - EXPECT_EQ(WAIT_OBJECT_0, ::WaitForMultipleObjects(2, events, false, - 4000)); -} -
diff --git a/base/win/typed_event_handler_unittest.cc b/base/win/typed_event_handler_unittest.cc deleted file mode 100644 index 76dba80..0000000 --- a/base/win/typed_event_handler_unittest.cc +++ /dev/null
@@ -1,49 +0,0 @@ -// 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/win/typed_event_handler.h" - -#include <windows.foundation.h> - -#include "base/test/bind_test_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace win { - -TEST(TypedEventHandlerTest, InvokeSuccess) { - bool called_callback = false; - TypedEventHandler<IInspectable*, IInspectable*> handler( - base::BindLambdaForTesting([&](IInspectable* sender, IInspectable* args) { - EXPECT_EQ(reinterpret_cast<IInspectable*>(0x01), sender); - EXPECT_EQ(reinterpret_cast<IInspectable*>(0x02), args); - called_callback = true; - return S_OK; - })); - - EXPECT_FALSE(called_callback); - HRESULT hr = handler.Invoke(reinterpret_cast<IInspectable*>(0x01), - reinterpret_cast<IInspectable*>(0x02)); - EXPECT_TRUE(called_callback); - EXPECT_EQ(S_OK, hr); -} - -TEST(TypedEventHandlerTest, InvokeFail) { - bool called_callback = false; - TypedEventHandler<IInspectable*, IInspectable*> handler( - base::BindLambdaForTesting([&](IInspectable* sender, IInspectable* args) { - EXPECT_EQ(nullptr, sender); - EXPECT_EQ(nullptr, args); - called_callback = true; - return E_FAIL; - })); - - EXPECT_FALSE(called_callback); - HRESULT hr = handler.Invoke(nullptr, nullptr); - EXPECT_TRUE(called_callback); - EXPECT_EQ(E_FAIL, hr); -} - -} // namespace win -} // namespace base
diff --git a/base/win/wait_chain_unittest.cc b/base/win/wait_chain_unittest.cc deleted file mode 100644 index 74a0ce5..0000000 --- a/base/win/wait_chain_unittest.cc +++ /dev/null
@@ -1,317 +0,0 @@ -// 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/win/wait_chain.h" - -#include <memory> -#include <string> - -#include "base/bind.h" -#include "base/callback.h" -#include "base/command_line.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_piece.h" -#include "base/test/multiprocess_test.h" -#include "base/threading/simple_thread.h" -#include "base/win/win_util.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/multiprocess_func_list.h" - -namespace base { -namespace win { - -namespace { - -// Appends |handle| as a command line switch. -void AppendSwitchHandle(CommandLine* command_line, - StringPiece switch_name, - HANDLE handle) { - command_line->AppendSwitchASCII(switch_name.as_string(), - UintToString(HandleToUint32(handle))); -} - -// Retrieves the |handle| associated to |switch_name| from the command line. -ScopedHandle GetSwitchValueHandle(CommandLine* command_line, - StringPiece switch_name) { - std::string switch_string = - command_line->GetSwitchValueASCII(switch_name.as_string()); - unsigned int switch_uint = 0; - if (switch_string.empty() || !StringToUint(switch_string, &switch_uint)) { - DLOG(ERROR) << "Missing or invalid " << switch_name << " argument."; - return ScopedHandle(); - } - return ScopedHandle(reinterpret_cast<HANDLE>(switch_uint)); -} - -// Helper function to create a mutex. -ScopedHandle CreateMutex(bool inheritable) { - SECURITY_ATTRIBUTES security_attributes = {sizeof(SECURITY_ATTRIBUTES), - nullptr, inheritable}; - return ScopedHandle(::CreateMutex(&security_attributes, FALSE, NULL)); -} - -// Helper function to create an event. -ScopedHandle CreateEvent(bool inheritable) { - SECURITY_ATTRIBUTES security_attributes = {sizeof(SECURITY_ATTRIBUTES), - nullptr, inheritable}; - return ScopedHandle( - ::CreateEvent(&security_attributes, FALSE, FALSE, nullptr)); -} - -// Helper thread class that runs the callback then stops. -class SingleTaskThread : public SimpleThread { - public: - explicit SingleTaskThread(const Closure& task) - : SimpleThread("WaitChainTest SingleTaskThread"), task_(task) {} - - void Run() override { task_.Run(); } - - private: - Closure task_; - - DISALLOW_COPY_AND_ASSIGN(SingleTaskThread); -}; - -// Helper thread to cause a deadlock by acquiring 2 mutexes in a given order. -class DeadlockThread : public SimpleThread { - public: - DeadlockThread(HANDLE mutex_1, HANDLE mutex_2) - : SimpleThread("WaitChainTest DeadlockThread"), - wait_event_(CreateEvent(false)), - mutex_acquired_event_(CreateEvent(false)), - mutex_1_(mutex_1), - mutex_2_(mutex_2) {} - - void Run() override { - // Acquire the mutex then signal the main thread. - EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(mutex_1_, INFINITE)); - EXPECT_TRUE(::SetEvent(mutex_acquired_event_.Get())); - - // Wait until both threads are holding their mutex before trying to acquire - // the other one. - EXPECT_EQ(WAIT_OBJECT_0, - ::WaitForSingleObject(wait_event_.Get(), INFINITE)); - - // To unblock the deadlock, one of the threads will get terminated (via - // TerminateThread()) without releasing the mutex. This causes the other - // thread to wake up with WAIT_ABANDONED. - EXPECT_EQ(WAIT_ABANDONED, ::WaitForSingleObject(mutex_2_, INFINITE)); - } - - // Blocks until a mutex is acquired. - void WaitForMutexAcquired() { - EXPECT_EQ(WAIT_OBJECT_0, - ::WaitForSingleObject(mutex_acquired_event_.Get(), INFINITE)); - } - - // Signal the thread to acquire the second mutex. - void SignalToAcquireMutex() { EXPECT_TRUE(::SetEvent(wait_event_.Get())); } - - // Terminates the thread. - bool Terminate() { - ScopedHandle thread_handle(::OpenThread(THREAD_TERMINATE, FALSE, tid())); - return ::TerminateThread(thread_handle.Get(), 0); - } - - private: - ScopedHandle wait_event_; - ScopedHandle mutex_acquired_event_; - - // The 2 mutex to acquire. - HANDLE mutex_1_; - HANDLE mutex_2_; - - DISALLOW_COPY_AND_ASSIGN(DeadlockThread); -}; - -// Creates a thread that joins |thread_to_join| and then terminates when it -// finishes execution. -std::unique_ptr<SingleTaskThread> CreateJoiningThread( - SimpleThread* thread_to_join) { - std::unique_ptr<SingleTaskThread> thread(new SingleTaskThread( - Bind(&SimpleThread::Join, Unretained(thread_to_join)))); - thread->Start(); - - return thread; -} - -// Creates a thread that calls WaitForSingleObject() on the handle and then -// terminates when it unblocks. -std::unique_ptr<SingleTaskThread> CreateWaitingThread(HANDLE handle) { - std::unique_ptr<SingleTaskThread> thread(new SingleTaskThread( - Bind(IgnoreResult(&::WaitForSingleObject), handle, INFINITE))); - thread->Start(); - - return thread; -} - -// Creates a thread that blocks on |mutex_2| after acquiring |mutex_1|. -std::unique_ptr<DeadlockThread> CreateDeadlockThread(HANDLE mutex_1, - HANDLE mutex_2) { - std::unique_ptr<DeadlockThread> thread(new DeadlockThread(mutex_1, mutex_2)); - thread->Start(); - - // Wait until the first mutex is acquired before returning. - thread->WaitForMutexAcquired(); - - return thread; -} - -// Child process to test the cross-process capability of the WCT api. -// This process will simulate a hang while holding a mutex that the parent -// process is waiting on. -MULTIPROCESS_TEST_MAIN(WaitChainTestProc) { - CommandLine* command_line = CommandLine::ForCurrentProcess(); - - ScopedHandle mutex = GetSwitchValueHandle(command_line, "mutex"); - CHECK(mutex.IsValid()); - - ScopedHandle sync_event(GetSwitchValueHandle(command_line, "sync_event")); - CHECK(sync_event.IsValid()); - - // Acquire mutex. - CHECK(::WaitForSingleObject(mutex.Get(), INFINITE) == WAIT_OBJECT_0); - - // Signal back to the parent process that the mutex is hold. - CHECK(::SetEvent(sync_event.Get())); - - // Wait on a signal from the parent process before terminating. - CHECK(::WaitForSingleObject(sync_event.Get(), INFINITE) == WAIT_OBJECT_0); - - return 0; -} - -// Start a child process and passes the |mutex| and the |sync_event| to the -// command line. -Process StartChildProcess(HANDLE mutex, HANDLE sync_event) { - CommandLine command_line = GetMultiProcessTestChildBaseCommandLine(); - - AppendSwitchHandle(&command_line, "mutex", mutex); - AppendSwitchHandle(&command_line, "sync_event", sync_event); - - LaunchOptions options; - options.handles_to_inherit.push_back(mutex); - options.handles_to_inherit.push_back(sync_event); - return SpawnMultiProcessTestChild("WaitChainTestProc", command_line, options); -} - -// Returns true if the |wait_chain| is an alternating sequence of thread objects -// and synchronization objects. -bool WaitChainStructureIsCorrect(const WaitChainNodeVector& wait_chain) { - // Checks thread objects. - for (size_t i = 0; i < wait_chain.size(); i += 2) { - if (wait_chain[i].ObjectType != WctThreadType) - return false; - } - - // Check synchronization objects. - for (size_t i = 1; i < wait_chain.size(); i += 2) { - if (wait_chain[i].ObjectType == WctThreadType) - return false; - } - return true; -} - -// Returns true if the |wait_chain| goes through more than 1 process. -bool WaitChainIsCrossProcess(const WaitChainNodeVector& wait_chain) { - if (wait_chain.size() == 0) - return false; - - // Just check that the process id changes somewhere in the chain. - // Note: ThreadObjects are every 2 nodes. - DWORD first_process = wait_chain[0].ThreadObject.ProcessId; - for (size_t i = 2; i < wait_chain.size(); i += 2) { - if (first_process != wait_chain[i].ThreadObject.ProcessId) - return true; - } - return false; -} - -} // namespace - -// Creates 2 threads that acquire their designated mutex and then try to -// acquire each others' mutex to cause a deadlock. -TEST(WaitChainTest, Deadlock) { - // 2 mutexes are needed to get a deadlock. - ScopedHandle mutex_1 = CreateMutex(false); - ASSERT_TRUE(mutex_1.IsValid()); - ScopedHandle mutex_2 = CreateMutex(false); - ASSERT_TRUE(mutex_2.IsValid()); - - std::unique_ptr<DeadlockThread> deadlock_thread_1 = - CreateDeadlockThread(mutex_1.Get(), mutex_2.Get()); - std::unique_ptr<DeadlockThread> deadlock_thread_2 = - CreateDeadlockThread(mutex_2.Get(), mutex_1.Get()); - - // Signal the threads to try to acquire the other mutex. - deadlock_thread_1->SignalToAcquireMutex(); - deadlock_thread_2->SignalToAcquireMutex(); - // Sleep to make sure the 2 threads got a chance to execute. - Sleep(10); - - // Create a few waiting threads to get a longer wait chain. - std::unique_ptr<SingleTaskThread> waiting_thread_1 = - CreateJoiningThread(deadlock_thread_1.get()); - std::unique_ptr<SingleTaskThread> waiting_thread_2 = - CreateJoiningThread(waiting_thread_1.get()); - - WaitChainNodeVector wait_chain; - bool is_deadlock; - ASSERT_TRUE(GetThreadWaitChain(waiting_thread_2->tid(), &wait_chain, - &is_deadlock, nullptr, nullptr)); - - EXPECT_EQ(9U, wait_chain.size()); - EXPECT_TRUE(is_deadlock); - EXPECT_TRUE(WaitChainStructureIsCorrect(wait_chain)); - EXPECT_FALSE(WaitChainIsCrossProcess(wait_chain)); - - ASSERT_TRUE(deadlock_thread_1->Terminate()); - - // The SimpleThread API expect Join() to be called before destruction. - deadlock_thread_2->Join(); - waiting_thread_2->Join(); -} - -// Creates a child process that acquires a mutex and then blocks. A chain of -// threads then blocks on that mutex. -TEST(WaitChainTest, CrossProcess) { - ScopedHandle mutex = CreateMutex(true); - ASSERT_TRUE(mutex.IsValid()); - ScopedHandle sync_event = CreateEvent(true); - ASSERT_TRUE(sync_event.IsValid()); - - Process child_process = StartChildProcess(mutex.Get(), sync_event.Get()); - ASSERT_TRUE(child_process.IsValid()); - - // Wait for the child process to signal when it's holding the mutex. - EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(sync_event.Get(), INFINITE)); - - // Create a few waiting threads to get a longer wait chain. - std::unique_ptr<SingleTaskThread> waiting_thread_1 = - CreateWaitingThread(mutex.Get()); - std::unique_ptr<SingleTaskThread> waiting_thread_2 = - CreateJoiningThread(waiting_thread_1.get()); - std::unique_ptr<SingleTaskThread> waiting_thread_3 = - CreateJoiningThread(waiting_thread_2.get()); - - WaitChainNodeVector wait_chain; - bool is_deadlock; - ASSERT_TRUE(GetThreadWaitChain(waiting_thread_3->tid(), &wait_chain, - &is_deadlock, nullptr, nullptr)); - - EXPECT_EQ(7U, wait_chain.size()); - EXPECT_FALSE(is_deadlock); - EXPECT_TRUE(WaitChainStructureIsCorrect(wait_chain)); - EXPECT_TRUE(WaitChainIsCrossProcess(wait_chain)); - - // Unblock child process and wait for it to terminate. - ASSERT_TRUE(::SetEvent(sync_event.Get())); - ASSERT_TRUE(child_process.WaitForExit(nullptr)); - - // The SimpleThread API expect Join() to be called before destruction. - waiting_thread_3->Join(); -} - -} // namespace win -} // namespace base
diff --git a/base/win/win_includes_unittest.cc b/base/win/win_includes_unittest.cc deleted file mode 100644 index 20c6cbc..0000000 --- a/base/win/win_includes_unittest.cc +++ /dev/null
@@ -1,33 +0,0 @@ -// 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. - -// This file ensures that these header files don't include Windows.h and can -// compile without including Windows.h. This helps to improve compile times. - -#include "base/atomicops.h" -#include "base/files/file_util.h" -#include "base/files/platform_file.h" -#include "base/process/process_handle.h" -#include "base/synchronization/condition_variable.h" -#include "base/synchronization/lock.h" -#include "base/threading/platform_thread.h" -#include "base/threading/thread_local_storage.h" -#include "base/win/registry.h" -#include "base/win/scoped_handle.h" -#include "base/win/win_util.h" - -#ifdef _WINDOWS_ -#error Windows.h was included inappropriately. -#endif - -// Make sure windows.h can be included after windows_types.h -#include "base/win/windows_types.h" - -#include <windows.h> - -// Check that type sizes match. -static_assert(sizeof(CHROME_CONDITION_VARIABLE) == sizeof(CONDITION_VARIABLE), - "Definition mismatch."); -static_assert(sizeof(CHROME_SRWLOCK) == sizeof(SRWLOCK), - "Definition mismatch.");
diff --git a/base/win/win_util_unittest.cc b/base/win/win_util_unittest.cc deleted file mode 100644 index 6d5cf61..0000000 --- a/base/win/win_util_unittest.cc +++ /dev/null
@@ -1,82 +0,0 @@ -// 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/win/win_util.h" - -#include "base/files/file_path.h" -#include "base/macros.h" -#include "base/scoped_native_library.h" -#include "base/stl_util.h" -#include "base/win/win_client_metrics.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace win { - -namespace { - -// Saves the current thread's locale ID when initialized, and restores it when -// the instance is going out of scope. -class ThreadLocaleSaver { - public: - ThreadLocaleSaver() : original_locale_id_(GetThreadLocale()) {} - ~ThreadLocaleSaver() { SetThreadLocale(original_locale_id_); } - - private: - LCID original_locale_id_; - - DISALLOW_COPY_AND_ASSIGN(ThreadLocaleSaver); -}; - -} // namespace - -// The test is somewhat silly, because some bots some have UAC enabled and some -// have it disabled. At least we check that it does not crash. -TEST(BaseWinUtilTest, TestIsUACEnabled) { - UserAccountControlIsEnabled(); -} - -TEST(BaseWinUtilTest, TestGetUserSidString) { - std::wstring user_sid; - EXPECT_TRUE(GetUserSidString(&user_sid)); - EXPECT_TRUE(!user_sid.empty()); -} - -TEST(BaseWinUtilTest, TestGetNonClientMetrics) { - NONCLIENTMETRICS_XP metrics = {0}; - GetNonClientMetrics(&metrics); - EXPECT_GT(metrics.cbSize, 0u); - EXPECT_GT(metrics.iScrollWidth, 0); - EXPECT_GT(metrics.iScrollHeight, 0); -} - -TEST(BaseWinUtilTest, TestGetLoadedModulesSnapshot) { - std::vector<HMODULE> snapshot; - - ASSERT_TRUE(GetLoadedModulesSnapshot(::GetCurrentProcess(), &snapshot)); - size_t original_snapshot_size = snapshot.size(); - ASSERT_GT(original_snapshot_size, 0u); - snapshot.clear(); - - // Load in a new module. Pick msvidc32.dll as it is present from WinXP to - // Win10 and yet rarely used. - const wchar_t dll_name[] = L"msvidc32.dll"; - ASSERT_EQ(NULL, ::GetModuleHandle(dll_name)); - - base::ScopedNativeLibrary new_dll((base::FilePath(dll_name))); - ASSERT_NE(static_cast<HMODULE>(NULL), new_dll.get()); - ASSERT_TRUE(GetLoadedModulesSnapshot(::GetCurrentProcess(), &snapshot)); - ASSERT_GT(snapshot.size(), original_snapshot_size); - ASSERT_TRUE(base::ContainsValue(snapshot, new_dll.get())); -} - -TEST(BaseWinUtilTest, TestUint32ToInvalidHandle) { - // Ensure that INVALID_HANDLE_VALUE is preserved when going to a 32-bit value - // and back on 64-bit platforms. - uint32_t invalid_handle = base::win::HandleToUint32(INVALID_HANDLE_VALUE); - EXPECT_EQ(INVALID_HANDLE_VALUE, base::win::Uint32ToHandle(invalid_handle)); -} - -} // namespace win -} // namespace base
diff --git a/base/win/windows_version_unittest.cc b/base/win/windows_version_unittest.cc deleted file mode 100644 index f0d6d96..0000000 --- a/base/win/windows_version_unittest.cc +++ /dev/null
@@ -1,22 +0,0 @@ -// 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/win/windows_version.h" - -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace win { -namespace { - -TEST(WindowsVersion, GetVersionExAndKernelVersionMatch) { - // If this fails, we're running in compatibility mode, or need to update the - // application manifest. - EXPECT_EQ(OSInfo::GetInstance()->version(), - OSInfo::GetInstance()->Kernel32Version()); -} - -} // namespace -} // namespace win -} // namespace base
diff --git a/base/win/winrt_storage_util_unittest.cc b/base/win/winrt_storage_util_unittest.cc deleted file mode 100644 index 530ab23..0000000 --- a/base/win/winrt_storage_util_unittest.cc +++ /dev/null
@@ -1,42 +0,0 @@ -// 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/win/winrt_storage_util.h" - -#include <string.h> -#include <wrl/client.h> - -#include "base/strings/string_util.h" -#include "base/win/core_winrt_util.h" -#include "base/win/scoped_com_initializer.h" -#include "base/win/scoped_hstring.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace win { - -TEST(WinrtStorageUtilTest, CreateBufferFromData) { - ScopedCOMInitializer com_initializer(ScopedCOMInitializer::kMTA); - - if (!ResolveCoreWinRTDelayload() || - !ScopedHString::ResolveCoreWinRTStringDelayload()) { - return; - } - - const std::vector<uint8_t> data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IBuffer> buffer; - ASSERT_HRESULT_SUCCEEDED( - CreateIBufferFromData(data.data(), data.size(), &buffer)); - - uint8_t* p_buffer_data; - uint32_t length; - ASSERT_HRESULT_SUCCEEDED( - GetPointerToBufferData(buffer.Get(), &p_buffer_data, &length)); - - ASSERT_EQ(data.size(), length); - EXPECT_EQ(0, memcmp(p_buffer_data, data.data(), data.size())); -} - -} // namespace win -} // namespace base
diff --git a/base/win/wrapped_window_proc_unittest.cc b/base/win/wrapped_window_proc_unittest.cc deleted file mode 100644 index 25ba2d4..0000000 --- a/base/win/wrapped_window_proc_unittest.cc +++ /dev/null
@@ -1,78 +0,0 @@ -// 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/win/wrapped_window_proc.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -DWORD kExceptionCode = 12345; -WPARAM kCrashMsg = 98765; - -// A trivial WindowProc that generates an exception. -LRESULT CALLBACK TestWindowProc(HWND hwnd, UINT message, - WPARAM wparam, LPARAM lparam) { - if (message == kCrashMsg) - RaiseException(kExceptionCode, 0, 0, NULL); - return DefWindowProc(hwnd, message, wparam, lparam); -} - -// This class implements an exception filter that can be queried about a past -// exception. -class TestWrappedExceptionFiter { - public: - TestWrappedExceptionFiter() : called_(false) { - EXPECT_FALSE(s_filter_); - s_filter_ = this; - } - - ~TestWrappedExceptionFiter() { - EXPECT_EQ(s_filter_, this); - s_filter_ = NULL; - } - - bool called() { - return called_; - } - - // The actual exception filter just records the exception. - static int Filter(EXCEPTION_POINTERS* info) { - EXPECT_FALSE(s_filter_->called_); - if (info->ExceptionRecord->ExceptionCode == kExceptionCode) - s_filter_->called_ = true; - return EXCEPTION_EXECUTE_HANDLER; - } - - private: - bool called_; - static TestWrappedExceptionFiter* s_filter_; -}; -TestWrappedExceptionFiter* TestWrappedExceptionFiter::s_filter_ = NULL; - -} // namespace. - -TEST(WrappedWindowProc, CatchesExceptions) { - HINSTANCE hinst = GetModuleHandle(NULL); - std::wstring class_name(L"TestClass"); - - WNDCLASS wc = {0}; - wc.lpfnWndProc = base::win::WrappedWindowProc<TestWindowProc>; - wc.hInstance = hinst; - wc.lpszClassName = class_name.c_str(); - RegisterClass(&wc); - - HWND window = CreateWindow(class_name.c_str(), 0, 0, 0, 0, 0, 0, HWND_MESSAGE, - 0, hinst, 0); - ASSERT_TRUE(window); - - // Before generating the exception we make sure that the filter will see it. - TestWrappedExceptionFiter wrapper; - base::win::WinProcExceptionFilter old_filter = - base::win::SetWinProcExceptionFilter(TestWrappedExceptionFiter::Filter); - - SendMessage(window, kCrashMsg, 0, 0); - EXPECT_TRUE(wrapper.called()); - - base::win::SetWinProcExceptionFilter(old_filter); -}