• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Xevion / Pac-Man / 16584527047

29 Jul 2025 01:49AM UTC coverage: 84.893% (+79.4%) from 5.538%
16584527047

push

github

Xevion
refactor: remove StartingPosition MapTile, track pacman start explicitly in parser

23 of 23 new or added lines in 3 files covered. (100.0%)

247 existing lines in 14 files now uncovered.

2568 of 3025 relevant lines covered (84.89%)

987.28 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.36
/src/map/builder.rs
1
//! Map construction and building functionality.
2

3
use crate::constants::{MapTile, BOARD_CELL_SIZE, CELL_SIZE};
4
use crate::entity::direction::{Direction, DIRECTIONS};
5
use crate::entity::graph::{Graph, Node, NodeId};
6
use crate::map::parser::MapTileParser;
7
use crate::map::render::MapRenderer;
8
use crate::texture::sprite::{AtlasTile, SpriteAtlas};
9
use glam::{IVec2, UVec2, Vec2};
10
use sdl2::render::{Canvas, RenderTarget};
11
use std::collections::{HashMap, VecDeque};
12
use tracing::debug;
13

14
pub struct NodePositions {
15
    pub pacman: NodeId,
16
    pub blinky: NodeId,
17
    pub pinky: NodeId,
18
    pub inky: NodeId,
19
    pub clyde: NodeId,
20
}
21

22
/// The main map structure containing the game board and navigation graph.
23
pub struct Map {
24
    /// The current state of the map.
25
    current: [[MapTile; BOARD_CELL_SIZE.y as usize]; BOARD_CELL_SIZE.x as usize],
26
    /// The node map for entity movement.
27
    pub graph: Graph,
28
    /// A mapping from grid positions to node IDs.
29
    pub grid_to_node: HashMap<IVec2, NodeId>,
30
    /// A mapping of the starting positions of the entities.
31
    pub start_positions: NodePositions,
32
    /// Pac-Man's starting position.
33
    pacman_start: Option<IVec2>,
34
}
35

