| Index: components/metrics/call_stack_profile_struct_traits_unittest.cc | 
| diff --git a/components/metrics/call_stack_profile_struct_traits_unittest.cc b/components/metrics/call_stack_profile_struct_traits_unittest.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..400d257b855c7c450da4d3d55a2fd11dfe57d889 | 
| --- /dev/null | 
| +++ b/components/metrics/call_stack_profile_struct_traits_unittest.cc | 
| @@ -0,0 +1,204 @@ | 
| +// 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 <utility> | 
| + | 
| +#include "base/logging.h" | 
| +#include "base/macros.h" | 
| +#include "base/message_loop/message_loop.h" | 
| +#include "components/metrics/call_stack_profile_collector_test.mojom.h" | 
| +#include "mojo/public/cpp/bindings/binding.h" | 
| +#include "testing/gtest/include/gtest/gtest.h" | 
| + | 
| +namespace metrics { | 
| + | 
| +namespace { | 
| + | 
| +base::StackSamplingProfiler::CallStackProfile CreateProfile( | 
| +    const std::vector<base::StackSamplingProfiler::Module>& modules, | 
| +    const std::vector<base::StackSamplingProfiler::Sample>& samples, | 
| +    base::TimeDelta profile_duration, | 
| +    base::TimeDelta sampling_period) { | 
| +  base::StackSamplingProfiler::CallStackProfile profile; | 
| +  profile.modules = modules; | 
| +  profile.samples = samples; | 
| +  profile.profile_duration = profile_duration; | 
| +  profile.sampling_period = sampling_period; | 
| +  return profile; | 
| +} | 
| + | 
| +} | 
| + | 
| +class CallStackProfileCollectorTestImpl | 
| +    : public mojom::CallStackProfileCollectorTest { | 
| + public: | 
| +  explicit CallStackProfileCollectorTestImpl( | 
| +      mojo::InterfaceRequest<mojom::CallStackProfileCollectorTest> request) | 
| +      : binding_(this, std::move(request)) { | 
| +  } | 
| + | 
| +  // CallStackProfileCollectorTest: | 
| +  void BounceFrame(const base::StackSamplingProfiler::Frame& in, | 
| +                   const BounceFrameCallback& callback) override { | 
| +    callback.Run(in); | 
| +  } | 
| + | 
| +  void BounceModule(const base::StackSamplingProfiler::Module& in, | 
| +                    const BounceModuleCallback& callback) override { | 
| +    callback.Run(in); | 
| +  } | 
| + | 
| +  void BounceProfile(const base::StackSamplingProfiler::CallStackProfile& in, | 
| +                     const BounceProfileCallback& callback) override { | 
| +    callback.Run(in); | 
| +  } | 
| + | 
| + private: | 
| +  mojo::Binding<CallStackProfileCollectorTest> binding_; | 
| +}; | 
| + | 
| +// Checks serialization/deserialization of Module fields. | 
| +TEST(CallStackProfileStructTraitsTest, Module) { | 
| +  using Module = base::StackSamplingProfiler::Module; | 
| + | 
| +  base::MessageLoop message_loop; | 
| + | 
| +  mojom::CallStackProfileCollectorTestPtr proxy; | 
| +  CallStackProfileCollectorTestImpl impl(GetProxy(&proxy)); | 
| + | 
| +  const Module serialize_cases[] = { | 
| +    Module(0x0, "abcd", base::FilePath(base::FilePath::kCurrentDirectory)), | 
| +    Module(0x10, "abcd", base::FilePath(base::FilePath::kCurrentDirectory)), | 
| +    Module(1ULL << (sizeof(uintptr_t) * 8) * 3 / 4, "abcd", | 
| +           base::FilePath(base::FilePath::kCurrentDirectory)), | 
| +    Module(0x10, "", base::FilePath(base::FilePath::kCurrentDirectory)), | 
| +  }; | 
| + | 
| +  for (const Module& input : serialize_cases) { | 
| +    Module output; | 
| +    EXPECT_TRUE(proxy->BounceModule(input, &output)); | 
| + | 
| +    EXPECT_EQ(input.base_address, output.base_address); | 
| +    EXPECT_EQ(input.id, output.id); | 
| +    EXPECT_EQ(input.filename, output.filename); | 
| +  } | 
| +} | 
| + | 
| +// Checks serialization/deserialization of Frame fields. | 
| +TEST(CallStackProfileStructTraitsTest, Frame) { | 
| +  using Frame = base::StackSamplingProfiler::Frame; | 
| + | 
| +  base::MessageLoop message_loop; | 
| + | 
| +  mojom::CallStackProfileCollectorTestPtr proxy; | 
| +  CallStackProfileCollectorTestImpl impl(GetProxy(&proxy)); | 
| + | 
| +  const Frame serialize_cases[] = { | 
| +    Frame(0x0, 10), | 
| +    Frame(0x10, 10), | 
| +    Frame(1ULL << (sizeof(uintptr_t) * 8) * 3 / 4, 10), | 
| +    Frame(0xabcd, 0), | 
| +    Frame(0xabcd, 1), | 
| +    Frame(0xabcd, 10), | 
| +    Frame(0xabcd, Frame::kUnknownModuleIndex), | 
| +  }; | 
| + | 
| +  for (const Frame& input : serialize_cases) { | 
| +    Frame output; | 
| +    EXPECT_TRUE(proxy->BounceFrame(input, &output)); | 
| + | 
| +    EXPECT_EQ(input.instruction_pointer, output.instruction_pointer); | 
| +    EXPECT_EQ(input.module_index, output.module_index); | 
| +  } | 
| +} | 
| + | 
| +// Checks serialization/deserialization of Profile fields, including validation | 
| +// of the Frame module_index field. | 
| +TEST(CallStackProfileStructTraitsTest, Profile) { | 
| +  using Module = base::StackSamplingProfiler::Module; | 
| +  using Frame = base::StackSamplingProfiler::Frame; | 
| +  using Sample = base::StackSamplingProfiler::Sample; | 
| +  using Profile = base::StackSamplingProfiler::CallStackProfile; | 
| + | 
| +  base::MessageLoop message_loop; | 
| + | 
| +  mojom::CallStackProfileCollectorTestPtr proxy; | 
| +  CallStackProfileCollectorTestImpl impl(GetProxy(&proxy)); | 
| + | 
| +  struct SerializeCase { | 
| +    Profile profile; | 
| +    bool expect_success; | 
| +  }; | 
| +  const SerializeCase serialize_cases[] = { | 
| +    { | 
| +      CreateProfile(std::vector<Module>(), std::vector<Sample>(), | 
| +                    base::TimeDelta::FromSeconds(1), | 
| +                    base::TimeDelta::FromSeconds(2)), | 
| +      true | 
| +    }, | 
| +    { | 
| +      CreateProfile({ Module(0x4000, "a", base::FilePath()) }, | 
| +                    std::vector<Sample>(), | 
| +                    base::TimeDelta::FromSeconds(1), | 
| +                    base::TimeDelta::FromSeconds(2)), | 
| +      true | 
| +    }, | 
| +    { | 
| +      CreateProfile({ | 
| +                      Module(0x4000, "a", base::FilePath()), | 
| +                      Module(0x4100, "b", base::FilePath()), | 
| +                    }, | 
| +                    { | 
| +                      { | 
| +                        Frame(0x4010, 0), | 
| +                        Frame(0x4110, 1), | 
| +                        Frame(0x4110, Frame::kUnknownModuleIndex), | 
| +                      } | 
| +                    }, | 
| +                    base::TimeDelta::FromSeconds(1), | 
| +                    base::TimeDelta::FromSeconds(2)), | 
| +      true | 
| +    }, | 
| +    // The out of range module index in the second sample should cause the | 
| +    // entire deserialization to fail. | 
| +    { | 
| +      CreateProfile({ | 
| +                      Module(0x4000, "a", base::FilePath()), | 
| +                      Module(0x4100, "b", base::FilePath()), | 
| +                    }, | 
| +                    { | 
| +                      { | 
| +                        Frame(0x4010, 0), | 
| +                        Frame(0x4110, 1), | 
| +                        Frame(0x4110, Frame::kUnknownModuleIndex), | 
| +                      }, | 
| +                      { | 
| +                        Frame(0x4010, 0), | 
| +                        Frame(0x4110, 2), | 
| +                      }, | 
| +                    }, | 
| +                    base::TimeDelta::FromSeconds(1), | 
| +                    base::TimeDelta::FromSeconds(2)), | 
| +      false | 
| +    }, | 
| +  }; | 
| + | 
| +  for (const SerializeCase& input : serialize_cases) { | 
| +    SCOPED_TRACE(&input - &serialize_cases[0]); | 
| + | 
| +    Profile output; | 
| +    EXPECT_EQ(input.expect_success, | 
| +              proxy->BounceProfile(input.profile, &output)); | 
| + | 
| +    if (!input.expect_success) | 
| +      continue; | 
| + | 
| +    EXPECT_EQ(input.profile.modules, output.modules); | 
| +    EXPECT_EQ(input.profile.samples, output.samples); | 
| +    EXPECT_EQ(input.profile.profile_duration, output.profile_duration); | 
| +    EXPECT_EQ(input.profile.sampling_period, output.sampling_period); | 
| +  } | 
| +} | 
| + | 
| +}  // namespace metrics | 
|  |