[asterisk-commits] file: trunk r382340 - in /trunk: include/asterisk/ main/ tests/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Mar 1 12:02:00 CST 2013


Author: file
Date: Fri Mar  1 12:01:56 2013
New Revision: 382340

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=382340
Log:
Add support for registering a sorcery handler which supports multiple fields using a regex.

Review: https://reviewboard.asterisk.org/r/2332/

Modified:
    trunk/include/asterisk/sorcery.h
    trunk/main/sorcery.c
    trunk/tests/test_sorcery.c

Modified: trunk/include/asterisk/sorcery.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/sorcery.h?view=diff&rev=382340&r1=382339&r2=382340
==============================================================================
--- trunk/include/asterisk/sorcery.h (original)
+++ trunk/include/asterisk/sorcery.h Fri Mar  1 12:01:56 2013
@@ -132,6 +132,17 @@
 typedef int (*sorcery_field_handler)(const void *obj, const intptr_t *args, char **buf);
 
 /*!
+ * \brief A callback function for translating multiple values into an ast_variable list
+ *
+ * \param obj Object to get values from
+ * \param fields Pointer to store the list of fields
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ */
+typedef int (*sorcery_fields_handler)(const void *obj, struct ast_variable **fields);
+
+/*!
  * \brief A callback function for performing a transformation on an object set
  *
  * \param set The existing object set
@@ -340,6 +351,21 @@
  * \param diff Diff handler
  */
 void ast_sorcery_object_set_diff_handler(struct ast_sorcery *sorcery, const char *type, sorcery_diff_handler diff);
+
+/*!
+ * \brief Register a regex for multiple fields within an object
+ *
+ * \param sorcery Pointer to a sorcery structure
+ * \param type Type of object
+ * \param regex A regular expression pattern for the fields
+ * \param config_handler A custom handler for translating the string representation of the fields
+ * \param sorcery_handler A custom handler for translating the native representation of the fields
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ */
+int ast_sorcery_object_fields_register(struct ast_sorcery *sorcery, const char *type, const char *regex, aco_option_handler config_handler,
+									   sorcery_fields_handler sorcery_handler);
 
 /*!
  * \brief Register a field within an object

Modified: trunk/main/sorcery.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/sorcery.c?view=diff&rev=382340&r1=382339&r2=382340
==============================================================================
--- trunk/main/sorcery.c (original)
+++ trunk/main/sorcery.c Fri Mar  1 12:01:56 2013
@@ -90,8 +90,11 @@
 	/*! \brief Name of the field */
 	char name[MAX_OBJECT_FIELD];
 
-	/*! \brief Callback function for translation */
+	/*! \brief Callback function for translation of a single value */
 	sorcery_field_handler handler;
+
+	/*! \brief Callback function for translation of multiple values */
+	sorcery_fields_handler multiple_handler;
 
 	/*! \brief Position of the field */
 	intptr_t args[];
@@ -514,6 +517,24 @@
 	}
 
 	object_type->diff = diff;
