Skip to content

Commit

Permalink
test_parse_pitch
Browse files Browse the repository at this point in the history
  • Loading branch information
noahbaculi committed Jul 18, 2023
1 parent 3dd2506 commit 8bc05e4
Showing 1 changed file with 82 additions and 5 deletions.
87 changes: 82 additions & 5 deletions src/parser.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{arrangement::Line, pitch::Pitch};
use anyhow::{anyhow, Result};
use itertools::Itertools;
use regex::Regex;
use regex::RegexBuilder;
use std::{collections::HashSet, str::FromStr};
use strum_macros::EnumString;

Expand Down Expand Up @@ -59,10 +59,16 @@ fn parse_measure_break(input_line: &str) -> Option<Line<Vec<Pitch>>> {
None
}

/// Parses input line to extract valid musical pitches, returning an error if any part of the
/// input line cannot be parsed into a pitch.
fn parse_pitch(input_index: usize, input_line: &str) -> Result<Line<Vec<Pitch>>> {
let pattern = r"(?P<three_char_pitch>[a-gA-G][#|♯|b|♭][0-9])|(?P<two_char_pitch>[a-gA-G][0-9])";
let re = Regex::new(pattern).unwrap();
let (each_matched_indices, matched_pitches): (Vec<Vec<usize>>, Vec<Pitch>) = re
let pattern = r"(?P<three_char_pitch>[A-G][#|♯|b|♭][0-9])|(?P<two_char_pitch>[A-G][0-9])";
// let re = Regex::new(pattern);
let re = RegexBuilder::new(pattern)
.case_insensitive(true)
.build()
.expect("Regex pattern should be valid");
let (matched_index_ranges, matched_pitches): (Vec<Vec<usize>>, Vec<Pitch>) = re
.find_iter(input_line)
.filter_map(|regex_match| {
if let Ok(pitch) = Pitch::from_str(regex_match.as_str()) {
Expand All @@ -72,7 +78,7 @@ fn parse_pitch(input_index: usize, input_line: &str) -> Result<Line<Vec<Pitch>>>
})
.unzip();

let matched_indices: HashSet<usize> = each_matched_indices.into_iter().flatten().collect();
let matched_indices: HashSet<usize> = matched_index_ranges.into_iter().flatten().collect();
let input_indices: HashSet<usize> = (0..input_line.len()).collect();

let unmatched_indices: Vec<usize> = input_indices
Expand Down Expand Up @@ -104,6 +110,77 @@ fn parse_pitch(input_index: usize, input_line: &str) -> Result<Line<Vec<Pitch>>>

Ok(Line::Playable(matched_pitches))
}
#[cfg(test)]
mod test_parse_pitch {
use super::*;

#[test]
fn single_natural_pitch() -> Result<()> {
assert_eq!(parse_pitch(0, "A0")?, Line::Playable(vec![Pitch::A0]));
assert_eq!(parse_pitch(0, "E6")?, Line::Playable(vec![Pitch::E6]));
Ok(())
}
#[test]
fn single_sharp_pitch() {
assert_eq!(
parse_pitch(0, "D#2").unwrap(),
Line::Playable(vec![Pitch::DSharpEFlat2])
);
}
#[test]
fn single_flat_pitch() {
assert_eq!(
parse_pitch(0, "Db2").unwrap(),
Line::Playable(vec![Pitch::CSharpDFlat2])
);
assert_eq!(
parse_pitch(0, "Bb2").unwrap(),
Line::Playable(vec![Pitch::ASharpBFlat2])
);
}
#[test]
fn case_insensitivity() {
assert_eq!(
parse_pitch(0, "A3").unwrap(),
Line::Playable(vec![Pitch::A3])
);
assert_eq!(
parse_pitch(0, "a3").unwrap(),
Line::Playable(vec![Pitch::A3])
);
assert_eq!(
parse_pitch(0, "Bb2").unwrap(),
Line::Playable(vec![Pitch::ASharpBFlat2])
);
assert_eq!(
parse_pitch(0, "bB2").unwrap(),
Line::Playable(vec![Pitch::ASharpBFlat2])
);
assert_eq!(
parse_pitch(0, "bb2").unwrap(),
Line::Playable(vec![Pitch::ASharpBFlat2])
);
}
#[test]
fn multiple_pitches() {
assert_eq!(
parse_pitch(0, "C3G2A#1F8").unwrap(),
Line::Playable(vec![Pitch::C3, Pitch::G2, Pitch::ASharpBFlat1, Pitch::F8])
);
}
#[test]
fn invalid_typo() {
let error_msg = format!("{}", parse_pitch(12, "ZA2G#444B3").unwrap_err());
let expected_error_msg = "Input 'Z' on line 13 could not be parsed into a pitch.\nInput '44' on line 13 could not be parsed into a pitch.";
assert_eq!(error_msg, expected_error_msg);
}
#[test]
fn invalid_random() {
let error_msg = format!("{}", parse_pitch(0, "baS3Q-hNr").unwrap_err());
let expected_error_msg = "Input 'baS3Q-hNr' on line 1 could not be parsed into a pitch.";
assert_eq!(error_msg, expected_error_msg);
}
}

/// Returns a vector of consecutive slices of the input numbers.
///
Expand Down

0 comments on commit 8bc05e4

Please sign in to comment.