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 ( # noqa: E402 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()