@@ -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