Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 106 additions & 0 deletions cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
cmake_minimum_required(VERSION 3.15)

# Set the project name and version
project(Platform.IO VERSION 1.0.0 LANGUAGES CXX)

# Set C++ standard
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

# Platform.IO library
add_library(Platform.IO INTERFACE)

# Header files
target_include_directories(Platform.IO INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:include>
)

# Target compile features
target_compile_features(Platform.IO INTERFACE cxx_std_20)

# Find required system libraries
find_package(Threads REQUIRED)
target_link_libraries(Platform.IO INTERFACE Threads::Threads)

# Enable testing
option(BUILD_TESTS "Build tests" ON)
if(BUILD_TESTS)
enable_testing()

# Find Google Test
find_package(GTest QUIET)
if(NOT GTest_FOUND)
# Download and build Google Test
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/release-1.12.1.zip
)
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
endif()

# Test executable
add_executable(Platform.IO.Tests
Platform.IO.Tests/TemporaryFileTests.cpp
Platform.IO.Tests/FileHelpersTests.cpp
)

target_link_libraries(Platform.IO.Tests
Platform.IO
gtest_main
gtest
pthread
)

target_include_directories(Platform.IO.Tests PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
)

# Register tests
include(GoogleTest)
gtest_discover_tests(Platform.IO.Tests)
endif()

# Installation
install(DIRECTORY Platform.IO/
DESTINATION include/Platform.IO
FILES_MATCHING PATTERN "*.h"
)

install(TARGETS Platform.IO
EXPORT Platform.IOTargets
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
RUNTIME DESTINATION bin
INCLUDES DESTINATION include
)

install(EXPORT Platform.IOTargets
FILE Platform.IOTargets.cmake
NAMESPACE Platform::
DESTINATION lib/cmake/Platform.IO
)

# Create package config files
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
Platform.IOConfigVersion.cmake
VERSION ${PACKAGE_VERSION}
COMPATIBILITY AnyNewerVersion
)

configure_package_config_file(
${CMAKE_CURRENT_SOURCE_DIR}/Platform.IOConfig.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/Platform.IOConfig.cmake
INSTALL_DESTINATION lib/cmake/Platform.IO
)

install(FILES
${CMAKE_CURRENT_BINARY_DIR}/Platform.IOConfig.cmake
${CMAKE_CURRENT_BINARY_DIR}/Platform.IOConfigVersion.cmake
DESTINATION lib/cmake/Platform.IO
)
19 changes: 11 additions & 8 deletions cpp/Platform.IO.Tests.TemporaryFileTest/Program.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
ο»Ώnamespace Platform::IO::Tests::TemporaryFileTest
ο»Ώ#include <iostream>
#include "../Platform.IO/TemporaryFile.h"

using namespace Platform::IO;

int main()
{
class Program
{
static void Main()
{
using TemporaryFile tempFile = new();
Console.WriteLine(tempFile);
}
};
TemporaryFile tempFile;
std::cout << tempFile.Filename << std::endl;
}
// TemporaryFile destructor automatically deletes the file
return 0;
}
100 changes: 88 additions & 12 deletions cpp/Platform.IO.Tests/FileHelpersTests.cpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,91 @@
ο»Ώnamespace Platform::IO::Tests
ο»Ώ#include <gtest/gtest.h>
#include <filesystem>
#include <cstdint>
#include "../Platform.IO/FileHelpers.h"
#include "../Platform.IO/TemporaryFile.h"

using namespace Platform::IO;

