Skip to content

Commit

Permalink
test: add test cases for global metadata checks
Browse files Browse the repository at this point in the history
  • Loading branch information
mhx committed Aug 24, 2024
1 parent 87f07d1 commit 6fc1a46
Show file tree
Hide file tree
Showing 2 changed files with 173 additions and 0 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,7 @@ if(WITH_TESTS)
filesystem_writer_test
fits_categorizer_test
fragment_category_test
global_metadata_test
incompressible_categorizer_test
integral_value_parser_test
lazy_value_test
Expand Down
172 changes: 172 additions & 0 deletions test/global_metadata_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/**
* \author Marcus Holland-Moritz ([email protected])
* \copyright Copyright (c) Marcus Holland-Moritz
*
* This file is part of dwarfs.
*
* dwarfs is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* dwarfs is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with dwarfs. If not, see <https://www.gnu.org/licenses/>.
*/

#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include <dwarfs/reader/internal/metadata_types.h>

#include <dwarfs/gen-cpp2/metadata_layouts.h>

#include "test_logger.h"

using namespace dwarfs::reader::internal;
using namespace dwarfs::thrift::metadata;
using namespace apache::thrift::frozen;
using namespace dwarfs::test;

class global_metadata_test : public ::testing::Test {
public:
void check(metadata const& raw) {
auto meta = freeze(raw);
global_metadata::check_consistency(lgr, meta);
}

static auto throws_error(std::string_view msg) {
return testing::ThrowsMessage<dwarfs::error>(testing::StartsWith(msg));
};

test_logger lgr;
};

TEST_F(global_metadata_test, check_empty_tables) {
metadata raw;
EXPECT_THAT([&] { check(raw); }, throws_error("empty inodes table"));

raw.inodes()->resize(1);
EXPECT_THAT([&] { check(raw); }, throws_error("empty directories table"));

raw.directories()->resize(1);
EXPECT_THAT([&] { check(raw); }, throws_error("empty chunk_table table"));

raw.chunk_table()->resize(1);
EXPECT_THAT([&] { check(raw); },
throws_error("empty entry_table_v2_2 table"));

raw.dir_entries().emplace();
EXPECT_THAT([&] { check(raw); }, throws_error("empty dir_entries table"));

raw.dir_entries()->resize(1);
EXPECT_THAT([&] { check(raw); }, throws_error("empty modes table"));
}

TEST_F(global_metadata_test, check_index_range) {
metadata raw;
raw.directories()->resize(1);
raw.chunk_table()->resize(1);
raw.modes()->resize(1);
raw.uids()->resize(1);
raw.gids()->resize(1);
raw.names()->resize(1);
raw.entry_table_v2_2()->push_back(1);
auto& ino = raw.inodes()->emplace_back();

ino.mode_index() = 1;
EXPECT_THAT([&] { check(raw); }, throws_error("mode_index out of range"));
ino.mode_index() = 0;

ino.owner_index() = 1;
EXPECT_THAT([&] { check(raw); }, throws_error("owner_index out of range"));
ino.owner_index() = 0;

ino.group_index() = 1;
EXPECT_THAT([&] { check(raw); }, throws_error("group_index out of range"));
ino.group_index() = 0;

ino.name_index_v2_2() = 1;
EXPECT_THAT([&] { check(raw); },
throws_error("name_index_v2_2 out of range"));
ino.name_index_v2_2() = 0;

EXPECT_THAT([&] { check(raw); },
throws_error("entry_table_v2_2 value out of range"));

// make this metadata v2.3+
raw.dir_entries().emplace();
auto& de = raw.dir_entries()->emplace_back();

raw.compact_names().emplace();
EXPECT_THAT([&] { check(raw); }, throws_error("empty compact_names index"));
raw.compact_names().reset();

de.name_index() = 1;
EXPECT_THAT([&] { check(raw); }, throws_error("name_index out of range"));
de.name_index() = 0;

de.inode_num() = 1;
EXPECT_THAT([&] { check(raw); }, throws_error("inode_num out of range"));
}

TEST_F(global_metadata_test, check_packed_tables) {
metadata raw;
raw.inodes()->resize(1);
raw.directories()->resize(1);
raw.chunk_table()->resize(1);
raw.chunks()->resize(1);
raw.modes()->resize(1);
raw.uids()->resize(1);
raw.gids()->resize(1);
raw.names()->resize(1);
auto& des = raw.dir_entries().emplace();
des.resize(1);

auto& ds = *raw.directories();
ds.resize(2);

ds[0].first_entry() = 1;
ds[1].first_entry() = 0;
EXPECT_THAT([&] { check(raw); },
throws_error("first_entry values not sorted"));

ds[0].first_entry() = 0;
ds[1].first_entry() = 2; // sentinel value may be equal to entry count
EXPECT_THAT([&] { check(raw); }, throws_error("first_entry out of range"));

ds[1].first_entry() = 1;
ds[1].parent_entry() = 1;
EXPECT_THAT([&] { check(raw); }, throws_error("parent_entry out of range"));
ds[1].parent_entry() = 0;

auto& ct = *raw.chunk_table();
ct.resize(2);
ct[0] = 1;
ct[1] = 0;
EXPECT_THAT([&] { check(raw); },
throws_error("chunk_table values not sorted"));
ct[0] = 0;
EXPECT_THAT([&] { check(raw); },
throws_error("chunk_table end value mismatch"));

auto& opts = raw.options().emplace();
opts.packed_directories() = true;
ds[1].parent_entry() = 1;
EXPECT_THAT([&] { check(raw); },
throws_error("parent_entry set in packed directory"));
ds[1].parent_entry() = 0;
ds[1].first_entry() = 0;
EXPECT_THAT([&] { check(raw); },
throws_error("first_entry inconsistency in packed directories"));
ds[1].first_entry() = 1;

opts.packed_chunk_table() = true;
EXPECT_THAT([&] { check(raw); },
throws_error("packed chunk_table inconsistency"));
}

0 comments on commit 6fc1a46

Please sign in to comment.