@@ -482,106 +482,6 @@ def test_time_executemany(cursor, db_connection):
482482 db_connection.commit()
483483
484484
485- # ---------------------------------------------------------------------------
486- # Unit tests for ParseSqlTimeTextToPythonObject (exposed via _test_parse_time_text)
487- # These exercise defensive C++ branches that are unreachable through normal
488- # ODBC queries: null/zero-length input, SQL_NO_TOTAL, oversized length,
489- # whitespace-only buffers, and malformed text without colon separators.
490- # ---------------------------------------------------------------------------
491-
492-
493- class TestParseSqlTimeText:
494- """Direct tests for the C++ ParseSqlTimeTextToPythonObject helper."""
495-
496- @staticmethod
497- def _parse(text, length):
498- from mssql_python.ddbc_bindings import _test_parse_time_text
499-
500- return _test_parse_time_text(text, length)
501-
502- @staticmethod
503- def _sql_no_total():
504- from mssql_python.ddbc_bindings import SQL_NO_TOTAL
505-
506- return SQL_NO_TOTAL
507-
508- def test_zero_length_returns_none(self):
509- """Lines 64-65: timeTextLen <= 0 → py::none()"""
510- assert self._parse("12:00:00", 0) is None
511-
512- def test_negative_length_returns_none(self):
513- """Lines 64-65: timeTextLen < 0 (but not SQL_NO_TOTAL) → py::none()"""
514- assert self._parse("12:00:00", -999) is None
515-
516- def test_sql_no_total_uses_bounded_scan(self):
517- """Lines 71-73: SQL_NO_TOTAL → memchr-bounded length scan."""
518- result = self._parse("14:30:00.123456", self._sql_no_total())
519- assert result == time(14, 30, 0, 123456)
520-
521- def test_oversized_length_is_clamped(self):
522- """Lines 77-78: timeTextLen > SQL_TIME_TEXT_MAX_LEN-1 → clamp."""
523- result = self._parse("09:15:30.000000", 9999)
524- assert result == time(9, 15, 30)
525-
526- def test_whitespace_only_returns_none(self):
527- """Lines 85-86: value is all whitespace → py::none()"""
528- assert self._parse(" \t\n ", 7) is None
529-
530- def test_missing_colon_raises(self):
531- """Lines 94-95: no ':' separators → ThrowStdException."""
532- with pytest.raises(Exception, match="missing ':' separators"):
533- self._parse("no-colons-here", 14)
534-
535- def test_normal_time_with_fraction(self):
536- """Sanity check: normal parse path."""
537- result = self._parse("08:05:03.100000", 15)
538- assert result == time(8, 5, 3, 100000)
539-
540- def test_normal_time_without_fraction(self):
541- """Sanity check: parse path without fractional part."""
542- result = self._parse("23:59:59", 8)
543- assert result == time(23, 59, 59)
544-
545- # --- try-catch on std::stoi ---
546-
547- def test_invalid_hour_raises(self):
548- """std::stoi fails on non-numeric hour → descriptive error."""
549- with pytest.raises(Exception, match="Failed to parse hour"):
550- self._parse("AB:00:00", 8)
551-
552- def test_invalid_minute_raises(self):
553- """std::stoi fails on non-numeric minute → descriptive error."""
554- with pytest.raises(Exception, match="Failed to parse minute"):
555- self._parse("12:XY:00", 8)
556-
557- def test_invalid_second_raises(self):
558- """std::stoi fails on non-numeric second → descriptive error."""
559- with pytest.raises(Exception, match="Failed to parse second"):
560- self._parse("12:00:ZZ", 8)
561-
562- def test_invalid_microsecond_treated_as_zero(self):
563- """Non-digit fractional chars are stripped, resulting in microsecond=0."""
564- result = self._parse("12:00:00.ABCDEF", 15)
565- assert result == time(12, 0, 0, 0)
566-
567- # --- range validation ---
568-
569- def test_hour_out_of_range_raises(self):
570- """Hour > 23 → descriptive range error."""
571- with pytest.raises(Exception, match="Hour out of range"):
572- self._parse("25:00:00", 8)
573-
574- def test_minute_out_of_range_raises(self):
575- """Minute > 59 → descriptive range error."""
576- with pytest.raises(Exception, match="Minute out of range"):
577- self._parse("12:60:00", 8)
578-
579- def test_second_out_of_range_raises(self):
580- """Second > 59 → descriptive range error."""
581- with pytest.raises(Exception, match="Second out of range"):
582- self._parse("12:00:99", 8)
583-
584-
585485# ---------------------------------------------------------------------------
586486# Unit tests for _normalize_time_param helper
587487# ---------------------------------------------------------------------------
0 commit comments