| /*****************************************************************************\ |
| * Copyright (C) SchedMD LLC. |
| * |
| * This file is part of Slurm, a resource management program. |
| * For details, see <https://slurm.schedmd.com/>. |
| * Please also read the included file: DISCLAIMER. |
| * |
| * Slurm is free software; you can redistribute it and/or modify it under |
| * the terms of the GNU General Public License as published by the Free |
| * Software Foundation; either version 2 of the License, or (at your option) |
| * any later version. |
| * |
| * In addition, as a special exception, the copyright holders give permission |
| * to link the code of portions of this program with the OpenSSL library under |
| * certain conditions as described in each individual source file, and |
| * distribute linked combinations including the two. You must obey the GNU |
| * General Public License in all respects for all of the code used other than |
| * OpenSSL. If you modify file(s) with this exception, you may extend this |
| * exception to your version of the file(s), but you are not obligated to do |
| * so. If you do not wish to do so, delete this exception statement from your |
| * version. If you delete this exception statement from all source files in |
| * the program, then also delete it here. |
| * |
| * Slurm is distributed in the hope that it will be useful, but WITHOUT ANY |
| * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
| * details. |
| * |
| * You should have received a copy of the GNU General Public License along |
| * with Slurm; if not, write to the Free Software Foundation, Inc., |
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| \*****************************************************************************/ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| #include <check.h> |
| |
| #include "slurm/slurm_errno.h" |
| #include "src/common/data.h" |
| #include "src/common/log.h" |
| #include "src/common/read_config.h" |
| #include "src/common/slurm_protocol_defs.h" |
| #include "src/common/xmalloc.h" |
| #include "src/common/xstring.h" |
| |
| #define check_with_data_get_bool_converted(str, b) \ |
| do { \ |
| bool bres; \ |
| int rc; \ |
| data_set_string(d, str); \ |
| rc = data_get_bool_converted(d, &bres); \ |
| ck_assert_msg(rc == 0, \ |
| "bool convert string:%s->%s rc:%s [%d]", \ |
| str ? str : "(null)", (b ? "true" : "false"), \ |
| slurm_strerror(rc), rc); \ |
| if (!rc) \ |
| ck_assert_msg(bres == b, \ |
| "bool converted: %s -> %s == %s", \ |
| str ? str : "(null)", (bres ? "true" : "false"), \ |
| (b ? "true" : "false")); \ |
| } while (0) |
| |
| static data_for_each_cmd_t |
| _find_dict_bool(const char *key, const data_t *data, void *arg) |
| { |
| int *found = arg; |
| |
| ck_assert_msg(data_get_type(data) == DATA_TYPE_BOOL, "entry bool type"); |
| |
| if (data_get_bool(data)) |
| (*found)++; |
| |
| ck_assert(key != NULL); |
| return DATA_FOR_EACH_CONT; |
| } |
| |
| static data_for_each_cmd_t |
| _invert_dict_bool(const char *key, data_t *data, void *arg) |
| { |
| ck_assert_msg(data_get_type(data) == DATA_TYPE_BOOL, "entry bool type"); |
| ck_assert(key != NULL); |
| data_set_bool(data, !data_get_bool(data)); |
| return DATA_FOR_EACH_CONT; |
| } |
| |
| static data_for_each_cmd_t |
| _del_dict_bool_true(const char *key, data_t *data, void *arg) |
| { |
| int *max = arg; |
| |
| ck_assert(key != NULL); |
| ck_assert_msg(data_get_type(data) == DATA_TYPE_BOOL, "entry bool type"); |
| |
| if (*max <= 0) |
| return DATA_FOR_EACH_STOP; |
| |
| if (data_get_bool(data)) { |
| *max -= 1; |
| return DATA_FOR_EACH_DELETE; |
| } |
| |
| return DATA_FOR_EACH_CONT; |
| } |
| |
| static data_for_each_cmd_t _del_list_odd(data_t *data, void *arg) |
| { |
| int *max = arg; |
| |
| ck_assert_msg(data_get_type(data) == DATA_TYPE_INT_64, |
| "entry int type"); |
| |
| if (*max <= 0) |
| return DATA_FOR_EACH_STOP; |
| |
| if (data_get_int(data) % 2 == 1) { |
| *max -= 1; |
| return DATA_FOR_EACH_DELETE; |
| } |
| |
| return DATA_FOR_EACH_CONT; |
| } |
| |
| data_for_each_cmd_t _check_list_order(const data_t *data, void *arg) |
| { |
| int *found = arg; |
| |
| ck_assert_msg(data_get_int(data) == *found, |
| "check value"); |
| |
| *found += 1; |
| return DATA_FOR_EACH_CONT; |
| } |
| |
| |
| START_TEST(test_list_iteration) |
| { |
| int max; |
| int found = 0; |
| data_t *d = data_new(); |
| data_set_list(d); |
| |
| ck_assert_msg(data_get_type(d) == DATA_TYPE_LIST, "check list type"); |
| |
| data_set_int(data_list_append(d), 5); |
| data_set_int(data_list_prepend(d), 4); |
| data_set_int(data_list_append(d), 6); |
| data_set_int(data_list_prepend(d), 3); |
| data_set_int(data_list_append(d), 7); |
| data_set_int(data_list_prepend(d), 2); |
| data_set_int(data_list_append(d), 8); |
| data_set_int(data_list_prepend(d), 1); |
| data_set_int(data_list_append(d), 9); |
| data_set_int(data_list_prepend(d), 0); |
| |
| ck_assert_msg(data_get_type(d) == DATA_TYPE_LIST, "check list type"); |
| ck_assert_msg(data_get_list_length(d) == 10, "list count"); |
| |
| found = 0; |
| ck_assert_msg(data_list_for_each_const(d, _check_list_order, &found) == |
| 10, "order touch count"); |
| ck_assert_msg(found == 10, "check max found"); |
| |
| data_set_int(data_list_append(d), 10); |
| |
| found = 0; |
| ck_assert_msg(data_list_for_each_const(d, _check_list_order, &found) == |
| 11, "order touch count"); |
| ck_assert_msg(found == 11, "check max found"); |
| |
| max = 1; |
| data_list_for_each(d, _del_list_odd, &max); |
| ck_assert_msg(data_get_list_length(d) == 10, "list count"); |
| ck_assert_msg(max == 0, "check remove count"); |
| |
| max = 20; |
| data_list_for_each(d, _del_list_odd, &max); |
| ck_assert_msg(data_get_list_length(d) == 6, "list count"); |
| ck_assert_msg(max == 16, "check remove count"); |
| |
| FREE_NULL_DATA(d); |
| } |
| END_TEST |
| |
| START_TEST(test_dict_iteration) |
| { |
| int max; |
| int found = 0; |
| data_t *d = data_new(); |
| data_set_dict(d); |
| |
| data_set_bool(data_key_set(d, "true1"), true); |
| data_set_bool(data_key_set(d, "true2"), true); |
| data_set_bool(data_key_set(d, "true3"), true); |
| data_set_bool(data_key_set(d, "true4"), true); |
| data_set_bool(data_key_set(d, "true5"), true); |
| data_set_bool(data_key_set(d, "false1"), false); |
| data_set_bool(data_key_set(d, "false2"), false); |
| data_set_bool(data_key_set(d, "false3"), false); |
| data_set_bool(data_key_set(d, "false4"), false); |
| data_set_bool(data_key_set(d, "false5"), false); |
| ck_assert_msg(data_get_dict_length(d) == 10, "dict cardinality"); |
| ck_assert_msg(data_dict_for_each_const(d, _find_dict_bool, &found) == |
| 10, "find true"); |
| ck_assert_msg(found == 5, "found true"); |
| |
| ck_assert_msg(data_dict_for_each(d, _invert_dict_bool, NULL) == 10, |
| "invert true"); |
| ck_assert_msg(data_get_dict_length(d) == 10, "dict cardinality"); |
| found = 0; |
| ck_assert_msg(data_dict_for_each_const(d, _find_dict_bool, &found) == |
| 10, "find true"); |
| ck_assert_msg(found == 5, "found true"); |
| |
| max = 1; |
| data_dict_for_each(d, _del_dict_bool_true, &max); |
| ck_assert_msg(max == 0, "remove 1 true"); |
| |
| found = 0; |
| ck_assert_msg(data_dict_for_each_const(d, _find_dict_bool, &found) == 9, |
| "find true"); |
| ck_assert_msg(found == 4, "found true"); |
| ck_assert_msg(data_get_dict_length(d) == 9, "dict cardinality"); |
| |
| max = 0; |
| data_dict_for_each(d, _del_dict_bool_true, &max); |
| ck_assert_msg(max == 0, "no op remove"); |
| ck_assert_msg(data_get_dict_length(d) == 9, |
| "dict cardinality after no op"); |
| |
| max = 4; |
| data_dict_for_each(d, _del_dict_bool_true, &max); |
| ck_assert_msg(max == 0, "remove all true"); |
| ck_assert_msg(data_get_dict_length(d) == 5, "dict cardinality"); |
| |
| FREE_NULL_DATA(d); |
| } |
| END_TEST |
| |
| START_TEST(test_dict_typeset) |
| { |
| data_t *d = data_new(); |
| |
| ck_assert_msg(data_get_type(d) == DATA_TYPE_NULL, "default type"); |
| data_set_dict(d); |
| ck_assert_msg(data_get_type(d) == DATA_TYPE_DICT, "dict type"); |
| ck_assert_msg(data_get_dict_length(d) == 0, "dict cardinality"); |
| data_key_set(d, "test1"); |
| data_key_set(d, "test2"); |
| data_key_set(d, "test3"); |
| data_key_set(d, "test4"); |
| data_key_set(d, "test5"); |
| ck_assert_msg(data_get_dict_length(d) == 5, "dict cardinality"); |
| |
| data_set_list(d); |
| ck_assert_msg(data_get_type(d) == DATA_TYPE_LIST, "list type"); |
| ck_assert_msg(data_get_list_length(d) == 0, "list cardinality"); |
| data_list_append(d); |
| data_list_prepend(d); |
| data_list_prepend(d); |
| data_list_append(d); |
| data_list_append(d); |
| ck_assert_msg(data_get_list_length(d) == 5, "list cardinality"); |
| |
| data_set_int(d, 100); |
| ck_assert_msg(data_get_type(d) == DATA_TYPE_INT_64, "int type"); |
| ck_assert_msg(data_get_int(d) == 100, "check int value"); |
| |
| char *str = NULL; |
| ck_assert_msg(data_get_string_converted(d, &str) == 0, |
| "convert 100 to string"); |
| ck_assert_msg(xstrcmp(str, "100") == 0, "check 100 got converted"); |
| xfree(str); |
| |
| ck_assert_msg(data_convert_type(d, DATA_TYPE_STRING) == |
| DATA_TYPE_STRING, "convert 100 to string"); |
| ck_assert_msg(data_get_type(d) == DATA_TYPE_STRING, "int type"); |
| ck_assert_msg(xstrcmp(data_get_string(d), "100") == 0, |
| "check 100 got converted"); |
| |
| int64_t b = 0; |
| ck_assert_msg(data_get_int_converted(d, &b) == 0, |
| "convert 100 from string"); |
| ck_assert_msg(data_get_type(d) == DATA_TYPE_STRING, |
| "check still string type"); |
| ck_assert_msg(b == 100, "check string conversion from 100"); |
| |
| ck_assert_msg(data_convert_type(d, DATA_TYPE_INT_64) == |
| DATA_TYPE_INT_64, "convert 100 from string"); |
| ck_assert_msg(data_get_type(d) == DATA_TYPE_INT_64, "int type"); |
| ck_assert_msg(data_get_int(d) == 100, |
| "check string conversion from 100"); |
| |
| data_set_float(d, 3.14); |
| ck_assert_msg(data_get_type(d) == DATA_TYPE_FLOAT, "float type"); |
| |
| str = NULL; |
| ck_assert_msg(data_get_string_converted(d, &str) == 0, |
| "convert 3.14 to string"); |
| ck_assert_msg(xstrcmp(str, "3.140000") == 0, |
| "check 3.14 got converted"); |
| xfree(str); |
| ck_assert_msg(data_get_type(d) == DATA_TYPE_FLOAT, "float type"); |
| |
| ck_assert_msg(data_convert_type(d, DATA_TYPE_FLOAT) == DATA_TYPE_FLOAT, |
| "convert 100 from string"); |
| ck_assert_msg(data_get_type(d) == DATA_TYPE_FLOAT, "int type"); |
| ck_assert_msg(data_get_float(d) == 3.14, |
| "check string conversion from 3.14"); |
| |
| data_set_float(d, -3.14); |
| ck_assert_msg(data_get_type(d) == DATA_TYPE_FLOAT, "float type"); |
| |
| str = NULL; |
| ck_assert_msg(data_get_string_converted(d, &str) == 0, |
| "convert -3.14 to string"); |
| ck_assert_msg(xstrcmp(str, "-3.140000") == 0, |
| "check -3.14 got converted"); |
| xfree(str); |
| ck_assert_msg(data_get_type(d) == DATA_TYPE_FLOAT, "float type"); |
| ck_assert_msg(data_get_float(d) == -3.14, |
| "check string conversion from -3.14"); |
| |
| data_set_null(d); |
| ck_assert_msg(data_get_type(d) == DATA_TYPE_NULL, "default type"); |
| |
| FREE_NULL_DATA(d); |
| ck_assert_msg(d == NULL, "free check"); |
| } |
| END_TEST |
| |
| static data_for_each_cmd_t _list_is_index(const data_t *data, void *arg) |
| { |
| int *i_ptr = arg; |
| int64_t v; |
| |
| ck_assert(!data_get_int_converted(data, &v)); |
| ck_assert_int_eq(v, *i_ptr); |
| |
| (*i_ptr)++; |
| |
| return DATA_FOR_EACH_CONT; |
| } |
| |
| static data_for_each_cmd_t _dict_is_index(const char *key, const data_t *data, |
| void *arg) |
| { |
| int *i_ptr = arg; |
| int64_t v; |
| data_t *d = data_set_string(data_new(), key); |
| |
| ck_assert(data_convert_type(d, DATA_TYPE_INT_64) == DATA_TYPE_INT_64); |
| ck_assert(data_get_int(d) == *i_ptr); |
| ck_assert(!data_get_int_converted(data, &v)); |
| ck_assert_int_eq(v, *i_ptr); |
| |
| (*i_ptr)++; |
| |
| return DATA_FOR_EACH_CONT; |
| } |
| |
| START_TEST(test_convert_list_dict) |
| { |
| static const int c = 10; |
| data_t *d = data_set_dict(data_new()); |
| |
| for (int i = 0; i < c; i++) |
| data_set_string_fmt(data_key_set_int(d, i), "%d", i); |
| |
| for (int i = 0; i < c; i++) { |
| int64_t v; |
| |
| ck_assert(!data_get_int_converted(data_key_get_int(d, i), &v)); |
| ck_assert_int_eq(v, i); |
| } |
| |
| ck_assert(data_convert_type(d, DATA_TYPE_LIST) == DATA_TYPE_LIST); |
| ck_assert(data_get_type(d) == DATA_TYPE_LIST); |
| |
| { |
| int i = 0; |
| ck_assert(data_list_for_each_const(d, _list_is_index, &i) == c); |
| ck_assert_int_eq(i, c); |
| } |
| |
| ck_assert(data_convert_type(d, DATA_TYPE_DICT) == DATA_TYPE_DICT); |
| ck_assert(data_get_type(d) == DATA_TYPE_DICT); |
| |
| { |
| int i = 0; |
| ck_assert(data_dict_for_each_const(d, _dict_is_index, &i) == c); |
| ck_assert_int_eq(i, c); |
| } |
| |
| FREE_NULL_DATA(d); |
| } |
| |
| END_TEST |
| |
| START_TEST(test_detection) |
| { |
| data_t *d = data_new(); |
| |
| check_with_data_get_bool_converted("1", true); |
| check_with_data_get_bool_converted("100", true); |
| check_with_data_get_bool_converted("-100", true); |
| check_with_data_get_bool_converted("true", true); |
| check_with_data_get_bool_converted("taco", true); |
| check_with_data_get_bool_converted("0", false); |
| check_with_data_get_bool_converted("false", false); |
| check_with_data_get_bool_converted("-0", false); |
| check_with_data_get_bool_converted(NULL, false); |
| |
| FREE_NULL_DATA(d); |
| } |
| END_TEST |
| |
| Suite *suite_data(void) |
| { |
| Suite *s = suite_create("Data"); |
| TCase *tc_core = tcase_create("Data"); |
| |
| tcase_add_test(tc_core, test_detection); |
| tcase_add_test(tc_core, test_dict_typeset); |
| tcase_add_test(tc_core, test_dict_iteration); |
| tcase_add_test(tc_core, test_list_iteration); |
| tcase_add_test(tc_core, test_convert_list_dict); |
| |
| suite_add_tcase(s, tc_core); |
| return s; |
| } |
| |
| int main(void) |
| { |
| int number_failed; |
| log_options_t log_opts = LOG_OPTS_INITIALIZER; |
| const char *debug_env = getenv("SLURM_DEBUG"); |
| const char *debug_flags_env = getenv("SLURM_DEBUG_FLAGS"); |
| |
| if (debug_env) |
| log_opts.stderr_level = log_string2num(debug_env); |
| if (debug_flags_env) |
| debug_str2flags(debug_flags_env, &slurm_conf.debug_flags); |
| |
| log_init("data-test", log_opts, 0, NULL); |
| |
| SRunner *sr = srunner_create(suite_data()); |
| |
| srunner_run_all(sr, CK_ENV); |
| number_failed = srunner_ntests_failed(sr); |
| srunner_free(sr); |
| |
| log_fini(); |
| return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; |
| } |