namespace Platform::IO::Tests
{
TEST_CLASS(FileHelpersTests)
{
public: TEST_METHOD(WriteReadTest)
{
auto temporaryFile = Path.GetTempFileName();
auto originalValue = 42UL;
FileHelpers.WriteFirst(temporaryFile, originalValue);
auto readValue = FileHelpers.ReadFirstOrDefault<std::uint64_t>(temporaryFile);
Assert::AreEqual(readValue, originalValue);
File.Delete(temporaryFile);
}
class FileHelpersTests : public ::testing::Test
{
protected:
void SetUp() override {}
void TearDown() override {}
};

TEST_F(FileHelpersTests, WriteReadTest)
{
TemporaryFile temporaryFile;
const std::uint64_t originalValue = 42UL;

FileHelpers::WriteFirst(temporaryFile.Filename, originalValue);
auto readValue = FileHelpers::ReadFirstOrDefault<std::uint64_t>(temporaryFile.Filename);

EXPECT_EQ(readValue, originalValue);
}

TEST_F(FileHelpersTests, WriteReadMultipleValuesTest)
{
TemporaryFile temporaryFile;
const std::vector<std::uint32_t> originalValues = {1, 2, 3, 4, 5};

// Write values to file
std::ofstream file(temporaryFile.Filename, std::ios::binary);
for (const auto& value : originalValues) {
file.write(reinterpret_cast<const char*>(&value), sizeof(value));
}
file.close();

// Read all values back
auto readValues = FileHelpers::ReadAll<std::uint32_t>(temporaryFile.Filename);

EXPECT_EQ(readValues.size(), originalValues.size());
for (std::size_t i = 0; i < originalValues.size(); ++i) {
EXPECT_EQ(readValues[i], originalValues[i]);
}

// Test reading first and last
auto firstValue = FileHelpers::ReadFirstOrDefault<std::uint32_t>(temporaryFile.Filename);
auto lastValue = FileHelpers::ReadLastOrDefault<std::uint32_t>(temporaryFile.Filename);

EXPECT_EQ(firstValue, originalValues.front());
EXPECT_EQ(lastValue, originalValues.back());
}

TEST_F(FileHelpersTests, FileSizeTest)
{
TemporaryFile temporaryFile;

// Initially should be empty
EXPECT_EQ(FileHelpers::GetSize(temporaryFile.Filename), 0);

const std::string testData = "Hello, World!";
std::ofstream file(temporaryFile.Filename);
file << testData;
file.close();

EXPECT_EQ(FileHelpers::GetSize(temporaryFile.Filename), testData.length());
}

TEST_F(FileHelpersTests, AppendLineTest)
{
TemporaryFile temporaryFile;

const std::string line1 = "First line";
const std::string line2 = "Second line";

FileHelpers::AppendLine(temporaryFile.Filename, line1);
FileHelpers::AppendLine(temporaryFile.Filename, line2);

std::vector<std::string> lines;
FileHelpers::EachLine(temporaryFile.Filename, [&lines](const std::string& line) {
lines.push_back(line);
});

EXPECT_EQ(lines.size(), 2);
EXPECT_EQ(lines[0], line1);
EXPECT_EQ(lines[1], line2);
}
}
57 changes: 36 additions & 21 deletions cpp/Platform.IO.Tests/TemporaryFileTests.cpp
Original file line number Diff line number Diff line change
@@ -1,29 +1,44 @@
ο»Ώnamespace Platform::IO::Tests
ο»Ώ#include <gtest/gtest.h>
#include <filesystem>
#include "../Platform.IO/TemporaryFile.h"

using namespace Platform::IO;

namespace Platform::IO::Tests
{
TEST_CLASS(TemporaryFileTests)
class TemporaryFileTests : public ::testing::Test
{
public: TEST_METHOD(TemporaryFileTest)
protected:
void SetUp() override {}
void TearDown() override {}
};

TEST_F(TemporaryFileTests, TemporaryFileTestWithoutConsoleApp)
{
std::string fileName;
{
using Process process = new();
process.StartInfo.FileName = Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), "..", "..", "..", "..", "Platform.IO.Tests.TemporaryFileTest", "bin", "Debug", "net5", "Platform.IO.Tests.TemporaryFileTest"));
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.Start();
auto path = process.StandardOutput.ReadLine();
Assert::IsTrue(File.Exists(path));
process.WaitForExit();
Assert::IsFalse(File.Exists(path));
TemporaryFile tempFile;
fileName = tempFile.Filename;
EXPECT_TRUE(std::filesystem::exists(fileName));
}
// After the TemporaryFile goes out of scope, the file should be deleted
EXPECT_FALSE(std::filesystem::exists(fileName));
}

public: TEST_METHOD(TemporaryFileTestWithoutConsoleApp)
TEST_F(TemporaryFileTests, TemporaryFileMoveSemanticsTest)
{
std::string fileName;
{
std::string fileName = 0;
using (TemporaryFile tempFile = new())
{
fileName = tempFile;
Assert::IsTrue(File.Exists(fileName));
}
Assert::IsFalse(File.Exists(fileName));
TemporaryFile tempFile1;
fileName = tempFile1.Filename;
EXPECT_TRUE(std::filesystem::exists(fileName));

// Test move constructor
TemporaryFile tempFile2 = std::move(tempFile1);
EXPECT_EQ(tempFile2.Filename, fileName);
EXPECT_TRUE(std::filesystem::exists(fileName));
}
};
// After both TemporaryFile objects go out of scope, the file should be deleted
EXPECT_FALSE(std::filesystem::exists(fileName));
}
}
Loading
Loading