Skip to content

Commit 041c30b

Browse files
Add more tests
1 parent e5ac292 commit 041c30b

File tree

1 file changed

+160
-5
lines changed

1 file changed

+160
-5
lines changed

src/conversions/jiff.rs

+160-5
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,8 @@ impl From<jiff::Error> for PyErr {
540540
#[cfg(test)]
541541
mod tests {
542542
use super::*;
543+
#[cfg(not(Py_LIMITED_API))]
544+
use crate::types::timezone_utc;
543545
use crate::{types::PyTuple, BoundObject};
544546
use jiff::tz::Offset;
545547
use std::cmp::Ordering;
@@ -562,7 +564,7 @@ mod tests {
562564
Some(&locals),
563565
)
564566
.unwrap();
565-
let result: PyResult<FixedOffset> = locals.get_item("zi").unwrap().unwrap().extract();
567+
let result: PyResult<Offset> = locals.get_item("zi").unwrap().unwrap().extract();
566568
assert!(result.is_err());
567569
let res = result.err().unwrap();
568570
// Also check the error message is what we expect
@@ -601,6 +603,40 @@ mod tests {
601603
});
602604
}
603605

606+
#[test]
607+
fn test_invalid_types_fail() {
608+
Python::with_gil(|py| {
609+
let none = py.None().into_bound(py);
610+
assert_eq!(
611+
none.extract::<Span>().unwrap_err().to_string(),
612+
"TypeError: 'NoneType' object cannot be converted to 'PyDelta'"
613+
);
614+
assert_eq!(
615+
none.extract::<Offset>().unwrap_err().to_string(),
616+
"TypeError: 'NoneType' object cannot be converted to 'PyTzInfo'"
617+
);
618+
assert_eq!(
619+
none.extract::<TimeZone>().unwrap_err().to_string(),
620+
"TypeError: 'NoneType' object cannot be converted to 'PyTzInfo'"
621+
);
622+
assert_eq!(
623+
none.extract::<Time>().unwrap_err().to_string(),
624+
"TypeError: 'NoneType' object cannot be converted to 'PyTime'"
625+
);
626+
assert_eq!(
627+
none.extract::<Date>().unwrap_err().to_string(),
628+
"TypeError: 'NoneType' object cannot be converted to 'PyDate'"
629+
);
630+
assert_eq!(
631+
none.extract::<DateTime>().unwrap_err().to_string(),
632+
"TypeError: 'NoneType' object cannot be converted to 'PyDateTime'"
633+
);
634+
assert_eq!(
635+
none.extract::<Zoned>().unwrap_err().to_string(),
636+
"TypeError: 'NoneType' object cannot be converted to 'PyDateTime'"
637+
);
638+
});
639+
}
604640

