diff --git a/run_tests.lua b/run_tests.lua index a1437fe..04690fb 100644 --- a/run_tests.lua +++ b/run_tests.lua @@ -4,10 +4,12 @@ local luaunit = require "luaunit" local fennel = require "fennel" table.insert(package.loaders or package.searchers, fennel.searcher) +debug.traceback = fennel.traceback + local function get_lua_files(dir) local files = {} for file in lfs.dir(dir) do - if file:match "%.lua$" then + if file:match "%.fnl$" then table.insert(files, dir .. "/" .. file) end end @@ -18,7 +20,7 @@ local testdir = "tests" local testfiles = get_lua_files(testdir) for _, testfile in ipairs(testfiles) do - dofile(testfile) + fennel.dofile(testfile) end os.exit(luaunit.LuaUnit.run()) diff --git a/test-macros.fnl b/test-macros.fnl new file mode 100644 index 0000000..265908d --- /dev/null +++ b/test-macros.fnl @@ -0,0 +1,8 @@ +(local {: view} (require :fennel)) + +(fn parameterized [name params func] + (icollect [i p (ipairs params)] + `(tset _G ,(.. :test_ name "_" i) + #(,func ((or _G.unpack table.unpack) ,p))))) + +{: parameterized} diff --git a/tests/chords.fnl b/tests/chords.fnl new file mode 100644 index 0000000..102c1c1 --- /dev/null +++ b/tests/chords.fnl @@ -0,0 +1,218 @@ +(local {: assertEquals} (require :luaunit)) + +(local {: Chord : Interval} (require :modest)) +(local {: map} (require :modest.utils)) + +(import-macros {: parameterized} :test-macros) + +;; This file includes test cases adapted from the test suites of teoria, sharp11 and mingus libraries. +;; https://github.com/jsrmath/sharp11/blob/master/test/chord.test.js +;; https://github.com/saebekassebil/teoria/blob/master/test/chords.js +;; https://github.com/bspaans/python-mingus/blob/master/tests/unit/core/test_chords.py + +(fn test-notes [chord notes octave] + (assertEquals (map tostring + (: (Chord.fromstring chord) :notes octave)) + notes (.. "Mismatched notes for chord: " chord))) + +(parameterized :symbol_aliases + [["C∆7" [:C :E :G :B]] + [:Cmin [:C "E♭" :G]] + ["CminMaj9#11" [:C "E♭" :G :B :D "F♯"]] + ["Cmin(maj)7" [:C "E♭" :G :B]] + [:Co [:C "E♭" "G♭"]]] test-notes) + +(parameterized :mingus_testcases + [[:Amin [:A :C :E]] + [:Am [:A :C :E]] + [:A- [:A :C :E]] + [:Amaj [:A "C♯" :E]] + [:AM [:A "C♯" :E]] + [:A [:A "C♯" :E]] + [:Adim [:A :C "E♭"]] + [:Aaug [:A "C♯" "E♯"]] + [:A+ [:A "C♯" "E♯"]] + ["A7#5" [:A "C♯" "E♯" :G]] + [:Aaug7 [:A "C♯" "E♯" :G]] + [:Amin7 [:A :C :E :G]] + [:Am7 [:A :C :E :G]] + [:Ami7 [:A :C :E :G]] + [:A-7 [:A :C :E :G]] + [:Amaj7 [:A "C♯" :E "G♯"]] + [:AM7 [:A "C♯" :E "G♯"]] + [:Ama7 [:A "C♯" :E "G♯"]] + [:A7 [:A "C♯" :E :G]] + [:Amin7b5 [:A :C "E♭" :G]] + [:Am7b5 [:A :C "E♭" :G]] + [:Adim7 [:A :C "E♭" "G♭"]] + [:Am/M7 [:A :C :E "G♯"]] + [:Am/ma7 [:A :C :E "G♯"]] + [:AmM7 [:A :C :E "G♯"]] + [:Am/maj7 [:A :C :E "G♯"]] + [:Amin6 [:A :C :E "F♯"]] + [:Am6 [:A :C :E "F♯"]] + [:Amaj6 [:A "C♯" :E "F♯"]] + [:A6 [:A "C♯" :E "F♯"]] + [:A6/9 [:A "C♯" :E "F♯" :B]] + [:A/G [:G :A "C♯" :E]] + [:Amin/G [:G :A :C :E]] + [:Am/M7/G [:G :A :C :E "G♯"]] + [:Asus2 [:A :B :E]] + [:Asus4 [:A :D :E]] + [:A7sus4 [:A :D :E :G]] + [:Asus [:A :D :E]] + [:Asus4b9 [:A :D :E "B♭"]] + [:Asusb9 [:A :D :E "B♭"]] + [:Amaj9 [:A "C♯" :E "G♯" :B]] + [:A9 [:A "C♯" :E :G :B]] + [:Amin9 [:A :C :E :G :B]] + [:Am9 [:A :C :E :G :B]] + ["A7#11" [:A "C♯" :E :G "D♯"]] + [:A7b9 [:A "C♯" :E :G "B♭"]] + ["A7#9" [:A "C♯" :E :G "B♯"]] + [:A7b5 [:A "C♯" "E♭" :G]]] test-notes) + +(parameterized :basic_chords + [[:C [:C :E :G]] + [:Cm [:C "E♭" :G]] + [:C6 [:C :E :G :A]] + [:C7 [:C :E :G "B♭"]] + [:C9 [:C :E :G "B♭" :D]] + [:Cm7 [:C "E♭" :G "B♭"]] + [:CM7 [:C :E :G :B]] + [:CM9 [:C :E :G :B :D]] + [:CmM7 [:C "E♭" :G :B]] + [:C+ [:C :E "G♯"]] + [:C+7 [:C :E "G♯" "B♭"]] + [:C+M7 [:C :E "G♯" :B]] + [:Cdim [:C "E♭" "G♭"]] + [:Cdim7 [:C "E♭" "G♭" "B𝄫"]] + ["Cø" [:C "E♭" "G♭" "B♭"]] + ["Cø7" [:C "E♭" "G♭" "B♭"]] + [:Csus4 [:C :F :G]] + [:Csus2 [:C :D :G]] + [:C6/9 [:C :E :G :A :D]] + [:Cm6/9 [:C "E♭" :G :A :D]] + [:C/Bb ["B♭" :C :E :G]]] + test-notes) + +(parameterized :chords_with_alterations + [[:Cm7b5 [:C "E♭" "G♭" "B♭"]] + [:C7b9 [:C :E :G "B♭" "D♭"]] + ["C7♯9" [:C :E :G "B♭" "D♯"]] + ["C7♯11" [:C :E :G "B♭" "F♯"]] + ["C13♯11" [:C :E :G "B♭" :D "F♯" :A]] + ["C13#9b5" [:C :E "G♭" "B♭" "D♯" :F :A]]] + test-notes) + +(parameterized :add_chords + [[:Cadd9 [:C :E :G :D]] + [:Cadd11 [:C :E :G :F]] + [:Cadd13 [:C :E :G :A]] + [:C7add9 [:C :E :G "B♭" :D]] + [:C7add11 [:C :E :G "B♭" :F]] + [:C7add13 [:C :E :G "B♭" :A]] + [:C9add11 [:C :E :G "B♭" :D :F]] + [:C9add13 [:C :E :G "B♭" :D :A]] + [:C11add13 [:C :E :G "B♭" :D :F :A]]] + test-notes) + +(parameterized :chords_not_in_c + [[:Emaj7 [:E "G♯" :B "D♯"]] + [:A+ [:A "C♯" "E♯"]] + [:Bb+ ["B♭" :D "F♯"]] + ["F#maj7" ["F♯" "A♯" "C♯" "E♯"]] + [:Bmaj7 [:B "D♯" "F♯" "A♯"]] + ["B#maj7" ["B♯" "D𝄪" "F𝄪" "A𝄪"]] + [:Eb7b5 ["E♭" :G "B𝄫" "D♭"]] + ["D#7b5" ["D♯" "F𝄪" :A "C♯"]] + [:Eb9 ["E♭" :G "B♭" "D♭" :F]] + ["G#7(#9)" ["G♯" "B♯" "D♯" "F♯" "A𝄪"]] + ["Ab7(b9)" ["A♭" :C "E♭" "G♭" "B𝄫"]] + ["F#11(#11)" ["F♯" "A♯" "C♯" :E "G♯" "B♯"]] + [:Ab13 ["A♭" :C "E♭" "G♭" "B♭" "D♭" :F]] + [:Dmb6 [:D :F :A "B♭"]] + ["F#m11(b5b9)" ["F♯" :A :C :E :G :B]] + [:A7/G [:G :A "C♯" :E :G]] + ["G/F#" ["F♯" :G :B :D]] + ["A#6" ["A♯" "C𝄪" "E♯" "F𝄪"]] + [:Bb6 ["B♭" :D :F :G]] + [:Am6 [:A :C :E "F♯"]] + ["D(#6)" [:D "F♯" :A "B♯"]] + [:Eo [:E :G "B♭"]] + ["Eø" [:E :G "B♭" :D]] + [:Do [:D :F "A♭"]] + ["Dø" [:D :F "A♭" :C]] + [:Fo7 [:F "A♭" "C♭" "E𝄫"]] + ["G#ø7" ["G♯" :B :D "F♯"]] + [:Bmin11 [:B :D "F♯" :A "C♯" :E]] + [:E5 [:E :B]] + [:A5 [:A :E]] + ["D13#5b9" [:D "F♯" "A♯" :C "E♭" :G :B]] + [:Ab6/9 ["A♭" :C "E♭" :F "B♭"]] + [:DM [:D "F♯" :A]] + ["EM#5" [:E "G♯" "B♯"]] + [:FM9 [:F :A :C :E :G]]] test-notes) + +(parameterized :octave_aware + [[:C [:C4 :E4 :G4] 4] + [:C9 [:C4 :E4 :G4 "B♭4" :D5] 4] + [:C/Bb ["B♭3" :C4 :E4 :G4] 4]] test-notes) + +(parameterized + :numeric [[:C [0 4 7]] + [:Cm [0 3 7]] + [:C6 [0 4 7 9]] + [:C7 [0 4 7 10]] + [:Emaj7 [4 8 11 15]] + [:A+ [9 13 17]] + [:Bb+ [10 14 18]] + [:C/Bb [(- 2) 0 4 7]] + [:Cdim [0 3 6]] + [:Cdim7 [0 3 6 9]]] + (fn [chord numeric] + (assertEquals (: (Chord.fromstring chord) :numeric) numeric + (.. "Mismatched numeric notation for chord: " chord)))) + +(parameterized + :tostring [["Cø" "C7(b5)"] + [:Ab6/9] + [:C6] + ["D13#5b9" "D13(#5b9)"] + [:C/Bb] + [:CM7] + [:CmM7] + [:Eaug] + [:F5] + ["F(#11)"]] + (fn [chord to_string] + (let [parsed-chord (Chord.fromstring chord)] + (assertEquals (parsed-chord:toascii) + (or to_string chord) + (.. "Mismatched string for chord: " chord))))) + +(parameterized + :transposition [[:C/Bb :E/D :M3] + [:C7 :G7 :P12] + [:E7 :G7 :m3] + [:E7 :Eb7 :d8]] + (fn [chord transposed interval] + (local parsed-interval (Interval.fromstring interval)) + + (fn get-transpose-result [i] + (: (: (Chord.fromstring chord) :transpose i) :toascii)) + + (fn get-transpose-down-result [i] + (: (: (Chord.fromstring transposed) :transpose_down i) + :toascii)) + + (assertEquals (get-transpose-result parsed-interval) + (get-transpose-result interval) + transposed + (.. "Mismatched transposition result for chord: " + chord)) + (assertEquals (get-transpose-down-result parsed-interval) + (get-transpose-down-result interval) + chord + (.. "Mismatched transpose_down result for chord: " + chord)))) diff --git a/tests/chords.lua b/tests/chords.lua deleted file mode 100644 index 7803e24..0000000 --- a/tests/chords.lua +++ /dev/null @@ -1,210 +0,0 @@ -local luaunit = require "luaunit" -local lib = require "modest" - -local u = require "modest.utils" - -local unpack = unpack or table.unpack - --- most of test cases in this file are based on the test suites of teoria and sharp11 libraries --- https://github.com/jsrmath/sharp11/blob/master/test/chord.test.js --- https://github.com/saebekassebil/teoria/blob/master/test/chords.js - -local function test_chords(chords, octave) - for _, test in ipairs(chords) do - local parsed_chord = lib.Chord.fromstring(test.chord) - - luaunit.assertEquals( - u.map(tostring, parsed_chord:notes(octave)), - test.letters, - "Mismatched notes for chord: " .. test.chord - ) - - if test.numeric then - luaunit.assertEquals( - parsed_chord:numeric(), - test.numeric, - "Mismatched numeric notation for chord: " .. test.chord - ) - end - end -end - -function test_chord_symbol_aliases() - local chords = { - { chord = "C∆7", letters = { "C", "E", "G", "B" } }, - { chord = "Cmin", letters = { "C", "E♭", "G" } }, - { chord = "CminMaj9#11", letters = { "C", "E♭", "G", "B", "D", "F♯" } }, - { chord = "Cmin(maj)7", letters = { "C", "E♭", "G", "B" } }, - { chord = "Co", letters = { "C", "E♭", "G♭" } }, - } - - test_chords(chords) -end - -function test_basic_chords() - local chords = { - { chord = "C", letters = { "C", "E", "G" }, numeric = { 0, 4, 7 } }, - { chord = "Cm", letters = { "C", "E♭", "G" }, numeric = { 0, 3, 7 } }, - { chord = "C6", letters = { "C", "E", "G", "A" }, numeric = { 0, 4, 7, 9 } }, - { chord = "C7", letters = { "C", "E", "G", "B♭" }, numeric = { 0, 4, 7, 10 } }, - { chord = "C9", letters = { "C", "E", "G", "B♭", "D" } }, - { chord = "Cm7", letters = { "C", "E♭", "G", "B♭" } }, - { chord = "CM7", letters = { "C", "E", "G", "B" } }, - { chord = "CM9", letters = { "C", "E", "G", "B", "D" } }, - { chord = "CmM7", letters = { "C", "E♭", "G", "B" } }, - { chord = "C+", letters = { "C", "E", "G♯" } }, - { chord = "C+7", letters = { "C", "E", "G♯", "B♭" } }, - { chord = "C+M7", letters = { "C", "E", "G♯", "B" } }, - { chord = "Cdim", letters = { "C", "E♭", "G♭" }, numeric = { 0, 3, 6 } }, - { chord = "Cdim7", letters = { "C", "E♭", "G♭", "B𝄫" }, numeric = { 0, 3, 6, 9 } }, - { chord = "Cø", letters = { "C", "E♭", "G♭", "B♭" } }, - { chord = "Cø7", letters = { "C", "E♭", "G♭", "B♭" } }, - { chord = "Csus4", letters = { "C", "F", "G" } }, - { chord = "Csus2", letters = { "C", "D", "G" } }, - { chord = "C6/9", letters = { "C", "E", "G", "A", "D" } }, - { chord = "Cm6/9", letters = { "C", "E♭", "G", "A", "D" } }, - { chord = "C/Bb", letters = { "B♭", "C", "E", "G" }, numeric = { -2, 0, 4, 7 } }, - } - - test_chords(chords) -end - -function test_chords_with_alterations() - local chords = { - { chord = "Cm7b5", letters = { "C", "E♭", "G♭", "B♭" } }, - { chord = "C7b9", letters = { "C", "E", "G", "B♭", "D♭" } }, - { chord = "C7♯9", letters = { "C", "E", "G", "B♭", "D♯" } }, - { chord = "C7♯11", letters = { "C", "E", "G", "B♭", "F♯" } }, - { chord = "C13♯11", letters = { "C", "E", "G", "B♭", "D", "F♯", "A" } }, - { chord = "C13#9b5", letters = { "C", "E", "G♭", "B♭", "D♯", "F", "A" } }, - } - - test_chords(chords) -end - -function test_add_chords() - local chords = { - { chord = "Cadd9", letters = { "C", "E", "G", "D" } }, - { chord = "Cadd11", letters = { "C", "E", "G", "F" } }, - { chord = "Cadd13", letters = { "C", "E", "G", "A" } }, - { chord = "C7add9", letters = { "C", "E", "G", "B♭", "D" } }, - { chord = "C7add11", letters = { "C", "E", "G", "B♭", "F" } }, - { chord = "C7add13", letters = { "C", "E", "G", "B♭", "A" } }, - { chord = "C9add11", letters = { "C", "E", "G", "B♭", "D", "F" } }, - { chord = "C9add13", letters = { "C", "E", "G", "B♭", "D", "A" } }, - { chord = "C11add13", letters = { "C", "E", "G", "B♭", "D", "F", "A" } }, - } - - test_chords(chords) -end - -function test_chords_not_in_c() - local chords = { - { chord = "Emaj7", letters = { "E", "G♯", "B", "D♯" }, numeric = { 4, 8, 11, 15 } }, - { chord = "A+", letters = { "A", "C♯", "E♯" }, numeric = { 9, 13, 17 } }, - { chord = "Bb+", letters = { "B♭", "D", "F♯" }, numeric = { 10, 14, 18 } }, - { chord = "F#maj7", letters = { "F♯", "A♯", "C♯", "E♯" } }, - { chord = "Bmaj7", letters = { "B", "D♯", "F♯", "A♯" } }, - { chord = "B#maj7", letters = { "B♯", "D𝄪", "F𝄪", "A𝄪" } }, - { chord = "Eb7b5", letters = { "E♭", "G", "B𝄫", "D♭" } }, - { chord = "D#7b5", letters = { "D♯", "F𝄪", "A", "C♯" } }, - { chord = "Eb9", letters = { "E♭", "G", "B♭", "D♭", "F" } }, - { chord = "G#7(#9)", letters = { "G♯", "B♯", "D♯", "F♯", "A𝄪" } }, - { chord = "Ab7(b9)", letters = { "A♭", "C", "E♭", "G♭", "B𝄫" } }, - { chord = "F#11(#11)", letters = { "F♯", "A♯", "C♯", "E", "G♯", "B♯" } }, - { chord = "Ab13", letters = { "A♭", "C", "E♭", "G♭", "B♭", "D♭", "F" } }, - { chord = "Dmb6", letters = { "D", "F", "A", "B♭" } }, - { chord = "F#m11(b5b9)", letters = { "F♯", "A", "C", "E", "G", "B" } }, - { chord = "A7/G", letters = { "G", "A", "C♯", "E", "G" } }, - { chord = "G/F#", letters = { "F♯", "G", "B", "D" } }, - { chord = "A#6", letters = { "A♯", "C𝄪", "E♯", "F𝄪" } }, - { chord = "Bb6", letters = { "B♭", "D", "F", "G" } }, - { chord = "Am6", letters = { "A", "C", "E", "F♯" } }, - { chord = "D(#6)", letters = { "D", "F♯", "A", "B♯" } }, - { chord = "Eo", letters = { "E", "G", "B♭" } }, - { chord = "Eø", letters = { "E", "G", "B♭", "D" } }, - { chord = "Do", letters = { "D", "F", "A♭" } }, - { chord = "Dø", letters = { "D", "F", "A♭", "C" } }, - { chord = "Fo7", letters = { "F", "A♭", "C♭", "E𝄫" } }, - { chord = "G#ø7", letters = { "G♯", "B", "D", "F♯" } }, - { chord = "Bmin11", letters = { "B", "D", "F♯", "A", "C♯", "E" } }, - { chord = "E5", letters = { "E", "B" } }, - { chord = "A5", letters = { "A", "E" } }, - { chord = "D13#5b9", letters = { "D", "F♯", "A♯", "C", "E♭", "G", "B" } }, - { chord = "Ab6/9", letters = { "A♭", "C", "E♭", "F", "B♭" } }, - { chord = "DM", letters = { "D", "F♯", "A" } }, - { chord = "EM#5", letters = { "E", "G♯", "B♯" } }, - { chord = "FM9", letters = { "F", "A", "C", "E", "G" } }, - } - - test_chords(chords) -end - -function test_octave_aware() - local chords = { - { chord = "C", letters = { "C4", "E4", "G4" } }, - { chord = "C9", letters = { "C4", "E4", "G4", "B♭4", "D5" } }, - { chord = "C/Bb", letters = { "B♭3", "C4", "E4", "G4" } }, - } - - test_chords(chords, 4) -end - -function test_chord_tostring() - local chords = { - { chord = "Cø", to_string = "C7(b5)" }, - { chord = "Ab6/9" }, - { chord = "C6" }, - { chord = "D13#5b9", to_string = "D13(#5b9)" }, - { chord = "C/Bb" }, - { chord = "CM7" }, - { chord = "CmM7" }, - { chord = "Eaug" }, - { chord = "F5" }, - { chord = "F(#11)" }, - } - - for _, test in ipairs(chords) do - local parsed_chord = lib.Chord.fromstring(test.chord) - - luaunit.assertEquals( - parsed_chord:toascii(), - test.to_string or test.chord, - "Mismatched string for chord: " .. test.chord - ) - end -end - -function test_chord_transposition() - local chords = { - { "C/Bb", "E/D", "M3" }, - { "C7", "G7", "P12" }, - { "E7", "G7", "m3" }, - { "E7", "Eb7", "d8" }, - } - - for _, test in ipairs(chords) do - local chord, transposed_chord, interval = unpack(test) - local parsed_interval = lib.Interval.fromstring(interval) - - local get_transpose_result = function(i) return lib.Chord.fromstring(chord):transpose(i):toascii() end - - local get_transpose_down_result = function(i) - return lib.Chord.fromstring(transposed_chord):transpose_down(i):toascii() - end - - luaunit.assertEquals( - get_transpose_result(parsed_interval), - get_transpose_result(interval), - transposed_chord, - "Mismatched transposition result for chord: " .. chord - ) - - luaunit.assertEquals( - get_transpose_down_result(parsed_interval), - get_transpose_down_result(interval), - chord, - "Mismatched transpose_down result for chord: " .. chord - ) - end -end diff --git a/tests/intervals.fnl b/tests/intervals.fnl new file mode 100644 index 0000000..ecda86c --- /dev/null +++ b/tests/intervals.fnl @@ -0,0 +1,79 @@ +(local {: assertEquals : assertError} (require :luaunit)) + +(local {: Note : Interval} (require :modest)) + +(import-macros {: parameterized} :test-macros) + +(fn assert-intervals [note1 note2 interval semitones transposition] + (local transposition (or transposition note2)) + (local parsed-interval (Interval.fromstring interval)) + (assertEquals (: (Interval.identify note1 note2) :tostring) + interval + "Mismatched interval name") + (assertEquals (: (Interval.identify note1 note2) :semitones) + semitones + "Mismatched semitones") + (assertEquals (: (Interval.identify (note1:toascii) (note2:toascii)) :tostring) + interval + "Can't identify interval by strings") + (assertEquals (note1:transpose parsed-interval) + transposition + "Mismatched transposition result") + (assertEquals (note1:transpose interval) + transposition + "Can't tranpose by string") + (assertEquals (transposition:transpose_down parsed-interval) + note1 + "Mismatched result for transpose_down") + (assertEquals (transposition:transpose_down interval) + note1 + "Can't transpose down by string")) + +(parameterized :across_octave + [[(Note.new :C 0 0) (Note.new :C 0 1) :P8 12] + [(Note.new :C 0 0) (Note.new :D 0 1) :M9 14] + [(Note.new :C 0 0) (Note.new :D 1 1) :A9 15] + [(Note.new :B 0 0) (Note.new :C 1 1) :M2 2] + [(Note.new :D 0 0) (Note.new :C 0 1) :m7 10] + [(Note.new :C 0 0) (Note.new :C 0 2) :P15 24] + [(Note.new :C 0 0) (Note.new :D 0 2) :M16 26] + [(Note.new :D 0 0) (Note.new :C 0 2) :m14 22] + [(Note.new :B 0 0) (Note.new :C 1 2) :M9 14] + [(Note.new :C 0 4) (Note.new :C 1 5) :A8 13] + [(Note.new :C 0 4) (Note.new :C (- 1) 5) :d8 11] + [(Note.new :C 0 4) (Note.new :C (- 1) 6) :d15 23]] + assert-intervals) + +(parameterized :octave_unaware + [[(Note.new :C 0 nil) (Note.new :C 0 nil) :P1 0] + [(Note.new :C 0 nil) (Note.new :D 0 nil) :M2 2] + [(Note.new :B (- 1) nil) (Note.new :C 0 nil) :M2 2] + [(Note.new :D 0 nil) (Note.new :C 0 nil) :m7 10] + [(Note.new :C 0 nil) (Note.new :E (- 1) nil) :m3 3] + [(Note.new :C 0 nil) (Note.new :C (- 1) nil) :d8 11] + [(Note.new :D 0 nil) (Note.new :C 0 4) :m7 10 (Note.new :C 0 nil)] + [(Note.new :D 0 4) (Note.new :C 0 nil) :m7 10 (Note.new :C 0 5)]] + assert-intervals) + +(parameterized :unison + [[(Note.new :C 0 0) (Note.new :C 0 0) :P1 0] + [(Note.new :D 1 0) (Note.new :D 1 0) :P1 0] + [(Note.new :B 1 0) (Note.new :C 0 1) :d2 0]] + assert-intervals) + +(parameterized :interval_to_semitones + [[:A4 6] + [:A7 12] + [:M10 16] + [:M3 4] + [:P11 17] + [:P4 5] + [:d2 0] + [:d3 2]] + (fn [interval semitones] + (assertEquals (: (Interval.fromstring interval) :semitones) semitones + (.. "Mismatched semitones amount for interval " interval)))) + +(parameterized :invalid_intervals + [[:d1] [:M5] [:P3]] + (partial assertError Interval.fromstring)) diff --git a/tests/intervals.lua b/tests/intervals.lua deleted file mode 100644 index 066ae15..0000000 --- a/tests/intervals.lua +++ /dev/null @@ -1,124 +0,0 @@ -local luaunit = require "luaunit" -local lib = require "modest" - -local Note = lib.Note -local Interval = lib.Interval - -local unpack = unpack or table.unpack - -local function assert_intervals(test_cases) - for _, test_case in ipairs(test_cases) do - local note1, note2, interval, semitones = unpack(test_case) - local transposition = test_case.transposition or note2 - - luaunit.assertEquals( - Interval.identify(note1, note2):tostring(), - interval, - "Mismatched interval name for notes " .. tostring(note1) .. " " .. tostring(note2) - ) - - luaunit.assertEquals( - Interval.identify(note1, note2):semitones(), - semitones, - "Mismatched semitones for notes " .. tostring(note1) .. " " .. tostring(note2) - ) - - luaunit.assertEquals( - Interval.identify(note1:toascii(), note2:toascii()):tostring(), - interval, - "Can't identify by strings" .. tostring(note1) .. " " .. tostring(note2) - ) - - luaunit.assertEquals( - note1:transpose(Interval.fromstring(interval)), - transposition, - "Mismatched transposition result " .. tostring(note1) .. " " .. tostring(note2) - ) - - luaunit.assertEquals( - note1:transpose(interval), - transposition, - "Can't tranpose by string" .. tostring(note1) .. " " .. tostring(note2) - ) - - luaunit.assertEquals( - transposition:transpose_down(Interval.fromstring(interval)), - note1, - "Mismatched result for transpose_down " .. tostring(transposition) .. " " .. interval - ) - - luaunit.assertEquals( - transposition:transpose_down(interval), - note1, - "Can't transpose down by string " .. tostring(transposition) .. " " .. interval - ) - end -end - -local across_octave = { - { Note.new("C", 0, 0), Note.new("C", 0, 1), "P8", 12 }, - { Note.new("C", 0, 0), Note.new("D", 0, 1), "M9", 14 }, - { Note.new("C", 0, 0), Note.new("D", 1, 1), "A9", 15 }, - { Note.new("B", 0, 0), Note.new("C", 1, 1), "M2", 2 }, - { Note.new("D", 0, 0), Note.new("C", 0, 1), "m7", 10 }, - { Note.new("C", 0, 0), Note.new("C", 0, 2), "P15", 24 }, - { Note.new("C", 0, 0), Note.new("D", 0, 2), "M16", 26 }, - { Note.new("D", 0, 0), Note.new("C", 0, 2), "m14", 22 }, - { Note.new("B", 0, 0), Note.new("C", 1, 2), "M9", 14 }, - { Note.new("C", 0, 4), Note.new("C", 1, 5), "A8", 13 }, - { Note.new("C", 0, 4), Note.new("C", -1, 5), "d8", 11 }, - { Note.new("C", 0, 4), Note.new("C", -1, 6), "d15", 23 }, -} - -function test_across_octaves() assert_intervals(across_octave) end - -local octave_unaware = { - { Note.new("C", 0, nil), Note.new("C", 0, nil), "P1", 0 }, - { Note.new("C", 0, nil), Note.new("D", 0, nil), "M2", 2 }, - { Note.new("B", -1, nil), Note.new("C", 0, nil), "M2", 2 }, - { Note.new("D", 0, nil), Note.new("C", 0, nil), "m7", 10 }, - { Note.new("C", 0, nil), Note.new("E", -1, nil), "m3", 3 }, - { Note.new("C", 0, nil), Note.new("C", -1, nil), "d8", 11 }, - { Note.new("D", 0, nil), Note.new("C", 0, 4), "m7", 10, transposition = Note.new("C", 0, nil) }, - { Note.new("D", 0, 4), Note.new("C", 0, nil), "m7", 10, transposition = Note.new("C", 0, 5) }, -} - -function test_octave_unaware() assert_intervals(octave_unaware) end - -local unison = { - { Note.new("C", 0, 0), Note.new("C", 0, 0), "P1", 0 }, - { Note.new("D", 1, 0), Note.new("D", 1, 0), "P1", 0 }, - { Note.new("B", 1, 0), Note.new("C", 0, 1), "d2", 0 }, -} - -function test_unisons() assert_intervals(unison) end - -local interval_to_semitones = { - M3 = 4, - P4 = 5, - M10 = 16, - P11 = 17, - d3 = 2, - A4 = 6, - d2 = 0, - A7 = 12, -} - -function test_interval_to_semitones() - for interval, expected_semitones in pairs(interval_to_semitones) do - luaunit.assertEquals( - Interval.fromstring(interval):semitones(), - expected_semitones, - "Mismatched semitones amount for interval " .. interval - ) - end -end - -local invalid_intervals = { "d1", "M5", "P3" } - -function test_invalid_intervals() - for _, inv_int in pairs(invalid_intervals) do - local _, err = pcall(function() Interval.fromstring(inv_int) end) - luaunit.assertNotEquals(err, nil, "Interval " .. inv_int .. " validated") - end -end diff --git a/tests/notes.fnl b/tests/notes.fnl new file mode 100644 index 0000000..d4acba1 --- /dev/null +++ b/tests/notes.fnl @@ -0,0 +1,15 @@ +(local {: assertEquals} (require :luaunit)) + +(local {: Note} (require :modest)) + +(import-macros {: parameterized} :test-macros) + +(parameterized :note_to_pitchclass + [[(Note.new :C 0 0) 0] + [(Note.new :C 0 5) 0] + [(Note.new :D 1 0) 3] + [(Note.new :B (- 1) 0) 10] + [(Note.new :B 1 0) 0]] + (fn [note integer] + (assertEquals (note:pitch_class) integer))) + diff --git a/tests/notes.lua b/tests/notes.lua deleted file mode 100644 index 212fd21..0000000 --- a/tests/notes.lua +++ /dev/null @@ -1,21 +0,0 @@ -local luaunit = require "luaunit" -local lib = require "modest" - -local Note = lib.Note - -local unpack = unpack or table.unpack - -local note_to_pitchclass = { - { Note.new("C", 0, 0), 0 }, - { Note.new("C", 0, 5), 0 }, - { Note.new("D", 1, 0), 3 }, - { Note.new("B", -1, 0), 10 }, - { Note.new("B", 1, 0), 0 }, -} - -function test_note_pitchclass() - for _, tbl in ipairs(note_to_pitchclass) do - local note, integer = unpack(tbl) - luaunit.assertEquals(note:pitch_class(), integer) - end -end