36
impl Map {
37
    /// Creates a new `Map` instance from a raw board layout.
38
    ///
39
    /// This constructor initializes the map tiles based on the provided character layout
40
    /// and then generates a navigation graph from the walkable areas.
41
    ///
42
    /// # Panics
43
    ///
44
    /// This function will panic if the board layout contains unknown characters or if
45
    /// the house door is not defined by exactly two '=' characters.
46
    pub fn new(raw_board: [&str; BOARD_CELL_SIZE.y as usize]) -> Map {
32✔
47
        let parsed_map = MapTileParser::parse_board(raw_board).expect("Failed to parse board layout");
32✔
48

32✔
49
        let map = parsed_map.tiles;
32✔
50
        let house_door = parsed_map.house_door;
32✔
51
        let tunnel_ends = parsed_map.tunnel_ends;
32✔
52
        let pacman_start = parsed_map.pacman_start;
32✔
53

32✔
54
        let mut graph = Graph::new();
32✔
55
        let mut grid_to_node = HashMap::new();
32✔
56

32✔
57
        let cell_offset = Vec2::splat(CELL_SIZE as f32 / 2.0);
32✔
58

32✔
59
        // Find a starting point for the graph generation, preferably Pac-Man's position.
32✔
60
        let start_pos = pacman_start.expect("Pac-Man's starting position not found");
32✔
61

32✔
62
        // Add the starting position to the graph/queue
32✔
63
        let mut queue = VecDeque::new();
32✔
64
        queue.push_back(start_pos);
32✔
65
        let pos = Vec2::new(
32✔
66
            (start_pos.x * CELL_SIZE as i32) as f32,
32✔
67
            (start_pos.y * CELL_SIZE as i32) as f32,
32✔
68
        ) + cell_offset;
32✔
69
        let node_id = graph.add_node(Node { position: pos });
32✔
70
        grid_to_node.insert(start_pos, node_id);
32✔
71

72
        // Iterate over the queue, adding nodes to the graph and connecting them to their neighbors
73
        while let Some(source_position) = queue.pop_front() {
9,568✔
74
            for &dir in DIRECTIONS.iter() {
38,144✔
75
                let new_position = source_position + dir.as_ivec2();
38,144✔
76

38,144✔
77
                // Skip if the new position is out of bounds
38,144✔
78
                if new_position.x < 0
38,144✔
79
                    || new_position.x >= BOARD_CELL_SIZE.x as i32
38,112✔
80
                    || new_position.y < 0
38,080✔
81
                    || new_position.y >= BOARD_CELL_SIZE.y as i32
38,080✔
82
                {
83
                    continue;
64✔
84
                }
38,080✔
85

38,080✔
86
                // Skip if the new position is already in the graph
38,080✔
87
                if grid_to_node.contains_key(&new_position) {
38,080✔
88
                    continue;
10,720✔
89
                }
27,360✔
90

91
                // Skip if the new position is not a walkable tile
92
                if matches!(
17,856✔
93
                    map[new_position.x as usize][new_position.y as usize],
27,360✔
94
                    MapTile::Pellet | MapTile::PowerPellet | MapTile::Empty | MapTile::Tunnel
95
                ) {
9,504✔
96
                    // Add the new position to the graph/queue
9,504✔
97
                    let pos = Vec2::new(
9,504✔
98
                        (new_position.x * CELL_SIZE as i32) as f32,
9,504✔
99
                        (new_position.y * CELL_SIZE as i32) as f32,
9,504✔
100
                    ) + cell_offset;
9,504✔
101
                    let new_node_id = graph.add_node(Node { position: pos });
9,504✔
102
                    grid_to_node.insert(new_position, new_node_id);
9,504✔
103
                    queue.push_back(new_position);
9,504✔
104

9,504✔
105
                    // Connect the new node to the source node
9,504✔
106
                    let source_node_id = grid_to_node
9,504✔
107
                        .get(&source_position)
9,504✔
108
                        .unwrap_or_else(|| panic!("Source node not found for {source_position}"));
9,504✔
109

9,504✔
110
                    // Connect the new node to the source node
9,504✔
111
                    graph
9,504✔
112
                        .connect(*source_node_id, new_node_id, false, None, dir)
9,504✔
113
                        .expect("Failed to add edge");
9,504✔
114
                }
17,856✔
115
            }
116
        }
117

118
        // While most nodes are already connected to their neighbors, some may not be, so we need to connect them
119
        for (grid_pos, &node_id) in &grid_to_node {
9,568✔
120
            for dir in DIRECTIONS {
47,680✔
121
                // If the node doesn't have an edge in this direction, look for a neighbor in that direction
122
                if graph.adjacency_list[node_id].get(dir).is_none() {
38,144✔
123
                    let neighbor = grid_pos + dir.as_ivec2();
18,528✔
124
                    // If the neighbor exists, connect the node to it
125
                    if let Some(&neighbor_id) = grid_to_node.get(&neighbor) {
18,528✔
126
                        graph
608✔
127
                            .connect(node_id, neighbor_id, false, None, dir)
608✔
128
                            .expect("Failed to add edge");
608✔
129
                    }
17,920✔
130
                }
19,616✔
131
            }
132
        }
133

134
        // Build house structure
135
        let (house_entrance_node_id, left_center_node_id, center_center_node_id, right_center_node_id) =
32✔
136
            Self::build_house(&mut graph, &grid_to_node, &house_door);
32✔
137

32✔
138
        let start_positions = NodePositions {
32✔
139
            pacman: grid_to_node[&start_pos],
32✔
140
            blinky: house_entrance_node_id,
32✔
141
            pinky: left_center_node_id,
32✔
142
            inky: right_center_node_id,
32✔
143
            clyde: center_center_node_id,
32✔
144
        };
32✔
145

32✔
146
        // Build tunnel connections
32✔
147
        Self::build_tunnels(&mut graph, &grid_to_node, &tunnel_ends);
32✔
148

32✔
149
        Map {
32✔
150
            current: map,
32✔
151
            graph,
32✔
152
            grid_to_node,
32✔
153
            start_positions,
32✔
154
            pacman_start,
32✔
155
        }
32✔
156
    }
32✔
157

158
    /// Finds the starting position for a given entity ID.
159
    ///
160
    /// # Arguments
161
    ///
162
    /// * `entity_id` - The entity ID (0 for Pac-Man, 1-4 for ghosts)
163
    ///
164
    /// # Returns
165
    ///
166
    /// The starting position as a grid coordinate (`UVec2`), or `None` if not found.
167
    pub fn find_starting_position(&self, entity_id: u8) -> Option<UVec2> {
26✔
168
        // For now, only Pac-Man (entity_id 0) is supported
26✔
169
        if entity_id == 0 {
26✔
170
            return self.pacman_start.map(|pos| UVec2::new(pos.x as u32, pos.y as u32));
22✔
171
        }
4✔
172
        None
4✔
173
    }
26✔
174

175
    /// Renders the map to the given canvas.
176
    ///
177
    /// This function draws the static map texture to the screen at the correct
178
    /// position and scale.
UNCOV
179
    pub fn render<T: RenderTarget>(&self, canvas: &mut Canvas<T>, atlas: &mut SpriteAtlas, map_texture: &mut AtlasTile) {
×
180
        MapRenderer::render_map(canvas, atlas, map_texture);
×
181
    }
×
182

183
    /// Renders a debug visualization of the navigation graph.
184
    ///
185
    /// This function is intended for development and debugging purposes. It draws the
186
    /// nodes and edges of the graph on top of the map, allowing for visual
187
    /// inspection of the navigation paths.
188
    pub fn debug_render_nodes<T: RenderTarget>(&self, canvas: &mut Canvas<T>) {
×
189
        MapRenderer::debug_render_nodes(&self.graph, canvas);
×
UNCOV
190
    }
×
191

192
    /// Builds the house structure in the graph.
193
    fn build_house(
32✔
194
        graph: &mut Graph,
32✔
195
        grid_to_node: &HashMap<IVec2, NodeId>,
32✔
196
        house_door: &[Option<IVec2>; 2],
32✔
197
    ) -> (usize, usize, usize, usize) {
32✔
198
        // Calculate the position of the house entrance node
32✔
199
        let (house_entrance_node_id, house_entrance_node_position) = {
32✔
200
            // Translate the grid positions to the actual node ids
32✔
201
            let left_node = grid_to_node
32✔
202
                .get(&(house_door[0].expect("First house door position not acquired") + Direction::Left.as_ivec2()))
32✔
203
                .expect("Left house door node  not found");
32✔
204
            let right_node = grid_to_node
32✔
205
                .get(&(house_door[1].expect("Second house door position not acquired") + Direction::Right.as_ivec2()))
32✔
206
                .expect("Right house door node  not found");
32✔
207

32✔
208
            // Calculate the position of the house node
32✔
209
            let (node_id, node_position) = {
32✔
210
                let left_pos = graph.get_node(*left_node).unwrap().position;
32✔
211
                let right_pos = graph.get_node(*right_node).unwrap().position;
32✔
212
                let house_node = graph.add_node(Node {
32✔
213
                    position: left_pos.lerp(right_pos, 0.5),
32✔
214
                });
32✔
215
                (house_node, left_pos.lerp(right_pos, 0.5))
32✔
216
            };
32✔
217

32✔
218
            // Connect the house door to the left and right nodes
32✔
219
            graph
32✔
220
                .connect(node_id, *left_node, true, None, Direction::Left)
32✔
221
                .expect("Failed to connect house door to left node");
32✔
222
            graph
32✔
223
                .connect(node_id, *right_node, true, None, Direction::Right)
32✔
224
                .expect("Failed to connect house door to right node");
32✔
225

32✔
226
            (node_id, node_position)
32✔
227
        };
32✔
228

32✔
229
        // A helper function to help create the various 'lines' of nodes within the house
32✔
230
        let create_house_line = |graph: &mut Graph, center_pos: Vec2| -> (NodeId, NodeId) {
96✔
231
            // Place the nodes at, above, and below the center position
96✔
232
            let center_node_id = graph.add_node(Node { position: center_pos });
96✔
233
            let top_node_id = graph.add_node(Node {
96✔
234
                position: center_pos + (Direction::Up.as_ivec2() * (CELL_SIZE as i32 / 2)).as_vec2(),
96✔
235
            });
96✔
236
            let bottom_node_id = graph.add_node(Node {
96✔
237
                position: center_pos + (Direction::Down.as_ivec2() * (CELL_SIZE as i32 / 2)).as_vec2(),
96✔
238
            });
96✔
239

96✔
240
            // Connect the center node to the top and bottom nodes
96✔
241
            graph
96✔
242
                .connect(center_node_id, top_node_id, false, None, Direction::Up)
96✔
243
                .expect("Failed to connect house line to left node");
96✔
244
            graph
96✔
245
                .connect(center_node_id, bottom_node_id, false, None, Direction::Down)
96✔
246
                .expect("Failed to connect house line to right node");
96✔
247

96✔
248
            (center_node_id, top_node_id)
96✔
249
        };
96✔
250

251
        // Calculate the position of the center line's center node
252
        let center_line_center_position =
32✔
253
            house_entrance_node_position + (Direction::Down.as_ivec2() * (3 * CELL_SIZE as i32)).as_vec2();
32✔
254

32✔
255
        // Create the center line
32✔
256
        let (center_center_node_id, center_top_node_id) = create_house_line(graph, center_line_center_position);
32✔
257

32✔
258
        // Connect the house entrance to the top line
32✔
259
        graph
32✔
260
            .connect(house_entrance_node_id, center_top_node_id, false, None, Direction::Down)
32✔
261
            .expect("Failed to connect house entrance to top line");
32✔
262

32✔
263
        // Create the left line
32✔
264
        let (left_center_node_id, _) = create_house_line(
32✔
265
            graph,
32✔
266
            center_line_center_position + (Direction::Left.as_ivec2() * (CELL_SIZE as i32 * 2)).as_vec2(),
32✔
267
        );
32✔
268

32✔
269
        // Create the right line
32✔
270
        let (right_center_node_id, _) = create_house_line(
32✔
271
            graph,
32✔
272
            center_line_center_position + (Direction::Right.as_ivec2() * (CELL_SIZE as i32 * 2)).as_vec2(),
32✔
273
        );
32✔
274

32✔
275
        debug!("Left center node id: {left_center_node_id}");
32✔
276

277
        // Connect the center line to the left and right lines
278
        graph
32✔
279
            .connect(center_center_node_id, left_center_node_id, false, None, Direction::Left)
32✔
280
            .expect("Failed to connect house entrance to left top line");
32✔
281

32✔
282
        graph
32✔
283
            .connect(center_center_node_id, right_center_node_id, false, None, Direction::Right)
32✔
284
            .expect("Failed to connect house entrance to right top line");
32✔
285

32✔
286
        debug!("House entrance node id: {house_entrance_node_id}");
32✔
287

288
        (
32✔
289
            house_entrance_node_id,
32✔
290
            left_center_node_id,
32✔
291
            center_center_node_id,
32✔
292
            right_center_node_id,
32✔
293
        )
32✔
294
    }
32✔
295

296
    /// Builds the tunnel connections in the graph.
297
    fn build_tunnels(graph: &mut Graph, grid_to_node: &HashMap<IVec2, NodeId>, tunnel_ends: &[Option<IVec2>; 2]) {
32✔
298
        // Create the hidden tunnel nodes
32✔
299
        let left_tunnel_hidden_node_id = {
32✔
300
            let left_tunnel_entrance_node_id = grid_to_node[&tunnel_ends[0].expect("Left tunnel end not found")];
32✔
301
            let left_tunnel_entrance_node = graph
32✔
302
                .get_node(left_tunnel_entrance_node_id)
32✔
303
                .expect("Left tunnel entrance node not found");
32✔
304

32✔
305
            graph
32✔
306
                .connect_node(
32✔
307
                    left_tunnel_entrance_node_id,
32✔
308
                    Direction::Left,
32✔
309
                    Node {
32✔
310
                        position: left_tunnel_entrance_node.position
32✔
311
                            + (Direction::Left.as_ivec2() * (CELL_SIZE as i32 * 2)).as_vec2(),
32✔
312
                    },
32✔
313
                )
32✔
314
                .expect("Failed to connect left tunnel entrance to left tunnel hidden node")
32✔
315
        };
32✔
316

32✔
317
        // Create the right tunnel nodes
32✔
318
        let right_tunnel_hidden_node_id = {
32✔
319
            let right_tunnel_entrance_node_id = grid_to_node[&tunnel_ends[1].expect("Right tunnel end not found")];
32✔
320
            let right_tunnel_entrance_node = graph
32✔
321
                .get_node(right_tunnel_entrance_node_id)
32✔
322
                .expect("Right tunnel entrance node not found");
32✔
323

32✔
324
            graph
32✔
325
                .connect_node(
32✔
326
                    right_tunnel_entrance_node_id,
32✔
327
                    Direction::Right,
32✔
328
                    Node {
32✔
329
                        position: right_tunnel_entrance_node.position
32✔
330
                            + (Direction::Right.as_ivec2() * (CELL_SIZE as i32 * 2)).as_vec2(),
32✔
331
                    },
32✔
332
                )
32✔
333
                .expect("Failed to connect right tunnel entrance to right tunnel hidden node")
32✔
334
        };
32✔
335

32✔
336
        // Connect the left tunnel hidden node to the right tunnel hidden node
32✔
337
        graph
32✔
338
            .connect(
32✔
339
                left_tunnel_hidden_node_id,
32✔
340
                right_tunnel_hidden_node_id,
32✔
341
                false,
32✔
342
                Some(0.0),
32✔
343
                Direction::Left,
32✔
344
            )
32✔
345
            .expect("Failed to connect left tunnel hidden node to right tunnel hidden node");
32✔
346
    }
32✔
347
}
348

