diff --git a/.github/workflows/python-tests.yml b/.github/workflows/python-tests.yml new file mode 100644 index 0000000..fa75a27 --- /dev/null +++ b/.github/workflows/python-tests.yml @@ -0,0 +1,18 @@ +name: python-tests +on: [push, pull_request] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.10' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + - name: Run tests + run: pytest -q diff --git a/aps_logcomp/__init__.py b/aps_logcomp/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_integration_midi.py b/tests/test_integration_midi.py new file mode 100644 index 0000000..8b03d2b --- /dev/null +++ b/tests/test_integration_midi.py @@ -0,0 +1,27 @@ +import os +from aps_logcomp import main + +def test_integration_generate_midi(tmp_path): + # Minimal music: one instrument, one play + content = "Music X 100 { Instrument piano { play 60 1 } }" + tokenizer = main.Tokenizer(content) + parser = main.Parser(tokenizer) + music_node = parser.parse_program() + + # Build context by evaluating nodes (this populates context["instrumentos"]) + context = {} + music_node.evaluate(context) + + # instrument map: piano -> GM program 0 + instrument_map = {"piano": 0} + + out_base = tmp_path / "out_test" + # criar_midi_com_duracoes writes {nome}.mid, so pass a path-like name + out_name = str(out_base) + + # call the function under test + main.criar_midi_com_duracoes(context, music_node.bpm, out_name, music_node.instrumentos, instrument_map) + + out_file = out_base.with_suffix(".mid") + assert out_file.exists(), "MIDI file was not created" + assert out_file.stat().st_size > 0, "MIDI file size is zero" diff --git a/tests/test_tokenizer_parser.py b/tests/test_tokenizer_parser.py new file mode 100644 index 0000000..4295695 --- /dev/null +++ b/tests/test_tokenizer_parser.py @@ -0,0 +1,23 @@ +import pytest +from aps_logcomp import main + +def test_tokenizer_basic_sequence(): + content = "Music Song 120 { Instrument piano { play 60 1 } }" + tokenizer = main.Tokenizer(content) + tokens = tokenizer.tokenize() + types = [t.type for t in tokens] + # Expected prefix of token types + expected = ["MUSIC", "ID", "NUMBER", "LBRACE", "INSTRUMENT", "ID", + "LBRACE", "PLAY", "NUMBER", "NUMBER", "RBRACE", "RBRACE"] + assert types[:len(expected)] == expected + +def test_parser_produces_music_node(): + content = "Music Foobar 100 { Instrument piano { play 63 1 } }" + tokenizer = main.Tokenizer(content) + parser = main.Parser(tokenizer) + node = parser.parse_program() + assert isinstance(node, main.MusicNode) + assert node.nome == "Foobar" + assert node.bpm == 100 + # at least one instrument parsed + assert len(node.instrumentos) >= 1