cef/tests/ceftests/stream_unittest.cc

350 lines
9.3 KiB
C++
Raw Permalink Normal View History

// Copyright (c) 2009 The Chromium Embedded Framework 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 <algorithm>
Introduce the use of Chromium types (issue #1336). Changes to the CEF public API: - Add base::Bind, base::Callback, base::Lock, base::WeakPtr, scoped_refptr, scoped_ptr and supporting types. - Add include/wrapper/cef_closure_task.h helpers for converting a base::Closure to a CefTask. - Change CefRefPtr to extend scoped_refptr. -- Change CefBase method signatures to match RefCountedThreadSafeBase. - Change IMPLEMENT_REFCOUNTING to use base::AtomicRefCount*. -- Remove the CefAtomic* functions. -- IMPLEMENT_REFCOUNTING now enforces via a compile-time error that the correct class name was passed to the macro. - Change IMPLEMENT_LOCKING to use base::Lock. -- Remove the CefCriticalSection class. -- Deprecate the IMPLEMENT_LOCKING macro. -- base::Lock will DCHECK() in Debug builds if lock usage is reentrant. - Move include/internal/cef_tuple.h to include/base/cef_tuple.h. - Allow an empty |callback| parameter passed to CefBeginTracing. Changes to the CEF implementation: - Fix incorrect names passed to the IMPLEMENT_REFCOUNTING macro. - Fix instances of reentrant locking in the CefXmlObject and CefRequest implementations. - Remove use of the IMPLEMENT_LOCKING macro. Changes to cef_unittests: - Add tests/unittests/chromium_includes.h and always include it first from unit test .cc files to avoid name conflicts with Chromium types. - Fix wrong header include ordering. - Remove use of the IMPLEMENT_LOCKING macro. Changes to cefclient and cefsimple: - Use base::Bind and cef_closure_task.h instead of NewCefRunnable*. - Remove use of the IMPEMENT_LOCKING macro. - Fix incorrect/unnecessary locking. - Add additional runtime thread checks. - Windows: Perform actions on the UI thread instead of the main thread when running in multi-threaded-message-loop mode to avoid excessive locking. git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@1769 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
2014-07-15 00:18:51 +02:00
#include "include/cef_stream.h"
#include "tests/gtest/include/gtest/gtest.h"
static void VerifyStreamReadBehavior(CefRefPtr<CefStreamReader> stream,
const std::string& contents) {
int contentSize = static_cast<int>(contents.size());
const char* contentStr = contents.c_str();
// Move to the beginning of the stream
ASSERT_EQ(0, stream->Seek(0, SEEK_SET));
ASSERT_EQ(0, stream->Tell());
// Move to the end of the stream
ASSERT_EQ(0, stream->Seek(0, SEEK_END));
ASSERT_EQ(contentSize, stream->Tell());
// Move to the beginning of the stream
ASSERT_EQ(0, stream->Seek(-contentSize, SEEK_CUR));
ASSERT_EQ(0, stream->Tell());
// Read 10 characters at a time and verify the result
char buff[10];
int res, read, offset = 0;
do {
read = std::min(static_cast<int>(sizeof(buff)), contentSize - offset);
res = static_cast<int>(stream->Read(buff, 1, read));
ASSERT_EQ(read, res);
ASSERT_TRUE(!memcmp(contentStr + offset, buff, res));
offset += res;
} while (offset < contentSize);
// Read past the end of the file
stream->Read(buff, 1, 1);
ASSERT_TRUE(stream->Eof());
}
static void VerifyStreamWriteBehavior(CefRefPtr<CefStreamWriter> stream,
const std::string& contents) {
int contentSize = static_cast<int>(contents.size());
const char* contentStr = contents.c_str();
// Write 10 characters at a time and verify the result
int res, write, offset = 0;
do {
write = std::min(10, contentSize - offset);
res = static_cast<int>(stream->Write(contentStr + offset, 1, write));
ASSERT_EQ(write, res);
offset += res;
ASSERT_EQ(offset, stream->Tell());
} while (offset < contentSize);
// Move to the beginning of the stream
ASSERT_EQ(0, stream->Seek(-contentSize, SEEK_CUR));
ASSERT_EQ(0, stream->Tell());
// Move to the end of the stream
ASSERT_EQ(0, stream->Seek(0, SEEK_END));
ASSERT_EQ(contentSize, stream->Tell());
// Move to the beginning of the stream
ASSERT_EQ(0, stream->Seek(0, SEEK_SET));
ASSERT_EQ(0, stream->Tell());
}
TEST(StreamTest, ReadFile) {
const char* fileName = "StreamTest.VerifyReadFile.txt";
CefString fileNameStr = "StreamTest.VerifyReadFile.txt";
std::string contents = "This is my test\ncontents for the file";
// Create the file
FILE* f = nullptr;
#ifdef _WIN32
fopen_s(&f, fileName, "wb");
#else
f = fopen(fileName, "wb");
#endif
ASSERT_TRUE(f != nullptr);
ASSERT_EQ((size_t)1, fwrite(contents.c_str(), contents.size(), 1, f));
fclose(f);
// Test the stream
CefRefPtr<CefStreamReader> stream(
CefStreamReader::CreateForFile(fileNameStr));
ASSERT_TRUE(stream.get() != nullptr);
ASSERT_TRUE(stream->MayBlock());
VerifyStreamReadBehavior(stream, contents);
// Release the file pointer
stream = nullptr;
// Delete the file
#ifdef _WIN32
ASSERT_EQ(0, _unlink(fileName));
#else
ASSERT_EQ(0, unlink(fileName));
#endif
}
TEST(StreamTest, ReadData) {
std::string contents = "This is my test\ncontents for the file";
// Test the stream
CefRefPtr<CefStreamReader> stream(CefStreamReader::CreateForData(
static_cast<void*>(const_cast<char*>(contents.c_str())),
contents.size()));
ASSERT_TRUE(stream.get() != nullptr);
ASSERT_FALSE(stream->MayBlock());
VerifyStreamReadBehavior(stream, contents);
}
TEST(StreamTest, WriteFile) {
const char* fileName = "StreamTest.VerifyWriteFile.txt";
CefString fileNameStr = "StreamTest.VerifyWriteFile.txt";
std::string contents = "This is my test\ncontents for the file";
// Test the stream
CefRefPtr<CefStreamWriter> stream(
CefStreamWriter::CreateForFile(fileNameStr));
ASSERT_TRUE(stream.get() != nullptr);
ASSERT_TRUE(stream->MayBlock());
VerifyStreamWriteBehavior(stream, contents);
// Release the file pointer
stream = nullptr;
// Read the file that was written
FILE* f = nullptr;
char* buff = new char[contents.size()];
#ifdef _WIN32
fopen_s(&f, fileName, "rb");
#else
f = fopen(fileName, "rb");
#endif
ASSERT_TRUE(f != nullptr);
ASSERT_EQ((size_t)1, fread(buff, contents.size(), 1, f));
// Read past the end of the file
fgetc(f);
ASSERT_TRUE(feof(f));
fclose(f);
// Verify the file contents
ASSERT_TRUE(!memcmp(contents.c_str(), buff, contents.size()));
delete[] buff;
// Delete the file
#ifdef _WIN32
ASSERT_EQ(0, _unlink(fileName));
#else
ASSERT_EQ(0, unlink(fileName));
#endif
}
bool g_ReadHandlerTesterDeleted = false;
class ReadHandlerTester : public CefReadHandler {
public:
ReadHandlerTester() = default;
~ReadHandlerTester() override { g_ReadHandlerTesterDeleted = true; }
size_t Read(void* ptr, size_t size, size_t n) override {
read_called_ = true;
read_ptr_ = ptr;
read_size_ = size;
read_n_ = n;
return 10;
}
int Seek(int64_t offset, int whence) override {
seek_called_ = true;
seek_offset_ = offset;
seek_whence_ = whence;
return 10;
}
int64_t Tell() override {
tell_called_ = true;
return 10;
}
int Eof() override {
eof_called_ = true;
return 10;
}
bool MayBlock() override { return false; }
bool read_called_ = false;
const void* read_ptr_ = nullptr;
size_t read_size_ = 0;
size_t read_n_ = 0;
bool seek_called_ = false;
int64_t seek_offset_ = 0;
int seek_whence_ = 0;
bool tell_called_ = false;
bool eof_called_ = false;
IMPLEMENT_REFCOUNTING(ReadHandlerTester);
};
TEST(StreamTest, ReadHandler) {
ReadHandlerTester* handler = new ReadHandlerTester();
ASSERT_TRUE(handler != nullptr);
CefRefPtr<CefStreamReader> stream(CefStreamReader::CreateForHandler(handler));
ASSERT_TRUE(stream.get() != nullptr);
ASSERT_FALSE(stream->MayBlock());
// CefReadHandler Read
const char* read_ptr = "My data";
size_t read_size = sizeof(read_ptr);
size_t read_n = 1;
size_t read_res = stream->Read(
static_cast<void*>(const_cast<char*>(read_ptr)), read_size, read_n);
ASSERT_TRUE(handler->read_called_);
ASSERT_EQ((size_t)10, read_res);
ASSERT_EQ(read_ptr, handler->read_ptr_);
ASSERT_EQ(read_size, handler->read_size_);
ASSERT_EQ(read_n, handler->read_n_);
// CefReadHandler Seek
int64_t seek_offset = 10;
int seek_whence = SEEK_CUR;
int seek_res = stream->Seek(seek_offset, seek_whence);
ASSERT_TRUE(handler->seek_called_);
ASSERT_EQ(10, seek_res);
ASSERT_EQ(seek_offset, handler->seek_offset_);
ASSERT_EQ(seek_whence, handler->seek_whence_);
// CefReadHandler Tell
int64_t tell_res = stream->Tell();
ASSERT_TRUE(handler->tell_called_);
ASSERT_EQ(10, tell_res);
// CefReadHandler Eof
int eof_res = stream->Eof();
ASSERT_TRUE(handler->eof_called_);
ASSERT_EQ(10, eof_res);
// Delete the stream
stream = nullptr;
// Verify that the handler object was deleted
ASSERT_TRUE(g_ReadHandlerTesterDeleted);
}
bool g_WriteHandlerTesterDeleted = false;
class WriteHandlerTester : public CefWriteHandler {
public:
WriteHandlerTester() = default;
~WriteHandlerTester() override { g_WriteHandlerTesterDeleted = true; }
size_t Write(const void* ptr, size_t size, size_t n) override {
write_called_ = true;
write_ptr_ = ptr;
write_size_ = size;
write_n_ = n;
return 10;
}
int Seek(int64_t offset, int whence) override {
seek_called_ = true;
seek_offset_ = offset;
seek_whence_ = whence;
return 10;
}
int64_t Tell() override {
tell_called_ = true;
return 10;
}
int Flush() override {
flush_called_ = true;
return 10;
}
bool MayBlock() override { return false; }
bool write_called_ = false;
const void* write_ptr_ = nullptr;
size_t write_size_ = 0;
size_t write_n_ = 0;
bool seek_called_ = false;
int64_t seek_offset_ = 0;
int seek_whence_ = 0;
bool tell_called_ = false;
bool flush_called_ = false;
IMPLEMENT_REFCOUNTING(WriteHandlerTester);
};
TEST(StreamTest, WriteHandler) {
WriteHandlerTester* handler = new WriteHandlerTester();
ASSERT_TRUE(handler != nullptr);
CefRefPtr<CefStreamWriter> stream(CefStreamWriter::CreateForHandler(handler));
ASSERT_TRUE(stream.get() != nullptr);
ASSERT_FALSE(stream->MayBlock());
// CefWriteHandler Write
const char* write_ptr = "My data";
size_t write_size = sizeof(write_ptr);
size_t write_n = 1;
size_t write_res = stream->Write(write_ptr, write_size, write_n);
ASSERT_TRUE(handler->write_called_);
ASSERT_EQ((size_t)10, write_res);
ASSERT_EQ(write_ptr, handler->write_ptr_);
ASSERT_EQ(write_size, handler->write_size_);
ASSERT_EQ(write_n, handler->write_n_);
// CefWriteHandler Seek
int64_t seek_offset = 10;
int seek_whence = SEEK_CUR;
int seek_res = stream->Seek(seek_offset, seek_whence);
ASSERT_TRUE(handler->seek_called_);
ASSERT_EQ(10, seek_res);
ASSERT_EQ(seek_offset, handler->seek_offset_);
ASSERT_EQ(seek_whence, handler->seek_whence_);
// CefWriteHandler Tell
int64_t tell_res = stream->Tell();
ASSERT_TRUE(handler->tell_called_);
ASSERT_EQ(10, tell_res);
// CefWriteHandler Flush
int flush_res = stream->Flush();
ASSERT_TRUE(handler->flush_called_);
ASSERT_EQ(10, flush_res);
// Delete the stream
stream = nullptr;
// Verify that the handler object was deleted
ASSERT_TRUE(g_WriteHandlerTesterDeleted);
}