|
| 1 | +"""Test cases for the Stroke model.""" |
| 2 | + |
| 3 | +import pandas as pd |
| 4 | + |
| 5 | +from graphomotor.core import models |
| 6 | + |
| 7 | + |
| 8 | +def _make_points(line_number: int = 0) -> pd.DataFrame: |
| 9 | + """Create a stroke DataFrame matching real Alphabet CSV structure. |
| 10 | +
|
| 11 | + In the real data each stroke (line_number) contains many rows with the same |
| 12 | + line_number value, plus x, y, seconds, and timestamp columns. |
| 13 | + """ |
| 14 | + return pd.DataFrame( |
| 15 | + { |
| 16 | + "line_number": [line_number] * 5, |
| 17 | + "x": [18.35, 18.24, 18.15, 18.12, 17.99], |
| 18 | + "y": [92.84, 92.85, 92.88, 92.92, 93.01], |
| 19 | + "seconds": [0.0, 0.02, 0.037, 0.046, 0.062], |
| 20 | + } |
| 21 | + ) |
| 22 | + |
| 23 | + |
| 24 | +def test_stroke_initialization() -> None: |
| 25 | + """Stroke should store points and line_number with default feature values.""" |
| 26 | + points = _make_points(line_number=0) |
| 27 | + stroke = models.Stroke(points=points, line_number=0) |
| 28 | + |
| 29 | + assert stroke.line_number == 0 |
| 30 | + assert stroke.points.equals(points) |
| 31 | + assert list(stroke.points.columns) == ["line_number", "x", "y", "seconds"] |
| 32 | + assert len(stroke.points) == 5 |
| 33 | + assert stroke.duration == 0.0 |
| 34 | + assert stroke.distance == 0.0 |
| 35 | + assert stroke.mean_speed == 0.0 |
| 36 | + assert stroke.speed_variance == 0.0 |
| 37 | + assert stroke.smoothness == 0.0 |
| 38 | + assert stroke.hesitation_count == 0 |
| 39 | + assert stroke.hesitation_duration == 0.0 |
| 40 | + assert stroke.velocities == [] |
| 41 | + assert stroke.accelerations == [] |
| 42 | + |
| 43 | + |
| 44 | +def test_stroke_features_are_mutable() -> None: |
| 45 | + """Computed features should be writable after initialization.""" |
| 46 | + stroke = models.Stroke(points=_make_points(line_number=0), line_number=0) |
| 47 | + |
| 48 | + stroke.duration = 0.5 |
| 49 | + stroke.distance = 25.0 |
| 50 | + stroke.mean_speed = 50.0 |
| 51 | + stroke.velocities = [40.0, 50.0, 60.0] |
| 52 | + |
| 53 | + assert stroke.duration == 0.5 |
| 54 | + assert stroke.distance == 25.0 |
| 55 | + assert stroke.mean_speed == 50.0 |
| 56 | + assert stroke.velocities == [40.0, 50.0, 60.0] |
| 57 | + |
| 58 | + |
| 59 | +def test_grid_cell_stores_strokes() -> None: |
| 60 | + """GridCell should hold Stroke objects in its strokes list.""" |
| 61 | + cell = models.GridCell(x_min=0.0, x_max=30.0, y_min=70.0, y_max=100.0) |
| 62 | + stroke_a = models.Stroke(points=_make_points(line_number=0), line_number=0) |
| 63 | + stroke_b = models.Stroke(points=_make_points(line_number=1), line_number=1) |
| 64 | + |
| 65 | + cell.strokes.append(stroke_a) |
| 66 | + cell.strokes.append(stroke_b) |
| 67 | + |
| 68 | + assert len(cell.strokes) == 2 |
| 69 | + assert cell.strokes[0].line_number == 0 |
| 70 | + assert cell.strokes[1].line_number == 1 |
| 71 | + |
| 72 | + |
| 73 | +def test_grid_cell_strokes_default_empty() -> None: |
| 74 | + """GridCell should default to an empty strokes list.""" |
| 75 | + cell = models.GridCell(x_min=0.0, x_max=10.0, y_min=0.0, y_max=10.0) |
| 76 | + assert cell.strokes == [] |
0 commit comments