Compare commits

...

3 Commits

5 changed files with 105 additions and 15 deletions

15
.gitignore vendored
View File

@@ -1,8 +1,17 @@
# IDE, Other files
.vscode
.idea
rust-sdl2-emscripten/
# Build files
target/
dist/
emsdk/
.idea
rust-sdl2-emscripten/
assets/site/build.css
# Site build f iles
tailwindcss-*
assets/site/build.css
# Coverage reports
lcov.info
coverage.html

View File

@@ -1,17 +1,32 @@
set shell := ["bash", "-c"]
set windows-shell := ["powershell.exe", "-NoLogo", "-Command"]
coverage_exclude_pattern := "app.rs|audio.rs|error.rs"
# Regex to exclude files from coverage report, double escapes for Justfile + CLI
# You can use src\\\\..., but the filename alone is acceptable too
coverage_exclude_pattern := "src\\\\app.rs|audio.rs|src\\\\error.rs|platform\\\\emscripten.rs"
# !!! --ignore-filename-regex should be used on both reports & coverage testing
# !!! --remap-path-prefix prevents the absolute path from being used in the generated report
# Generate HTML report (for humans, source line inspection)
html: coverage
cargo llvm-cov report \
--remap-path-prefix \
--ignore-filename-regex "{{ coverage_exclude_pattern }}" \
--html \
--open
# Display report (for humans)
report-coverage: coverage
cargo llvm-cov report \
--remap-path-prefix \
--ignore-filename-regex "{{ coverage_exclude_pattern }}"
# Run & generate report (for CI)
coverage:
cargo llvm-cov \
--lcov \
--remap-path-prefix \
--ignore-filename-regex "{{ coverage_exclude_pattern }}" \
--output-path lcov.info \
--profile coverage \

View File

@@ -1,7 +1,7 @@
use smallvec::SmallVec;
use std::collections::HashMap;
use crate::entity::traversal::Position;
use crate::entity::{graph::NodeId, traversal::Position};
/// Trait for entities that can participate in collision detection.
pub trait Collidable {
@@ -19,7 +19,7 @@ pub trait Collidable {
#[derive(Default)]
pub struct CollisionSystem {
/// Maps node IDs to lists of entity IDs that are at that node
node_entities: HashMap<usize, Vec<EntityId>>,
node_entities: HashMap<NodeId, Vec<EntityId>>,
/// Maps entity IDs to their current positions
entity_positions: HashMap<EntityId, Position>,
/// Next available entity ID
@@ -62,7 +62,7 @@ impl CollisionSystem {
}
/// Gets all entity IDs at a specific node
pub fn entities_at_node(&self, node: usize) -> &[EntityId] {
pub fn entities_at_node(&self, node: NodeId) -> &[EntityId] {
self.node_entities.get(&node).map(|v| v.as_slice()).unwrap_or(&[])
}
@@ -115,7 +115,7 @@ fn positions_overlap(a: &Position, b: &Position) -> bool {
}
/// Gets all nodes that an entity is currently at or between.
fn get_nodes(pos: &Position) -> SmallVec<[usize; 2]> {
fn get_nodes(pos: &Position) -> SmallVec<[NodeId; 2]> {
let mut nodes = SmallVec::new();
match pos {
Position::AtNode(node) => nodes.push(*node),

View File

@@ -192,14 +192,15 @@ impl Graph {
// Check if the edge already exists in this direction or to the same target
if let Some(err) = adjacency_list.edges().find_map(|e| {
// If we're not replacing the edge, we don't want to replace an edge that already exists in this direction
if !replace && e.direction == direction {
Some(Err("Edge already exists in this direction."))
} else if e.target == to {
Some(Err("Edge already exists."))
} else {
None
if !replace {
// If we're not replacing the edge, we don't want to replace an edge that already exists in this direction
if e.direction == direction {
return Some(Err("Edge already exists in this direction."));
} else if e.target == to {
return Some(Err("Edge already exists."));
}
}
None
}) {
return err;
}

View File

@@ -86,6 +86,71 @@ fn test_graph_edge_permissions() {
assert_eq!(edge.permissions, EdgePermissions::GhostsOnly);
}
#[test]
fn should_add_connected_node() {
let mut graph = Graph::new();
let node1 = graph.add_node(Node {
position: glam::Vec2::new(0.0, 0.0),
});
let node2 = graph
.add_connected(
node1,
Direction::Right,
Node {
position: glam::Vec2::new(16.0, 0.0),
},
)
.unwrap();
assert_eq!(graph.node_count(), 2);
let edge = graph.find_edge(node1, node2);
assert!(edge.is_some());
assert_eq!(edge.unwrap().direction, Direction::Right);
}
#[test]
fn should_error_on_negative_edge_distance() {
let mut graph = Graph::new();
let node1 = graph.add_node(Node {
position: glam::Vec2::new(0.0, 0.0),
});
let node2 = graph.add_node(Node {
position: glam::Vec2::new(16.0, 0.0),
});
let result = graph.add_edge(node1, node2, false, Some(-1.0), Direction::Right, EdgePermissions::All);
assert!(result.is_err());
}
#[test]
fn should_error_on_duplicate_edge_without_replace() {
let mut graph = create_test_graph();
let result = graph.add_edge(0, 1, false, None, Direction::Right, EdgePermissions::All);
assert!(result.is_err());
}
#[test]
fn should_allow_replacing_an_edge() {
let mut graph = create_test_graph();
let result = graph.add_edge(0, 1, true, Some(42.0), Direction::Right, EdgePermissions::All);
assert!(result.is_ok());
let edge = graph.find_edge(0, 1).unwrap();
assert_eq!(edge.distance, 42.0);
}
#[test]
fn should_find_edge_between_nodes() {
let graph = create_test_graph();
let edge = graph.find_edge(0, 1);
assert!(edge.is_some());
assert_eq!(edge.unwrap().target, 1);
let non_existent_edge = graph.find_edge(0, 99);
assert!(non_existent_edge.is_none());
}
#[test]
fn test_traverser_basic() {
let graph = create_test_graph();