Initial commit
Add spruce scraper with CLI, session management, parsers, progress tracking, recheck logic, and test suite. Includes example config and README.
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
"""Tests for spruce.parsers — all pure, no network required."""
|
||||
|
||||
import pytest
|
||||
from spruce.parsers import (
|
||||
_grid_count,
|
||||
_grid_values,
|
||||
parse_machine_option,
|
||||
parse_scan_row,
|
||||
parse_scan_view,
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# parse_machine_option
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_parse_machine_option_basic():
|
||||
raw = "BW3%2D20%20%5BAMR%2D26%5D|205.149.147.130|17026|26|8026|3.0.0.33|50.00"
|
||||
m = parse_machine_option("BW3-20 [AMR-26]", raw)
|
||||
assert m["label"] == "BW3-20 [AMR-26]"
|
||||
assert m["machine_id"] == "26"
|
||||
assert m["ip"] == "205.149.147.130"
|
||||
assert m["version"] == "3.0.0.33"
|
||||
assert m["option_value"] == raw
|
||||
|
||||
|
||||
def test_parse_machine_option_short_value():
|
||||
# Fewer pipe-delimited parts should not raise; missing fields return ""
|
||||
m = parse_machine_option("Lonely Machine", "LM|10.0.0.1")
|
||||
assert m["ip"] == "10.0.0.1"
|
||||
assert m["machine_id"] == ""
|
||||
assert m["port2"] == ""
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# parse_scan_row
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
VALID_CELLS = [
|
||||
"158374",
|
||||
"Plot 20 AMR26 Full Tube Scan",
|
||||
"2024-07-29 05:00",
|
||||
"mm",
|
||||
"(0,0)-(310,740)-(3.01,2.26)",
|
||||
"100",
|
||||
"Horizontal",
|
||||
"Raster",
|
||||
"2024-07-29 04:59:46",
|
||||
"2024-07-30 02:51:07",
|
||||
"0",
|
||||
"SPRUCE",
|
||||
"Completed",
|
||||
"X",
|
||||
]
|
||||
|
||||
|
||||
def test_parse_scan_row_valid():
|
||||
sc = parse_scan_row(VALID_CELLS)
|
||||
assert sc is not None
|
||||
assert sc["scan_id"] == 158374
|
||||
assert sc["name"] == "Plot 20 AMR26 Full Tube Scan"
|
||||
assert sc["status"] == "Completed"
|
||||
assert sc["scan_time"] == "2024-07-29 05:00"
|
||||
|
||||
|
||||
def test_parse_scan_row_ignores_non_digit_first_cell():
|
||||
assert parse_scan_row(["ID", "Name", "Scan Time"]) is None
|
||||
assert parse_scan_row(["Scan ID:", "158374"]) is None
|
||||
|
||||
|
||||
def test_parse_scan_row_empty():
|
||||
assert parse_scan_row([]) is None
|
||||
|
||||
|
||||
def test_parse_scan_row_minimal():
|
||||
sc = parse_scan_row(["42"])
|
||||
assert sc is not None
|
||||
assert sc["scan_id"] == 42
|
||||
assert sc["name"] == ""
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# parse_scan_view (uses fixture HTML from conftest.py)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_parse_scan_view_scan_id(scan_view_html):
|
||||
meta = parse_scan_view(scan_view_html)
|
||||
assert meta.get("scan_id") == 158374
|
||||
|
||||
|
||||
def test_parse_scan_view_grid_dimensions(scan_view_html):
|
||||
meta = parse_scan_view(scan_view_html)
|
||||
assert meta.get("nx") == 103
|
||||
assert meta.get("ny") == 328
|
||||
|
||||
|
||||
def test_parse_scan_view_step_sizes(scan_view_html):
|
||||
meta = parse_scan_view(scan_view_html)
|
||||
assert meta.get("dx") == pytest.approx(3.01)
|
||||
assert meta.get("dy") == pytest.approx(2.26)
|
||||
|
||||
|
||||
def test_parse_scan_view_total_tiles(scan_view_html):
|
||||
meta = parse_scan_view(scan_view_html)
|
||||
# 103 × 328 = 33784
|
||||
assert meta.get("total_tiles") == 103 * 328
|
||||
|
||||
|
||||
def test_parse_scan_view_empty_string():
|
||||
meta = parse_scan_view("")
|
||||
assert meta == {}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# _grid_count
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_grid_count_typical():
|
||||
assert _grid_count(0, 310, 3.01) == 103
|
||||
assert _grid_count(0, 740, 2.26) == 328
|
||||
|
||||
|
||||
def test_grid_count_zero_step():
|
||||
assert _grid_count(0, 100, 0) == 0
|
||||
|
||||
|
||||
def test_grid_count_single():
|
||||
assert _grid_count(0, 1, 1) == 1
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# _grid_values
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_grid_values_basic():
|
||||
vals = _grid_values(0.0, 3, 3.01)
|
||||
assert vals == [0.0, 3.01, 6.02]
|
||||
|
||||
|
||||
def test_grid_values_empty():
|
||||
assert _grid_values(0.0, 0, 1.0) == []
|
||||
|
||||
|
||||
def test_grid_values_rounded():
|
||||
# Floating-point accumulation should be rounded to 2 dp
|
||||
vals = _grid_values(0.0, 4, 0.1)
|
||||
for v in vals:
|
||||
assert v == round(v, 2)
|
||||
Reference in New Issue
Block a user