1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2018, Olivier MATZ <zer0@droids-corp.org>
11 #include <ecoli_string.h>
12 #include <ecoli_malloc.h>
13 #include <ecoli_keyval.h>
14 #include <ecoli_node.h>
15 #include <ecoli_log.h>
16 #include <ecoli_test.h>
17 #include <ecoli_config.h>
19 EC_LOG_TYPE_REGISTER(config);
21 #ifndef EC_COUNT_OF //XXX
22 #define EC_COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / \
23 ((size_t)(!(sizeof(x) % sizeof(0[x])))))
27 __ec_config_dump(FILE *out, const char *key, const struct ec_config *config,
30 ec_config_dict_validate(const struct ec_keyval *dict,
31 const struct ec_config_schema *schema,
34 /* return ec_value type as a string */
36 ec_config_type_str(enum ec_config_type type)
39 case EC_CONFIG_TYPE_BOOL: return "bool";
40 case EC_CONFIG_TYPE_INT64: return "int64";
41 case EC_CONFIG_TYPE_UINT64: return "uint64";
42 case EC_CONFIG_TYPE_STRING: return "string";
43 case EC_CONFIG_TYPE_NODE: return "node";
44 case EC_CONFIG_TYPE_LIST: return "list";
45 case EC_CONFIG_TYPE_DICT: return "dict";
46 default: return "unknown";
51 __ec_config_schema_validate(const struct ec_config_schema *schema,
52 size_t schema_len, enum ec_config_type type)
57 if (type == EC_CONFIG_TYPE_LIST) {
58 if (schema[0].key != NULL) {
60 EC_LOG(EC_LOG_ERR, "list schema key must be NULL\n");
63 } else if (type == EC_CONFIG_TYPE_DICT) {
64 for (i = 0; i < schema_len; i++) {
65 if (schema[i].key == NULL) {
68 "dict schema key should not be NULL\n");
74 EC_LOG(EC_LOG_ERR, "invalid schema type\n");
78 for (i = 0; i < schema_len; i++) {
79 /* check for duplicate name if more than one element */
80 for (j = i + 1; j < schema_len; j++) {
81 if (!strcmp(schema[i].key, schema[j].key)) {
84 "duplicate key <%s> in schema\n",
90 switch (schema[i].type) {
91 case EC_CONFIG_TYPE_BOOL:
92 case EC_CONFIG_TYPE_INT64:
93 case EC_CONFIG_TYPE_UINT64:
94 case EC_CONFIG_TYPE_STRING:
95 case EC_CONFIG_TYPE_NODE:
96 if (schema[i].subschema != NULL ||
97 schema[i].subschema_len != 0) {
100 "key <%s> should not have subtype/subschema\n",
105 case EC_CONFIG_TYPE_LIST:
106 if (schema[i].subschema == NULL ||
107 schema[i].subschema_len != 1) {
110 "key <%s> must have subschema of length 1\n",
115 case EC_CONFIG_TYPE_DICT:
116 if (schema[i].subschema == NULL ||
117 schema[i].subschema_len == 0) {
120 "key <%s> must have subschema\n",
126 EC_LOG(EC_LOG_ERR, "invalid type for key <%s>\n",
132 if (schema[i].subschema == NULL)
135 ret = __ec_config_schema_validate(schema[i].subschema,
136 schema[i].subschema_len,
139 EC_LOG(EC_LOG_ERR, "cannot parse subschema %s%s\n",
140 schema[i].key ? "key=" : "",
141 schema[i].key ? : "");
150 ec_config_schema_validate(const struct ec_config_schema *schema,
153 return __ec_config_schema_validate(schema, schema_len,
154 EC_CONFIG_TYPE_DICT);
158 __ec_config_schema_dump(FILE *out, const struct ec_config_schema *schema,
159 size_t schema_len, size_t indent)
163 for (i = 0; i < schema_len; i++) {
164 fprintf(out, "%*s" "%s%s%stype=%s desc='%s'\n",
166 schema[i].key ? "key=": "",
167 schema[i].key ? : "",
168 schema[i].key ? " ": "",
169 ec_config_type_str(schema[i].type),
171 if (schema[i].subschema == NULL)
173 __ec_config_schema_dump(out, schema[i].subschema,
174 schema[i].subschema_len, indent + 1);
179 ec_config_schema_dump(FILE *out, const struct ec_config_schema *schema,
182 fprintf(out, "------------------- schema dump:\n");
184 if (schema == NULL || schema_len == 0) {
185 fprintf(out, "no schema\n");
189 __ec_config_schema_dump(out, schema, schema_len, 0);
193 ec_config_bool(bool boolean)
195 struct ec_config *value = NULL;
197 value = ec_calloc(1, sizeof(*value));
201 value->type = EC_CONFIG_TYPE_BOOL;
202 value->boolean = boolean;
208 ec_config_i64(int64_t i64)
210 struct ec_config *value = NULL;
212 value = ec_calloc(1, sizeof(*value));
216 value->type = EC_CONFIG_TYPE_INT64;
223 ec_config_u64(uint64_t u64)
225 struct ec_config *value = NULL;
227 value = ec_calloc(1, sizeof(*value));
231 value->type = EC_CONFIG_TYPE_UINT64;
237 /* duplicate string */
239 ec_config_string(const char *string)
241 struct ec_config *value = NULL;
247 s = ec_strdup(string);
251 value = ec_calloc(1, sizeof(*value));
255 value->type = EC_CONFIG_TYPE_STRING;
266 /* "consume" the node */
268 ec_config_node(struct ec_node *node)
270 struct ec_config *value = NULL;
275 value = ec_calloc(1, sizeof(*value));
279 value->type = EC_CONFIG_TYPE_NODE;
291 ec_config_set_schema(struct ec_config *dict,
292 const struct ec_config_schema *schema,
295 if (dict->type != EC_CONFIG_TYPE_DICT) {
300 if (ec_config_schema_validate(schema, schema_len) < 0)
303 dict->schema = schema;
304 dict->schema_len = schema_len;
313 ec_config_dict(const struct ec_config_schema *schema,
316 struct ec_config *value = NULL;
317 struct ec_keyval *dict = NULL;
323 value = ec_calloc(1, sizeof(*value));
327 value->type = EC_CONFIG_TYPE_DICT;
330 if (ec_config_set_schema(value, schema, schema_len) < 0)
336 ec_keyval_free(dict);
344 struct ec_config *value = NULL;
346 value = ec_calloc(1, sizeof(*value));
350 value->type = EC_CONFIG_TYPE_LIST;
351 TAILQ_INIT(&value->list);
356 static const struct ec_config_schema *
357 ec_config_schema_lookup(const struct ec_config_schema *schema,
358 size_t schema_len, const char *key,
359 enum ec_config_type type)
363 for (i = 0; i < schema_len; i++) {
364 if (!strcmp(key, schema[i].key) &&
365 type == schema[i].type)
374 ec_config_free(struct ec_config *value)
379 switch (value->type) {
380 case EC_CONFIG_TYPE_STRING:
381 ec_free(value->string);
383 case EC_CONFIG_TYPE_NODE:
384 ec_node_free(value->node);
386 case EC_CONFIG_TYPE_LIST:
387 while (!TAILQ_EMPTY(&value->list)) {
389 v = TAILQ_FIRST(&value->list);
390 TAILQ_REMOVE(&value->list, v, next);
394 case EC_CONFIG_TYPE_DICT:
395 ec_keyval_free(value->dict);
405 ec_config_list_cmp(const struct ec_config_list *list1,
406 const struct ec_config_list *list2)
408 const struct ec_config *v1, *v2;
410 for (v1 = TAILQ_FIRST(list1), v2 = TAILQ_FIRST(list2);
411 v1 != NULL && v2 != NULL;
412 v1 = TAILQ_NEXT(v1, next), v2 = TAILQ_NEXT(v2, next)) {
413 if (ec_config_cmp(v1, v2))
416 if (v1 != NULL || v2 != NULL)
422 /* XXX -> ec_keyval_cmp() */
424 ec_config_dict_cmp(const struct ec_keyval *d1,
425 const struct ec_keyval *d2)
427 const struct ec_config *v1, *v2;
428 struct ec_keyval_iter *iter = NULL;
431 if (ec_keyval_len(d1) != ec_keyval_len(d2))
434 for (iter = ec_keyval_iter(d1);
435 ec_keyval_iter_valid(iter);
436 ec_keyval_iter_next(iter)) {
437 key = ec_keyval_iter_get_key(iter);
438 v1 = ec_keyval_iter_get_val(iter);
439 v2 = ec_keyval_get(d2, key);
441 if (ec_config_cmp(v1, v2))
445 ec_keyval_iter_free(iter);
449 ec_keyval_iter_free(iter);
454 ec_config_cmp(const struct ec_config *value1,
455 const struct ec_config *value2)
457 if (value1->type != value2->type)
460 switch (value1->type) {
461 case EC_CONFIG_TYPE_BOOL:
462 if (value1->boolean == value2->boolean)
464 case EC_CONFIG_TYPE_INT64:
465 if (value1->i64 == value2->i64)
467 case EC_CONFIG_TYPE_UINT64:
468 if (value1->u64 == value2->u64)
470 case EC_CONFIG_TYPE_STRING:
471 if (!strcmp(value1->string, value2->string))
473 case EC_CONFIG_TYPE_NODE:
474 if (value1->node == value2->node)
476 case EC_CONFIG_TYPE_LIST:
477 return ec_config_list_cmp(&value1->list, &value2->list);
478 case EC_CONFIG_TYPE_DICT:
479 return ec_config_dict_cmp(value1->dict, value2->dict);
488 ec_config_list_validate(const struct ec_config_list *list,
489 const struct ec_config_schema *sch)
491 const struct ec_config *value;
493 TAILQ_FOREACH(value, list, next) {
494 if (value->type != sch->type) {
499 if (value->type == EC_CONFIG_TYPE_LIST) {
500 if (ec_config_list_validate(&value->list,
503 } else if (value->type == EC_CONFIG_TYPE_DICT) {
504 if (ec_config_dict_validate(value->dict,
505 sch->subschema, sch->subschema_len) < 0)
514 ec_config_dict_validate(const struct ec_keyval *dict,
515 const struct ec_config_schema *schema,
518 const struct ec_config *value;
519 struct ec_keyval_iter *iter = NULL;
520 const struct ec_config_schema *sch;
523 for (iter = ec_keyval_iter(dict);
524 ec_keyval_iter_valid(iter);
525 ec_keyval_iter_next(iter)) {
527 key = ec_keyval_iter_get_key(iter);
528 value = ec_keyval_iter_get_val(iter);
529 sch = ec_config_schema_lookup(schema, schema_len,
536 if (value->type == EC_CONFIG_TYPE_LIST) {
537 if (ec_config_list_validate(&value->list,
540 } else if (value->type == EC_CONFIG_TYPE_DICT) {
541 if (ec_config_dict_validate(value->dict,
542 sch->subschema, sch->subschema_len) < 0)
547 ec_keyval_iter_free(iter);
551 ec_keyval_iter_free(iter);
556 ec_config_validate(const struct ec_config *dict)
558 if (dict->type != EC_CONFIG_TYPE_DICT) {
562 if (dict->schema == NULL || dict->schema_len == 0) {
567 if (ec_config_dict_validate(dict->dict, dict->schema,
568 dict->schema_len) < 0)
578 ec_config_get(struct ec_config *config, const char *key)
583 return ec_keyval_get(config->dict, key);
587 ec_config_list_first(struct ec_config *list)
589 if (list == NULL || list->type != EC_CONFIG_TYPE_LIST) {
594 return TAILQ_FIRST(&list->list);
598 ec_config_list_next(struct ec_config *list, struct ec_config *config)
601 return TAILQ_NEXT(config, next);
604 /* value is consumed */
605 int ec_config_set(struct ec_config *config, const char *key,
606 struct ec_config *value)
608 void (*free_cb)(struct ec_config *) = ec_config_free;
610 if (config == NULL || key == NULL || value == NULL) {
614 if (config->type != EC_CONFIG_TYPE_DICT) {
619 return ec_keyval_set(config->dict, key, value,
620 (void (*)(void *))free_cb);
623 ec_config_free(value);
627 /* value is consumed */
629 ec_config_add(struct ec_config *list,
630 struct ec_config *value)
632 if (list->type != EC_CONFIG_TYPE_LIST) {
637 TAILQ_INSERT_TAIL(&list->list, value, next);
642 ec_config_free(value);
646 void ec_config_del(struct ec_config *list, struct ec_config *config)
648 TAILQ_REMOVE(&list->list, config, next);
649 ec_config_free(config);
653 ec_config_list_dump(FILE *out, const struct ec_config_list *list,
656 const struct ec_config *v;
658 fprintf(out, "%*s" "type=list:\n", (int)indent * 4, "");
660 TAILQ_FOREACH(v, list, next) {
661 if (__ec_config_dump(out, NULL, v, indent + 1) < 0)
669 ec_config_dict_dump(FILE *out, const struct ec_keyval *dict,
672 const struct ec_config *value;
673 struct ec_keyval_iter *iter;
676 fprintf(out, "%*s" "type=dict:\n", (int)indent * 4, "");
677 for (iter = ec_keyval_iter(dict);
678 ec_keyval_iter_valid(iter);
679 ec_keyval_iter_next(iter)) {
680 key = ec_keyval_iter_get_key(iter);
681 value = ec_keyval_iter_get_val(iter);
682 if (__ec_config_dump(out, key, value, indent + 1) < 0)
685 ec_keyval_iter_free(iter);
689 ec_keyval_iter_free(iter);
694 __ec_config_dump(FILE *out, const char *key, const struct ec_config *value,
697 char *val_str = NULL;
699 switch (value->type) {
700 case EC_CONFIG_TYPE_BOOL:
702 ec_asprintf(&val_str, "true");
704 ec_asprintf(&val_str, "false");
706 case EC_CONFIG_TYPE_INT64:
707 ec_asprintf(&val_str, "%"PRIu64, value->u64);
709 case EC_CONFIG_TYPE_UINT64:
710 ec_asprintf(&val_str, "%"PRIi64, value->i64);
712 case EC_CONFIG_TYPE_STRING:
713 ec_asprintf(&val_str, "%s", value->string);
715 case EC_CONFIG_TYPE_NODE:
716 ec_asprintf(&val_str, "%p", value->node);
718 case EC_CONFIG_TYPE_LIST:
719 return ec_config_list_dump(out, &value->list, indent);
720 case EC_CONFIG_TYPE_DICT:
721 return ec_config_dict_dump(out, value->dict, indent);
727 /* errno is already set on error */
731 fprintf(out, "%*s" "%s%s%stype=%s val=%s\n", (int)indent * 4, "",
735 ec_config_type_str(value->type), val_str);
746 ec_config_dump(FILE *out, const struct ec_config *config)
748 fprintf(out, "------------------- config dump:\n");
750 if (config == NULL) {
751 fprintf(out, "no config\n");
755 if (__ec_config_dump(out, NULL, config, 0) < 0)
756 fprintf(out, "error while dumping\n");
759 /* LCOV_EXCL_START */
760 static const struct ec_config_schema sch_intlist_elt[] = {
762 .desc = "This is a description for int",
763 .type = EC_CONFIG_TYPE_INT64,
767 static const struct ec_config_schema sch_dict[] = {
770 .desc = "This is a description for int",
771 .type = EC_CONFIG_TYPE_INT64,
775 .desc = "This is a description for int2",
776 .type = EC_CONFIG_TYPE_INT64,
780 static const struct ec_config_schema sch_dictlist_elt[] = {
782 .desc = "This is a description for dict",
783 .type = EC_CONFIG_TYPE_DICT,
784 .subschema = sch_dict,
785 .subschema_len = EC_COUNT_OF(sch_dict),
789 static const struct ec_config_schema sch_baseconfig[] = {
792 .desc = "This is a description for bool",
793 .type = EC_CONFIG_TYPE_BOOL,
797 .desc = "This is a description for int",
798 .type = EC_CONFIG_TYPE_INT64,
802 .desc = "This is a description for string",
803 .type = EC_CONFIG_TYPE_STRING,
807 .desc = "This is a description for node",
808 .type = EC_CONFIG_TYPE_NODE,
812 .desc = "This is a description for list",
813 .type = EC_CONFIG_TYPE_LIST,
814 .subschema = sch_intlist_elt,
815 .subschema_len = EC_COUNT_OF(sch_intlist_elt),
818 .key = "my_dictlist",
819 .desc = "This is a description for list",
820 .type = EC_CONFIG_TYPE_LIST,
821 .subschema = sch_dictlist_elt,
822 .subschema_len = EC_COUNT_OF(sch_dictlist_elt),
826 static int ec_config_testcase(void)
828 struct ec_node *node = NULL;
829 struct ec_keyval *dict = NULL;
830 const struct ec_config *value = NULL;
831 struct ec_config *config = NULL, *list = NULL, *subconfig = NULL;
832 struct ec_config *list_, *config_;
836 node = ec_node("empty", EC_NO_ID);
840 if (ec_config_schema_validate(sch_baseconfig,
841 EC_COUNT_OF(sch_baseconfig)) < 0) {
842 EC_LOG(EC_LOG_ERR, "invalid config schema\n");
846 ec_config_schema_dump(stdout, sch_baseconfig,
847 EC_COUNT_OF(sch_baseconfig));
849 config = ec_config_dict(sch_baseconfig, EC_COUNT_OF(sch_baseconfig));
853 ret = ec_config_set(config, "my_bool", ec_config_bool(true));
854 testres |= EC_TEST_CHECK(ret == 0, "cannot set boolean");
855 value = ec_config_get(config, "my_bool");
856 testres |= EC_TEST_CHECK(
858 value->type == EC_CONFIG_TYPE_BOOL &&
859 value->boolean == true,
860 "unexpected boolean value");
862 ret = ec_config_set(config, "my_int", ec_config_i64(1234));
863 testres |= EC_TEST_CHECK(ret == 0, "cannot set int");
864 value = ec_config_get(config, "my_int");
865 testres |= EC_TEST_CHECK(
867 value->type == EC_CONFIG_TYPE_INT64 &&
869 "unexpected int value");
871 testres |= EC_TEST_CHECK(
872 ec_config_validate(config) == 0,
873 "cannot validate config\n");
875 ret = ec_config_set(config, "my_string", ec_config_string("toto"));
876 testres |= EC_TEST_CHECK(ret == 0, "cannot set string");
877 value = ec_config_get(config, "my_string");
878 testres |= EC_TEST_CHECK(
880 value->type == EC_CONFIG_TYPE_STRING &&
881 !strcmp(value->string, "toto"),
882 "unexpected string value");
884 list = ec_config_list();
888 subconfig = ec_config_dict(sch_dict, EC_COUNT_OF(sch_dict));
889 if (subconfig == NULL)
892 ret = ec_config_set(subconfig, "my_int", ec_config_i64(1));
893 testres |= EC_TEST_CHECK(ret == 0, "cannot set int");
894 value = ec_config_get(subconfig, "my_int");
895 testres |= EC_TEST_CHECK(
897 value->type == EC_CONFIG_TYPE_INT64 &&
899 "unexpected int value");
901 ret = ec_config_set(subconfig, "my_int2", ec_config_i64(2));
902 testres |= EC_TEST_CHECK(ret == 0, "cannot set int");
903 value = ec_config_get(subconfig, "my_int2");
904 testres |= EC_TEST_CHECK(
906 value->type == EC_CONFIG_TYPE_INT64 &&
908 "unexpected int value");
910 testres |= EC_TEST_CHECK(
911 ec_config_validate(subconfig) == 0,
912 "cannot validate subconfig\n");
914 ret = ec_config_add(list, subconfig);
915 subconfig = NULL; /* freed */
916 testres |= EC_TEST_CHECK(ret == 0, "cannot add in list");
918 subconfig = ec_config_dict(sch_dict, EC_COUNT_OF(sch_dict));
919 if (subconfig == NULL)
922 ret = ec_config_set(subconfig, "my_int", ec_config_i64(3));
923 testres |= EC_TEST_CHECK(ret == 0, "cannot set int");
924 value = ec_config_get(subconfig, "my_int");
925 testres |= EC_TEST_CHECK(
927 value->type == EC_CONFIG_TYPE_INT64 &&
929 "unexpected int value");
931 ret = ec_config_set(subconfig, "my_int2", ec_config_i64(4));
932 testres |= EC_TEST_CHECK(ret == 0, "cannot set int");
933 value = ec_config_get(subconfig, "my_int2");
934 testres |= EC_TEST_CHECK(
936 value->type == EC_CONFIG_TYPE_INT64 &&
938 "unexpected int value");
940 testres |= EC_TEST_CHECK(
941 ec_config_validate(subconfig) == 0,
942 "cannot validate subconfig\n");
944 ret = ec_config_add(list, subconfig);
945 subconfig = NULL; /* freed */
946 testres |= EC_TEST_CHECK(ret == 0, "cannot add in list");
948 ret = ec_config_set(config, "my_dictlist", list);
950 testres |= EC_TEST_CHECK(ret == 0, "cannot set list");
952 testres |= EC_TEST_CHECK(
953 ec_config_validate(config) == 0,
954 "cannot validate config\n");
956 list_ = ec_config_get(config, "my_dictlist");
957 printf("list = %p\n", list_);
958 for (config_ = ec_config_list_first(list_); config_ != NULL;
959 config_ = ec_config_list_next(list_, config_)) {
960 ec_config_dump(stdout, config_);
963 ec_config_dump(stdout, config);
965 /* remove the first element */
966 ec_config_del(list_, ec_config_list_first(list_));
967 testres |= EC_TEST_CHECK(
968 ec_config_validate(config) == 0,
969 "cannot validate config\n");
972 value.type = EC_CONFIG_TYPE_NODE;
973 value.node = ec_node_clone(node);
974 ret = ec_config_set(config, "node", value);
975 testres |= EC_TEST_CHECK(ret == 0, "cannot set node");
976 pvalue = ec_config_get(config, "node");
977 testres |= EC_TEST_CHECK(
979 ec_config_cmp(pvalue, &value) == 0,
980 "unexpected node value");
982 subconfig = ec_config(dict, EC_COUNT_OF(dict));
983 if (subconfig == NULL)
986 value.type = EC_CONFIG_TYPE_INT64;
988 ret = ec_config_set(subconfig, "int", value);
989 testres |= EC_TEST_CHECK(ret == 0, "cannot set int");
990 pvalue = ec_config_get(subconfig, "int");
991 testres |= EC_TEST_CHECK(
993 ec_config_cmp(pvalue, &value) == 0,
994 "unexpected int value");
996 value.type = EC_CONFIG_TYPE_DICT;
997 value.dict = subconfig;
998 subconfig = NULL; /* will be freed when freeing config */
999 ret = ec_config_set(config, "dict", value);
1000 testres |= EC_TEST_CHECK(ret == 0, "cannot set dict");
1001 pvalue = ec_config_get(config, "dict");
1002 testres |= EC_TEST_CHECK(
1004 ec_config_cmp(pvalue, &value) == 0,
1005 "unexpected dict value");
1007 value.type = EC_CONFIG_TYPE_INT64;
1009 pvalue = ec_config_get(
1010 ec_config_get(config, "dict")->dict, "int");
1011 testres |= EC_TEST_CHECK(
1013 ec_config_cmp(pvalue, &value) == 0,
1014 "unexpected int value");
1016 value.type = EC_CONFIG_TYPE_INT64;
1018 ret = ec_config_add(config, "intlist", value);
1019 testres |= EC_TEST_CHECK(ret == 0, "cannot add int in list");
1020 value.type = EC_CONFIG_TYPE_INT64;
1022 ret = ec_config_add(config, "intlist", value);
1023 testres |= EC_TEST_CHECK(ret == 0, "cannot add int in list");
1024 value.type = EC_CONFIG_TYPE_INT64;
1026 ret = ec_config_add(config, "intlist", value);
1027 testres |= EC_TEST_CHECK(ret == 0, "cannot add int in list");
1029 value.type = EC_CONFIG_TYPE_INT64;
1031 ret = ec_config_set(config, "invalid", value);
1032 testres |= EC_TEST_CHECK(ret < 0,
1033 "should not be able to set invalid key");
1034 pvalue = ec_config_get(config, "invalid");
1035 testres |= EC_TEST_CHECK(pvalue == NULL,
1036 "invalid key returned a value");
1039 ec_config_dump(stdout, config);
1041 ec_config_free(list);
1042 ec_config_free(subconfig);
1043 ec_config_free(config);
1044 ec_keyval_free(dict);
1050 ec_config_free(list);
1051 ec_config_free(subconfig);
1052 ec_config_free(config);
1053 ec_keyval_free(dict);
1058 /* LCOV_EXCL_STOP */
1060 static struct ec_test ec_config_test = {
1062 .test = ec_config_testcase,
1065 EC_TEST_REGISTER(ec_config_test);