def test_trigger_on_sequence(self): mock = unittest.mock.Mock() seq1 = Sequence(Note(1), Note(2), Note(3)) self.assertFalse(self.MEL.handlers) # Empty check self.MEL.add_handler(mock, seq1) press_sequence(self.loopback, seq1) mock.assert_called()
def test_init_errors(self): pass with self.assertRaises(ValueError): notes = (Note(1), Note(2), Note(3)) for _ in range(NoteList.max_depth + 1): notes = [notes] NoteList(notes) with self.assertRaises( TypeError): # Expected iterable of Notes or NoteList NoteList(object())
def test_from_ident(self): c1 = Chord(Note(69), Note(73), Note(76)) c2 = Chord.from_ident("A4 Major") self.assertEqual(c1, c2) with self.assertRaises(AssertionError): Chord.from_ident("") with self.assertRaises(ValueError): Chord.from_ident("test test") with self.assertRaises( ValueError ): # This is a different error message in _get_semitones_from_chord_name Chord.from_ident("A4 test")
def test_decorator_chord(self): mock = unittest.mock.Mock() self.assertFalse(self.MEL.handlers) # Empty c1 = Chord(Note(5), Note(10), Note(15)) @self.MEL.on_notes(c1) def sub(): mock() self.assertTrue(self.MEL.handlers) # Not empty press_chord(self.loopback, c1) mock.assert_called()
def test_decorator_sequence(self): mock = unittest.mock.Mock() self.assertFalse(self.MEL.handlers) # Empty seq1 = Sequence(Note(5), Note(10), Note(15)) @self.MEL.on_notes(seq1) def sub(): mock() press_sequence(self.loopback, seq1) self.assertTrue(self.MEL.handlers) # Not empty mock.assert_called()
def test_freq(self): self.assertEqual(Note("A4").freq, 440.00) self.assertEqual(Note("C6").freq, 1046.50) self.assertEqual(Note("C0").freq, 16.35) self.assertEqual(Note("A-1").freq, 13.75) self.assertEqual(Note("Cb4").freq, 246.94) self.assertEqual(Note("B3").freq, 246.94)
def test_init(self): expected = (Note(5), Note(7)) seq1 = Sequence(Note(5), Note(7)) self.assertEqual(seq1.notes, expected) seq2 = Sequence((Note(5), Note(7))) self.assertEqual(seq2.notes, expected) seq3 = Sequence(expected) self.assertEqual(seq3.notes, expected)
def test_eq_deque(self): notes = (Note(15), Note(10), Note(20)) seq1 = Sequence(notes) notes_deque = collections.deque() notes_deque.append(Note(50)) # Fill with some junk first notes_deque.append(Note(50)) notes_deque.append(Note(50)) for n in notes: notes_deque.append(n) self.assertEqual(seq1, notes_deque) notes_deque.append(Note(51)) self.assertNotEqual(seq1, notes_deque)
def test_chord_and_sequence(self): chord_mock = unittest.mock.Mock() sequence_mock = unittest.mock.Mock() c1 = Chord(Note(1), Note(2), Note(3)) seq1 = Sequence(Note(1), Note(2), Note(3)) self.MEL.add_handler(chord_mock, c1) self.MEL.add_handler(sequence_mock, seq1) press_chord(self.loopback, c1) # Should trigger both chord_mock.assert_called() sequence_mock.assert_called()
def test_multiple_callbacks_same_chord(self): mock1 = unittest.mock.Mock() mock2 = unittest.mock.Mock() c1 = Chord(Note(20), Note(40), Note(60)) c2 = Chord(Note(20), Note(40), Note(60)) self.MEL.add_handler(mock1, c1) self.MEL.add_handler(mock2, c2) press_chord(self.loopback, c1) mock1.assert_called() mock2.assert_called()
def test_multiple_callbacks_same_sequence(self): mock1 = unittest.mock.Mock() mock2 = unittest.mock.Mock() seq1 = Sequence(Note(20), Note(40), Note(60)) seq2 = Sequence(Note(20), Note(40), Note(60)) self.MEL.add_handler(mock1, seq1) self.MEL.add_handler(mock2, seq2) press_sequence(self.loopback, seq1) mock1.assert_called() mock2.assert_called()
def __init__(self, *args): try: for _ in range(self.max_depth): if isinstance(args, NoteList): # NoteList self.notes = args.notes return if all(isinstance(x, Note) for x in args): # Note self.notes = args # Triggers the setter return if all(isinstance(x, int) for x in args): # int, assumed MIDI representation self.notes = [Note(x) for x in args] return args = args[0] # Go one level deeper else: raise ValueError( f"Illegal configuration of notes, got '{type(args)}'") except TypeError: raise TypeError( f"Expected iterable of Notes or NoteList, got '{type(args)}'")
def test_sequence_handlers_add_remove(self): mock1 = unittest.mock.Mock() mock2 = unittest.mock.Mock() seq1 = Sequence(Note(1), Note(2), Note(3)) seq2 = Sequence(Note(4), Note(5), Note(6)) self.assertFalse(self.MEL.handlers) # Empty self.MEL.add_handler(mock1, seq1) self.assertTrue(self.MEL.handlers) # Not empty self.MEL.clear_handlers() self.assertFalse(self.MEL.handlers) # Now test a single removal self.MEL.add_handler(mock1, seq1) self.MEL.add_handler(mock2, seq2) self.assertTrue(self.MEL.handlers) # Not empty self.assertIn(seq1, self.MEL.handlers) self.assertIn(seq2, self.MEL.handlers) self.MEL.clear_handlers(seq1) self.assertNotIn(seq1, self.MEL.handlers) self.assertIn(seq2, self.MEL.handlers)
def test_init_from_iter(self): nl1 = NoteList(Note(5), Note(7)) self.assertEqual(nl1._notes, (Note(5), Note(7))) nl2 = NoteList([Note(5), Note(7)]) self.assertEqual(nl2._notes, (Note(5), Note(7)))
def test_from_note_chord(self): c1 = Chord(Note(69), Note(73), Note(76)) c2 = Chord.from_note_chord(Note(69), "Major") self.assertEqual(c1, c2)
def test_equality(self): c1 = Chord(Note(69), Note(73), Note(76)) c2 = Chord(Note(69), Note(73), Note(76)) self.assertEqual(c1, c2) nl_ordered = NoteList(Note(69), Note(73), Note(76)) # Pre-ordered self.assertEqual(nl_ordered, c1) nl_unordered = NoteList(Note(73), Note(69), Note(76)) # Un-ordered self.assertEqual(nl_unordered, c1) seq1 = Sequence(Note(69), Note(73), Note(76)) self.assertNotEqual(c1, seq1) # Different note list lengths should automatically be not equal c3 = Chord(Note(69), Note(73), Note(76), Note(100)) self.assertNotEqual(c1, c3)
def test_eq_notelist(self): notes = (Note(15), Note(10), Note(20)) seq1 = Sequence(notes) nl1 = NoteList(notes) self.assertEqual(seq1, nl1)
def test_init_from_int(self): nl1 = NoteList(1, 2, 3) nl2 = NoteList(Note(1), Note(2), Note(3)) self.assertEqual(nl1, nl2)
def test_eq_sequence(self): notes = (Note(15), Note(10), Note(20)) seq1 = Sequence(notes) seq2 = Sequence.from_midi_list([15, 10, 20]) self.assertEqual(seq1, seq2)
def test_eq_chord(self): notes = (Note(15), Note(10), Note(20)) seq1 = Sequence(notes) c1 = Chord(notes) self.assertNotEqual(seq1, c1) # Chord should sort the notes, while Sequence doesn't
def test_eq_tuple(self): notes = (Note(15), Note(10), Note(20)) seq1 = Sequence(notes) self.assertEqual(seq1, notes)
def from_midi_list(cls, midi_list): return cls([Note(x) for x in midi_list])
def from_ascii( cls, note_string ): # TODO note_string is similar to note_str in the Note class, maybe rename this? note_string = note_string.replace(",", "") return cls([Note(x) for x in note_string.split(" ")])
def test_hash(self): notes = (Note(10), Note(15), Note(20) ) # Sorted to emulate NoteList.notes setter method nl1 = NoteList(notes) self.assertEqual(hash(notes), hash(nl1))
def test_from_midi_list(self): nl1 = NoteList.from_midi_list([69, 73, 76]) self.assertEqual(nl1.notes, (Note(69), Note(73), Note(76)))
def test_hash(self): seq1 = Sequence(Note(69), Note(73), Note(76)) self.assertEqual(hash(seq1), 643362958232848345) self.assertEqual(Sequence.__hash__, NoteList.__hash__)
def test_from_ascii(self): expected = (Note(69), Note(73), Note(76)) nl1 = NoteList.from_ascii("A4, C#5, E5") nl2 = NoteList.from_ascii("A4 C#5 E5") self.assertEqual(nl1.notes, expected) self.assertEqual(nl2.notes, expected)
def from_ident(cls, ident_chord_name): base_note, *chord_name = ident_chord_name.split(" ") assert chord_name, "No chord name detected, make sure there's a space in ident_chord_name." base_note = Note(base_note) chord_name = " ".join(chord_name).strip() return cls.from_note_chord(base_note, chord_name)
def test_hash(self): c1 = Chord(Note(69), Note(73), Note(76)) self.assertEqual(hash(c1), 643362958232848345) self.assertEqual(Chord.__hash__, NoteList.__hash__)
def from_note_chord(cls, note_obj, chord_name): note_list = [Note(note_obj.midi + semitone) for semitone in cls._get_semitones_from_chord_name(chord_name)] return cls(note_list)