Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# Run all cargo checks and tests.
build:
lint:
cargo fmt
cargo clippy
cargo clippy --all-targets --all-features -- -D warnings
RUSTDOCFLAGS="-D missing_docs" cargo doc --document-private-items --no-deps

test:
cargo test --release

benchmark-small:
Expand Down
2 changes: 1 addition & 1 deletion src/data/course_generator/literacy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -642,7 +642,7 @@ mod test {
// Manifest with an empty name.
let course_manifest = CourseManifest {
id: "course_id".into(),
name: "".into(),
name: String::new(),
dependencies: vec![],
encompassed: vec![],
superseded: vec![],
Expand Down
37 changes: 13 additions & 24 deletions src/exercise_scorer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -592,7 +592,7 @@ mod test {
},
];
let medium_difficulty = PowerLawScorer::estimate_difficulty(&medium_trials);
assert!(medium_difficulty >= 4.0 && medium_difficulty < 7.0);
assert!((4.0..7.0).contains(&medium_difficulty));

// A mixed history should yield an intermediate difficulty from aggregate failures.
let mixed_trials = vec![
Expand Down Expand Up @@ -670,7 +670,7 @@ mod test {

/// Verifies scoring an exercise with an invalid timestamp still returns a sane score.
#[test]
fn invalid_timestamp() -> Result<()> {
fn invalid_timestamp() {
let score = score_helper(
ExerciseType::Declarative,
&[ExerciseTrial {
Expand All @@ -684,12 +684,11 @@ mod test {
assert!(score.value >= 0.0 && score.value <= 5.0);
assert!(score.value < 1.0); // Low due to long time elapsed
assert!((0.0..=1.0).contains(&score.urgency));
Ok(())
}

/// Verifies extreme timestamp gaps do not overflow elapsed-time calculations.
#[test]
fn extreme_timestamp_gap_does_not_overflow() -> Result<()> {
fn extreme_timestamp_gap_does_not_overflow() {
let score = score_helper(
ExerciseType::Declarative,
&[
Expand All @@ -709,7 +708,6 @@ mod test {
);
assert!(score.value >= 0.0 && score.value <= 5.0);
assert!((0.0..=1.0).contains(&score.urgency));
Ok(())
}

/// Verifies stability computation evolves correctly through reviews.
Expand Down Expand Up @@ -961,7 +959,7 @@ mod test {
let failure_gain =
PowerLawScorer::compute_spacing_gain(&ExerciseType::Declarative, 10.0, stability, -0.5);

assert!(short_interval_gain >= 1.0 && short_interval_gain <= 1.0 + SPACING_EFFECT_WEIGHT);
assert!((1.0..=1.0 + SPACING_EFFECT_WEIGHT).contains(&short_interval_gain));
assert!(long_interval_gain > short_interval_gain);
assert_eq!(neutral_gain, 1.0);
assert_eq!(failure_gain, 1.0);
Expand Down Expand Up @@ -1143,7 +1141,7 @@ mod test {

/// Verifies that a recent bad performance results in a very low score.
#[test]
fn score_bad_recent() -> Result<()> {
fn score_bad_recent() {
let trials = vec![
ExerciseTrial {
score: 1.0,
Expand Down Expand Up @@ -1173,12 +1171,11 @@ mod test {
Utc::now().timestamp(),
);
assert!(score.value < 2.0);
Ok(())
}

/// Verifies score for mixed performance history.
#[test]
fn score_mixed_performance() -> Result<()> {
fn score_mixed_performance() {
let trials = vec![
ExerciseTrial {
score: 3.0,
Expand Down Expand Up @@ -1238,7 +1235,6 @@ mod test {
Utc::now().timestamp(),
);
assert!(score.value > 1.0 && score.value < 4.0);
Ok(())
}

/// Verifies that trials not sorted in descending order by timestamp return an error.
Expand Down Expand Up @@ -1266,7 +1262,7 @@ mod test {

/// Verifies that trials with old timestamp result in a low score.
#[test]
fn score_old_timestamp() -> Result<()> {
fn score_old_timestamp() {
let score = score_helper(
ExerciseType::Declarative,
&[ExerciseTrial {
Expand All @@ -1278,12 +1274,11 @@ mod test {
Utc::now().timestamp(),
);
assert!(score.value < 3.0);
Ok(())
}

/// Verifies that the score for multiple good trials is very close to the maximum score.
#[test]
fn score_multiple_good() -> Result<()> {
fn score_multiple_good() {
let trials = vec![
ExerciseTrial {
score: 5.0,
Expand Down Expand Up @@ -1333,12 +1328,11 @@ mod test {
Utc::now().timestamp(),
);
assert!(score.value > 4.0);
Ok(())
}

/// Verifies that multiple bad trials result in a very low score.
#[test]
fn score_multiple_bad() -> Result<()> {
fn score_multiple_bad() {
let trials = vec![
ExerciseTrial {
score: 1.0,
Expand Down Expand Up @@ -1388,13 +1382,12 @@ mod test {
Utc::now().timestamp(),
);
assert!(score.value < 2.0);
Ok(())
}

/// Verifies that many old and well-spaced trials with good scores return a score that is still
/// good due to high stability.
#[test]
fn score_old_good_trials() -> Result<()> {
fn score_old_good_trials() {
let trials = vec![
ExerciseTrial {
score: 5.0,
Expand Down Expand Up @@ -1441,13 +1434,12 @@ mod test {
Utc::now().timestamp(),
);
assert!(score.value >= 3.5);
Ok(())
}

/// Verifies that very old trials of an exercise with good scores return a high score due to
/// strong stability.
#[test]
fn score_very_good_old_trials() -> Result<()> {
fn score_very_good_old_trials() {
let trials = vec![
ExerciseTrial {
score: 5.0,
Expand Down Expand Up @@ -1494,7 +1486,6 @@ mod test {
Utc::now().timestamp(),
);
assert!(score.value >= 3.5);
Ok(())
}

/// Verifies that urgency increases as an otherwise identical review becomes older.
Expand Down Expand Up @@ -1636,7 +1627,7 @@ mod test {

/// Verifies that positive deltas increase the score beyond the score with no deltas provided.
#[test]
fn score_with_positive_deltas() -> Result<()> {
fn score_with_positive_deltas() {
let trials = vec![
ExerciseTrial {
score: 3.0,
Expand Down Expand Up @@ -1680,12 +1671,11 @@ mod test {
Utc::now().timestamp(),
);
assert!(delta_score.value > base_score.value);
Ok(())
}

/// Verifies that negative deltas decrease the score below the score with no deltas provided.
#[test]
fn score_with_negative_deltas() -> Result<()> {
fn score_with_negative_deltas() {
let trials = vec![
ExerciseTrial {
score: 3.0,
Expand Down Expand Up @@ -1729,6 +1719,5 @@ mod test {
Utc::now().timestamp(),
);
assert!(delta_score.value < base_score.value);
Ok(())
}
}
16 changes: 6 additions & 10 deletions src/practice_deltas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,16 +237,12 @@ mod test {
fn assert_deltas(expected: &[f32], actual: &[ExerciseDelta]) {
let only_deltas: Vec<f32> = actual.iter().map(|t| t.delta).collect();
assert_eq!(expected, only_deltas);
let timestamp_sorted = actual
.iter()
.enumerate()
.map(|(i, _)| {
if i == 0 {
return true;
}
actual[i - 1].timestamp >= actual[i].timestamp
})
.all(|b| b);
let timestamp_sorted = actual.iter().enumerate().all(|(i, _)| {
if i == 0 {
return true;
}
actual[i - 1].timestamp >= actual[i].timestamp
});
assert!(timestamp_sorted);
}

Expand Down
18 changes: 7 additions & 11 deletions src/practice_rewards.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,16 +319,12 @@ mod test {
assert_eq!(expected_rewards, only_rewards);
let only_weights: Vec<f32> = actual.iter().map(|t| t.weight).collect();
assert_eq!(expected_weights, only_weights);
let timestamps_sorted = actual
.iter()
.enumerate()
.map(|(i, _)| {
if i == 0 {
return true;
}
actual[i - 1].timestamp >= actual[i].timestamp
})
.all(|b| b);
let timestamps_sorted = actual.iter().enumerate().all(|(i, _)| {
if i == 0 {
return true;
}
actual[i - 1].timestamp >= actual[i].timestamp
});
assert!(timestamps_sorted);
}

Expand Down Expand Up @@ -393,7 +389,7 @@ mod test {
unit_id,
value: i as f32,
weight: 1.0,
timestamp: i as i64,
timestamp: i64::from(i),
}])?;
}

Expand Down
16 changes: 6 additions & 10 deletions src/practice_stats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,16 +262,12 @@ mod test {
fn assert_scores(expected: &[f32], actual: &[ExerciseTrial]) {
let only_scores: Vec<f32> = actual.iter().map(|t| t.score).collect();
assert_eq!(expected, only_scores);
let timestamp_sorted = actual
.iter()
.enumerate()
.map(|(i, _)| {
if i == 0 {
return true;
}
actual[i - 1].timestamp >= actual[i].timestamp
})
.all(|b| b);
let timestamp_sorted = actual.iter().enumerate().all(|(i, _)| {
if i == 0 {
return true;
}
actual[i - 1].timestamp >= actual[i].timestamp
});
assert!(timestamp_sorted);
}

Expand Down
16 changes: 8 additions & 8 deletions src/scheduler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1212,12 +1212,12 @@ mod test {
fn select(
lesson_score: f32,
num_candidates: usize,
options: PassingScoreOptions,
options: &PassingScoreOptions,
) -> Vec<Candidate> {
let candidates = (0..num_candidates)
.map(|idx| candidate(idx as u32, 0.0, 1.0))
.collect::<Vec<_>>();
DepthFirstScheduler::select_candidates(candidates, lesson_score, &options)
DepthFirstScheduler::select_candidates(candidates, lesson_score, options)
}

/// Returns a candidate with the given exercise and lesson IDs.
Expand Down Expand Up @@ -1255,7 +1255,7 @@ mod test {
let candidates = select(
2.0,
5,
PassingScoreOptions {
&PassingScoreOptions {
min_score: 3.0,
min_fraction: 0.2,
min_avg_trials: 2.0,
Expand All @@ -1271,7 +1271,7 @@ mod test {
let candidates = select(
2.0,
5,
PassingScoreOptions {
&PassingScoreOptions {
min_score: 3.0,
min_fraction: 0.0,
min_avg_trials: 2.0,
Expand All @@ -1287,7 +1287,7 @@ mod test {
let candidates = select(
3.0,
2,
PassingScoreOptions {
&PassingScoreOptions {
min_score: 3.0,
min_fraction: 0.2,
min_avg_trials: 2.0,
Expand All @@ -1303,7 +1303,7 @@ mod test {
let candidates = select(
3.8,
10,
PassingScoreOptions {
&PassingScoreOptions {
min_score: 3.0,
min_fraction: 0.2,
min_avg_trials: 2.0,
Expand All @@ -1319,7 +1319,7 @@ mod test {
let candidates = select(
3.01,
2,
PassingScoreOptions {
&PassingScoreOptions {
min_score: 3.0,
min_fraction: 0.0,
min_avg_trials: 2.0,
Expand All @@ -1334,7 +1334,7 @@ mod test {
let candidates = select(
5.0,
11,
PassingScoreOptions {
&PassingScoreOptions {
min_score: 3.0,
min_fraction: 0.2,
min_avg_trials: 2.0,
Expand Down
4 changes: 2 additions & 2 deletions src/scheduler/filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -460,9 +460,9 @@ mod test {
assert!(final_candidates.len() < batch_size);

// Verify that remainders are not added when the batch is already full enough.
let mut final_candidates_full = (0..batch_size * 3 / 4 + 1)
let mut final_candidates_full = (0..=(batch_size * 3 / 4))
.map(|i| Candidate {
exercise_id: Ustr::from(&format!("exercise{}", i)),
exercise_id: Ustr::from(&format!("exercise{i}")),
..Default::default()
})
.collect::<Vec<_>>();
Expand Down
2 changes: 1 addition & 1 deletion src/scheduler/relearn_pile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ mod tests {
..SchedulerOptions::default()
});
for i in 0..20 {
let exercise_id = Ustr::from(&format!("exercise_{}", i));
let exercise_id = Ustr::from(&format!("exercise_{i}"));
relearn_pile.update(exercise_id, &MasteryScore::One);
}
let pile = relearn_pile.select_exercises_helper();
Expand Down
Loading
Loading