aboutsummaryrefslogtreecommitdiff
path: root/kernel/src/filesystem/open_file_description.tests.cpp
blob: db8eb490026440b6a0dac3e0abbbb72473e921c0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#include "kernel/filesystem/open_file_description.hpp"

#include "kernel/filesystem/vfs.hpp"
#include "kernel/test_support/filesystem/inode.hpp"
#include "kernel/test_support/filesystem/storage_boot_module_vfs_fixture.hpp"

#include <kstd/memory>
#include <kstd/print>
#include <kstd/vector>

#include <catch2/catch_test_macros.hpp>

#include <cstddef>
#include <filesystem>
#include <string_view>

SCENARIO("Open file description construction", "[filesystem][open_file_description]")
{
  GIVEN("an inode and an open file description for that inode")
  {
    auto inode = kstd::make_shared<kernel::tests::filesystem::inode>();
    auto file_description = kernel::filesystem::open_file_description{inode};

    THEN("the initial offset is zero")
    {
      REQUIRE(file_description.offset() == 0);
    }
  }
}

SCENARIO("Open file description read/write offset management", "[filesystem][open_file_description]")
{
  GIVEN("an inode that tracks read/write calls and an open file description for that inode")
  {
    auto inode = kstd::make_shared<kernel::tests::filesystem::inode>();
    auto file_description = kernel::filesystem::open_file_description{inode};

    THEN("the offset is updated correctly after reads")
    {
      REQUIRE(file_description.read(nullptr, 100) == 100);
      REQUIRE(file_description.offset() == 100);
      REQUIRE(file_description.read(nullptr, 50) == 50);
      REQUIRE(file_description.offset() == 150);
    }

    THEN("the offset is updated correctly after writes")
    {
      REQUIRE(file_description.write(nullptr, 200) == 200);
      REQUIRE(file_description.offset() == 200);
      REQUIRE(file_description.write(nullptr, 25) == 25);
      REQUIRE(file_description.offset() == 225);
    }

    THEN("reads and writes both update the same offset")
    {
      REQUIRE(file_description.read(nullptr, 10) == 10);
      REQUIRE(file_description.offset() == 10);
      REQUIRE(file_description.write(nullptr, 20) == 20);
      REQUIRE(file_description.offset() == 30);
      REQUIRE(file_description.read(nullptr, 5) == 5);
      REQUIRE(file_description.offset() == 35);
      REQUIRE(file_description.write(nullptr, 15) == 15);
      REQUIRE(file_description.offset() == 50);
    }
  }
}

SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture,
                "Open file description read with real image", "[filesystem][open_file_description][img]")
{
  auto const image_path = std::filesystem::path{KERNEL_TEST_ASSETS_DIR} / "ext2_1KB_fs.img";

  GIVEN("an open file description for a file in a real image")
  {
    REQUIRE(std::filesystem::exists(image_path));
    REQUIRE_NOTHROW(setup_modules_from_img_and_init_vfs({"test_img_module"}, {image_path}));

    auto & vfs = kernel::filesystem::vfs::get();
    auto ofd = vfs.open("/information/info_1.txt");
    REQUIRE(ofd != nullptr);

    THEN("the file can be read and the offset is updated")
    {
      kstd::vector<std::byte> buffer(32);
      auto bytes_read = ofd->read(buffer.data(), buffer.size());
      REQUIRE(bytes_read == 32);
      REQUIRE(ofd->offset() == 32);

      std::string_view buffer_as_str{reinterpret_cast<char *>(buffer.data()), static_cast<size_t>(bytes_read)};
      auto const content_end = buffer_as_str.find('\0');
      REQUIRE(buffer_as_str.substr(0, content_end) == "info_1\n");

      for (auto i = content_end; i < buffer_as_str.size(); ++i)
      {
        REQUIRE(buffer_as_str[i] == '\0');
      }
    }

    THEN("the file can be read multiple times")
    {
      kstd::vector<std::byte> buffer(4);
      auto bytes_read_1 = ofd->read(buffer.data(), buffer.size() / 2);
      REQUIRE(bytes_read_1 == buffer.size() / 2);
      REQUIRE(ofd->offset() == buffer.size() / 2);

      auto bytes_read_2 = ofd->read(buffer.data() + buffer.size() / 2, buffer.size() / 2);
      REQUIRE(bytes_read_2 == buffer.size() / 2);
      REQUIRE(ofd->offset() == buffer.size());

      std::string_view buffer_as_str{reinterpret_cast<char *>(buffer.data()), bytes_read_1 + bytes_read_2};
      REQUIRE(buffer_as_str == "info");
    }
  }
}