summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--src/plist.c20
-rw-r--r--test/Makefile.am5
-rw-r--r--test/date_val.c42
-rwxr-xr-xtest/date_val.test5
5 files changed, 68 insertions, 5 deletions
diff --git a/.gitignore b/.gitignore
index d7d27da..6924ef3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -54,6 +54,7 @@ test/plist_btest
test/plist_jtest
test/plist_otest
test/integer_set_test
+test/date_val_test
test/xml_behavior_test
test/bplist_behavior_test
test/data/*.out
diff --git a/src/plist.c b/src/plist.c
index 677e94e..85c2338 100644
--- a/src/plist.c
+++ b/src/plist.c
@@ -1889,13 +1889,23 @@ void plist_get_date_val(plist_t node, int32_t * sec, int32_t * usec)
return;
plist_get_type_and_value(node, &type, (void *) &val, &length);
assert(length == sizeof(double));
+ /* Inverse of plist_set_date_val (val = sec + usec / 1000000):
+ * whole seconds rounded down, the fraction rounded to microseconds. */
+ double whole = floor(val);
+ double frac_usec = round((val - whole) * 1000000);
+ if (frac_usec >= 1000000) {
+ whole += 1;
+ frac_usec -= 1000000;
+ }
+ /* keep the int32_t conversion defined */
+ if (whole > INT32_MAX)
+ whole = INT32_MAX;
+ else if (whole < INT32_MIN)
+ whole = INT32_MIN;
if (sec)
- *sec = (int32_t)val;
+ *sec = (int32_t)whole;
if (usec)
- {
- val = fabs((val - (int64_t)val) * 1000000);
- *usec = (int32_t)val;
- }
+ *usec = (int32_t)frac_usec;
}
void plist_get_unix_date_val(plist_t node, int64_t *sec)
diff --git a/test/Makefile.am b/test/Makefile.am
index 1d98349..2e2b04e 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -11,6 +11,7 @@ noinst_PROGRAMS = \
plist_test \
plist_test++ \
integer_set_test \
+ date_val_test \
plist_btest \
plist_jtest \
plist_otest \
@@ -31,6 +32,9 @@ plist_test_LDADD = $(top_builddir)/src/libplist-2.0.la
integer_set_test_SOURCES = integer_set.c
integer_set_test_LDADD = $(top_builddir)/src/libplist-2.0.la
+date_val_test_SOURCES = date_val.c
+date_val_test_LDADD = $(top_builddir)/src/libplist-2.0.la
+
plist_btest_SOURCES = plist_btest.c
plist_btest_LDADD = $(top_builddir)/src/libplist-2.0.la
@@ -47,6 +51,7 @@ bplist_behavior_test_SOURCES = bplist_behavior_test.c
bplist_behavior_test_LDADD = $(top_builddir)/src/libplist-2.0.la
TESTS = \
+ date_val.test \
empty.test \
small.test \
medium.test \
diff --git a/test/date_val.c b/test/date_val.c
new file mode 100644
index 0000000..127e194
--- /dev/null
+++ b/test/date_val.c
@@ -0,0 +1,42 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <plist/plist.h>
+
+/* plist_get_date_val must return exactly what plist_set_date_val stored,
+ * including dates before the epoch (negative seconds). */
+
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
+static int check(int32_t sec, int32_t usec)
+{
+ int32_t s = 0, u = 0;
+ plist_t d = plist_new_date(0, 0);
+ plist_set_date_val(d, sec, usec);
+ plist_get_date_val(d, &s, &u);
+ plist_free(d);
+ if (s != sec || u != usec) {
+ printf("set(%d, %d) -> get(%d, %d)\n", sec, usec, s, u);
+ return 1;
+ }
+ return 0;
+}
+
+int main(int argc, char** argv)
+{
+ int err = 0;
+ int32_t sec, usec;
+
+ err |= check(5, 6);
+ err |= check(0, 999999);
+ err |= check(-3, 250000);
+ err |= check(-1, 1);
+ err |= check(1000000000, 123456);
+ for (sec = -2; sec <= 2 && !err; sec++) {
+ for (usec = 0; usec < 1000000 && !err; usec += 7) {
+ err |= check(sec, usec);
+ }
+ }
+ return err;
+}
diff --git a/test/date_val.test b/test/date_val.test
new file mode 100755
index 0000000..9cdf504
--- /dev/null
+++ b/test/date_val.test
@@ -0,0 +1,5 @@
+## -*- sh -*-
+
+set -e
+
+$top_builddir/test/date_val_test