+}
+
+int ast_sorcery_object_fields_register(struct ast_sorcery *sorcery, const char *type, const char *regex, aco_option_handler config_handler, sorcery_fields_handler sorcery_handler)
+{
+	RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
+	RAII_VAR(struct ast_sorcery_object_field *, object_field, NULL, ao2_cleanup);
+
+	if (!object_type || !object_type->type.item_alloc || !config_handler || !(object_field = ao2_alloc(sizeof(*object_field), NULL))) {
+		return -1;
+	}
+
+	ast_copy_string(object_field->name, regex, sizeof(object_field->name));
+	object_field->multiple_handler = sorcery_handler;
+
+	ao2_link(object_type->fields, object_field);
+	__aco_option_register(object_type->info, regex, ACO_REGEX, object_type->file->types, "", OPT_CUSTOM_T, config_handler, 0, 0);
+
+	return 0;
 }
 
 int __ast_sorcery_object_field_register(struct ast_sorcery *sorcery, const char *type, const char *name, const char *default_val, enum aco_option_type opt_type,
@@ -662,24 +683,30 @@
 
 	i = ao2_iterator_init(object_type->fields, 0);
 
-	for (; (object_field = ao2_iterator_next(&i)); ao2_ref(object_field, -1)) {
-		RAII_VAR(char *, buf, NULL, ast_free);
-		struct ast_variable *tmp;
-
-		/* Any fields with no handler just get skipped */
-		if (!object_field->handler) {
+	for (; (object_field = ao2_iterator_next(&i)) && !res; ao2_ref(object_field, -1)) {
+		struct ast_variable *tmp = NULL;
+
+		if (object_field->multiple_handler) {
+			if ((res = object_field->multiple_handler(object, &tmp))) {
+				ast_variables_destroy(tmp);
+			}
+		} else if (object_field->handler) {
+			char *buf = NULL;
+
+			if ((res = object_field->handler(object, object_field->args, &buf)) ||
+				!(tmp = ast_variable_new(object_field->name, S_OR(buf, ""), ""))) {
+				res = -1;
+			}
+
+			ast_free(buf);
+		} else {
 			continue;
 		}
 
-		if ((res = object_field->handler(object, object_field->args, &buf)) ||
-		    !(tmp = ast_variable_new(object_field->name, S_OR(buf, ""), ""))) {
-			res = -1;
-			ao2_ref(object_field, -1);
-			break;
-		}
-
-		tmp->next = fields;
-		fields = tmp;
+		if (!res) {
+			tmp->next = fields;
+			fields = tmp;
+		}
 	}
 
 	ao2_iterator_destroy(&i);

Modified: trunk/tests/test_sorcery.c
URL: http://svnview.digium.com/svn/asterisk/trunk/tests/test_sorcery.c?view=diff&rev=382340&r1=382339&r2=382340
==============================================================================
--- trunk/tests/test_sorcery.c (original)
+++ trunk/tests/test_sorcery.c Fri Mar  1 12:01:56 2013
@@ -93,6 +93,24 @@
 	return 0;
 }
 
+/*! \brief Internal function which sets some values */
+static int test_sorcery_regex_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+	struct test_sorcery_object *test = obj;
+
+	test->bob = 256;
+
+	return 0;
+}
+
+/*! \brief Internal function which creates some ast_variable structures */
+static int test_sorcery_regex_fields(const void *obj, struct ast_variable **fields)
+{
+	*fields = ast_variable_new("toast-bob", "10", "");
+
+	return 0;
+}
+
 /*! \brief Test structure for caching */
 struct sorcery_test_caching {
 	/*! \brief Whether the object has been created in the cache or not */
@@ -429,6 +447,55 @@
 
 	if (ast_sorcery_object_field_register(sorcery, "test", "bob", "5", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, bob))) {
 		ast_test_status_update(test, "Could not successfully register object field when mapping and object type exists\n");
+		return AST_TEST_FAIL;
+	}
+
+	return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(object_fields_register)
+{
+	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
+
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = "object_fields_register";
+		info->category = "/main/sorcery/";
+		info->summary = "sorcery object regex fields registration unit test";
+		info->description =
+			"Test object regex fields registration in sorcery with a provided id";
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
+	}
+
+	if (!(sorcery = ast_sorcery_open())) {
+		ast_test_status_update(test, "Failed to open sorcery structure\n");
+		return AST_TEST_FAIL;
+	}
+
+	if (!ast_sorcery_object_fields_register(sorcery, "test", "^toast-", test_sorcery_regex_handler, test_sorcery_regex_fields)) {
+		ast_test_status_update(test, "Registered a regex object field successfully when no mappings or object types exist\n");
+		return AST_TEST_FAIL;
+	}
+
+	if (ast_sorcery_apply_default(sorcery, "test", "memory", NULL)) {
+		ast_test_status_update(test, "Failed to set a known wizard as a default\n");
+		return AST_TEST_FAIL;
+	}
+
+	if (!ast_sorcery_object_fields_register(sorcery, "test", "^toast-", test_sorcery_regex_handler, test_sorcery_regex_fields)) {
+		ast_test_status_update(test, "Registered a regex object field successfully when object type does not exist\n");
+		return AST_TEST_FAIL;
+	}
+
+	if (ast_sorcery_object_register(sorcery, "test", test_sorcery_object_alloc, NULL, NULL)) {
+		ast_test_status_update(test, "Failed to register object type\n");
+		return AST_TEST_FAIL;
+	}
+
+	if (ast_sorcery_object_fields_register(sorcery, "test", "^toast-", test_sorcery_regex_handler, test_sorcery_regex_fields)) {
+		ast_test_status_update(test, "Registered a regex object field successfully when no mappings or object types exist\n");
 		return AST_TEST_FAIL;
 	}
 
@@ -801,6 +868,64 @@
 	return res;
 }
 
+AST_TEST_DEFINE(objectset_create_regex)
+{
+	int res = AST_TEST_PASS;
+	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
+	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
+	RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
+	struct ast_variable *field;
+
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = "objectset_create_regex";
+		info->category = "/main/sorcery/";
+		info->summary = "sorcery object set creation with regex fields unit test";
+		info->description =
+			"Test object set creation with regex fields in sorcery";
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
+	}
+
+	if (!(sorcery = ast_sorcery_open())) {
+		ast_test_status_update(test, "Failed to open sorcery structure\n");
+		return AST_TEST_FAIL;
+	}
+
+	if (ast_sorcery_apply_default(sorcery, "test", "memory", NULL) ||
+	    ast_sorcery_object_register(sorcery, "test", test_sorcery_object_alloc, NULL, test_apply_handler)) {
+		ast_test_status_update(test, "Failed to register 'test' object type\n");
+		return AST_TEST_FAIL;
+	}
+
+	ast_sorcery_object_fields_register(sorcery, "test", "^toast-", test_sorcery_regex_handler, test_sorcery_regex_fields);
+
+	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
+		ast_test_status_update(test, "Failed to allocate a known object type\n");
+		return AST_TEST_FAIL;
+	}
+
+	if (!(objset = ast_sorcery_objectset_create(sorcery, obj))) {
+		ast_test_status_update(test, "Failed to create an object set for a known sane object\n");
+		return AST_TEST_FAIL;
+	}
+
+	for (field = objset; field; field = field->next) {
+		if (!strcmp(field->name, "toast-bob")) {
+			if (strcmp(field->value, "10")) {
+				ast_test_status_update(test, "Object set failed to create proper value for 'bob'\n");
+				res = AST_TEST_FAIL;
+			}
+		} else {
+			ast_test_status_update(test, "Object set created field '%s' which is unknown\n", field->name);
+			res = AST_TEST_FAIL;
+		}
+	}
+
+	return res;
+}
+
 AST_TEST_DEFINE(objectset_apply)
 {
 	int res = AST_TEST_PASS;
@@ -1003,6 +1128,57 @@
 	}
 
 	return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(objectset_apply_fields)
