blob: 89afc456260cabbc238a928b5eff5c439a5c97b8 [file] [log] [blame]
// Copyright 2015 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 <stdint.h>
#include <string.h>
#include <utility>
#include <vector>
#include "mojo/file_utils/file_util.h"
#include "mojo/public/cpp/application/application_test_base.h"
#include "mojo/public/cpp/application/connect.h"
#include "mojo/public/cpp/bindings/synchronous_interface_ptr.h"
#include "mojo/public/cpp/utility/run_loop.h"
#include "mojo/services/files/interfaces/directory.mojom-sync.h"
#include "mojo/services/files/interfaces/file.mojom-sync.h"
#include "mojo/services/files/interfaces/files.mojom-sync.h"
namespace file_utils {
namespace test {
namespace {
using FileUtilTest = mojo::test::ApplicationTestBase;
// Writes |input| to |file| and that the requisite number of bytes was written.
void WriteFileHelper(mojo::SynchronousInterfacePtr<mojo::files::File>* file,
const std::string& input) {
auto bytes_to_write = mojo::Array<uint8_t>::New(input.size());
memcpy(bytes_to_write.data(), input.data(), input.size());
mojo::files::Error error = mojo::files::Error::INTERNAL;
uint32_t num_bytes_written = 0;
ASSERT_TRUE((*file)->Write(std::move(bytes_to_write), 0,
mojo::files::Whence::FROM_CURRENT, &error,
&num_bytes_written));
EXPECT_EQ(mojo::files::Error::OK, error);
EXPECT_EQ(input.size(), num_bytes_written);
}
// Seeks to |offset| in |file| (from the current position), verifying that the
// resulting position is |expected_position|.
void SeekFileHelper(mojo::SynchronousInterfacePtr<mojo::files::File>* file,
int64_t offset,
int64_t expected_position) {
int64_t position = -1;
mojo::files::Error error = mojo::files::Error::INTERNAL;
ASSERT_TRUE((*file)->Seek(offset, mojo::files::Whence::FROM_CURRENT, &error,
&position));
EXPECT_EQ(mojo::files::Error::OK, error);
EXPECT_EQ(expected_position, position);
}
// Reads |expected_output.size()| bytes from |file| at offset |offset| (using
// Whence::FROM_CURRENT), and verify that the result matches |expected_output|.
void ReadFileHelper(mojo::SynchronousInterfacePtr<mojo::files::File>* file,
int64_t offset,
const std::string& expected_output) {
mojo::Array<uint8_t> bytes_read;
mojo::files::Error error = mojo::files::Error::INTERNAL;
uint32_t num_bytes_to_read = expected_output.size();
ASSERT_TRUE((*file)->Read(num_bytes_to_read, offset,
mojo::files::Whence::FROM_CURRENT, &error,
&bytes_read));
EXPECT_EQ(mojo::files::Error::OK, error);
ASSERT_EQ(num_bytes_to_read, bytes_read.size());
EXPECT_EQ(
0, memcmp(bytes_read.data(), expected_output.data(), num_bytes_to_read));
}
// Closes |file| and verifies that no error occurs.
void CloseFileHelper(mojo::SynchronousInterfacePtr<mojo::files::File>* file) {
mojo::files::Error error = mojo::files::Error::INTERNAL;
ASSERT_TRUE((*file)->Close(&error));
EXPECT_EQ(mojo::files::Error::OK, error);
}
// Opens the file named |path_name| in |directory| and verifies that no error
// occurs. Returns the newly-opened file.
mojo::SynchronousInterfacePtr<mojo::files::File> OpenFileHelper(
mojo::SynchronousInterfacePtr<mojo::files::Directory>* directory,
const std::string& path_name) {
mojo::SynchronousInterfacePtr<mojo::files::File> temp_file;
mojo::files::Error error = mojo::files::Error::INTERNAL;
EXPECT_TRUE(
(*directory)
->OpenFile(path_name, GetSynchronousProxy(&temp_file),
mojo::files::kOpenFlagWrite | mojo::files::kOpenFlagRead,
&error));
EXPECT_EQ(mojo::files::Error::OK, error);
return temp_file;
}
TEST_F(FileUtilTest, BasicCreateTemporaryFile) {
mojo::SynchronousInterfacePtr<mojo::files::Files> files;
mojo::ConnectToService(shell(), "mojo:files", GetSynchronousProxy(&files));
mojo::files::Error error = mojo::files::Error::INTERNAL;
mojo::SynchronousInterfacePtr<mojo::files::Directory> directory;
ASSERT_TRUE(files->OpenFileSystem(
nullptr, mojo::GetSynchronousProxy(&directory), &error));
EXPECT_EQ(mojo::files::Error::OK, error);
std::string filename1;
auto file1 = mojo::SynchronousInterfacePtr<mojo::files::File>::Create(
CreateTemporaryFileInDir(&directory, &filename1));
ASSERT_TRUE(file1);
std::string filename2;
auto file2 = mojo::SynchronousInterfacePtr<mojo::files::File>::Create(
CreateTemporaryFileInDir(&directory, &filename2));
ASSERT_TRUE(file2);
std::string filename3;
auto file3 = mojo::SynchronousInterfacePtr<mojo::files::File>::Create(
CreateTemporaryFileInDir(&directory, &filename3));
ASSERT_TRUE(file3);
// The temp filenames should not be equal.
EXPECT_NE(filename1, filename2);
EXPECT_NE(filename1, filename3);
EXPECT_NE(filename2, filename3);
// Test that 'Write' can be called on the temp files.
WriteFileHelper(&file1, "abcde");
WriteFileHelper(&file2, "fghij");
WriteFileHelper(&file3, "lmnop");
// Test that 'Seek' can be called on the temp files.
SeekFileHelper(&file1, -5, 0);
SeekFileHelper(&file2, -4, 1);
SeekFileHelper(&file3, -3, 2);
// Test that 'Read' can be called on the temp files.
ReadFileHelper(&file1, 0, "abcde");
ReadFileHelper(&file2, 0, "ghij");
ReadFileHelper(&file3, 0, "nop");
// Test that the files can be closed.
CloseFileHelper(&file1);
CloseFileHelper(&file2);
CloseFileHelper(&file3);
// Test that the files can be reopened after closing.
file1 = OpenFileHelper(&directory, filename1);
file2 = OpenFileHelper(&directory, filename2);
file3 = OpenFileHelper(&directory, filename3);
// Verify the contents of the reopened files.
ReadFileHelper(&file1, 0, "abcde");
ReadFileHelper(&file2, 0, "fghij");
ReadFileHelper(&file3, 0, "lmnop");
// Test that the files can be closed once more.
CloseFileHelper(&file1);
CloseFileHelper(&file2);
CloseFileHelper(&file3);
}
} // namespace
} // namespace test
} // namespace file_utils