| Index: content/browser/font_access/font_access_service_unittest.cc
 | 
| diff --git a/content/browser/font_access/font_access_service_unittest.cc b/content/browser/font_access/font_access_service_unittest.cc
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..0a38804613db84557f6b6e1b078fe03ccd2789cb
 | 
| --- /dev/null
 | 
| +++ b/content/browser/font_access/font_access_service_unittest.cc
 | 
| @@ -0,0 +1,294 @@
 | 
| +// 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 "content/browser/font_access/font_access_service_impl.h"
 | 
| +#include "content/browser/font_access/font_getter.h"
 | 
| +#include "content/common/font_access/font_access_service.mojom.h"
 | 
| +#include "content/public/test/mock_render_process_host.h"
 | 
| +#include "content/public/test/test_browser_context.h"
 | 
| +#include "content/public/test/test_browser_thread_bundle.h"
 | 
| +#include "mojo/public/cpp/bindings/interface_ptr.h"
 | 
| +#include "mojo/public/cpp/bindings/interface_request.h"
 | 
| +#include "mojo/public/cpp/system/buffer.h"
 | 
| +#include "testing/gtest/include/gtest/gtest.h"
 | 
| +
 | 
| +namespace content {
 | 
| +
 | 
| +class CacheClobberCounter {
 | 
| + public:
 | 
| +  CacheClobberCounter() : counter(0) {}
 | 
| +
 | 
| +  void SetCacheMap(const FontCacheMap& cache_map) { cache_map_ = cache_map; }
 | 
| +
 | 
| +  scoped_ptr<FontCacheMap> GetFakeCacheMap() {
 | 
| +    scoped_ptr<FontCacheMap> clone_map(new FontCacheMap(cache_map_));
 | 
| +    counter++;
 | 
| +    return clone_map;
 | 
| +  }
 | 
| +
 | 
| +  int counter;
 | 
| +  FontCacheMap cache_map_;
 | 
| +};
 | 
| +
 | 
| +class FontAccessServiceTest : public testing::Test {
 | 
| + public:
 | 
| +  FontAccessServiceTest()
 | 
| +      : context_(new TestBrowserContext()),
 | 
| +        host_(new MockRenderProcessHost(context_.get())),
 | 
| +        counter_(new CacheClobberCounter()) {}
 | 
| +
 | 
| +  void SetUp() override {
 | 
| +    // Create a dummy mojo channel so that the FontAccessServiceImpl can be
 | 
| +    // instantiated
 | 
| +    mojo::InterfaceRequest<FontAccessService> request =
 | 
| +        mojo::GetProxy(&interface_ptr_);
 | 
| +    // Create a new FontAccessServiceImpl bound to the dummy channel.
 | 
| +    service_impl_.reset(new FontAccessServiceImpl(
 | 
| +        base::Bind(&CacheClobberCounter::GetFakeCacheMap,
 | 
| +                   base::Unretained(counter_.get())),
 | 
| +        std::move(request)));
 | 
| +    base::RunLoop().RunUntilIdle();
 | 
| +  }
 | 
| +
 | 
| +  void SetCacheMap(const FontCacheMap& cache_map) {
 | 
| +    counter_->SetCacheMap(cache_map);
 | 
| +  }
 | 
| +
 | 
| +  static void VerifyFontListCallback(
 | 
| +      const FontCacheMap& real_map,
 | 
| +      size_t expected_fonts,
 | 
| +      base::Closure quit,
 | 
| +      const mojo::Array<FontDescriptionPtr>& values) {
 | 
| +    EXPECT_EQ(expected_fonts, values.size());
 | 
| +    // Verify that all of the fonts were there.
 | 
| +    for (size_t i = 0; i < values.size(); i++) {
 | 
| +      FontCacheMap::const_iterator iter;
 | 
| +      iter = real_map.find(values[i]->family);
 | 
| +      EXPECT_NE(iter, real_map.end());
 | 
| +      FontStyleMap::const_iterator faceIter;
 | 
| +      faceIter = iter->second.find(values[i]->style);
 | 
| +      EXPECT_NE(faceIter, iter->second.end());
 | 
| +    }
 | 
| +
 | 
| +    quit.Run();
 | 
| +  }
 | 
| +
 | 
| +  static void VerifyFontBlobCallback(int64_t expected_length,
 | 
| +                                     base::Closure quit,
 | 
| +                                     mojo::ScopedSharedBufferHandle buffer,
 | 
| +                                     int64_t length) {
 | 
| +    quit.Run();
 | 
| +    EXPECT_EQ(length, expected_length);
 | 
| +  }
 | 
| +
 | 
| +  mojo::InterfacePtr<FontAccessService> interface_ptr_;
 | 
| +  content::TestBrowserThreadBundle thread_bundle_;
 | 
| +  scoped_ptr<TestBrowserContext> context_;
 | 
| +  scoped_ptr<MockRenderProcessHost> host_;
 | 
| +  scoped_ptr<FontAccessServiceImpl> service_impl_;
 | 
| +  scoped_ptr<CacheClobberCounter> counter_;
 | 
| +
 | 
| + private:
 | 
| +  DISALLOW_COPY_AND_ASSIGN(FontAccessServiceTest);
 | 
| +};
 | 
| +
 | 
| +TEST_F(FontAccessServiceTest, GetFonts) {
 | 
| +  FontCacheMap fonts;
 | 
| +  FontStyleMap face_map;
 | 
| +  face_map.insert(
 | 
| +      std::make_pair("Style1", FontInformation("Path", "FullName")));
 | 
| +  fonts.insert(std::make_pair("Font", face_map));
 | 
| +  SetCacheMap(fonts);
 | 
| +
 | 
| +  base::RunLoop run_loop;
 | 
| +  service_impl_->GetFontList(
 | 
| +      base::Bind(&FontAccessServiceTest::VerifyFontListCallback, fonts, 1,
 | 
| +                 run_loop.QuitClosure()));
 | 
| +  run_loop.Run();
 | 
| +  EXPECT_EQ(1, counter_->counter);
 | 
| +}
 | 
| +
 | 
| +TEST_F(FontAccessServiceTest, GetFontsRecaches) {
 | 
| +  FontCacheMap fonts;
 | 
| +  FontStyleMap face_map;
 | 
| +  face_map.insert(
 | 
| +      std::make_pair("Style1", FontInformation("Path", "FullName")));
 | 
| +  fonts.insert(std::make_pair("Font", face_map));
 | 
| +  SetCacheMap(fonts);
 | 
| +
 | 
| +  {
 | 
| +    base::RunLoop run_loop;
 | 
| +    service_impl_->GetFontList(
 | 
| +        base::Bind(&FontAccessServiceTest::VerifyFontListCallback, fonts, 1,
 | 
| +                   run_loop.QuitClosure()));
 | 
| +    run_loop.Run();
 | 
| +  }
 | 
| +
 | 
| +  fonts.insert(std::make_pair("Font2", face_map));
 | 
| +  SetCacheMap(fonts);
 | 
| +  {
 | 
| +    base::RunLoop run_loop;
 | 
| +    service_impl_->GetFontList(
 | 
| +        base::Bind(&FontAccessServiceTest::VerifyFontListCallback, fonts, 2,
 | 
| +                   run_loop.QuitClosure()));
 | 
| +    run_loop.Run();
 | 
| +  }
 | 
| +
 | 
| +  EXPECT_EQ(2, counter_->counter);
 | 
| +}
 | 
| +
 | 
| +TEST_F(FontAccessServiceTest, GetFontBlob) {
 | 
| +  base::ScopedTempDir temp_dir;
 | 
| +  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 | 
| +  base::FilePath file_path = temp_dir.path().AppendASCII("test_file.ttf");
 | 
| +  base::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;
 | 
| +  int bytes_written = file.Write(0, data_to_write, kTestDataSize);
 | 
| +  EXPECT_EQ(kTestDataSize, bytes_written);
 | 
| +
 | 
| +  FontCacheMap fonts;
 | 
| +  FontStyleMap face_map;
 | 
| +  face_map.insert(std::make_pair(
 | 
| +      "Style1", FontInformation(file_path.AsUTF8Unsafe(), "FullName")));
 | 
| +  fonts.insert(std::make_pair("Font", face_map));
 | 
| +  SetCacheMap(fonts);
 | 
| +
 | 
| +  {
 | 
| +    base::RunLoop run_loop;
 | 
| +    service_impl_->GetFontData(
 | 
| +        "Font", "Style1",
 | 
| +        base::Bind(&FontAccessServiceTest::VerifyFontBlobCallback,
 | 
| +                   kTestDataSize, run_loop.QuitClosure()));
 | 
| +    run_loop.Run();
 | 
| +  }
 | 
| +
 | 
| +  EXPECT_EQ(1, counter_->counter);
 | 
| +}
 | 
| +
 | 
| +TEST_F(FontAccessServiceTest, GetFontBlobIsCached) {
 | 
| +  base::ScopedTempDir temp_dir;
 | 
| +  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 | 
| +  base::FilePath file_path = temp_dir.path().AppendASCII("test_file.ttf");
 | 
| +  base::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;
 | 
| +  int bytes_written = file.Write(0, data_to_write, kTestDataSize);
 | 
| +  EXPECT_EQ(kTestDataSize, bytes_written);
 | 
| +
 | 
| +  FontCacheMap fonts;
 | 
| +  FontStyleMap face_map;
 | 
| +  face_map.insert(std::make_pair(
 | 
| +      "Style1", FontInformation(file_path.AsUTF8Unsafe(), "FullName")));
 | 
| +  fonts.insert(std::make_pair("Font", face_map));
 | 
| +  SetCacheMap(fonts);
 | 
| +
 | 
| +  {
 | 
| +    base::RunLoop run_loop;
 | 
| +    service_impl_->GetFontData(
 | 
| +        "Font", "Style1",
 | 
| +        base::Bind(&FontAccessServiceTest::VerifyFontBlobCallback,
 | 
| +                   kTestDataSize, run_loop.QuitClosure()));
 | 
| +    run_loop.Run();
 | 
| +  }
 | 
| +  {
 | 
| +    base::RunLoop run_loop;
 | 
| +    service_impl_->GetFontData(
 | 
| +        "Font", "Style1",
 | 
| +        base::Bind(&FontAccessServiceTest::VerifyFontBlobCallback,
 | 
| +                   kTestDataSize, run_loop.QuitClosure()));
 | 
| +    run_loop.Run();
 | 
| +  }
 | 
| +
 | 
| +  EXPECT_EQ(1, counter_->counter);
 | 
| +}
 | 
| +
 | 
| +TEST_F(FontAccessServiceTest, GetFontBlobRecachesOnMiss) {
 | 
| +  base::ScopedTempDir temp_dir;
 | 
| +  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 | 
| +  base::FilePath file_path = temp_dir.path().AppendASCII("test_file.ttf");
 | 
| +  base::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;
 | 
| +  int bytes_written = file.Write(0, data_to_write, kTestDataSize);
 | 
| +  EXPECT_EQ(kTestDataSize, bytes_written);
 | 
| +
 | 
| +  FontCacheMap fonts;
 | 
| +  FontStyleMap face_map;
 | 
| +  face_map.insert(std::make_pair(
 | 
| +      "Style1", FontInformation(file_path.AsUTF8Unsafe(), "FullName")));
 | 
| +  fonts.insert(std::make_pair("Font", face_map));
 | 
| +  SetCacheMap(fonts);
 | 
| +
 | 
| +  // Populates the cache and returns the first font.
 | 
| +  {
 | 
| +    base::RunLoop run_loop;
 | 
| +    service_impl_->GetFontData(
 | 
| +        "Font", "Style1",
 | 
| +        base::Bind(&FontAccessServiceTest::VerifyFontBlobCallback,
 | 
| +                   kTestDataSize, run_loop.QuitClosure()));
 | 
| +    run_loop.Run();
 | 
| +  }
 | 
| +
 | 
| +  // Expected cache miss and a second miss after recaching.
 | 
| +  {
 | 
| +    base::RunLoop run_loop;
 | 
| +    service_impl_->GetFontData(
 | 
| +        "Font2", "Style1",
 | 
| +        base::Bind(&FontAccessServiceTest::VerifyFontBlobCallback, 0,
 | 
| +                   run_loop.QuitClosure()));
 | 
| +    run_loop.Run();
 | 
| +  }
 | 
| +  EXPECT_EQ(2, counter_->counter);
 | 
| +
 | 
| +  fonts.insert(std::make_pair("Font2", face_map));
 | 
| +  SetCacheMap(fonts);
 | 
| +
 | 
| +  // Expected cache miss with eventual result on recache.
 | 
| +  {
 | 
| +    base::RunLoop run_loop;
 | 
| +    service_impl_->GetFontData(
 | 
| +        "Font2", "Style1",
 | 
| +        base::Bind(&FontAccessServiceTest::VerifyFontBlobCallback,
 | 
| +                   kTestDataSize, run_loop.QuitClosure()));
 | 
| +    run_loop.Run();
 | 
| +  }
 | 
| +
 | 
| +  EXPECT_EQ(3, counter_->counter);
 | 
| +}
 | 
| +
 | 
| +TEST_F(FontAccessServiceTest, FontBlobPathIsInvalid) {
 | 
| +  base::ScopedTempDir temp_dir;
 | 
| +  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 | 
| +  base::FilePath file_path = temp_dir.path().AppendASCII("test_file.ttf");
 | 
| +
 | 
| +  FontCacheMap fonts;
 | 
| +  FontStyleMap face_map;
 | 
| +  face_map.insert(std::make_pair(
 | 
| +      "Style1", FontInformation(file_path.AsUTF8Unsafe(), "FullName")));
 | 
| +  fonts.insert(std::make_pair("Font", face_map));
 | 
| +  SetCacheMap(fonts);
 | 
| +
 | 
| +  {
 | 
| +    base::RunLoop run_loop;
 | 
| +    service_impl_->GetFontData(
 | 
| +        "Font", "Style1",
 | 
| +        base::Bind(&FontAccessServiceTest::VerifyFontBlobCallback, 0,
 | 
| +                   run_loop.QuitClosure()));
 | 
| +    run_loop.Run();
 | 
| +  }
 | 
| +
 | 
| +  EXPECT_EQ(1, counter_->counter);
 | 
| +}
 | 
| +}
 | 
| 
 |