349
#[cfg(test)]
350
mod tests {
351
    use super::*;
352
    use crate::constants::{BOARD_CELL_SIZE, CELL_SIZE};
353
    use glam::{IVec2, UVec2, Vec2};
354

355
    fn create_minimal_test_board() -> [&'static str; BOARD_CELL_SIZE.y as usize] {
16✔
356
        let mut board = [""; BOARD_CELL_SIZE.y as usize];
16✔
357
        // Create a minimal valid board with house doors
16✔
358
        board[0] = "############################";
16✔
359
        board[1] = "#............##............#";
16✔
360
        board[2] = "#.####.#####.##.#####.####.#";
16✔
361
        board[3] = "#o####.#####.##.#####.####o#";
16✔
362
        board[4] = "#.####.#####.##.#####.####.#";
16✔
363
        board[5] = "#..........................#";
16✔
364
        board[6] = "#.####.##.########.##.####.#";
16✔
365
        board[7] = "#.####.##.########.##.####.#";
16✔
366
        board[8] = "#......##....##....##......#";
16✔
367
        board[9] = "######.##### ## #####.######";
16✔
368
        board[10] = "     #.##### ## #####.#     ";
16✔
369
        board[11] = "     #.##    ==    ##.#     ";
16✔
370
        board[12] = "     #.## ######## ##.#     ";
16✔
371
        board[13] = "######.## ######## ##.######";
16✔
372
        board[14] = "T     .   ########   .     T";
16✔
373
        board[15] = "######.## ######## ##.######";
16✔
374
        board[16] = "     #.## ######## ##.#     ";
16✔
375
        board[17] = "     #.##          ##.#     ";
16✔
376
        board[18] = "     #.## ######## ##.#     ";
16✔
377
        board[19] = "######.## ######## ##.######";
16✔
378
        board[20] = "#............##............#";
16✔
379
        board[21] = "#.####.#####.##.#####.####.#";
16✔
380
        board[22] = "#.####.#####.##.#####.####.#";
16✔
381
        board[23] = "#o..##.......X .......##..o#";
16✔
382
        board[24] = "###.##.##.########.##.##.###";
16✔
383
        board[25] = "###.##.##.########.##.##.###";
16✔
384
        board[26] = "#......##....##....##......#";
16✔
385
        board[27] = "#.##########.##.##########.#";
16✔
386
        board[28] = "#.##########.##.##########.#";
16✔
387
        board[29] = "#..........................#";
16✔
388
        board[30] = "############################";
16✔
389
        board
16✔
390
    }
16✔
391

392
    #[test]
393
    fn test_map_new() {
2✔
394
        let board = create_minimal_test_board();
2✔
395
        let map = Map::new(board);
2✔
396

2✔
397
        assert!(map.graph.node_count() > 0);
2✔
398
        assert!(!map.grid_to_node.is_empty());
2✔
399
    }
2✔
400

401
    #[test]
402
    fn test_find_starting_position_pacman() {
2✔
403
        let board = create_minimal_test_board();
2✔
404
        let map = Map::new(board);
2✔
405

2✔
406
        let pacman_pos = map.find_starting_position(0);
2✔
407
        assert!(pacman_pos.is_some());
2✔
408

409
        let pos = pacman_pos.unwrap();
2✔
410
        // Pacman should be found somewhere in the board
2✔
411
        assert!(pos.x < BOARD_CELL_SIZE.x);
2✔
412
        assert!(pos.y < BOARD_CELL_SIZE.y);
2✔
413
    }
2✔
414

415
    #[test]
416
    fn test_find_starting_position_ghost() {
2✔
417
        let board = create_minimal_test_board();
2✔
418
        let map = Map::new(board);
2✔
419

2✔
420
        // Test for ghost 1 (might not exist in this board)
2✔
421
        let ghost_pos = map.find_starting_position(1);
2✔
422
        // Ghost 1 might not exist, so this could be None
423
        if let Some(pos) = ghost_pos {
2✔
UNCOV
424
            assert!(pos.x < BOARD_CELL_SIZE.x);
×
UNCOV
425
            assert!(pos.y < BOARD_CELL_SIZE.y);
×
426
        }
2✔
427
    }
2✔
428

429
    #[test]
430
    fn test_find_starting_position_nonexistent() {
2✔
431
        let board = create_minimal_test_board();
2✔
432
        let map = Map::new(board);
2✔
433

2✔
434
        let pos = map.find_starting_position(99); // Non-existent entity
2✔
435
        assert!(pos.is_none());
2✔
436
    }
2✔
437

438
    #[test]
439
    fn test_map_graph_construction() {
2✔
440
        let board = create_minimal_test_board();
2✔
441
        let map = Map::new(board);
2✔
442

2✔
443
        // Check that nodes were created
2✔
444
        assert!(map.graph.node_count() > 0);
2✔
445

446
        // Check that grid_to_node mapping was created
447
        assert!(!map.grid_to_node.is_empty());
2✔
448

449
        // Check that some connections were made
450
        let mut has_connections = false;
2✔
451
        for intersection in &map.graph.adjacency_list {
2✔
452
            if intersection.edges().next().is_some() {
2✔
453
                has_connections = true;
2✔
454
                break;
2✔
UNCOV
455
            }
×
456
        }
457
        assert!(has_connections);
2✔
458
    }
2✔
459

460
    #[test]
461
    fn test_map_grid_to_node_mapping() {
2✔
462
        let board = create_minimal_test_board();
2✔
463
        let map = Map::new(board);
2✔
464

2✔
465
        // Check that Pac-Man's position is mapped
2✔
466
        let pacman_pos = map.find_starting_position(0).unwrap();
2✔
467
        let grid_pos = IVec2::new(pacman_pos.x as i32, pacman_pos.y as i32);
2✔
468

2✔
469
        assert!(map.grid_to_node.contains_key(&grid_pos));
2✔
470
        let node_id = map.grid_to_node[&grid_pos];
2✔
471
        assert!(map.graph.get_node(node_id).is_some());
2✔
472
    }
2✔
473

474
    #[test]
475
    fn test_map_node_positions() {
2✔
476
        let board = create_minimal_test_board();
2✔
477
        let map = Map::new(board);
2✔
478

479
        // Check that node positions are correctly calculated
480
        for (grid_pos, &node_id) in &map.grid_to_node {
598✔
481
            let node = map.graph.get_node(node_id).unwrap();
596✔
482
            let expected_pos = Vec2::new((grid_pos.x * CELL_SIZE as i32) as f32, (grid_pos.y * CELL_SIZE as i32) as f32)
596✔
483
                + Vec2::splat(CELL_SIZE as f32 / 2.0);
596✔
484

596✔
485
            assert_eq!(node.position, expected_pos);
596✔
486
        }
487
    }
2✔
488

489
    #[test]
490
    fn test_map_adjacent_connections() {
2✔
491
        let board = create_minimal_test_board();
2✔
492
        let map = Map::new(board);
2✔
493

2✔
494
        // Check that adjacent walkable tiles are connected
2✔
495
        // Find any node that has connections
2✔
496
        let mut found_connected_node = false;
2✔
497
        for (grid_pos, &node_id) in &map.grid_to_node {
2✔
498
            let intersection = &map.graph.adjacency_list[node_id];
2✔
499
            if intersection.edges().next().is_some() {
2✔
500
                found_connected_node = true;
2✔
501
                break;
2✔
UNCOV
502
            }
×
503
        }
504
        assert!(found_connected_node);
2✔
505
    }
2✔
506
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc