From db2f6ee5a4884dd507ee8672101bce6f1c1b447b Mon Sep 17 00:00:00 2001 From: Ennis Massey Date: Sun, 27 Aug 2017 20:57:31 +1200 Subject: [PATCH] Implemented errors in constructor, added associated tests --- midisnake/errors.py | 25 ++++++++++++++++++++++++ midisnake/structure.py | 15 +++++++++++--- tests/test_events.py | 44 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 midisnake/errors.py diff --git a/midisnake/errors.py b/midisnake/errors.py new file mode 100644 index 0000000..a2376c7 --- /dev/null +++ b/midisnake/errors.py @@ -0,0 +1,25 @@ +# MIT License +# +# Copyright (c) 27/08/17 Ennis Massey +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +class LengthError(Exception): + """Raised when data is the wrong length""" + pass \ No newline at end of file diff --git a/midisnake/structure.py b/midisnake/structure.py index ab51650..ea5e5dc 100644 --- a/midisnake/structure.py +++ b/midisnake/structure.py @@ -23,6 +23,8 @@ from io import BufferedReader from abc import ABCMeta, abstractmethod +from midisnake.errors import LengthError + __all__ = ["Header", "Event"] @@ -63,7 +65,16 @@ class Event(metaclass=ABCMeta): # pramga: no def __init__(self, data: int) -> None: self.raw_data = data - self._process(data) + if len(hex(data)[2:]) != 6: + err_msg = "Length of given data is incorrect. The length is {} and it should be 6".format( + len(hex(data)[2:])) + raise LengthError(err_msg) + if self.valid(data): + self._process(data) + else: + err_msg = "{} given invalid data".format(type(self).__name__) + raise ValueError(err_msg) + def __repr__(self) -> str: return "".format(self.event_name) @@ -71,7 +82,6 @@ def __repr__(self) -> str: def __str__(self) -> str: return "MIDIEvent: {}".format(self.event_name) - @classmethod def valid(cls, data: int) -> bool: """ @@ -111,7 +121,6 @@ class Track: events = None # type: List[Event] - class VariableLengthValue: """Parses and stores a MIDI variable length value diff --git a/tests/test_events.py b/tests/test_events.py index 6a82fbb..3cf037d 100644 --- a/tests/test_events.py +++ b/tests/test_events.py @@ -18,4 +18,46 @@ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. \ No newline at end of file +# SOFTWARE. +from unittest import TestCase +from unittest.mock import MagicMock, call + +from midisnake.events import NoteOff, NoteOn, PolyphonicAftertouch, PitchBend +from midisnake.errors import LengthError + + +class TestNoteOn(TestCase): + def test_validate(self): + test_val = NoteOn.valid(0x900000) + self.assertTrue(test_val, "Generic MIDI NoteOn message failed validation. Value was 0x{:X}".format(test_val)) + test_val = NoteOn.valid(0x800000) + self.assertFalse(test_val, + "Generic MIDI NoteOn message shouldn't have validated, but did. Value was 0x{:x}".format( + test_val) + ) + + def test_constructor(self): + # Test constructor of generic version + test_val = NoteOn(0x900000) + match_val = { + 'channel_number': 0, + 'note_name': 'C', + 'note_number': 0, + 'note_velocity': 0, + 'raw_data': 9437184 + } + self.assertEqual(vars(test_val), + match_val, "MIDI NoteOn constructed from value 0x{:X} is incorrect".format(0x900000) + ) + # Test Length Exceptions + with self.assertRaises(LengthError, + msg="NoteOn did not raise LengthError when given value 0x123001929391923919" + ) as exc: + NoteOn(0x123001929391923919) + + with self.assertRaises(LengthError, + msg="NoteOn did not raise LengthError when given value 0x1" + ) as exc: + NoteOn(0x1) + +