| Index: chrome_frame/test/urlmon_moniker_unittest.cc
|
| ===================================================================
|
| --- chrome_frame/test/urlmon_moniker_unittest.cc (revision 43957)
|
| +++ chrome_frame/test/urlmon_moniker_unittest.cc (working copy)
|
| @@ -5,222 +5,245 @@
|
| #include <atlbase.h>
|
| #include <atlcom.h>
|
|
|
| +#include "base/file_util.h"
|
| +#include "base/path_service.h"
|
| #include "base/scoped_comptr_win.h"
|
| -#include "chrome_frame/bho.h"
|
| -#include "chrome_frame/urlmon_moniker.h"
|
| +#include "chrome_frame/urlmon_bind_status_callback.h"
|
| #include "chrome_frame/test/urlmon_moniker_tests.h"
|
| -#include "gmock/gmock.h"
|
| -#include "gtest/gtest.h"
|
|
|
| -using testing::_;
|
| using testing::Return;
|
| -using testing::WithArg;
|
| -using testing::WithArgs;
|
| -using testing::SetArgumentPointee;
|
| -using testing::StrEq;
|
| using testing::Eq;
|
|
|
| -class UrlmonMonikerTest : public testing::Test {
|
| +class MonikerPatchTest : public testing::Test {
|
| protected:
|
| - UrlmonMonikerTest() {
|
| + MonikerPatchTest() {
|
| }
|
| +
|
| + virtual void SetUp() {
|
| + PathService::Get(base::DIR_SOURCE_ROOT, &test_file_path_);
|
| + test_file_path_ = test_file_path_.Append(FILE_PATH_LITERAL("chrome_frame"))
|
| + .Append(FILE_PATH_LITERAL("test"))
|
| + .Append(FILE_PATH_LITERAL("data"));
|
| + }
|
| +
|
| + bool ReadFileAsString(const wchar_t* file_name, std::string* file_contents) {
|
| + EXPECT_TRUE(file_name);
|
| + FilePath file_path = test_file_path_.Append(file_name);
|
| + return file_util::ReadFileToString(file_path, file_contents);
|
| + }
|
| +
|
| + static bool StringToStream(const std::string& data, IStream** ret) {
|
| + EXPECT_TRUE(!data.empty());
|
| +
|
| + ScopedComPtr<IStream> stream;
|
| + HRESULT hr = CreateStreamOnHGlobal(NULL, TRUE, stream.Receive());
|
| + EXPECT_HRESULT_SUCCEEDED(hr);
|
| + if (FAILED(hr)) {
|
| + return false;
|
| + }
|
| +
|
| + DWORD written = 0;
|
| + hr = stream->Write(data.c_str(), data.size(), &written);
|
| + EXPECT_HRESULT_SUCCEEDED(hr);
|
| + EXPECT_EQ(data.size(), written);
|
| +
|
| + bool result = false;
|
| + if (SUCCEEDED(hr)) {
|
| + RewindStream(stream);
|
| + *ret = stream.Detach();
|
| + result = true;
|
| + }
|
| +
|
| + return result;
|
| + }
|
| +
|
| + FilePath test_file_path_;
|
| };
|
|
|
| -// Tests the ReadStreamCache class by writing content into a stream object
|
| -// and verify that reading that stream through the ReadStreamCache class
|
| -// reads the correct content and also verifies that ReadStreamCache caches
|
| -// all the reads.
|
| -TEST_F(UrlmonMonikerTest, ReadStreamCache) {
|
| - CComObjectStackEx<ReadStreamCache> read_stream;
|
| - EXPECT_EQ(NULL, read_stream.cache());
|
| +// Tests the CacheStream class by writing content into a stream object
|
| +// and verify that reading that stream back
|
| +TEST_F(MonikerPatchTest, CacheStream) {
|
| + const char data[] = "ReadStreamCacheTest";
|
| + char ret[2 * sizeof(data)] = {0};
|
| + DWORD read = 0;
|
|
|
| - ScopedComPtr<IStream> test_stream;
|
| - ::CreateStreamOnHGlobal(NULL, TRUE, test_stream.Receive());
|
| - EXPECT_TRUE(NULL != test_stream);
|
| - const char test_string[] = "ReadStreamCacheTest";
|
| - DWORD written;
|
| - EXPECT_HRESULT_SUCCEEDED(test_stream->Write(test_string, sizeof(test_string),
|
| - &written));
|
| - EXPECT_HRESULT_SUCCEEDED(RewindStream(test_stream));
|
| + // Test 1: empty stream reads nothing
|
| + CComObjectStackEx<CacheStream> cache_stream1;
|
| + EXPECT_EQ(E_PENDING, cache_stream1.Read(ret, sizeof(ret), &read));
|
| + EXPECT_EQ(0, read);
|
|
|
| - read_stream.SetDelegate(test_stream);
|
| + // Test 2: Read from initialized cache
|
| + CComObjectStackEx<CacheStream> cache_stream2;
|
| + cache_stream2.Initialize(data, sizeof(data));
|
| + EXPECT_HRESULT_SUCCEEDED(cache_stream2.Read(ret, sizeof(ret), &read));
|
| + EXPECT_EQ(sizeof(data), read);
|
| + EXPECT_EQ(std::string(data), std::string(ret));
|
|
|
| - char buffer[0xff];
|
| - DWORD read = 0;
|
| - EXPECT_HRESULT_SUCCEEDED(read_stream.Read(buffer, sizeof(buffer), &read));
|
| - EXPECT_EQ(read, sizeof(test_string));
|
| - EXPECT_EQ(read_stream.GetCacheSize(), sizeof(test_string));
|
| - read_stream.RewindCache();
|
| - IStream* cache = read_stream.cache();
|
| - EXPECT_TRUE(NULL != cache);
|
| - if (cache) {
|
| - read = 0;
|
| - EXPECT_HRESULT_SUCCEEDED(cache->Read(buffer, sizeof(buffer), &read));
|
| - EXPECT_EQ(read, sizeof(test_string));
|
| - EXPECT_EQ(0, memcmp(test_string, buffer, sizeof(test_string)));
|
| - }
|
| + read = 0;
|
| + EXPECT_EQ(E_PENDING, cache_stream2.Read(ret, sizeof(ret), &read));
|
| + EXPECT_EQ(0, read);
|
| }
|
|
|
| -// Verifies that we can override bind results by using the SimpleBindingImpl
|
| -// class.
|
| -TEST_F(UrlmonMonikerTest, SimpleBindingImpl1) {
|
| - CComObjectStackEx<SimpleBindingImpl> test;
|
| - ScopedComPtr<IBinding> binding;
|
| - binding.QueryFrom(&test);
|
| - EXPECT_TRUE(binding != NULL);
|
| - test.OverrideBindResults(E_INVALIDARG);
|
| - DWORD hr = E_UNEXPECTED;
|
| - EXPECT_HRESULT_SUCCEEDED(binding->GetBindResult(NULL, &hr, NULL, NULL));
|
| - EXPECT_EQ(E_INVALIDARG, hr);
|
| - test.OverrideBindResults(E_ACCESSDENIED);
|
| - // {1AF15145-104B-4bd8-AA4F-97CEFD40D370} - just something non-null.
|
| - GUID guid = { 0x1af15145, 0x104b, 0x4bd8,
|
| - { 0xaa, 0x4f, 0x97, 0xce, 0xfd, 0x40, 0xd3, 0x70 } };
|
| - EXPECT_HRESULT_SUCCEEDED(binding->GetBindResult(&guid, &hr, NULL, NULL));
|
| - EXPECT_EQ(E_ACCESSDENIED, hr);
|
| - EXPECT_TRUE(guid == GUID_NULL);
|
| +ACTION_P3(ReadStream, buffer, size, ret) {
|
| + EXPECT_EQ(TYMED_ISTREAM, arg3->tymed);
|
| + *ret = arg3->pstm->Read(buffer, *size, size);
|
| }
|
|
|
| -// Tests the SimpleBindingImpl class with a delegate. Verifies that the
|
| -// delegate gets called and also that we can override the bind results.
|
| -TEST_F(UrlmonMonikerTest, SimpleBindingImpl2) {
|
| - CComObjectStackEx<MockBindingImpl> mock;
|
| - CComObjectStackEx<SimpleBindingImpl> test;
|
| +// Tests the implementation of BSCBFeedData to feed data to the
|
| +// specified IBindStatusCallback
|
| +TEST_F(MonikerPatchTest, BSCBFeedData) {
|
| + CComObjectStackEx<MockBindStatusCallbackImpl> mock;
|
| + const char data[] = "ReadStreamCacheTest";
|
| + const DWORD size = sizeof(data);
|
| + const CLIPFORMAT cf = 0xd0d0;
|
| + const DWORD flags = BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION;
|
| + const DWORD kArbitraryreadSize = 0xdeadbabe;
|
|
|
| - EXPECT_CALL(mock, QueryService(_, _, _))
|
| - .WillOnce(Return(E_ACCESSDENIED));
|
| - EXPECT_CALL(mock, GetBindResult(_, _, _, _))
|
| - .WillRepeatedly(DoAll(SetArgumentPointee<1>(E_ACCESSDENIED),
|
| - Return(S_OK)));
|
| - EXPECT_CALL(mock, Abort())
|
| - .WillOnce(Return(E_ACCESSDENIED));
|
| + char read_buffer1[size] = {0}, read_buffer2[size] = {0};
|
| + DWORD read_size1 = size, read_size2 = kArbitraryreadSize;
|
| + HRESULT ret1 = E_FAIL, ret2 = E_FAIL;
|
|
|
| - ScopedComPtr<IServiceProvider> svc;
|
| - svc.QueryFrom(test.GetUnknown());
|
| - EXPECT_TRUE(svc == NULL);
|
| + EXPECT_CALL(mock, OnDataAvailable(flags, size,
|
| + testing::Field(&FORMATETC::cfFormat, cf),
|
| + testing::Field(&STGMEDIUM::tymed, TYMED_ISTREAM)))
|
| + .WillOnce(testing::DoAll(
|
| + ReadStream(read_buffer1, &read_size1, &ret1),
|
| + ReadStream(read_buffer2, &read_size2, &ret2),
|
| + Return(S_OK)));
|
|
|
| - test.SetDelegate(&mock);
|
| + EXPECT_HRESULT_SUCCEEDED(CacheStream::BSCBFeedData(&mock, data, size, cf,
|
| + flags));
|
|
|
| - // Now we should have access to IServiceProvider
|
| - svc.QueryFrom(test.GetUnknown());
|
| - EXPECT_TRUE(svc != NULL);
|
| + EXPECT_HRESULT_SUCCEEDED(ret1);
|
| + EXPECT_STREQ(data, read_buffer1);
|
| + EXPECT_EQ(size, read_size1);
|
|
|
| - ScopedComPtr<IUnknown> unk;
|
| - EXPECT_EQ(E_ACCESSDENIED, svc->QueryService(GUID_NULL, IID_NULL,
|
| - reinterpret_cast<void**>(unk.Receive())));
|
| + EXPECT_EQ(E_PENDING, ret2);
|
| + EXPECT_STREQ("", read_buffer2);
|
| + EXPECT_EQ(kArbitraryreadSize, read_size2);
|
| +}
|
|
|
| - // Call through to the mock's GetBindResult implementation.
|
| - DWORD result;
|
| - test.GetBindResult(NULL, &result, NULL, NULL);
|
| - EXPECT_TRUE(result == E_ACCESSDENIED);
|
| - // Let the binding override the result code.
|
| - test.OverrideBindResults(INET_E_TERMINATED_BIND);
|
| - test.GetBindResult(NULL, &result, NULL, NULL);
|
| - EXPECT_TRUE(result == INET_E_TERMINATED_BIND);
|
| +const wchar_t kSmallHtmlMetaTag[] = L"sub_frame1.html";
|
| +const wchar_t kSmallHtmlNoMetaTag[] = L"host_browser.html";
|
|
|
| - EXPECT_EQ(E_ACCESSDENIED, test.Abort());
|
| +// Test various aspects of the SniffData class
|
| +TEST_F(MonikerPatchTest, SniffDataMetaTag) {
|
| + std::string small_html_meta_tag, small_html_no_meta_tag;
|
| + ASSERT_TRUE(ReadFileAsString(kSmallHtmlMetaTag, &small_html_meta_tag));
|
| + ASSERT_TRUE(ReadFileAsString(kSmallHtmlNoMetaTag, &small_html_no_meta_tag));
|
| +
|
| + ScopedComPtr<IStream> stream_with_meta, stream_no_meta;
|
| + ASSERT_TRUE(StringToStream(small_html_meta_tag, stream_with_meta.Receive()));
|
| + ASSERT_TRUE(StringToStream(small_html_no_meta_tag,
|
| + stream_no_meta.Receive()));
|
| +
|
| + // Initialize 2 sniffers 1 with meta tag and 1 without.
|
| + SniffData sniffer1, sniffer2;
|
| + EXPECT_TRUE(sniffer1.InitializeCache(std::wstring()));
|
| + EXPECT_TRUE(sniffer2.InitializeCache(std::wstring()));
|
| + EXPECT_HRESULT_SUCCEEDED(sniffer1.ReadIntoCache(stream_with_meta, true));
|
| + EXPECT_HRESULT_SUCCEEDED(sniffer2.ReadIntoCache(stream_no_meta, true));
|
| +
|
| + // Verify renderer type and size read.
|
| + EXPECT_TRUE(sniffer1.is_chrome());
|
| + EXPECT_EQ(SniffData::OTHER, sniffer2.renderer_type());
|
| + EXPECT_EQ(small_html_meta_tag.size(), sniffer1.size());
|
| + EXPECT_EQ(small_html_no_meta_tag.size(), sniffer2.size());
|
| }
|
|
|
| -// Tests the RequestData class. Content is fed to the object via OnX methods
|
| -// and then we verify that the cached content is correct by calling
|
| -// FireHttpNegotiateEvents and see if the notifications contain the correct
|
| -// content.
|
| -TEST_F(UrlmonMonikerTest, RequestHeaders) {
|
| - scoped_refptr<RequestData> test(new RequestData());
|
| - test->Initialize(NULL);
|
| +// Now test how the data is fed back the the bind status callback.
|
| +// case 1: callback reads data in 1 read
|
| +TEST_F(MonikerPatchTest, SniffDataPlayback1) {
|
| + std::string small_html_meta_tag;
|
| + ScopedComPtr<IStream> stream_with_meta;
|
| + SniffData sniffer;
|
|
|
| - const wchar_t url[] = L"http://www.chromium.org";
|
| - const wchar_t begin_headers[] = L"Cookie: endilega\r\n";
|
| - const wchar_t request_headers[] = L"GET / HTTP/1.0\r\nHost: cough\r\n\rn";
|
| - const wchar_t response_headers[] = L"HTTP 200 OK\r\nHave-a: good-day\r\n\r\n";
|
| - const wchar_t additional_headers[] = L"Referer: http://foo.com\r\n";
|
| + EXPECT_TRUE(sniffer.InitializeCache(std::wstring()));
|
| + ASSERT_TRUE(ReadFileAsString(kSmallHtmlMetaTag, &small_html_meta_tag));
|
| + ASSERT_TRUE(StringToStream(small_html_meta_tag, stream_with_meta.Receive()));
|
| + EXPECT_HRESULT_SUCCEEDED(sniffer.ReadIntoCache(stream_with_meta, true));
|
|
|
| - // Null pointers should be ignored.
|
| - RequestHeaders* headers = test->headers();
|
| - EXPECT_TRUE(NULL != headers);
|
| - headers->OnBeginningTransaction(NULL, NULL, NULL);
|
| - headers->OnBeginningTransaction(url, begin_headers, additional_headers);
|
| - headers->OnResponse(500, NULL, NULL);
|
| - headers->OnResponse(200, response_headers, request_headers);
|
| + CComObjectStackEx<MockBindStatusCallbackImpl> mock;
|
| + const CLIPFORMAT cf = 0xd0d0;
|
| + const DWORD flags = BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION;
|
| + const DWORD data_size = small_html_meta_tag.size();
|
|
|
| - CComObjectStackEx<MockHttpNegotiateImpl> mock;
|
| - EXPECT_CALL(mock, BeginningTransaction(StrEq(url), StrEq(begin_headers),
|
| - _, _))
|
| - .WillOnce(Return(S_OK));
|
| - EXPECT_CALL(mock, OnResponse(Eq(200), StrEq(response_headers),
|
| - StrEq(request_headers), _))
|
| - .WillOnce(Return(S_OK));
|
| + DWORD read_size1 = data_size * 2;
|
| + scoped_ptr<char> read_buffer1(new char[read_size1]);
|
| + ZeroMemory(read_buffer1.get(), read_size1);
|
|
|
| - EXPECT_EQ(0, headers->request_url().compare(url));
|
| + char read_buffer2[10] = {0};
|
| + DWORD read_size2 = sizeof(read_buffer2);
|
| + HRESULT ret1 = E_FAIL, ret2 = E_FAIL;
|
|
|
| - headers->FireHttpNegotiateEvents(&mock);
|
| + EXPECT_CALL(mock, OnDataAvailable(flags, data_size,
|
| + testing::Field(&FORMATETC::cfFormat, cf),
|
| + testing::Field(&STGMEDIUM::tymed, TYMED_ISTREAM)))
|
| + .WillOnce(testing::DoAll(
|
| + ReadStream(read_buffer1.get(), &read_size1, &ret1),
|
| + ReadStream(read_buffer2, &read_size2, &ret2),
|
| + Return(S_OK)));
|
| +
|
| + EXPECT_HRESULT_SUCCEEDED(sniffer.DrainCache(&mock, flags, cf));
|
| +
|
| + EXPECT_HRESULT_SUCCEEDED(ret1);
|
| + EXPECT_EQ(small_html_meta_tag, read_buffer1.get());
|
| + EXPECT_EQ(data_size, read_size1);
|
| +
|
| + EXPECT_EQ(E_PENDING, ret2);
|
| + EXPECT_STREQ("", read_buffer2);
|
| + EXPECT_EQ(sizeof(read_buffer2), read_size2);
|
| }
|
|
|
| -// Tests the HTML content portion of the RequestData class.
|
| -// Here we provide content in the form of a stream object and call
|
| -// OnDataAvailable to make the object cache the contents.
|
| -// Then we fetch the cached content stream by calling
|
| -// GetResetCachedContentStream and verify that it's contents are correct.
|
| -// In order to also test when data is cached outside of OnDataAvailable
|
| -// calls, we also call DelegateDataRead. In this test we simply use the
|
| -// original content again which will make the end results that the cached
|
| -// content should be double the test content.
|
| -TEST_F(UrlmonMonikerTest, RequestDataContent) {
|
| - scoped_refptr<RequestData> test(new RequestData());
|
| - test->Initialize(NULL);
|
| +// case 2: callback reads data in 2 reads.
|
| +TEST_F(MonikerPatchTest, SniffDataPlayback2) {
|
| + std::string small_html_meta_tag;
|
| + ScopedComPtr<IStream> stream_with_meta;
|
| + SniffData sniffer;
|
|
|
| + EXPECT_TRUE(sniffer.InitializeCache(std::wstring()));
|
| + ASSERT_TRUE(ReadFileAsString(kSmallHtmlMetaTag, &small_html_meta_tag));
|
| + ASSERT_TRUE(StringToStream(small_html_meta_tag, stream_with_meta.Receive()));
|
| + EXPECT_HRESULT_SUCCEEDED(sniffer.ReadIntoCache(stream_with_meta, true));
|
| +
|
| CComObjectStackEx<MockBindStatusCallbackImpl> mock;
|
| + const CLIPFORMAT cf = 0xd0d0;
|
| + const DWORD flags = BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION;
|
| + const DWORD data_size = small_html_meta_tag.size();
|
|
|
| - ScopedComPtr<IStream> data;
|
| - ::CreateStreamOnHGlobal(NULL, TRUE, data.Receive());
|
| - const char content[] = "<html><head>"
|
| - "<meta http-equiv=\"X-UA-Compatible\" content=\"chrome=1\" />"
|
| - "</head><body>Test HTML content</body></html>";
|
| - data->Write(content, sizeof(content) - 1, NULL);
|
| - STATSTG stat = {0};
|
| - data->Stat(&stat, STATFLAG_NONAME);
|
| - DCHECK(stat.cbSize.LowPart == (sizeof(content) - 1));
|
| - RewindStream(data);
|
| + DWORD read_size1 = data_size / 2; // First read is half the data.
|
| + DWORD read_size2 = data_size; // Second read, try to read past data.
|
| + scoped_ptr<char> read_buffer1(new char[read_size1]);
|
| + scoped_ptr<char> read_buffer2(new char[read_size2]);
|
| + ZeroMemory(read_buffer1.get(), read_size1);
|
| + ZeroMemory(read_buffer2.get(), read_size2);
|
|
|
| - FORMATETC format = {0};
|
| - format.cfFormat = ::RegisterClipboardFormat(L"application/chromepage");
|
| - format.tymed = TYMED_ISTREAM;
|
| - STGMEDIUM storage = {0};
|
| - storage.tymed = TYMED_ISTREAM;
|
| - storage.pstm = data;
|
| + char read_buffer3[10] = {0};
|
| + DWORD read_size3 = sizeof(read_buffer3);
|
| + HRESULT ret1 = E_FAIL, ret2 = E_FAIL, ret3 = E_FAIL;
|
|
|
| - DWORD flags = BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION |
|
| - BSCF_DATAFULLYAVAILABLE;
|
| -
|
| - EXPECT_CALL(mock, OnDataAvailable(Eq(flags), Eq(stat.cbSize.LowPart), _, _))
|
| - .WillOnce(DoAll(
|
| - WithArgs<3>(testing::Invoke(
|
| - &MockBindStatusCallbackImpl::ReadAllData)),
|
| + EXPECT_CALL(mock, OnDataAvailable(flags, data_size,
|
| + testing::Field(&FORMATETC::cfFormat, cf),
|
| + testing::Field(&STGMEDIUM::tymed, TYMED_ISTREAM)))
|
| + .WillOnce(testing::DoAll(
|
| + ReadStream(read_buffer1.get(), &read_size1, &ret1),
|
| + ReadStream(read_buffer2.get(), &read_size2, &ret2),
|
| + ReadStream(read_buffer3, &read_size3, &ret3),
|
| Return(S_OK)));
|
|
|
| - size_t bytes_read = 0;
|
| - test->DelegateDataRead(&mock, flags, stat.cbSize.LowPart, &format, &storage,
|
| - &bytes_read);
|
| + EXPECT_HRESULT_SUCCEEDED(sniffer.DrainCache(&mock, flags, cf));
|
|
|
| - DCHECK(bytes_read == stat.cbSize.LowPart);
|
| - DCHECK(test->GetCachedContentSize() == bytes_read);
|
| + EXPECT_HRESULT_SUCCEEDED(ret1);
|
| + EXPECT_HRESULT_SUCCEEDED(ret2);
|
| + EXPECT_EQ(data_size/2, read_size1);
|
| + EXPECT_EQ(data_size - read_size1, read_size2);
|
|
|
| - // Also test that the CacheAll method appends the stream.
|
| - RewindStream(data);
|
| - test->CacheAll(data);
|
| - DCHECK(test->GetCachedContentSize() == (bytes_read * 2));
|
| + std::string data_read;
|
| + data_read.append(read_buffer1.get(), read_size1);
|
| + data_read.append(read_buffer2.get(), read_size2);
|
| + EXPECT_EQ(small_html_meta_tag, data_read);
|
|
|
| - ScopedComPtr<IStream> cache;
|
| - EXPECT_HRESULT_SUCCEEDED(test->GetResetCachedContentStream(cache.Receive()));
|
| - if (cache) {
|
| - char buffer[0xffff];
|
| - DCHECK((bytes_read * 2) <= sizeof(buffer));
|
| - DWORD read = 0;
|
| - cache->Read(buffer, sizeof(buffer), &read);
|
| - EXPECT_EQ(read, bytes_read * 2);
|
| - EXPECT_EQ(0, memcmp(content, buffer, sizeof(content) - 1));
|
| - EXPECT_EQ(0, memcmp(content, buffer + sizeof(content) - 1,
|
| - sizeof(content) - 1));
|
| - }
|
| + EXPECT_EQ(E_PENDING, ret3);
|
| + EXPECT_STREQ("", read_buffer3);
|
| + EXPECT_EQ(sizeof(read_buffer3), read_size3);
|
| }
|
| -
|
|
|