diff --git a/.travis.yml b/.travis.yml index b169fb7..688657a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,4 +15,4 @@ install: - python setup.py install script: - - python -c "import audioread" + - pytest diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..b7e4789 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,2 @@ +[aliases] +test=pytest diff --git a/setup.py b/setup.py index 58845cb..bd90605 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ # included in all copies or substantial portions of the Software. import os -from distutils.core import setup +from setuptools import setup import imp version = imp.load_source('audioread.version', 'audioread/version.py') @@ -36,6 +36,14 @@ def _read(fn): packages=['audioread'], + setup_requires=[ + 'pytest-runner' + ], + + tests_require=[ + 'pytest' + ], + classifiers=[ 'Topic :: Multimedia :: Sound/Audio :: Conversion', 'Intended Audience :: Developers', diff --git a/test/conftest.py b/test/conftest.py new file mode 100644 index 0000000..08f7918 --- /dev/null +++ b/test/conftest.py @@ -0,0 +1,51 @@ +# This file is part of audioread. +# Copyright 2018, Sam Thursfield +# +# 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. + + +import json +import os + +import pytest + + +@pytest.fixture() +def audiofile(request): + """Fixture that provides an AudiofileSpec instance.""" + spec_path = os.path.join(DATADIR, request.param + '.json') + with open(spec_path, 'r') as f: + spec = json.load(f) + result = AudiofileSpec(**spec) + return result + + +# The audiofiles used for testing live in the data/ directory. They are defined +# by .json files and each one must be listed here by name. +TEST_AUDIOFILES = ['test-1', 'test-2'] + +DATADIR = os.path.join(os.path.dirname(__file__), 'data') + + +class AudiofileSpec(): + """Defines the expected attributes for a test audiofile.""" + def __init__(self, filename, duration, channels, samplerate): + self.path = os.path.join(DATADIR, filename) + self.duration = duration + self.channels = channels + self.samplerate = samplerate + + +def pytest_generate_tests(metafunc): + """Parametrize the audiofile() fixture using TEST_AUDIOFILES.""" + if 'audiofile' in metafunc.fixturenames: + metafunc.parametrize("audiofile", TEST_AUDIOFILES, indirect=True) diff --git a/test/data/test-1.json b/test/data/test-1.json new file mode 100644 index 0000000..66804ed --- /dev/null +++ b/test/data/test-1.json @@ -0,0 +1,6 @@ +{ + "filename": "test-1.mp3", + "duration": 15.0, + "channels": 1, + "samplerate": 22050 +} diff --git a/test/data/test-1.mp3 b/test/data/test-1.mp3 new file mode 100644 index 0000000..bbd4c76 Binary files /dev/null and b/test/data/test-1.mp3 differ diff --git a/test/data/test-2.json b/test/data/test-2.json new file mode 100644 index 0000000..a971549 --- /dev/null +++ b/test/data/test-2.json @@ -0,0 +1,6 @@ +{ + "filename": "test-2.mp3", + "duration": 2, + "channels": 2, + "samplerate": 44100 +} diff --git a/test/data/test-2.mp3 b/test/data/test-2.mp3 new file mode 100644 index 0000000..9d16f6f Binary files /dev/null and b/test/data/test-2.mp3 differ diff --git a/test/test_audioread.py b/test/test_audioread.py new file mode 100644 index 0000000..0f0150d --- /dev/null +++ b/test/test_audioread.py @@ -0,0 +1,51 @@ +# This file is part of audioread. +# Copyright 2018, Sam Thursfield +# +# 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. + + +import json +import os +import sys + +import pytest + +import audioread + + +# The 'audiofile' fixture is defined in conftest.py. + + +def test_audioread_early_exit(audiofile): + """Abort the read before it is completed. + + This test guards against regressions such as + https://github.com/beetbox/audioread/pull/78 + + """ + with audioread.audio_open(audiofile.path) as a: + assert int(a.duration) == int(audiofile.duration) + assert a.channels == audiofile.channels + assert a.samplerate == audiofile.samplerate + # Now we exit the context manager without reading any data. + + +def test_audioread_full(audiofile): + """Read the audio data from the file.""" + with audioread.audio_open(audiofile.path) as a: + assert int(a.duration) == int(audiofile.duration) + assert a.channels == audiofile.channels + assert a.samplerate == audiofile.samplerate + + # Now read all the data and assert that it's the correct type. + for block in a: + assert type(block) == bytes diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..de15067 --- /dev/null +++ b/tox.ini @@ -0,0 +1,6 @@ +[tox] +envlist = py27,py36 + +[testenv] +deps = pytest +commands = pytest {posargs}