Skip to content
This repository was archived by the owner on Aug 11, 2026. It is now read-only.

Commit e994c02

Browse files
committed
test: add comprehensive edge case tests for musical time conversion
- Added test for multi-level hierarchy overflow scenarios - Added test for truncated positions array handling with reference levels - Added test for recursive overflow at reference level boundaries - Added test for complex list-based hierarchy overflow - These tests specifically cover the edge cases Copilot's review identified - All 22 tests pass, increasing confidence in robustness
1 parent f047b17 commit e994c02

1 file changed

Lines changed: 90 additions & 1 deletion

File tree

idtap/tests/musical_time_test.py

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,4 +266,93 @@ def test_readable_string_variants(self):
266266
assert "Cycle 2" in readable2
267267
assert "Beat 2" in readable2
268268
assert "Sub-sub-subdivision 2" in readable2
269-
assert "0.123" in readable2
269+
assert "0.123" in readable2
270+
271+
def test_multilevel_hierarchy_overflow(self):
272+
"""Test hierarchy overflow with multiple carry-overs."""
273+
# Test case where overflow propagates through multiple levels
274+
meter = Meter(hierarchy=[2, 2, 2], tempo=480, start_time=0, repetitions=2)
275+
276+
# Test at the very end of first cycle (should trigger multi-level carry)
277+
# With hierarchy [2,2,2], we have 8 pulses per cycle
278+
# At 480 BPM = 8 beats/sec, so cycle duration = 0.25 sec
279+
end_of_first_cycle = 0.25 - 0.001
280+
result = meter.get_musical_time(end_of_first_cycle)
281+
assert result is not False
282+
assert result.cycle_number == 0
283+
284+
# Test at start of second cycle
285+
result = meter.get_musical_time(0.25)
286+
assert result is not False
287+
assert result.cycle_number == 1
288+
assert result.hierarchical_position == [0, 0, 0]
289+
290+
# Test with reference level during overflow
291+
result = meter.get_musical_time(0.249, reference_level=1)
292+
assert result is not False
293+
assert len(result.hierarchical_position) == 2
294+
295+
def test_truncated_positions_with_reference_levels(self):
296+
"""Test that truncated positions arrays are handled correctly."""
297+
meter = Meter(hierarchy=[3, 4, 2], tempo=120, start_time=0)
298+
299+
# Test with different reference levels to ensure truncation works
300+
# With tempo=120, each beat is 0.5 seconds
301+
# hierarchy [3,4,2] means 3 beats, each with 4 subdivisions, each with 2 sub-subdivisions
302+
time_point = 0.75 # Within the meter (1.5 beats in)
303+
304+
# Reference level 0 (beat level) - should truncate to 1 element
305+
result_beat = meter.get_musical_time(time_point, reference_level=0)
306+
assert result_beat is not False
307+
assert len(result_beat.hierarchical_position) == 1
308+
309+
# Reference level 1 (subdivision) - should truncate to 2 elements
310+
result_subdiv = meter.get_musical_time(time_point, reference_level=1)
311+
assert result_subdiv is not False
312+
assert len(result_subdiv.hierarchical_position) == 2
313+
314+
# Default (no reference level) - should have all 3 elements
315+
result_full = meter.get_musical_time(time_point)
316+
assert result_full is not False
317+
assert len(result_full.hierarchical_position) == 3
318+
319+
def test_recursive_overflow_edge_case(self):
320+
"""Test edge case where overflow happens at reference level boundary."""
321+
meter = Meter(hierarchy=[2, 3], tempo=60, start_time=0)
322+
323+
# Position at end of a subdivision that would cause overflow
324+
# With hierarchy [2,3], beat duration = 1 sec, subdivision = 0.333 sec
325+
# Test at end of beat 0, subdivision 2 (just before beat 1)
326+
time_at_subdivision_boundary = 0.999
327+
328+
result = meter.get_musical_time(time_at_subdivision_boundary, reference_level=0)
329+
assert result is not False
330+
assert result.beat == 0
331+
assert result.fractional_beat > 0.99
332+
333+
# Same time with subdivision reference should handle overflow correctly
334+
result = meter.get_musical_time(time_at_subdivision_boundary, reference_level=1)
335+
assert result is not False
336+
assert result.hierarchical_position[0] == 0 # Still in beat 0
337+
assert result.hierarchical_position[1] == 2 # Last subdivision
338+
339+
def test_complex_list_hierarchy_overflow(self):
340+
"""Test overflow with complex list-based hierarchy."""
341+
# Hierarchy with irregular groupings
342+
meter = Meter(hierarchy=[[2, 3], 2], tempo=120, start_time=0)
343+
344+
# Test at various points to ensure list handling works
345+
# hierarchy [[2,3], 2] means (2+3)=5 beats, each with 2 subdivisions
346+
# At tempo=120, each beat is 0.5 seconds
347+
result = meter.get_musical_time(1.0) # At 2 beats (1.0 / 0.5 = 2)
348+
assert result is not False
349+
assert result.beat == 2 # Third beat (index 2)
350+
351+
result = meter.get_musical_time(2.0) # At 4 beats
352+
assert result is not False
353+
assert result.beat == 4 # Fifth beat (index 4)
354+
355+
# Test with reference level on list hierarchy
356+
result = meter.get_musical_time(1.5, reference_level=0)
357+
assert result is not False
358+
assert len(result.hierarchical_position) == 1

0 commit comments

Comments
 (0)