| from __future__ import annotations |
|
|
| import sys |
| import unittest |
| from pathlib import Path |
|
|
| sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src")) |
|
|
| from turn_detection.data import ( |
| RecordValidationError, |
| normalize_nullable_bool, |
| normalize_record, |
| normalize_record_with_issues, |
| ) |
|
|
|
|
| class NullableBooleanTests(unittest.TestCase): |
| def test_null_is_not_false(self) -> None: |
| self.assertIsNone(normalize_nullable_bool(None)) |
| self.assertIsNone(normalize_nullable_bool("null")) |
| self.assertIs(normalize_nullable_bool(False), False) |
| self.assertIs(normalize_nullable_bool("0"), False) |
|
|
| def test_endpoint_text_aliases(self) -> None: |
| self.assertIs(normalize_nullable_bool("complete"), True) |
| self.assertIs(normalize_nullable_bool("not endpoint"), False) |
|
|
| def test_invalid_boolean_raises(self) -> None: |
| with self.assertRaises(ValueError): |
| normalize_nullable_bool(2, field_name="endpoint") |
|
|
|
|
| class RecordNormalizationTests(unittest.TestCase): |
| def test_upstream_schema_preserves_nullable_fillers(self) -> None: |
| record = normalize_record( |
| { |
| "audio": b"abc", |
| "id": "example-1", |
| "language": "en", |
| "endpoint_bool": True, |
| "midfiller": None, |
| "endfiller": False, |
| "synthetic": True, |
| "spoken_text": None, |
| "dataset": "chirp3_1", |
| "speaker_id": "speaker-7", |
| } |
| ) |
| self.assertEqual(record.record_id, "example-1") |
| self.assertIs(record.endpoint, True) |
| self.assertIsNone(record.midfiller) |
| self.assertIs(record.endfiller, False) |
| self.assertEqual(record.metadata["speaker_id"], "speaker-7") |
|
|
| def test_invalid_required_endpoint_is_reported(self) -> None: |
| raw = {"audio": b"abc", "id": "bad", "endpoint_bool": "maybe"} |
| with self.assertRaises(RecordValidationError): |
| normalize_record(raw) |
| result = normalize_record_with_issues(raw) |
| self.assertIsNone(result.record.endpoint) |
| self.assertIn("invalid_endpoint", {issue.code for issue in result.errors}) |
|
|
| def test_missing_id_gets_provenance_fallback(self) -> None: |
| result = normalize_record_with_issues( |
| { |
| "audio": b"abc", |
| "endpoint_bool": False, |
| "__source_file": "shard.parquet", |
| "__source_row": 9, |
| } |
| ) |
| self.assertEqual(result.record.record_id, "shard.parquet#9") |
| self.assertIn("missing_id", {issue.code for issue in result.warnings}) |
|
|
| def test_filler_flags_are_independent_and_not_coerced(self) -> None: |
| result = normalize_record_with_issues( |
| { |
| "audio": b"abc", |
| "id": "fillers", |
| "endpoint_bool": True, |
| "midfiller": True, |
| "endfiller": True, |
| } |
| ) |
| self.assertTrue(result.record.midfiller) |
| self.assertTrue(result.record.endfiller) |
| self.assertNotIn("conflicting_filler_flags", {issue.code for issue in result.warnings}) |
|
|
|
|
| if __name__ == "__main__": |
| unittest.main() |
|
|