diff --git a/fbpcf/io/api/LocalFileWriter.cpp b/fbpcf/io/api/LocalFileWriter.cpp index 08e98926..5a1c95dc 100644 --- a/fbpcf/io/api/LocalFileWriter.cpp +++ b/fbpcf/io/api/LocalFileWriter.cpp @@ -7,17 +7,30 @@ #include "fbpcf/io/api/LocalFileWriter.h" #include +#include #include #include namespace fbpcf::io { -LocalFileWriter::LocalFileWriter(std::string /* filePath */) {} +LocalFileWriter::LocalFileWriter(std::string filePath) { + outputStream_ = std::make_unique(filePath); +} int LocalFileWriter::close() { - return 0; + outputStream_->close(); + + return outputStream_->fail() ? -1 : 0; } -size_t LocalFileWriter::write(std::vector& /* buf */) { - return 0; + +size_t LocalFileWriter::write(std::vector& buf) { + outputStream_->write(buf.data(), buf.size()); + + if (outputStream_->fail()) { + throw std::runtime_error( + "Internal error when writing to local file. Stream integrity may have been affected."); + } + + return buf.size(); } LocalFileWriter::~LocalFileWriter() { diff --git a/fbpcf/io/api/LocalFileWriter.h b/fbpcf/io/api/LocalFileWriter.h index d0776a6e..99538409 100644 --- a/fbpcf/io/api/LocalFileWriter.h +++ b/fbpcf/io/api/LocalFileWriter.h @@ -7,6 +7,8 @@ #pragma once #include +#include +#include #include #include @@ -26,6 +28,9 @@ class LocalFileWriter : public IWriterCloser { int close() override; size_t write(std::vector& buf) override; ~LocalFileWriter() override; + + private: + std::unique_ptr outputStream_; }; } // namespace fbpcf::io diff --git a/fbpcf/io/api/test/LocalFileWriterTest.cpp b/fbpcf/io/api/test/LocalFileWriterTest.cpp new file mode 100644 index 00000000..446e0526 --- /dev/null +++ b/fbpcf/io/api/test/LocalFileWriterTest.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include "folly/logging/xlog.h" + +#include "fbpcf/io/api/LocalFileWriter.h" +#include "fbpcf/io/api/test/utils/IOTestHelper.h" + +namespace fbpcf::io { + +inline void cleanup(std::string fileToDelete) { + remove(fileToDelete.c_str()); +} + +TEST(LocalFileWriterTest, testWritingToFile) { + std::string baseDir = IOTestHelper::getBaseDirFromPath(__FILE__); + std::string fileToWriteTo = baseDir + "data/local_file_writer_test_file.txt"; + auto writer = std::make_unique(fileToWriteTo); + + /* + CASE 1 + Write simple string to file + */ + std::string toWrite = + "this file contains the expected text in local_file_writer_test_file.text"; + auto buf = + std::vector(toWrite.c_str(), toWrite.c_str() + toWrite.size()); + auto nBytes = writer->write(buf); + EXPECT_EQ(nBytes, toWrite.size()); + + /* + CASE 2 + Write arbitrary bytes to file + */ + std::vector arbitraryBytes{'\n', '\n', 'L', 'o', 'c', 'a', 'l', 'F', + 'i', 'l', 'e', 'W', 'r', 'i', 't', 'e', + 'r', 'T', 'e', 's', 't', ' '}; + nBytes = writer->write(arbitraryBytes); + EXPECT_EQ(nBytes, arbitraryBytes.size()); + + /* + CASE 3 + Write larger buffer + */ + std::string remainingLine = + "writes to the above file\nWe assert that it's contents match this file\n"; + auto buf2 = std::vector( + remainingLine.c_str(), remainingLine.c_str() + remainingLine.size()); + nBytes = writer->write(buf2); + EXPECT_EQ(nBytes, remainingLine.size()); + + EXPECT_EQ(writer->close(), 0); + + /* + Verify that file contents match the expected + */ + IOTestHelper::expectFileContentsMatch( + fileToWriteTo, baseDir + "data/expected_local_file_writer_test_file.txt"); + + cleanup(fileToWriteTo); +} + +} // namespace fbpcf::io diff --git a/fbpcf/io/api/test/data/expected_local_file_writer_test_file.txt b/fbpcf/io/api/test/data/expected_local_file_writer_test_file.txt new file mode 100644 index 00000000..fac62ab0 --- /dev/null +++ b/fbpcf/io/api/test/data/expected_local_file_writer_test_file.txt @@ -0,0 +1,4 @@ +this file contains the expected text in local_file_writer_test_file.text + +LocalFileWriterTest writes to the above file +We assert that it's contents match this file diff --git a/fbpcf/io/api/test/utils/IOTestHelper.h b/fbpcf/io/api/test/utils/IOTestHelper.h index 303660e6..cae4fe3f 100644 --- a/fbpcf/io/api/test/utils/IOTestHelper.h +++ b/fbpcf/io/api/test/utils/IOTestHelper.h @@ -8,6 +8,9 @@ #pragma once #include +#include +#include + #include namespace fbpcf::io { @@ -26,6 +29,23 @@ class IOTestHelper { static std::string getBaseDirFromPath(const std::string& filePath) { return filePath.substr(0, filePath.rfind("/") + 1); } + + static void expectFileContentsMatch( + std::string testFilePath, + std::string expectedFilePath) { + auto testFile = std::make_unique(testFilePath); + auto expectedFile = std::make_unique(expectedFilePath); + + while (!expectedFile->eof()) { + if (testFile->eof()) { + FAIL(); + } + + auto expected = expectedFile->get(); + auto test = testFile->get(); + EXPECT_EQ(test, expected); + } + } }; } // namespace fbpcf::io