From 9c0850f98d33f2fd2230a0a5469d39a2970f347a Mon Sep 17 00:00:00 2001 From: Stepland <16676308+Stepland@users.noreply.github.com> Date: Wed, 12 May 2021 12:58:22 +0200 Subject: [PATCH] [eve] Tests pass ! Add load_options to dump & load test strategy --- jubeatools/formats/eve/load.py | 18 +++++++++++------- jubeatools/formats/eve/tests/test_eve.py | 20 +++++++++++++------- jubeatools/testutils/strategies.py | 13 +++++++------ jubeatools/testutils/test_patterns.py | 6 ++++-- 4 files changed, 35 insertions(+), 22 deletions(-) diff --git a/jubeatools/formats/eve/load.py b/jubeatools/formats/eve/load.py index 4688cba..13ba2cf 100644 --- a/jubeatools/formats/eve/load.py +++ b/jubeatools/formats/eve/load.py @@ -43,11 +43,11 @@ def _load_eve(lines: List[str], file_path: Path, *, beat_snap: int = 240) -> son ] time_map = TimeMap.from_seconds(bpms) tap_notes: List[AnyNote] = [ - make_tap_note(e.time, e.value, time_map) + make_tap_note(e.time, e.value, time_map, beat_snap) for e in events_by_command[Command.PLAY] ] long_notes: List[AnyNote] = [ - make_long_notes(e.time, e.value, time_map) + make_long_note(e.time, e.value, time_map, beat_snap) for e in events_by_command[Command.LONG] ] all_notes = sorted(tap_notes + long_notes, key=lambda n: (n.time, n.position)) @@ -102,22 +102,26 @@ def parse_event(line: str) -> Event: return Event(tick, command, value) -def make_tap_note(ticks: int, value: int, time_map: TimeMap) -> song.TapNote: +def make_tap_note( + ticks: int, value: int, time_map: TimeMap, beat_snap: int +) -> song.TapNote: seconds = ticks_to_seconds(ticks) raw_beats = time_map.beats_at(seconds) - beats = round_beats(raw_beats) + beats = round_beats(raw_beats, beat_snap) position = song.NotePosition.from_index(value) return song.TapNote(time=beats, position=position) -def make_long_notes(ticks: int, value: int, time_map: TimeMap) -> song.LongNote: +def make_long_note( + ticks: int, value: int, time_map: TimeMap, beat_snap: int +) -> song.LongNote: seconds = ticks_to_seconds(ticks) raw_beats = time_map.beats_at(seconds) - beats = round_beats(raw_beats) + beats = round_beats(raw_beats, beat_snap) eve_long = EveLong.from_value(value) seconds_duration = ticks_to_seconds(eve_long.duration) raw_beats_duration = time_map.beats_at(seconds + seconds_duration) - raw_beats - beats_duration = round_beats(raw_beats_duration) + beats_duration = round_beats(raw_beats_duration, beat_snap) position = song.NotePosition.from_index(eve_long.position) direction = VALUE_TO_DIRECTION[eve_long.direction] step_vector = song.TAIL_DIRECTION_TO_OUTWARDS_VECTOR[direction] diff --git a/jubeatools/formats/eve/tests/test_eve.py b/jubeatools/formats/eve/tests/test_eve.py index 29aacf4..61f63d1 100644 --- a/jubeatools/formats/eve/tests/test_eve.py +++ b/jubeatools/formats/eve/tests/test_eve.py @@ -4,7 +4,7 @@ from decimal import Decimal from pathlib import Path from typing import Iterator -from hypothesis import Verbosity, given, settings +from hypothesis import given from hypothesis import strategies as st from jubeatools import song @@ -20,19 +20,24 @@ simple_beat_strat = jbst.beat_time( @st.composite def eve_compatible_song(draw: DrawFunc) -> song.Song: - """eve only keeps notes, timing info and difficulty""" + """eve only keeps notes, timing info and difficulty, + the precision you can get out of it is also severly limited""" diff = draw(st.sampled_from(list(song.Difficulty))) chart = draw( jbst.chart( timing_strat=jbst.timing_info( with_bpm_changes=True, - bpm_strat=st.decimals(min_value=1, max_value=500, places=2), + bpm_strat=st.decimals(min_value=50, max_value=300, places=2), beat_zero_offset_strat=st.decimals(min_value=0, max_value=20, places=2), - time_strat=simple_beat_strat, + time_strat=jbst.beat_time( + min_section=1, + max_section=10, + denominator_strat=st.sampled_from([4, 8, 3]), + ), ), notes_strat=jbst.notes( note_strat=st.one_of( - jbst.tap_note(time_start=simple_beat_strat), + jbst.tap_note(time_strat=simple_beat_strat), jbst.long_note( time_strat=simple_beat_strat, duration_strat=jbst.beat_time( @@ -41,7 +46,8 @@ def eve_compatible_song(draw: DrawFunc) -> song.Song: denominator_strat=st.sampled_from([4, 8, 3]), ), ), - ) + ), + beat_time_strat=simple_beat_strat, ), level_strat=st.just(Decimal(0)), ) @@ -59,11 +65,11 @@ def open_temp_dir() -> Iterator[Path]: @given(eve_compatible_song()) -@settings(verbosity=Verbosity.normal) def test_that_full_chart_roundtrips(song: song.Song) -> None: dump_and_load_then_compare( Format.EVE, song, temp_path=open_temp_dir(), bytes_decoder=lambda b: b.decode("ascii"), + load_options={"beat_snap": 24}, ) diff --git a/jubeatools/testutils/strategies.py b/jubeatools/testutils/strategies.py index 2aef23c..72d91c1 100644 --- a/jubeatools/testutils/strategies.py +++ b/jubeatools/testutils/strategies.py @@ -70,9 +70,9 @@ def note_position(draw: DrawFunc) -> NotePosition: @st.composite def tap_note( - draw: DrawFunc, time_start: st.SearchStrategy[BeatsTime] = beat_time(max_section=10) + draw: DrawFunc, time_strat: st.SearchStrategy[BeatsTime] = beat_time(max_section=10) ) -> TapNote: - time = draw(time_start) + time = draw(time_strat) position = draw(note_position()) return TapNote(time, position) @@ -117,9 +117,6 @@ def notes( tap_note(), long_note() ), beat_time_strat: st.SearchStrategy[BeatsTime] = beat_time(max_section=3), - beat_interval_strat: st.SearchStrategy[BeatsTime] = beat_time( - min_numerator=1, max_section=3 - ), ) -> Set[Union[TapNote, LongNote]]: raw_notes: Set[Union[TapNote, LongNote]] = draw(st.sets(note_strat, max_size=32)) @@ -135,7 +132,11 @@ def notes( if last_note_time is None: new_time = draw(beat_time_strat) else: - new_time = last_note_time + draw(beat_interval_strat) + numerator = draw( + st.integers(min_value=1, max_value=last_note_time.denominator * 4) + ) + distance = BeatsTime(numerator, last_note_time.denominator) + new_time = last_note_time + distance if isinstance(note, LongNote): notes.add( LongNote( diff --git a/jubeatools/testutils/test_patterns.py b/jubeatools/testutils/test_patterns.py index 7525ca8..ac5edc4 100644 --- a/jubeatools/testutils/test_patterns.py +++ b/jubeatools/testutils/test_patterns.py @@ -14,16 +14,18 @@ def dump_and_load_then_compare( song: song.Song, temp_path: ContextManager[Path], bytes_decoder: Callable[[bytes], str], + load_options: Optional[dict] = None, dump_options: Optional[dict] = None, ) -> None: + load_options = load_options or {} dump_options = dump_options or {} loader = LOADERS[format_] dumper = DUMPERS[format_] with temp_path as path: - files = dumper(song, path, **(dump_options or {})) + files = dumper(song, path, **dump_options) for path, bytes_ in files.items(): path.write_bytes(bytes_) note(f"Wrote to {path} :\n{bytes_decoder(bytes_)}") assert guess_format(path) == format_ - recovered_song = loader(path) + recovered_song = loader(path, **load_options) assert recovered_song == song