Skip to content

Commit 944c1e3

Browse files
committed
hypergraph io tests
1 parent ee60c42 commit 944c1e3

10 files changed

Lines changed: 512 additions & 29 deletions

File tree

include/gl/io/graph_fio.hpp

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,26 @@
99
#include <filesystem>
1010
#include <fstream>
1111

12-
namespace gl::io {
12+
namespace gl {
13+
namespace io {
1314

1415
struct write {};
1516

1617
struct append {};
1718

18-
namespace detail {
19+
} // namespace io
20+
21+
namespace traits {
1922

2023
template <typename T>
21-
concept c_io_save_mode = traits::c_one_of<T, write, append>;
24+
concept c_io_save_mode = traits::c_one_of<T, io::write, io::append>;
25+
26+
} // namespace traits
27+
28+
namespace io {
29+
namespace detail {
2230

23-
template <c_io_save_mode Mode>
31+
template <traits::c_io_save_mode Mode>
2432
requires(std::same_as<Mode, write>)
2533
[[nodiscard]] std::ofstream open_outfile(const std::filesystem::path& path) {
2634
if (std::filesystem::exists(path))
@@ -37,7 +45,7 @@ requires(std::same_as<Mode, write>)
3745
return file;
3846
}
3947

40-
template <c_io_save_mode Mode>
48+
template <traits::c_io_save_mode Mode>
4149
requires(std::same_as<Mode, append>)
4250
[[nodiscard]] std::ofstream open_outfile(const std::filesystem::path& path) {
4351
if (not std::filesystem::exists(path))
@@ -87,7 +95,7 @@ requires(std::same_as<Mode, append>)
8795

8896
} // namespace detail
8997

90-
template <traits::c_graph GraphType, detail::c_io_save_mode Mode = write>
98+
template <traits::c_graph GraphType, traits::c_io_save_mode Mode = write>
9199
void save(
92100
const GraphType& graph,
93101
const std::filesystem::path& path = "graph.gsf",
@@ -114,4 +122,5 @@ template <traits::c_graph GraphType>
114122
return graph;
115123
}
116124

117-
} // namespace gl::io
125+
} // namespace io
126+
} // namespace gl

include/hgl/io.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
#pragma once
66

77
#include "hgl/io/core.hpp"
8+
#include "hgl/io/hypergraph_fio.hpp"

include/hgl/io/hypergraph_fio.hpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Copyright (c) 2024-2026 Jakub Musiał
2+
// This file is part of the CPP-GL project (https://github.com/SpectraL519/cpp-gl).
3+
// Licensed under the MIT License. See the LICENSE file in the project root for full license information.
4+
5+
#pragma once
6+
7+
#include "gl/io/graph_fio.hpp"
8+
#include "gl/io/options.hpp"
9+
#include "gl/io/options_manip.hpp"
10+
#include "hgl/hypergraph.hpp"
11+
12+
#include <filesystem>
13+
#include <fstream>
14+
#include <initializer_list>
15+
16+
namespace hgl::io {
17+
18+
using gl::io::append;
19+
using gl::io::write;
20+
21+
namespace detail {
22+
23+
using gl::io::detail::open_infile;
24+
using gl::io::detail::open_outfile;
25+
26+
} // namespace detail
27+
28+
template <traits::c_hypergraph HypergraphType, traits::c_io_save_mode Mode = write>
29+
void save(
30+
const HypergraphType& hypergraph,
31+
const std::filesystem::path& path = "hypergraph.hgsf",
32+
const std::initializer_list<gl::io::options_manip>& options = {}
33+
) {
34+
std::ofstream file = detail::open_outfile<Mode>(path);
35+
36+
file << gl::io::spec_fmt;
37+
for (auto option : options)
38+
file << option;
39+
40+
file << hypergraph;
41+
}
42+
43+
template <traits::c_hypergraph HypergraphType>
44+
[[nodiscard]] HypergraphType load(const std::filesystem::path& path = "hypergraph.hgsf") {
45+
std::ifstream file = detail::open_infile(path);
46+
47+
file >> gl::io::spec_fmt;
48+
49+
HypergraphType hypergraph;
50+
file >> hypergraph;
51+
52+
return hypergraph;
53+
}
54+
55+
} // namespace hgl::io

tests/include/testing/common/io.hpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "doctest.h"
44

55
#include <concepts>
6+
#include <filesystem>
67
#include <ranges>
78
#include <sstream>
89
#include <string_view>
@@ -23,3 +24,22 @@ struct StringMaker<R> {
2324
};
2425

2526
} // namespace doctest
27+
28+
namespace fs = std::filesystem;
29+
30+
#define GL_REQUIRE_THROWS_FS_ERROR(expr, errc) \
31+
try { \
32+
expr; \
33+
FAIL("Expected `std::filesystem::filesystem_error` but no exception was thrown"); \
34+
} \
35+
catch (const fs::filesystem_error& e) { \
36+
const auto expected_code = std::make_error_code(errc); \
37+
if (e.code() != expected_code) { \
38+
FAIL(std::format( \
39+
"Expected error code {}, but got {}.", expected_code.value(), e.code().value() \
40+
)); \
41+
} \
42+
} \
43+
catch (...) { \
44+
FAIL("Expected `std::filesystem::filesystem_error` but caught a different exception"); \
45+
}

tests/include/testing/hgl/io.hpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#pragma once
2+
3+
#include "doctest.h"
4+
5+
#include <hgl/hypergraph.hpp>
6+
7+
#include <algorithm>
8+
9+
namespace hgl_testing {
10+
11+
template <hgl::traits::c_hypergraph HypergraphType>
12+
void verify_hypergraph_structure(const HypergraphType& actual, const HypergraphType& expected) {
13+
REQUIRE_EQ(actual.order(), expected.order());
14+
REQUIRE_EQ(actual.size(), expected.size());
15+
16+
for (const auto& he_actual : actual.hyperedges()) {
17+
const auto id = he_actual.id();
18+
REQUIRE(expected.has_hyperedge(id));
19+
20+
if constexpr (std::same_as<typename HypergraphType::directional_tag, hgl::undirected_t>) {
21+
auto actual_vs = actual.incident_vertex_ids(id) | std::ranges::to<std::vector>();
22+
auto expected_vs = expected.incident_vertex_ids(id) | std::ranges::to<std::vector>();
23+
CHECK(std::ranges::is_permutation(actual_vs, expected_vs));
24+
}
25+
else if constexpr (std::same_as<
26+
typename HypergraphType::directional_tag,
27+
hgl::bf_directed_t>) {
28+
auto actual_tail = actual.tail_vertex_ids(id) | std::ranges::to<std::vector>();
29+
auto expected_tail = expected.tail_vertex_ids(id) | std::ranges::to<std::vector>();
30+
CHECK(std::ranges::is_permutation(actual_tail, expected_tail));
31+
32+
auto actual_head = actual.head_vertex_ids(id) | std::ranges::to<std::vector>();
33+
auto expected_head = expected.head_vertex_ids(id) | std::ranges::to<std::vector>();
34+
CHECK(std::ranges::is_permutation(actual_head, expected_head));
35+
}
36+
}
37+
}
38+
39+
template <hgl::traits::c_hypergraph HypergraphType>
40+
void verify_vertex_properties(const HypergraphType& actual, const HypergraphType& expected) {
41+
const auto properties_proj = [](const auto& item) { return item.properties(); };
42+
43+
CHECK(std::ranges::equal(
44+
actual.vertices(),
45+
expected.vertices(),
46+
std::ranges::equal_to{},
47+
properties_proj,
48+
properties_proj
49+
));
50+
}
51+
52+
template <hgl::traits::c_hypergraph HypergraphType>
53+
void verify_hyperedge_properties(const HypergraphType& actual, const HypergraphType& expected) {
54+
const auto properties_proj = [](const auto& item) { return item.properties(); };
55+
56+
CHECK(std::ranges::equal(
57+
actual.hyperedges(),
58+
expected.hyperedges(),
59+
std::ranges::equal_to{},
60+
properties_proj,
61+
properties_proj
62+
));
63+
}
64+
65+
} // namespace hgl_testing

tests/source/gl/test_graph_file_io.cpp

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
#include "testing/common/io.hpp"
12
#include "testing/gl/constants.hpp"
23
#include "testing/gl/functional.hpp"
3-
#include "testing/gl/io_common.hpp"
4+
#include "testing/gl/io.hpp"
45

56
#include <gl/graph.hpp>
67
#include <gl/io/graph_fio.hpp>
@@ -10,27 +11,8 @@
1011

1112
#include <print>
1213

13-
namespace fs = std::filesystem;
14-
1514
namespace gl_testing {
1615

17-
#define GL_REQUIRE_THROWS_FS_ERROR(expr, errc) \
18-
try { \
19-
expr; \
20-
FAIL("Expected `std::filesystem::filesystem_error` but no exception was thrown"); \
21-
} \
22-
catch (const fs::filesystem_error& e) { \
23-
const auto expected_code = std::make_error_code(errc); \
24-
if (e.code() != expected_code) { \
25-
FAIL(std::format( \
26-
"Expected error code {}, but got {}.", expected_code.value(), e.code().value() \
27-
)); \
28-
} \
29-
} \
30-
catch (...) { \
31-
FAIL("Expected `std::filesystem::filesystem_error` but caught a different exception"); \
32-
}
33-
3416
TEST_SUITE_BEGIN("test_graph_file_io");
3517

3618
// Tests covering only the io functionality with the graph specification format enabled

tests/source/gl/test_graph_io.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#include "gl/io/options.hpp"
22
#include "testing/gl/constants.hpp"
3-
#include "testing/gl/io_common.hpp"
3+
#include "testing/gl/io.hpp"
44

55
#include <gl/graph.hpp>
66
#include <gl/io.hpp>
@@ -227,7 +227,7 @@ TEST_CASE_FIXTURE(
227227
"io operators should properly write and read the graph from a stream with both vertex and edge "
228228
"properties"
229229
) {
230-
ss << gl::io::with_vertex_properties << gl::io::with_edge_properties << sut_out;
230+
ss << gl::io::with_properties << sut_out;
231231
ss >> sut_in;
232232

233233
verify_graph_structure(sut_in, sut_out);

0 commit comments

Comments
 (0)