plugins types FEATURE sort callback in date_time
diff --git a/src/plugins_types/date_and_time.c b/src/plugins_types/date_and_time.c
index b60bf55..1cc0ec4 100644
--- a/src/plugins_types/date_and_time.c
+++ b/src/plugins_types/date_and_time.c
@@ -16,6 +16,7 @@
#include "plugins_types.h"
+#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <stdint.h>
@@ -172,6 +173,91 @@
}
/**
+ * @brief Decide if @p frac can be represented as zero.
+ *
+ * @param[in] frac Fractions of a second.
+ * @return 1 if @p frac can be represented as zero.
+ * @return 0 @p frac is not zero.
+ */
+static ly_bool
+lyplg_type_fractions_is_zero(char *frac)
+{
+ char *iter;
+
+ if (!frac) {
+ return 1;
+ }
+
+ for (iter = frac; *iter; iter++) {
+ if (*iter != '0') {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/**
+ * @brief Compare @p f1 and @p f2 for sorting.
+ *
+ * @param[in] f1 First fractions of a second.
+ * @param[in] f2 Second fractions of a second.
+ * @return 1 if @p f1 > @p f2.
+ * @return 0 if @p f1 == @p f2.
+ * @return -1 if @p f1 < @p f2.
+ */
+static int
+lyplg_type_sort_by_fractions(char *f1, char *f2)
+{
+ ly_bool f1_is_zero, f2_is_zero;
+ int df;
+
+ f1_is_zero = lyplg_type_fractions_is_zero(f1);
+ f2_is_zero = lyplg_type_fractions_is_zero(f2);
+
+ if (f1_is_zero && !f2_is_zero) {
+ return -1;
+ } else if (!f1_is_zero && f2_is_zero) {
+ return 1;
+ } else if (f1_is_zero && f2_is_zero) {
+ return 0;
+ }
+
+ /* both f1 and f2 have some non-zero number */
+ assert(!f1_is_zero && !f2_is_zero && f1 && f2);
+ df = strcmp(f1, f2);
+ if (df > 0) {
+ return 1;
+ } else if (df < 0) {
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
+/**
+ * @brief Implementation of ::lyplg_type_sort_clb for ietf-yang-types date-and-time type.
+ */
+static int
+lyplg_type_sort_date_and_time(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1, const struct lyd_value *val2)
+{
+ struct lyd_value_date_and_time *v1, *v2;
+ double dt;
+
+ LYD_VALUE_GET(val1, v1);
+ LYD_VALUE_GET(val2, v2);
+
+ /* compare timestamps */
+ dt = difftime(v1->time, v2->time);
+ if (dt != 0) {
+ return dt;
+ }
+
+ /* compare second fractions */
+ return lyplg_type_sort_by_fractions(v1->fractions_s, v2->fractions_s);
+}
+
+/**
* @brief Implementation of ::lyplg_type_print_clb for ietf-yang-types date-and-time type.
*/
static const void *
@@ -316,7 +402,7 @@
.plugin.store = lyplg_type_store_date_and_time,
.plugin.validate = NULL,
.plugin.compare = lyplg_type_compare_date_and_time,
- .plugin.sort = NULL,
+ .plugin.sort = lyplg_type_sort_date_and_time,
.plugin.print = lyplg_type_print_date_and_time,
.plugin.duplicate = lyplg_type_dup_date_and_time,
.plugin.free = lyplg_type_free_date_and_time,
diff --git a/tests/utests/types/yang_types.c b/tests/utests/types/yang_types.c
index 56778c4..51a7c7f 100644
--- a/tests/utests/types/yang_types.c
+++ b/tests/utests/types/yang_types.c
@@ -228,6 +228,86 @@
TEST_SUCCESS_LYB("a\" xmlns:aa=\"urn:tests:a", "l2", "/aa:l2[. = '4']");
}
+static void
+test_sort(void **state)
+{
+ const char *v1, *v2;
+ const char *schema;
+ struct lys_module *mod;
+ struct lyd_value val1 = {0}, val2 = {0};
+ struct lyplg_type *type = lyplg_type_plugin_find("ietf-yang-types", "2013-07-15", "date-and-time");
+ struct lysc_type *lysc_type;
+ struct ly_err_item *err = NULL;
+
+ /* create schema. Prepare common used variables */
+ schema = MODULE_CREATE_YANG("a",
+ "leaf-list ll {type yang:date-and-time;}");
+ UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
+ lysc_type = ((struct lysc_node_leaflist *)mod->compiled->data)->type;
+
+ /* v1 > v2, v2 < v1, v1 == v1 */
+ v1 = "2005-05-25T23:15:15Z";
+ assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
+ 0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
+ v2 = "2005-05-25T23:15:14Z";
+ assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
+ 0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &val2, NULL, &err));
+ assert_true(0 < type->sort(UTEST_LYCTX, &val1, &val2));
+ assert_true(0 > type->sort(UTEST_LYCTX, &val2, &val1));
+ assert_int_equal(0, type->sort(UTEST_LYCTX, &val1, &val1));
+ type->free(UTEST_LYCTX, &val1);
+ type->free(UTEST_LYCTX, &val2);
+
+ /* unknown timezone */
+ v1 = "2005-05-25T23:15:15Z";
+ assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
+ 0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
+ v2 = "2005-05-25T23:15:15-00:00";
+ assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
+ 0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &val2, NULL, &err));
+ assert_int_equal(0, type->sort(UTEST_LYCTX, &val1, &val2));
+ type->free(UTEST_LYCTX, &val1);
+ type->free(UTEST_LYCTX, &val2);
+
+ /* fractions of a second */
+ v1 = "2005-05-25T23:15:15.88888Z";
+ assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
+ 0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
+ v2 = "2005-05-25T23:15:15.88889Z";
+ assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
+ 0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &val2, NULL, &err));
+ assert_true(0 > type->sort(UTEST_LYCTX, &val1, &val2));
+ assert_true(0 < type->sort(UTEST_LYCTX, &val2, &val1));
+ assert_int_equal(0, type->sort(UTEST_LYCTX, &val1, &val1));
+ type->free(UTEST_LYCTX, &val1);
+ type->free(UTEST_LYCTX, &val2);
+
+ /* zero fractions of a second */
+ v1 = "2005-05-25T23:15:15.00Z";
+ assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
+ 0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
+ v2 = "2005-05-25T23:15:15Z";
+ assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
+ 0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &val2, NULL, &err));
+ assert_int_equal(0, type->sort(UTEST_LYCTX, &val1, &val2));
+ assert_int_equal(0, type->sort(UTEST_LYCTX, &val2, &val1));
+ type->free(UTEST_LYCTX, &val1);
+ type->free(UTEST_LYCTX, &val2);
+
+ /* zero fractions of a second and non-zero */
+ v1 = "2005-05-25T23:15:15.00Z";
+ assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
+ 0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
+ v2 = "2005-05-25T23:15:15.0001Z";
+ assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
+ 0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &val2, NULL, &err));
+ assert_int_equal(-1, type->sort(UTEST_LYCTX, &val1, &val2));
+ assert_int_equal(1, type->sort(UTEST_LYCTX, &val2, &val1));
+ assert_int_equal(0, type->sort(UTEST_LYCTX, &val1, &val1));
+ type->free(UTEST_LYCTX, &val1);
+ type->free(UTEST_LYCTX, &val2);
+}
+
int
main(void)
{
@@ -236,6 +316,7 @@
UTEST(test_print),
UTEST(test_duplicate),
UTEST(test_lyb),
+ UTEST(test_sort),
};
return cmocka_run_group_tests(tests, NULL, NULL);