Home | History | Annotate | Download | only in test
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <atlbase.h>
      6 #include <atlcom.h>
      7 
      8 #include "base/file_util.h"
      9 #include "base/path_service.h"
     10 #include "base/win/scoped_comptr.h"
     11 #include "chrome_frame/test/chrome_frame_test_utils.h"
     12 #include "chrome_frame/test/urlmon_moniker_tests.h"
     13 #include "chrome_frame/urlmon_bind_status_callback.h"
     14 
     15 using chrome_frame_test::ScopedVirtualizeHklmAndHkcu;
     16 using testing::Return;
     17 using testing::Eq;
     18 
     19 class MonikerPatchTest : public testing::Test {
     20  protected:
     21   MonikerPatchTest() {
     22   }
     23 
     24   virtual void SetUp() {
     25     DeleteAllSingletons();
     26     PathService::Get(base::DIR_SOURCE_ROOT, &test_file_path_);
     27     test_file_path_ = test_file_path_.Append(FILE_PATH_LITERAL("chrome_frame"))
     28         .Append(FILE_PATH_LITERAL("test"))
     29         .Append(FILE_PATH_LITERAL("data"));
     30   }
     31 
     32   bool ReadFileAsString(const wchar_t* file_name, std::string* file_contents) {
     33     EXPECT_TRUE(file_name);
     34     base::FilePath file_path = test_file_path_.Append(file_name);
     35     return base::ReadFileToString(file_path, file_contents);
     36   }
     37 
     38   static bool StringToStream(const std::string& data, IStream** ret) {
     39     EXPECT_TRUE(!data.empty());
     40 
     41     base::win::ScopedComPtr<IStream> stream;
     42     HRESULT hr = CreateStreamOnHGlobal(NULL, TRUE, stream.Receive());
     43     EXPECT_HRESULT_SUCCEEDED(hr);
     44     if (FAILED(hr)) {
     45       return false;
     46     }
     47 
     48     DWORD written = 0;
     49     hr = stream->Write(data.c_str(), data.size(), &written);
     50     EXPECT_HRESULT_SUCCEEDED(hr);
     51     EXPECT_EQ(data.size(), written);
     52 
     53     bool result = false;
     54     if (SUCCEEDED(hr)) {
     55       RewindStream(stream);
     56       *ret = stream.Detach();
     57       result = true;
     58     }
     59 
     60     return result;
     61   }
     62 
     63   base::FilePath test_file_path_;
     64   ScopedVirtualizeHklmAndHkcu virtualized_registry_;
     65 };
     66 
     67 // Tests the CacheStream class by writing content into a stream object
     68 // and verify that reading that stream back
     69 TEST_F(MonikerPatchTest, CacheStream) {
     70   const char data[] = "ReadStreamCacheTest";
     71   char ret[2 * sizeof(data)] = {0};
     72   DWORD read = 0;
     73 
     74   // Test 1: empty stream reads nothing
     75   CComObjectStackEx<CacheStream> cache_stream1;
     76   EXPECT_EQ(S_FALSE, cache_stream1.Read(ret, sizeof(ret), &read));
     77   EXPECT_EQ(0, read);
     78 
     79   // Test 2: Read from initialized cache
     80   CComObjectStackEx<CacheStream> cache_stream2;
     81   cache_stream2.Initialize(data, sizeof(data), false);
     82   EXPECT_HRESULT_SUCCEEDED(cache_stream2.Read(ret, sizeof(ret), &read));
     83   EXPECT_EQ(sizeof(data), read);
     84   EXPECT_EQ(std::string(data), std::string(ret));
     85 
     86   read = 0;
     87   EXPECT_EQ(E_PENDING, cache_stream2.Read(ret, sizeof(ret), &read));
     88   EXPECT_EQ(0, read);
     89 }
     90 
     91 ACTION_P3(ReadStream, buffer, size, ret) {
     92   EXPECT_EQ(TYMED_ISTREAM, arg3->tymed);
     93   *ret = arg3->pstm->Read(buffer, *size, size);
     94 }
     95 
     96 // Tests the implementation of BSCBFeedData to feed data to the
     97 // specified IBindStatusCallback
     98 TEST_F(MonikerPatchTest, BSCBFeedData) {
     99   CComObjectStackEx<MockBindStatusCallbackImpl> mock;
    100   const char data[] = "ReadStreamCacheTest";
    101   const DWORD size = sizeof(data);
    102   const CLIPFORMAT cf = 0xd0d0;
    103   const DWORD flags = BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION;
    104   const DWORD kArbitraryreadSize = 0xdeadbabe;
    105 
    106   char read_buffer1[size] = {0}, read_buffer2[size] = {0};
    107   DWORD read_size1 = size, read_size2 = kArbitraryreadSize;
    108   HRESULT ret1 = E_FAIL, ret2 = E_FAIL;
    109 
    110   EXPECT_CALL(mock, OnDataAvailable(flags, size,
    111                     testing::Field(&FORMATETC::cfFormat, cf),
    112                     testing::Field(&STGMEDIUM::tymed, TYMED_ISTREAM)))
    113       .WillOnce(testing::DoAll(
    114           ReadStream(read_buffer1, &read_size1, &ret1),
    115           ReadStream(read_buffer2, &read_size2, &ret2),
    116           Return(S_OK)));
    117 
    118   EXPECT_HRESULT_SUCCEEDED(CacheStream::BSCBFeedData(&mock, data, size, cf,
    119                                                      flags, false));
    120 
    121   EXPECT_HRESULT_SUCCEEDED(ret1);
    122   EXPECT_STREQ(data, read_buffer1);
    123   EXPECT_EQ(size, read_size1);
    124 
    125   EXPECT_EQ(E_PENDING, ret2);
    126   EXPECT_STREQ("", read_buffer2);
    127   EXPECT_EQ(kArbitraryreadSize, read_size2);
    128 }
    129 
    130 const wchar_t kSmallHtmlMetaTag[] = L"sub_frame1.html";
    131 const wchar_t kSmallHtmlNoMetaTag[] = L"host_browser.html";
    132 
    133 // Test various aspects of the SniffData class
    134 TEST_F(MonikerPatchTest, SniffDataMetaTag) {
    135   std::string small_html_meta_tag, small_html_no_meta_tag;
    136   ASSERT_TRUE(ReadFileAsString(kSmallHtmlMetaTag, &small_html_meta_tag));
    137   ASSERT_TRUE(ReadFileAsString(kSmallHtmlNoMetaTag, &small_html_no_meta_tag));
    138 
    139   base::win::ScopedComPtr<IStream> stream_with_meta, stream_no_meta;
    140   ASSERT_TRUE(StringToStream(small_html_meta_tag, stream_with_meta.Receive()));
    141   ASSERT_TRUE(StringToStream(small_html_no_meta_tag,
    142                              stream_no_meta.Receive()));
    143 
    144   // Initialize 2 sniffers 1 with meta tag and 1 without.
    145   SniffData sniffer1, sniffer2;
    146   EXPECT_HRESULT_SUCCEEDED(sniffer1.InitializeCache(std::wstring()));
    147   EXPECT_HRESULT_SUCCEEDED(sniffer2.InitializeCache(std::wstring()));
    148   EXPECT_HRESULT_SUCCEEDED(sniffer1.ReadIntoCache(stream_with_meta, true));
    149   EXPECT_HRESULT_SUCCEEDED(sniffer2.ReadIntoCache(stream_no_meta, true));
    150 
    151   // Verify renderer type and size read.
    152   EXPECT_TRUE(sniffer1.is_chrome());
    153   EXPECT_EQ(SniffData::OTHER, sniffer2.renderer_type());
    154   EXPECT_EQ(small_html_meta_tag.size(), sniffer1.size());
    155   EXPECT_EQ(small_html_no_meta_tag.size(), sniffer2.size());
    156 }
    157 
    158 // Now test how the data is fed back the the bind status callback.
    159 // case 1: callback reads data in 1 read
    160 TEST_F(MonikerPatchTest, SniffDataPlayback1) {
    161   std::string small_html_meta_tag;
    162   base::win::ScopedComPtr<IStream> stream_with_meta;
    163   SniffData sniffer;
    164 
    165   EXPECT_HRESULT_SUCCEEDED(sniffer.InitializeCache(std::wstring()));
    166   ASSERT_TRUE(ReadFileAsString(kSmallHtmlMetaTag, &small_html_meta_tag));
    167   ASSERT_TRUE(StringToStream(small_html_meta_tag, stream_with_meta.Receive()));
    168   EXPECT_HRESULT_SUCCEEDED(sniffer.ReadIntoCache(stream_with_meta, true));
    169 
    170   CComObjectStackEx<MockBindStatusCallbackImpl> mock;
    171   const CLIPFORMAT cf = 0xd0d0;
    172   const DWORD flags = BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION;
    173   const DWORD data_size = small_html_meta_tag.size();
    174 
    175   DWORD read_size1 = data_size * 2;
    176   scoped_ptr<char[]> read_buffer1(new char[read_size1]);
    177   ZeroMemory(read_buffer1.get(), read_size1);
    178 
    179   char read_buffer2[10] = {0};
    180   DWORD read_size2 = sizeof(read_buffer2);
    181   HRESULT ret1 = E_FAIL, ret2 = E_FAIL;
    182 
    183   EXPECT_CALL(mock, OnDataAvailable(flags, data_size,
    184                     testing::Field(&FORMATETC::cfFormat, cf),
    185                     testing::Field(&STGMEDIUM::tymed, TYMED_ISTREAM)))
    186       .WillOnce(testing::DoAll(
    187           ReadStream(read_buffer1.get(), &read_size1, &ret1),
    188           ReadStream(read_buffer2, &read_size2, &ret2),
    189           Return(S_OK)));
    190 
    191   EXPECT_HRESULT_SUCCEEDED(sniffer.DrainCache(&mock, flags, cf));
    192 
    193   EXPECT_HRESULT_SUCCEEDED(ret1);
    194   EXPECT_EQ(small_html_meta_tag, read_buffer1.get());
    195   EXPECT_EQ(data_size, read_size1);
    196 
    197   EXPECT_EQ(S_FALSE, ret2);
    198   EXPECT_STREQ("", read_buffer2);
    199   EXPECT_EQ(sizeof(read_buffer2), read_size2);
    200 }
    201 
    202 // case 2: callback reads data in 2 reads.
    203 TEST_F(MonikerPatchTest, SniffDataPlayback2) {
    204   std::string small_html_meta_tag;
    205   base::win::ScopedComPtr<IStream> stream_with_meta;
    206   SniffData sniffer;
    207 
    208   EXPECT_HRESULT_SUCCEEDED(sniffer.InitializeCache(std::wstring()));
    209   ASSERT_TRUE(ReadFileAsString(kSmallHtmlMetaTag, &small_html_meta_tag));
    210   ASSERT_TRUE(StringToStream(small_html_meta_tag, stream_with_meta.Receive()));
    211   EXPECT_HRESULT_SUCCEEDED(sniffer.ReadIntoCache(stream_with_meta, true));
    212 
    213   CComObjectStackEx<MockBindStatusCallbackImpl> mock;
    214   const CLIPFORMAT cf = 0xd0d0;
    215   const DWORD flags = BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION;
    216   const DWORD data_size = small_html_meta_tag.size();
    217 
    218   DWORD read_size1 = data_size / 2; // First read is half the data.
    219   DWORD read_size2 = data_size; // Second read, try to read past data.
    220   scoped_ptr<char[]> read_buffer1(new char[read_size1]);
    221   scoped_ptr<char[]> read_buffer2(new char[read_size2]);
    222   ZeroMemory(read_buffer1.get(), read_size1);
    223   ZeroMemory(read_buffer2.get(), read_size2);
    224 
    225   char read_buffer3[10] = {0};
    226   DWORD read_size3 = sizeof(read_buffer3);
    227   HRESULT ret1 = E_FAIL, ret2 = E_FAIL, ret3 = E_FAIL;
    228 
    229   EXPECT_CALL(mock, OnDataAvailable(flags, data_size,
    230                     testing::Field(&FORMATETC::cfFormat, cf),
    231                     testing::Field(&STGMEDIUM::tymed, TYMED_ISTREAM)))
    232       .WillOnce(testing::DoAll(
    233           ReadStream(read_buffer1.get(), &read_size1, &ret1),
    234           ReadStream(read_buffer2.get(), &read_size2, &ret2),
    235           ReadStream(read_buffer3, &read_size3, &ret3),
    236           Return(S_OK)));
    237 
    238   EXPECT_HRESULT_SUCCEEDED(sniffer.DrainCache(&mock, flags, cf));
    239 
    240   EXPECT_HRESULT_SUCCEEDED(ret1);
    241   EXPECT_HRESULT_SUCCEEDED(ret2);
    242   EXPECT_EQ(data_size/2, read_size1);
    243   EXPECT_EQ(data_size - read_size1, read_size2);
    244 
    245   std::string data_read;
    246   data_read.append(read_buffer1.get(), read_size1);
    247   data_read.append(read_buffer2.get(), read_size2);
    248   EXPECT_EQ(small_html_meta_tag, data_read);
    249 
    250   EXPECT_EQ(S_FALSE, ret3);
    251   EXPECT_STREQ("", read_buffer3);
    252   EXPECT_EQ(sizeof(read_buffer3), read_size3);
    253 }
    254