forked from rc/aircox
		
	- Add configuration files for packaging - Precommit now uses ruff Co-authored-by: bkfox <thomas bkfox net> Reviewed-on: rc/aircox#127
		
			
				
	
	
		
			118 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			118 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
import subprocess
 | 
						|
 | 
						|
import pytest
 | 
						|
 | 
						|
from aircox.test import Interface
 | 
						|
from aircox.controllers import sound_stats
 | 
						|
 | 
						|
 | 
						|
sox_output = """
 | 
						|
    DC offset   0.000000\n
 | 
						|
    Min level   0.000000\n
 | 
						|
    Max level   0.000000\n
 | 
						|
    Pk lev dB       -inf\n
 | 
						|
    RMS lev dB      -inf\n
 | 
						|
    RMS Pk dB       -inf\n
 | 
						|
    RMS Tr dB       -inf\n
 | 
						|
    Crest factor    1.00\n
 | 
						|
    Flat factor   179.37\n
 | 
						|
    Pk count       1.86G\n
 | 
						|
    Bit-depth       0/0\n
 | 
						|
    Num samples     930M\n
 | 
						|
    Length s   19383.312\n
 | 
						|
    Scale max   1.000000\n
 | 
						|
    Window s       0.050\n
 | 
						|
"""
 | 
						|
sox_values = {
 | 
						|
    "DC offset": 0.0,
 | 
						|
    "Min level": 0.0,
 | 
						|
    "Max level": 0.0,
 | 
						|
    "Pk lev dB": float("-inf"),
 | 
						|
    "RMS lev dB": float("-inf"),
 | 
						|
    "RMS Pk dB": float("-inf"),
 | 
						|
    "RMS Tr dB": float("-inf"),
 | 
						|
    "Flat factor": 179.37,
 | 
						|
    "length": 19383.312,
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
@pytest.fixture
 | 
						|
def sox_interfaces():
 | 
						|
    process = Interface(None, {"communicate": ("", sox_output.encode("utf-8"))})
 | 
						|
    subprocess = Interface.inject(sound_stats, "subprocess", {"Popen": lambda *_, **__: process})
 | 
						|
    yield {"process": process, "subprocess": subprocess}
 | 
						|
    subprocess._irelease()
 | 
						|
 | 
						|
 | 
						|
@pytest.fixture
 | 
						|
def sox_stats(sox_interfaces):
 | 
						|
    return sound_stats.SoxStats()
 | 
						|
 | 
						|
 | 
						|
@pytest.fixture
 | 
						|
def stats():
 | 
						|
    return sound_stats.SoundStats("/tmp/audio.wav", sample_length=10)
 | 
						|
 | 
						|
 | 
						|
@pytest.fixture
 | 
						|
def stats_interfaces(stats):
 | 
						|
    def iw(path, **kw):
 | 
						|
        kw["path"] = path
 | 
						|
        kw.setdefault("length", stats.sample_length * 2)
 | 
						|
        return kw
 | 
						|
 | 
						|
    SxS = sound_stats.SoxStats
 | 
						|
    sound_stats.SoxStats = iw
 | 
						|
    yield iw
 | 
						|
    sound_stats.SoxStats = SxS
 | 
						|
 | 
						|
 | 
						|
class TestSoxStats:
 | 
						|
    def test_parse(self, sox_stats):
 | 
						|
        values = sox_stats.parse(sox_output)
 | 
						|
        assert values == sox_values
 | 
						|
 | 
						|
    def test_analyse(self, sox_stats, sox_interfaces):
 | 
						|
        sox_stats.analyse("fake_path", 1, 2)
 | 
						|
        assert sox_interfaces["subprocess"]._trace("Popen") == (
 | 
						|
            (["sox", "fake_path", "-n", "trim", "1", "2", "stats"],),
 | 
						|
            {"stdout": subprocess.PIPE, "stderr": subprocess.PIPE},
 | 
						|
        )
 | 
						|
        assert sox_stats.values == sox_values
 | 
						|
 | 
						|
 | 
						|
class TestSoundStats:
 | 
						|
    def test_get_file_stats(self, stats):
 | 
						|
        file_stats = {"a": 134}
 | 
						|
        stats.stats = [file_stats]
 | 
						|
        assert stats.get_file_stats() is file_stats
 | 
						|
 | 
						|
    def test_get_file_stats_none(self, stats):
 | 
						|
        stats.stats = []
 | 
						|
        assert stats.get_file_stats() is None
 | 
						|
 | 
						|
    def test_analyse(self, stats, stats_interfaces):
 | 
						|
        stats.analyse()
 | 
						|
        assert stats.stats == [
 | 
						|
            {"path": stats.path, "length": stats.sample_length * 2},
 | 
						|
            {"path": stats.path, "at": 0, "length": stats.sample_length},
 | 
						|
            {"path": stats.path, "at": 10, "length": stats.sample_length},
 | 
						|
        ]
 | 
						|
 | 
						|
    def test_analyse_no_sample_length(self, stats, stats_interfaces):
 | 
						|
        stats.sample_length = 0
 | 
						|
        stats.analyse()
 | 
						|
        assert stats.stats == [{"length": 0, "path": stats.path}]
 | 
						|
 | 
						|
    def test_check(self, stats):
 | 
						|
        good = [{"val": i} for i in range(0, 11)]
 | 
						|
        bad = [{"val": i} for i in range(-10, 0)] + [{"val": i} for i in range(11, 20)]
 | 
						|
        stats.stats = good + bad
 | 
						|
        calls = {}
 | 
						|
        stats.resume = lambda *_: calls.setdefault("resume", True)
 | 
						|
        stats.check("val", 0, 10)
 | 
						|
 | 
						|
        assert calls == {"resume": True}
 | 
						|
        assert all(i < len(good) for i in stats.good)
 | 
						|
        assert all(i >= len(good) for i in stats.bad)
 |