Skip to content

Commit 921630c

Browse files
test(course_database): improve the only test
1 parent f79bde6 commit 921630c

File tree

1 file changed

+73
-66
lines changed

1 file changed

+73
-66
lines changed

src/course_database.rs

Lines changed: 73 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use anyhow::anyhow;
22
use core::str::FromStr;
3-
use petgraph::graph::{Graph, NodeIndex};
3+
use petgraph::graph::{DiGraph, NodeIndex};
44
use serde::Deserialize;
55
use std::fmt;
66

@@ -105,7 +105,7 @@ impl From<Course> for DatabaseNode {
105105
/// Abstraction over some way to retrieve course info for simplicity.
106106
/// There must only be one entry for each course.
107107
pub struct CourseDatabase {
108-
courses: Graph<DatabaseNode, Relation>,
108+
pub courses: DiGraph<DatabaseNode, Relation>,
109109
}
110110

111111
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -135,11 +135,11 @@ impl CourseDatabase {
135135
course_list.dedup_by(|a, b| a.id == b.id);
136136

137137
// Build the course graph
138-
let mut courses = Graph::new();
138+
let mut courses = DiGraph::new();
139139
let mut edge_queue = Vec::<(NodeIndex, CourseId, Relation)>::new();
140140

141141
fn descend_deptree(
142-
courses: &mut Graph<DatabaseNode, Relation>,
142+
courses: &mut DiGraph<DatabaseNode, Relation>,
143143
edge_queue: &mut Vec<(NodeIndex, CourseId, Relation)>,
144144
node: &NodeIndex,
145145
requirement: &Requirement,
@@ -158,6 +158,7 @@ impl CourseDatabase {
158158
}
159159
}
160160
req => {
161+
// Note that A corequisite B && B !corequisite A is true.
161162
edge_queue.push((*node, req.unwrap(), req.try_into().unwrap()));
162163
}
163164
}
@@ -204,13 +205,13 @@ impl CourseDatabase {
204205
Ok(Self { courses })
205206
}
206207

207-
pub fn get(&self, id: &CourseId) -> Option<Course> {
208+
pub fn index_of(&self, id: &CourseId) -> Option<NodeIndex> {
208209
let idx = self
209210
.courses
210211
.node_indices()
211212
.find(|node_idx| self.courses[*node_idx].has_id(id))?;
212213
Some(match &self.courses[idx] {
213-
DatabaseNode::Course(course) => course.clone(),
214+
DatabaseNode::Course(course) => idx,
214215
_ => unreachable!(),
215216
})
216217
}
@@ -219,6 +220,8 @@ impl CourseDatabase {
219220
#[cfg(test)]
220221
mod tests {
221222
use super::*;
223+
use petgraph::visit::EdgeRef;
224+
222225
static CMPUT_SMALL: &'static str = r#"[
223226
(
224227
id: (subject_id: "CMPUT", class_id: 101),
@@ -248,72 +251,76 @@ mod tests {
248251
requirements: Some(Prereq((subject_id: "MATH", class_id: 111))),
249252
),
250253
]"#;
254+
#[track_caller]
255+
fn assert_in_db(db: &CourseDatabase, id: &CourseId) -> NodeIndex {
256+
let Some(course_idx) = db.index_of(id) else {
257+
panic!("{} not in the Database", id);
258+
};
259+
260+
course_idx
261+
}
251262

252263
#[test]
253264
fn cmput_small() {
254-
let cd = match CourseDatabase::new(CMPUT_SMALL) {
255-
Ok(cd) => cd,
265+
let db = match CourseDatabase::new(CMPUT_SMALL) {
266+
Ok(db) => db,
256267
Err(err) => panic!("Faild to build CourseDatabase {:?}", err),
257268
};
258269

259-
assert!(
260-
matches!(
261-
cd.get(&CourseId {
262-
subject_id: "CMPUT".into(),
263-
class_id: 101
264-
}),
265-
Some(_)
266-
),
267-
"CMPUT 101 not in the Database"
270+
let cmput_101_id = CourseId {
271+
subject_id: "CMPUT".into(),
272+
class_id: 101,
273+
};
274+
let math_112_id = CourseId {
275+
subject_id: "MATH".into(),
276+
class_id: 112,
277+
};
278+
279+
let cmput_101 = assert_in_db(&db, &cmput_101_id);
280+
let cmput_102 = assert_in_db(
281+
&db,
282+
&CourseId {
283+
subject_id: "CMPUT".into(),
284+
class_id: 102,
285+
},
286+
);
287+
let math_111 = assert_in_db(
288+
&db,
289+
&CourseId {
290+
subject_id: "MATH".into(),
291+
class_id: 111,
292+
},
293+
);
294+
let math_112 = assert_in_db(&db, &math_112_id);
295+
296+
assert_eq!(
297+
db.courses.edges(cmput_101).count(),
298+
0,
299+
"CMPUT 101 was parsed as having dependencies when it has none"
268300
);
301+
let mut desired = vec![cmput_101_id, math_112_id];
302+
303+
for edge in db.courses.edges(cmput_102) {
304+
assert_eq!(
305+
*edge.weight(),
306+
Relation::Prereq,
307+
"All dependencies of CMPUT 102 should be prereqs"
308+
);
309+
assert_eq!(
310+
edge.source(),
311+
cmput_102,
312+
"There is something wrong with petgraph or the test"
313+
);
314+
let Some((idx, cid)) = desired
315+
.iter()
316+
.enumerate()
317+
.find(|cid| db.courses[edge.target()].has_id(cid.1))
318+
else {
319+
panic!("There was an unexpected dependency on CMPUT 102");
320+
};
321+
desired.remove(idx);
322+
}
323+
324+
assert!(desired.is_empty(), "CMPUT 101 had dependencies missing");
269325
}
270326
}
271-
272-
// impl Default for CourseDatabase {
273-
// // Simple course catalog to use for testing.
274-
// fn default() -> Self {
275-
// use Requirement::*;
276-
// let cmput_101 = Course::new("CMPUT", 101, None);
277-
// let cmput_102 = Course::new("CMPUT", 102,
278-
// Some(Prereq(cmput_101.id.clone())));
279-
//
280-
// let math_111 = Course::new("MATH", 111, None);
281-
// let math_112 = Course::new("MATH", 112,
282-
// Some(Prereq(math_111.id.clone())));
283-
//
284-
// let cmput_174 = Course::new(
285-
// "CMPUT",
286-
// 174,
287-
// Some(And(vec![
288-
// Prereq(math_112.id.clone()),
289-
// Coreq(cmput_102.id.clone()),
290-
// ])),
291-
// );
292-
// let cmput_175 = Course::new("CMPUT", 175,
293-
// Some(Prereq(cmput_174.id.clone())));
294-
//
295-
// let cmput_274 = Course::new("CMPUT", 274, None);
296-
// let cmput_275 = Course::new("CMPUT", 275,
297-
// Some(Prereq(cmput_274.id.clone())));
298-
//
299-
// let cmput_202 = Course::new("CMPUT", 202, None);
300-
//
301-
// let cmput_322 = Course::new(
302-
// "CMPUT",
303-
// 322,
304-
// Some(And(vec![
305-
// Or(vec![
306-
// Requirement::Prereq(cmput_275.id.clone()),
307-
// Requirement::Prereq(cmput_175.id.clone()),
308-
// ]),
309-
// Requirement::Prereq(cmput_202.id.clone()),
310-
// ])),
311-
// );
312-
// Self {
313-
// courses: vec![
314-
// cmput_101, cmput_102, math_111, math_112, cmput_174,
315-
// cmput_175, cmput_274, cmput_275, cmput_202, cmput_322,
316-
// ],
317-
// }
318-
// }
319-
// }

0 commit comments

Comments
 (0)