use cagire::forth::Value; use super::harness::{expect_error, expect_int, expect_stack}; fn ints(vals: &[i64]) -> Vec { vals.iter().map(|&v| Value::Int(v, None)).collect() } // Inversions #[test] fn invert_major_triad() { expect_stack("c4 maj inv", &ints(&[64, 67, 72])); } #[test] fn invert_twice() { expect_stack("c4 maj inv inv", &ints(&[67, 72, 76])); } #[test] fn down_invert_major_triad() { expect_stack("c4 maj dinv", &ints(&[55, 60, 64])); } #[test] fn down_invert_min7() { expect_stack("c4 min7 dinv", &ints(&[58, 60, 63, 67])); } #[test] fn invert_min7() { expect_stack("c4 min7 inv", &ints(&[63, 67, 70, 72])); } // Voicings #[test] fn drop2_maj7() { // c4 maj7 = [60, 64, 67, 71], 2nd from top = 67, drop to 55 expect_stack("c4 maj7 drop2", &ints(&[55, 60, 64, 71])); } #[test] fn drop3_maj7() { // c4 maj7 = [60, 64, 67, 71], 3rd from top = 64, drop to 52 expect_stack("c4 maj7 drop3", &ints(&[52, 60, 67, 71])); } // Key #[test] fn key_sets_tonal_center() { expect_int("g3 key! 0 major", 55); } #[test] fn key_with_degree() { // G3=55, degree 4 of major = semitone 7, so 55+7=62 expect_int("g3 key! 4 major", 62); } #[test] fn key_default_is_c4() { expect_int("0 major", 60); } #[test] fn key_a3_minor() { expect_int("a3 key! 0 minor", 57); } // Diatonic triads #[test] fn diatonic_triad_degree_0() { // C major: degrees 0,2,4 = C,E,G = 60,64,67 expect_stack("0 major triad", &ints(&[60, 64, 67])); } #[test] fn diatonic_triad_degree_1() { // D minor: degrees 1,3,5 = D,F,A = 62,65,69 expect_stack("1 major triad", &ints(&[62, 65, 69])); } #[test] fn diatonic_triad_degree_3() { // F major: degrees 3,5,7(=0+12) = F,A,C = 65,69,72 expect_stack("3 major triad", &ints(&[65, 69, 72])); } #[test] fn diatonic_triad_degree_4() { // G major: degrees 4,6,8(=1+12) = G,B,D = 67,71,74 expect_stack("4 major triad", &ints(&[67, 71, 74])); } // Diatonic sevenths #[test] fn diatonic_seventh_degree_0() { // C major7: degrees 0,2,4,6 = C,E,G,B = 60,64,67,71 expect_stack("0 major seventh", &ints(&[60, 64, 67, 71])); } #[test] fn diatonic_seventh_degree_1() { // D minor7: degrees 1,3,5,7(=0+12) = D,F,A,C = 62,65,69,72 expect_stack("1 major seventh", &ints(&[62, 65, 69, 72])); } #[test] fn diatonic_seventh_degree_4() { // G dom7: degrees 4,6,8(=1+12),10(=3+12) = G,B,D,F = 67,71,74,77 expect_stack("4 major seventh", &ints(&[67, 71, 74, 77])); } // Combined #[test] fn key_with_diatonic_triad() { // G3=55 key, degree 0 major triad = G,B,D = 55,59,62 expect_stack("g3 key! 0 major triad", &ints(&[55, 59, 62])); } #[test] fn key_with_triad_inv() { // C4 key, degree 0 minor triad = C,Eb,G = 60,63,67, then inv = Eb,G,C+12 = 63,67,72 expect_stack("0 minor triad inv", &ints(&[63, 67, 72])); } #[test] fn key_degree_4_triad_in_g() { // G3=55, degree 4 of major = notes at degrees 4,6,8(=1+12) // major pattern: [0,2,4,5,7,9,11] // degree 4 -> semitone 7, degree 6 -> semitone 11, degree 8(=1+12) -> 12+2=14 // 55+7=62, 55+11=66, 55+14=69 -> D, F#, A expect_stack("g3 key! 4 major triad", &ints(&[62, 66, 69])); } // Backwards compatibility #[test] fn scale_degree_still_works() { expect_int("0 major", 60); expect_int("7 major", 72); } #[test] fn chords_still_work() { expect_stack("c4 maj", &ints(&[60, 64, 67])); expect_stack("c4 min7", &ints(&[60, 63, 67, 70])); } // Transpose #[test] fn transpose_major_triad() { expect_stack("c4 maj 3 tp", &ints(&[63, 67, 70])); } #[test] fn transpose_down() { expect_stack("c4 maj -2 tp", &ints(&[58, 62, 65])); } #[test] fn transpose_zero() { expect_stack("c4 maj 0 tp", &ints(&[60, 64, 67])); } #[test] fn transpose_single_note() { expect_int("60 7 tp", 67); } #[test] fn transpose_octave() { expect_stack("c4 min7 12 tp", &ints(&[72, 75, 79, 82])); } // Error cases #[test] fn triad_without_scale_errors() { expect_error("0 triad", "unknown word"); } #[test] fn seventh_without_scale_errors() { expect_error("0 seventh", "unknown word"); }