blob: 80ca03a61fa590b039a277e1e2d30949ca608e75 [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 <vector>
#include "mojo/file_utils/file_util.h"
#include "mojo/public/cpp/application/application_impl.h"
#include "mojo/public/cpp/application/application_test_base.h"
#include "mojo/public/cpp/utility/run_loop.h"
#include "mojo/services/files/interfaces/directory.mojom.h"
#include "mojo/services/files/interfaces/file.mojom.h"
#include "mojo/services/files/interfaces/files.mojom.h"
namespace file_utils {
namespace test {
namespace {
using FileUtilTest = mojo::test::ApplicationTestBase;
// TODO(smklein): Stuff copied from mojo/services/files/c/lib/template_util.h
typedef char YesType;
struct NoType {
YesType dummy[2];
};
template <typename T>
struct IsMoveOnlyType {
template <typename U>
static YesType Test(const typename U::MoveOnlyTypeForCPP03*);
template <typename U>
static NoType Test(...);
static const bool value =
sizeof(Test<T>(0)) == sizeof(YesType) && !std::is_const<T>::value;
};
template <typename T>
typename std::enable_if<!IsMoveOnlyType<T>::value, T>::type& Forward(T& t) {
return t;
}
template <typename T>
typename std::enable_if<IsMoveOnlyType<T>::value, T>::type Forward(T& t) {
return t.Pass();
}
template <typename T1>
mojo::Callback<void(T1)> Capture(T1* t1) {
return [t1](T1 got_t1) { *t1 = Forward(got_t1); };
}
template <typename T1, typename T2>
mojo::Callback<void(T1, T2)> Capture(T1* t1, T2* t2) {
return [t1, t2](T1 got_t1, T2 got_t2) {
*t1 = Forward(got_t1);
*t2 = Forward(got_t2);
};
}
// TODO(smklein): (End of stuff copied from template_util.h)
// Given a FilePtr |file|, write the string |input| and verify
// the output matches the |input|'s size.
void WriteFileHelper(mojo::files::FilePtr* file, const std::string& input) {
std::vector<uint8_t> bytes_to_write;
for (size_t i = 0; i < input.size(); i++)
bytes_to_write.push_back(static_cast<uint8_t>(input[i]));
mojo::files::Error error = mojo::files::Error::INTERNAL;
uint32_t num_bytes_written = 0;
(*file)->Write(mojo::Array<uint8_t>::From(bytes_to_write), 0,
mojo::files::Whence::FROM_CURRENT,
Capture(&error, &num_bytes_written));
ASSERT_TRUE(file->WaitForIncomingResponse());
EXPECT_EQ(mojo::files::Error::OK, error);
EXPECT_EQ(bytes_to_write.size(), num_bytes_written);
}
// Given a FilePtr |file|, seek to offset |offset| using whence
// FROM_CURRENT. Verifies the post-seek position is |expected_position|.
void SeekFileHelper(mojo::files::FilePtr* file,
int64_t offset,
int64_t expected_position) {
int64_t position = -1;
mojo::files::Error error = mojo::files::Error::INTERNAL;
(*file)->Seek(offset, mojo::files::Whence::FROM_CURRENT,
Capture(&error, &position));
ASSERT_TRUE(file->WaitForIncomingResponse());
EXPECT_EQ(mojo::files::Error::OK, error);
EXPECT_EQ(expected_position, position);
}
// Given a FilePtr |file|, read from the file at offset |offset| (using
// Whence::FROM_CURRENT), and verify the result matches the string
// |expected_output|.
void ReadFileHelper(mojo::files::FilePtr* 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();
(*file)->Read(num_bytes_to_read, offset, mojo::files::Whence::FROM_CURRENT,
Capture(&error, &bytes_read));
ASSERT_TRUE(file->WaitForIncomingResponse());
EXPECT_EQ(mojo::files::Error::OK, error);
EXPECT_EQ(num_bytes_to_read, bytes_read.size());
for (size_t i = 0; i < expected_output.size(); i++)
EXPECT_EQ(static_cast<uint8_t>(expected_output[i]), bytes_read[i]);
}
// Open the file named |path_name| in |directory| and verify that no error
// occurs. Returns the newly opened file.
mojo::files::FilePtr OpenFileHelper(mojo::files::DirectoryPtr* directory,
const std::string& path_name) {
mojo::files::FilePtr temp_file;
mojo::files::Error error = mojo::files::Error::INTERNAL;
(*directory)
->OpenFile(path_name, GetProxy(&temp_file),
mojo::files::kOpenFlagWrite | mojo::files::kOpenFlagRead,
Capture(&error));
EXPECT_EQ(true, directory->WaitForIncomingResponse());
EXPECT_EQ(mojo::files::Error::OK, error);
return temp_file;
}
// Close the FilePtr |file| and verify that no error occurs.
void CloseFileHelper(mojo::files::FilePtr* file) {
mojo::files::Error error = mojo::files::Error::INTERNAL;
(*file)->Close(Capture(&error));
ASSERT_TRUE(file->WaitForIncomingResponse());
EXPECT_EQ(mojo::files::Error::OK, error);
}
TEST_F(FileUtilTest, BasicCreateTemporaryFile) {
mojo::files::FilesPtr files;
application_impl()->ConnectToServiceDeprecated("mojo:files", &files);
mojo::files::Error error = mojo::files::Error::INTERNAL;
mojo::files::DirectoryPtr directory;
files->OpenFileSystem(nullptr, mojo::GetProxy(&directory), Capture(&error));
ASSERT_TRUE(files.WaitForIncomingResponse());
EXPECT_EQ(mojo::files::Error::OK, error);
std::string filename1, filename2, filename3;
mojo::files::FilePtr file1, file2, file3;
file1 = CreateTemporaryFileInDir(&directory, &filename1);
ASSERT_TRUE(file1);
file2 = CreateTemporaryFileInDir(&directory, &filename2);
ASSERT_TRUE(file2);
file3 = 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