+{
+	int res = AST_TEST_PASS;
+	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
+	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
+	RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
+
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = "objectset_apply_fields";
+		info->category = "/main/sorcery/";
+		info->summary = "sorcery object apply regex fields unit test";
+		info->description =
+			"Test object set apply with regex fields in sorcery";
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
+	}
+
+	if (!(sorcery = ast_sorcery_open())) {
+		ast_test_status_update(test, "Failed to open sorcery structure\n");
+		return AST_TEST_FAIL;
+	}
+
+	if (ast_sorcery_apply_default(sorcery, "test", "memory", NULL) ||
+	    ast_sorcery_object_register(sorcery, "test", test_sorcery_object_alloc, NULL, test_apply_handler)) {
+		ast_test_status_update(test, "Failed to register 'test' object type\n");
+		return AST_TEST_FAIL;
+	}
+
+	ast_sorcery_object_fields_register(sorcery, "test", "^toast-", test_sorcery_regex_handler, test_sorcery_regex_fields);
+
+	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
+		ast_test_status_update(test, "Failed to allocate a known object type\n");
+		return AST_TEST_FAIL;
+	}
+
+	if (!(objset = ast_variable_new("toast-bob", "20", ""))) {
+		ast_test_status_update(test, "Failed to create an object set, test could not occur\n");
+		res = AST_TEST_FAIL;
+	} else if (ast_sorcery_objectset_apply(sorcery, obj, objset)) {
+		ast_test_status_update(test, "Failed to apply valid object set to object\n");
+		res = AST_TEST_FAIL;
+	} else if (obj->bob != 256) {
+		ast_test_status_update(test, "Regex field handler was not called when it should have been\n");
+		res = AST_TEST_FAIL;
+	}
+
+	return res;
 }
 
 AST_TEST_DEFINE(changeset_create)
@@ -2149,6 +2325,7 @@
 	AST_TEST_UNREGISTER(object_register);
 	AST_TEST_UNREGISTER(object_register_without_mapping);
 	AST_TEST_UNREGISTER(object_field_register);
+	AST_TEST_UNREGISTER(object_fields_register);
 	AST_TEST_UNREGISTER(object_alloc_with_id);
 	AST_TEST_UNREGISTER(object_alloc_without_id);
 	AST_TEST_UNREGISTER(object_copy);
@@ -2156,10 +2333,12 @@
 	AST_TEST_UNREGISTER(object_diff);
 	AST_TEST_UNREGISTER(object_diff_native);
 	AST_TEST_UNREGISTER(objectset_create);
+	AST_TEST_UNREGISTER(objectset_create_regex);
 	AST_TEST_UNREGISTER(objectset_apply);
 	AST_TEST_UNREGISTER(objectset_apply_handler);
 	AST_TEST_UNREGISTER(objectset_apply_invalid);
 	AST_TEST_UNREGISTER(objectset_transform);
+	AST_TEST_UNREGISTER(objectset_apply_fields);
 	AST_TEST_UNREGISTER(changeset_create);
 	AST_TEST_UNREGISTER(changeset_create_unchanged);
 	AST_TEST_UNREGISTER(object_create);
@@ -2191,6 +2370,7 @@
 	AST_TEST_REGISTER(object_register);
 	AST_TEST_REGISTER(object_register_without_mapping);
 	AST_TEST_REGISTER(object_field_register);
+	AST_TEST_REGISTER(object_fields_register);
 	AST_TEST_REGISTER(object_alloc_with_id);
 	AST_TEST_REGISTER(object_alloc_without_id);
 	AST_TEST_REGISTER(object_copy);
@@ -2198,10 +2378,12 @@
 	AST_TEST_REGISTER(object_diff);
 	AST_TEST_REGISTER(object_diff_native);
 	AST_TEST_REGISTER(objectset_create);
+	AST_TEST_REGISTER(objectset_create_regex);
 	AST_TEST_REGISTER(objectset_apply);
 	AST_TEST_REGISTER(objectset_apply_handler);
 	AST_TEST_REGISTER(objectset_apply_invalid);
 	AST_TEST_REGISTER(objectset_transform);
+	AST_TEST_REGISTER(objectset_apply_fields);
 	AST_TEST_REGISTER(changeset_create);
 	AST_TEST_REGISTER(changeset_create_unchanged);
 	AST_TEST_REGISTER(object_create);




More information about the asterisk-commits mailing list