605641
#[test]
606642
fn test_pyo3_date_into_pyobject() {
@@ -722,11 +758,9 @@ mod tests {
722758
#[cfg(all(Py_3_9, not(windows)))]
723759
fn test_pyo3_datetime_into_pyobject_tz() {
724760
Python::with_gil(|py| {
725-
let datetime = NaiveDate::from_ymd_opt(2024, 12, 11)
726-
.unwrap()
727-
.and_hms_opt(23, 3, 13)
761+
let datetime = DateTime::new(2024, 12, 11, 23, 3, 13, 0)
728762
.unwrap()
729-
.and_local_timezone(chrono_tz::Tz::Europe__London)
763+
.to_zoned(TimeZone::get("Europe/London").unwrap())
730764
.unwrap();
731765
let datetime = datetime.into_pyobject(py).unwrap();
732766
let py_datetime = new_py_datetime_ob(
@@ -747,6 +781,30 @@ mod tests {
747781
})
748782
}
749783

784+
#[test]
785+
fn test_pyo3_datetime_frompyobject_utc() {
786+
Python::with_gil(|py| {
787+
let year = 2014;
788+
let month = 5;
789+
let day = 6;
790+
let hour = 7;
791+
let minute = 8;
792+
let second = 9;
793+
let micro = 999_999;
794+
let tz_utc = timezone_utc(py);
795+
let py_datetime = new_py_datetime_ob(
796+
py,
797+
"datetime",
798+
(year, month, day, hour, minute, second, micro, tz_utc),
799+
);
800+
let py_datetime: Zoned = py_datetime.extract().unwrap();
801+
let datetime = DateTime::new(year, month, day, hour, minute, second, micro * 1000)
802+
.unwrap()
803+
.to_zoned(TimeZone::UTC)
804+
.unwrap();
805+
assert_eq!(py_datetime, datetime,);
806+
})
807+
}
750808

751809
#[test]
752810
fn test_pyo3_datetime_frompyobject_fixed_offset() {
@@ -774,6 +832,103 @@ mod tests {
774832
})
775833
}
776834

835+
#[test]
836+
fn test_pyo3_offset_fixed_into_pyobject() {
837+
Python::with_gil(|py| {
838+
// Chrono offset
839+
let offset = Offset::from_seconds(3600)
840+
.unwrap()
841+
.into_pyobject(py)
842+
.unwrap();
843+
// Python timezone from timedelta
844+
let td = new_py_datetime_ob(py, "timedelta", (0, 3600, 0));
845+
let py_timedelta = new_py_datetime_ob(py, "timezone", (td,));
846+
// Should be equal
847+
assert!(offset.eq(py_timedelta).unwrap());
848+
849+
// Same but with negative values
850+
let offset = Offset::from_seconds(-3600)
851+
.unwrap()
852+
.into_pyobject(py)
853+
.unwrap();
854+
let td = new_py_datetime_ob(py, "timedelta", (0, -3600, 0));
855+
let py_timedelta = new_py_datetime_ob(py, "timezone", (td,));
856+
assert!(offset.eq(py_timedelta).unwrap());
857+
})
858+
}
859+
860+
#[test]
861+
fn test_pyo3_offset_fixed_frompyobject() {
862+
Python::with_gil(|py| {
863+
let py_timedelta = new_py_datetime_ob(py, "timedelta", (0, 3600, 0));
864+
let py_tzinfo = new_py_datetime_ob(py, "timezone", (py_timedelta,));
865+
let offset: Offset = py_tzinfo.extract().unwrap();
866+
assert_eq!(Offset::from_seconds(3600).unwrap(), offset);
867+
})
868+
}
869+
870+
#[test]
871+
fn test_pyo3_offset_utc_into_pyobject() {
872+
Python::with_gil(|py| {
873+
let utc = Offset::UTC.into_pyobject(py).unwrap();
874+
let py_utc = python_utc(py);
875+
assert!(utc.is(&py_utc));
876+
})
877+
}
878+
879+
#[test]
880+
fn test_pyo3_offset_utc_frompyobject() {
881+
Python::with_gil(|py| {
882+
let py_utc = python_utc(py);
883+
let py_utc: Offset = py_utc.extract().unwrap();
884+
assert_eq!(Offset::UTC, py_utc);
885+
886+
let py_timedelta = new_py_datetime_ob(py, "timedelta", (0, 0, 0));
887+
let py_timezone_utc = new_py_datetime_ob(py, "timezone", (py_timedelta,));
888+
let py_timezone_utc: Offset = py_timezone_utc.extract().unwrap();
889+
assert_eq!(Offset::UTC, py_timezone_utc);
890+
891+
let py_timedelta = new_py_datetime_ob(py, "timedelta", (0, 3600, 0));
892+
let py_timezone = new_py_datetime_ob(py, "timezone", (py_timedelta,));
893+
assert_ne!(Offset::UTC, py_timezone.extract::<Offset>().unwrap());
894+
})
895+
}
896+
897+
#[test]
898+
fn test_pyo3_time_into_pyobject() {
899+
Python::with_gil(|py| {
900+
let check_time = |name: &'static str, hour, minute, second, ms, py_ms| {
901+
let time = Time::new(hour, minute, second, ms * 1000)
902+
.unwrap()
903+
.into_pyobject(py)
904+
.unwrap();
905+
let py_time = new_py_datetime_ob(py, "time", (hour, minute, second, py_ms));
906+
assert!(
907+
time.eq(&py_time).unwrap(),
908+
"{}: {} != {}",
909+
name,
910+
time,
911+
py_time
912+
);
913+
};
914+
915+
check_time("regular", 3, 5, 7, 999_999, 999_999);
916+
})
917+
}
918+
919+
#[test]
920+
fn test_pyo3_time_frompyobject() {
921+
let hour = 3;
922+
let minute = 5;
923+
let second = 7;
924+
let micro = 999_999;
925+
Python::with_gil(|py| {
926+
let py_time = new_py_datetime_ob(py, "time", (hour, minute, second, micro));
927+
let py_time: Time = py_time.extract().unwrap();
928+
let time = Time::new(hour, minute, second, micro * 1000).unwrap();
929+
assert_eq!(py_time, time);
930+
})
931+
}
777932

778933
fn new_py_datetime_ob<'py, A>(py: Python<'py>, name: &str, args: A) -> Bound<'py, PyAny>
779934
where

0 commit comments

Comments
 (0)