Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
io_graph_test.cc
Go to the documentation of this file.
1
2/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 2.0.0b
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
32
37#include <gtest/gtest.h>
38#include <sstream>
39#include <cstdio>
40#include <algorithm>
41#include <io_graph.H>
42#include <tpl_graph.H>
43
44using namespace Aleph;
45
46//============================================================================
47// Test Fixtures
48//============================================================================
49
50class IOGraphTest : public ::testing::Test
51{
52protected:
55 using Arc = Graph::Arc;
56
57 void SetUp() override
58 {
59 // Create a simple graph:
60 // 0 --1.5--> 1 --2.5--> 2
61 // |
62 // 3.5
63 // v
64 // 3
65
66 n0 = g.insert_node(100);
67 n1 = g.insert_node(200);
68 n2 = g.insert_node(300);
69 n3 = g.insert_node(400);
70
71 g.insert_arc(n0, n1, 1.5);
72 g.insert_arc(n1, n2, 2.5);
73 g.insert_arc(n1, n3, 3.5);
74
75 // Generate unique filename
76 binary_file = "/tmp/aleph_io_graph_test_" + std::to_string(rand()) + ".bin";
77 text_file = "/tmp/aleph_io_graph_test_" + std::to_string(rand()) + ".txt";
78 }
79
80 void TearDown() override
81 {
82 std::remove(binary_file.c_str());
83 std::remove(text_file.c_str());
84 }
85
86 // Helper to collect node values
87 std::vector<int> get_node_values(Graph & graph)
88 {
89 std::vector<int> values;
90 for (typename Graph::Node_Iterator it(graph); it.has_curr(); it.next())
91 values.push_back(it.get_curr()->get_info());
92 std::sort(values.begin(), values.end());
93 return values;
94 }
95
96 // Helper to collect arc values
97 std::vector<double> get_arc_values(Graph & graph)
98 {
99 std::vector<double> values;
100 for (typename Graph::Arc_Iterator it(graph); it.has_curr(); it.next())
101 values.push_back(it.get_curr()->get_info());
102 std::sort(values.begin(), values.end());
103 return values;
104 }
105
107 Node *n0, *n1, *n2, *n3;
108 std::string binary_file;
109 std::string text_file;
110};
111
112//============================================================================
113// Constructor Tests
114//============================================================================
115
121
127
129{
131
132 EXPECT_FALSE(io.is_verbose());
133
134 io.set_verbose(true);
135 EXPECT_TRUE(io.is_verbose());
136
137 io.set_verbose(false);
138 EXPECT_FALSE(io.is_verbose());
139}
140
141//============================================================================
142// Binary Mode Tests
143//============================================================================
144
146{
148
149 // Save
150 {
151 std::ofstream out(binary_file, std::ios::binary);
152 ASSERT_TRUE(out.is_open());
153 io.save(out);
154 }
155
156 // Load into new graph
157 Graph g2;
159
160 {
161 std::ifstream in(binary_file, std::ios::binary);
162 ASSERT_TRUE(in.is_open());
163 io2.load(in);
164 }
165
166 // Verify
167 EXPECT_EQ(g2.get_num_nodes(), 4u);
168 EXPECT_EQ(g2.get_num_arcs(), 3u);
169}
170
172{
174
175 // Save
176 {
177 std::ofstream out(binary_file, std::ios::binary);
178 io.save(out);
179 }
180
181 // Load
182 Graph g2;
184
185 {
186 std::ifstream in(binary_file, std::ios::binary);
187 io2.load(in);
188 }
189
190 EXPECT_EQ(get_node_values(g), get_node_values(g2));
191}
192
194{
196
197 // Save
198 {
199 std::ofstream out(binary_file, std::ios::binary);
200 io.save(out);
201 }
202
203 // Load
204 Graph g2;
206
207 {
208 std::ifstream in(binary_file, std::ios::binary);
209 io2.load(in);
210 }
211
212 EXPECT_EQ(get_arc_values(g), get_arc_values(g2));
213}
214
215//============================================================================
216// Text Mode Tests
217//============================================================================
218
220{
222
223 // Save
224 {
225 std::ofstream out(text_file);
226 ASSERT_TRUE(out.is_open());
227 io.save_in_text_mode(out);
228 }
229
230 // Load into new graph
231 Graph g2;
233
234 {
235 std::ifstream in(text_file);
236 ASSERT_TRUE(in.is_open());
237 io2.load_in_text_mode(in);
238 }
239
240 // Verify
241 EXPECT_EQ(g2.get_num_nodes(), 4u);
242 EXPECT_EQ(g2.get_num_arcs(), 3u);
243}
244
246{
248
249 // Save
250 {
251 std::ofstream out(text_file);
252 io.save_in_text_mode(out);
253 }
254
255 // Load
256 Graph g2;
258
259 {
260 std::ifstream in(text_file);
261 io2.load_in_text_mode(in);
262 }
263
264 EXPECT_EQ(get_node_values(g), get_node_values(g2));
265}
266
268{
270
271 std::ostringstream out;
272 io.save_in_text_mode(out);
273
274 std::string content = out.str();
275
276 // Should start with node count and arc count
277 EXPECT_TRUE(content.find("4") != std::string::npos); // 4 nodes
278 EXPECT_TRUE(content.find("3") != std::string::npos); // 3 arcs
279}
280
281//============================================================================
282// Empty Graph Tests
283//============================================================================
284
286{
289
290 // Save
291 {
292 std::ofstream out(binary_file, std::ios::binary);
293 io.save(out);
294 }
295
296 // Load
297 Graph g2;
299
300 {
301 std::ifstream in(binary_file, std::ios::binary);
302 io2.load(in);
303 }
304
305 EXPECT_EQ(g2.get_num_nodes(), 0u);
306 EXPECT_EQ(g2.get_num_arcs(), 0u);
307}
308
310{
313
314 // Save
315 {
316 std::ofstream out(text_file);
317 io.save_in_text_mode(out);
318 }
319
320 // Load
321 Graph g2;
323
324 {
325 std::ifstream in(text_file);
326 io2.load_in_text_mode(in);
327 }
328
329 EXPECT_EQ(g2.get_num_nodes(), 0u);
330 EXPECT_EQ(g2.get_num_arcs(), 0u);
331}
332
333//============================================================================
334// Single Node Graph Tests
335//============================================================================
336
338{
340 single_g.insert_node(42);
341
343
344 // Save
345 {
346 std::ofstream out(binary_file, std::ios::binary);
347 io.save(out);
348 }
349
350 // Load
351 Graph g2;
353
354 {
355 std::ifstream in(binary_file, std::ios::binary);
356 io2.load(in);
357 }
358
359 EXPECT_EQ(g2.get_num_nodes(), 1u);
360 EXPECT_EQ(g2.get_num_arcs(), 0u);
361
362 typename Graph::Node_Iterator it(g2);
363 EXPECT_EQ(it.get_curr()->get_info(), 42);
364}
365
366//============================================================================
367// Digraph Tests
368//============================================================================
369
370class IODigraphTest : public ::testing::Test
371{
372protected:
376
377 void SetUp() override
378 {
379 n0 = dg.insert_node(10);
380 n1 = dg.insert_node(20);
381 n2 = dg.insert_node(30);
382
383 dg.insert_arc(n0, n1, 1);
384 dg.insert_arc(n1, n2, 2);
385 dg.insert_arc(n2, n0, 3); // Cycle
386
387 binary_file = "/tmp/aleph_io_digraph_test_" + std::to_string(rand()) + ".bin";
388 text_file = "/tmp/aleph_io_digraph_test_" + std::to_string(rand()) + ".txt";
389 }
390
391 void TearDown() override
392 {
393 std::remove(binary_file.c_str());
394 std::remove(text_file.c_str());
395 }
396
398 Node *n0, *n1, *n2;
399 std::string binary_file;
400 std::string text_file;
401};
402
404{
406
407 // Save
408 {
409 std::ofstream out(binary_file, std::ios::binary);
410 io.save(out);
411 }
412
413 // Load
414 Digraph dg2;
416
417 {
418 std::ifstream in(binary_file, std::ios::binary);
419 io2.load(in);
420 }
421
422 EXPECT_EQ(dg2.get_num_nodes(), 3u);
423 EXPECT_EQ(dg2.get_num_arcs(), 3u);
424}
425
427{
429
430 // Save
431 {
432 std::ofstream out(text_file);
433 io.save_in_text_mode(out);
434 }
435
436 // Load
437 Digraph dg2;
439
440 {
441 std::ifstream in(text_file);
442 io2.load_in_text_mode(in);
443 }
444
445 EXPECT_EQ(dg2.get_num_nodes(), 3u);
446 EXPECT_EQ(dg2.get_num_arcs(), 3u);
447}
448
449//============================================================================
450// Default Functor Tests
451//============================================================================
452
454{
456 Graph g;
457 auto n = g.insert_node(12345);
458
460
461 std::ostringstream ss;
462 store(ss, g, n);
463
464 EXPECT_TRUE(ss.str().find("12345") != std::string::npos);
465}
466
468{
470 Graph g;
471 auto n1 = g.insert_node(1);
472 auto n2 = g.insert_node(2);
473 auto a = g.insert_arc(n1, n2, 3.14159);
474
476
477 std::ostringstream ss;
478 store(ss, g, a);
479
480 EXPECT_TRUE(ss.str().find("3.14") != std::string::npos);
481}
482
484{
486 Graph g;
487 auto n = g.insert_node(0);
488
490
491 std::istringstream ss("999");
492 load(ss, g, n);
493
494 EXPECT_EQ(n->get_info(), 999);
495}
496
498{
500 Graph g;
501 auto n1 = g.insert_node(1);
502 auto n2 = g.insert_node(2);
503 auto a = g.insert_arc(n1, n2, 0.0);
504
506
507 std::istringstream ss("2.718");
508 load(ss, g, a);
509
510 EXPECT_NEAR(a->get_info(), 2.718, 0.001);
511}
512
513//============================================================================
514// Setter Tests
515//============================================================================
516
518{
521 io.set_load_node(ln); // Should not throw
522 SUCCEED();
523}
524
526{
529 io.set_store_node(sn); // Should not throw
530 SUCCEED();
531}
532
534{
537 io.set_load_arc(la); // Should not throw
538 SUCCEED();
539}
540
542{
545 io.set_store_arc(sa); // Should not throw
546 SUCCEED();
547}
548
549//============================================================================
550// Error Handling Tests
551//============================================================================
552
554{
555 Graph g2;
557
558 std::ifstream bad_file("/nonexistent_file_12345.bin", std::ios::binary);
559
560 // Loading from a bad stream should throw
561 EXPECT_THROW(io.load(bad_file), std::runtime_error);
562}
563
565{
566 Graph g2;
568
569 std::ifstream bad_file("/nonexistent_file_12345.txt");
570
571 EXPECT_THROW(io.load_in_text_mode(bad_file), std::runtime_error);
572}
573
574//============================================================================
575// Round-Trip Tests
576//============================================================================
577
579{
580 // First save
581 {
583 std::ofstream out(binary_file, std::ios::binary);
584 io.save(out);
585 }
586
587 // First load
588 Graph g2;
589 {
591 std::ifstream in(binary_file, std::ios::binary);
592 io.load(in);
593 }
594
595 EXPECT_EQ(g2.get_num_nodes(), 4u);
596
597 // Second save (from loaded graph)
598 std::string second_file = binary_file + ".2";
599 {
601 std::ofstream out(second_file, std::ios::binary);
602 io.save(out);
603 }
604
605 // Second load
606 Graph g3;
607 {
609 std::ifstream in(second_file, std::ios::binary);
610 io.load(in);
611 }
612
613 EXPECT_EQ(g3.get_num_nodes(), 4u);
614 EXPECT_EQ(g3.get_num_arcs(), 3u);
615
616 std::remove(second_file.c_str());
617}
618
620{
621 // First save
622 {
624 std::ofstream out(text_file);
625 io.save_in_text_mode(out);
626 }
627
628 // First load
629 Graph g2;
630 {
632 std::ifstream in(text_file);
633 io.load_in_text_mode(in);
634 }
635
636 EXPECT_EQ(g2.get_num_nodes(), 4u);
637 EXPECT_EQ(g2.get_num_arcs(), 3u);
638}
639
640//============================================================================
641// Main
642//============================================================================
643
644int main(int argc, char **argv)
645{
646 ::testing::InitGoogleTest(&argc, argv);
647 return RUN_ALL_TESTS();
648}
int main()
Generic directed graph (digraph) wrapper template.
Definition graph-dry.H:3848
typename BaseGraph::Arc Arc
Definition graph-dry.H:3852
typename BaseGraph::Node Node
Definition graph-dry.H:3851
Graph serialization and deserialization class.
Definition io_graph.H:319
virtual Node * insert_node(Node *node) noexcept
Insertion of a node already allocated.
Definition tpl_graph.H:524
Graph_Arc< double > Arc
The node class type.
Definition tpl_graph.H:433
Arc * insert_arc(Node *src_node, Node *tgt_node, void *a)
Definition tpl_graph.H:604
std::string text_file
void SetUp() override
Digraph::Arc Arc
Digraph::Node Node
void TearDown() override
std::string binary_file
void SetUp() override
void TearDown() override
std::vector< int > get_node_values(Graph &graph)
std::string binary_file
std::string text_file
std::vector< double > get_arc_values(Graph &graph)
#define TEST(name)
Graph serialization and deserialization utilities.
TEST_F(IOGraphTest, ConstructFromReference)
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
DynList< T > maps(const C &c, Op op)
Classic map operation.
Default arc loading functor for binary and text modes.
Definition io_graph.H:257
Default node loading functor for binary and text modes.
Definition io_graph.H:222
Default arc storage functor for binary and text modes.
Definition io_graph.H:187
Default node storage functor for binary and text modes.
Definition io_graph.H:152
Arc of graph implemented with double-linked adjacency lists.
Definition tpl_graph.H:222
Generic graph and digraph implementations.