blob: 371f9b0af604f5ec1de42c035b27fb7232227788 [file] [log] [blame]
// 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 "third_party/blink/renderer/platform/bindings/movable_string.h"
#include <vector>
#include "base/test/metrics/histogram_tester.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace blink {
class MovableStringTest : public ::testing::Test {
protected:
void SetUp() override {
MovableStringTable::Instance().SetRendererBackgrounded(false);
}
};
TEST_F(MovableStringTest, Simple) {
MovableString movable_abc(String("abc").ReleaseImpl());
EXPECT_TRUE(MovableString().IsNull());
EXPECT_FALSE(movable_abc.IsNull());
EXPECT_TRUE(movable_abc.Is8Bit());
EXPECT_EQ(3u, movable_abc.length());
EXPECT_EQ(3u, movable_abc.CharactersSizeInBytes());
EXPECT_EQ(String("abc"), movable_abc.ToString());
MovableString copy = movable_abc;
EXPECT_EQ(copy.Impl(), movable_abc.Impl());
}
TEST_F(MovableStringTest, Park) {
base::HistogramTester histogram_tester;
MovableString movable(String("abc").Impl());
EXPECT_FALSE(movable.Impl()->is_parked());
EXPECT_TRUE(movable.Impl()->Park());
EXPECT_TRUE(movable.Impl()->is_parked());
// Not the only one to have a reference to the string.
String abc("abc");
MovableString movable2(abc.Impl());
EXPECT_FALSE(movable2.Impl()->Park());
abc = String();
EXPECT_TRUE(movable2.Impl()->Park());
histogram_tester.ExpectBucketCount(
"Memory.MovableStringParkingAction",
MovableStringImpl::ParkingAction::kParkedInBackground, 2);
histogram_tester.ExpectTotalCount("Memory.MovableStringParkingAction", 2);
}
TEST_F(MovableStringTest, Unpark) {
base::HistogramTester histogram_tester;
MovableString movable(String("abc").Impl());
EXPECT_FALSE(movable.Impl()->is_parked());
EXPECT_TRUE(movable.Impl()->Park());
EXPECT_TRUE(movable.Impl()->is_parked());
String unparked = movable.ToString();
EXPECT_EQ(String("abc"), unparked);
EXPECT_FALSE(movable.Impl()->is_parked());
histogram_tester.ExpectTotalCount("Memory.MovableStringParkingAction", 2);
histogram_tester.ExpectBucketCount(
"Memory.MovableStringParkingAction",
MovableStringImpl::ParkingAction::kParkedInBackground, 1);
histogram_tester.ExpectBucketCount(
"Memory.MovableStringParkingAction",
MovableStringImpl::ParkingAction::kUnparkedInForeground, 1);
}
TEST_F(MovableStringTest, TableSimple) {
base::HistogramTester histogram_tester;
std::vector<char> data(20000, 'a');
MovableString movable(String(data.data(), data.size()).ReleaseImpl());
ASSERT_FALSE(movable.Impl()->is_parked());
auto& table = MovableStringTable::Instance();
EXPECT_EQ(1u, table.table_.size());
// Small strings are not in the table.
MovableString small(String("abc").ReleaseImpl());
EXPECT_EQ(1u, table.table_.size());
// No parking as the current state is not "backgrounded".
table.SetRendererBackgrounded(false);
ASSERT_FALSE(table.IsRendererBackgrounded());
table.MaybeParkAll();
EXPECT_FALSE(movable.Impl()->is_parked());
histogram_tester.ExpectTotalCount("Memory.MovableStringsCount", 0);
table.SetRendererBackgrounded(true);
ASSERT_TRUE(table.IsRendererBackgrounded());
table.MaybeParkAll();
EXPECT_TRUE(movable.Impl()->is_parked());
histogram_tester.ExpectUniqueSample("Memory.MovableStringsCount", 1, 1);
// Park and unpark.
movable.ToString();
EXPECT_FALSE(movable.Impl()->is_parked());
table.MaybeParkAll();
EXPECT_TRUE(movable.Impl()->is_parked());
histogram_tester.ExpectUniqueSample("Memory.MovableStringsCount", 1, 2);
// More than one reference, no parking.
table.SetRendererBackgrounded(false);
String alive_unparked = movable.ToString(); // Unparked in foreground.
table.SetRendererBackgrounded(true);
table.MaybeParkAll();
EXPECT_FALSE(movable.Impl()->is_parked());
// Other reference is dropped, OK to park.
alive_unparked = String();
table.MaybeParkAll();
EXPECT_TRUE(movable.Impl()->is_parked());
histogram_tester.ExpectTotalCount("Memory.MovableStringParkingAction", 5);
histogram_tester.ExpectBucketCount(
"Memory.MovableStringParkingAction",
MovableStringImpl::ParkingAction::kParkedInBackground, 3);
histogram_tester.ExpectBucketCount(
"Memory.MovableStringParkingAction",
MovableStringImpl::ParkingAction::kUnparkedInBackground, 1);
histogram_tester.ExpectBucketCount(
"Memory.MovableStringParkingAction",
MovableStringImpl::ParkingAction::kUnparkedInForeground, 1);
}
TEST_F(MovableStringTest, TableMultiple) {
base::HistogramTester histogram_tester;
size_t size_kb = 20;
std::vector<char> data(size_kb * 1000, 'a');
MovableString movable(String(data.data(), data.size()).ReleaseImpl());
MovableString movable2(String(data.data(), data.size()).ReleaseImpl());
auto& table = MovableStringTable::Instance();
EXPECT_EQ(2u, table.table_.size());
movable2 = MovableString();
EXPECT_EQ(1u, table.table_.size());
MovableString copy = movable;
movable = MovableString();
EXPECT_EQ(1u, table.table_.size());
copy = MovableString();
EXPECT_EQ(0u, table.table_.size());
String str(data.data(), data.size());
MovableString movable3(str.Impl());
EXPECT_EQ(1u, table.table_.size());
// De-duplicated.
MovableString other_movable3(str.Impl());
EXPECT_EQ(1u, table.table_.size());
EXPECT_EQ(movable3.Impl(), other_movable3.Impl());
// If all the references to a string are in the table, park it.
str = String();
table.SetRendererBackgrounded(true);
ASSERT_TRUE(table.IsRendererBackgrounded());
table.MaybeParkAll();
EXPECT_TRUE(movable3.Impl()->is_parked());
// Only drop it from the table when the last one is gone.
movable3 = MovableString();
EXPECT_EQ(1u, table.table_.size());
other_movable3 = MovableString();
EXPECT_EQ(0u, table.table_.size());
histogram_tester.ExpectUniqueSample("Memory.MovableStringsCount", 1, 1);
histogram_tester.ExpectUniqueSample("Memory.MovableStringsTotalSizeKb",
size_kb, 1);
histogram_tester.ExpectTotalCount("Memory.MovableStringParkingAction", 1);
histogram_tester.ExpectBucketCount(
"Memory.MovableStringParkingAction",
MovableStringImpl::ParkingAction::kParkedInBackground, 1);
}
} // namespace blink