Skip to content
Snippets Groups Projects
test_sorcery.c 120 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	ast_str_reset(buf);
    	snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s)", "test_sorcery", "test", "blah", "nobob");
    	if (!ast_func_read2(NULL, expression, &buf, 16)) {
    		ast_free(buf);
    		ast_test_status_update(test, "Retrieved a non-existent field\n");
    		return AST_TEST_FAIL;
    	}
    
    	ast_str_reset(buf);
    	snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s)", "test_sorcery", "test", "blah", "bob");
    	if (ast_func_read2(NULL, expression, &buf, 16)) {
    		ast_free(buf);
    		ast_test_status_update(test, "Failed retrieve field 'bob'\n");
    		return AST_TEST_FAIL;
    	}
    	if (strcmp(ast_str_buffer(buf), "5")) {
    		ast_free(buf);
    
    		ast_test_status_update(test, "Failed retrieve field.  Got '%u', should be '5'\n", obj->bob);
    
    		return AST_TEST_FAIL;
    	}
    
    	ast_str_reset(buf);
    	snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s,single,1)", "test_sorcery", "test", "blah", "bob");
    	if (ast_func_read2(NULL, expression, &buf, 16)) {
    		ast_free(buf);
    		ast_test_status_update(test, "Failed retrieve field 'bob'\n");
    		return AST_TEST_FAIL;
    	}
    	if (strcmp(ast_str_buffer(buf), "5")) {
    		ast_free(buf);
    
    		ast_test_status_update(test, "Failed retrieve field.  Got '%u', should be '5'\n", obj->bob);
    
    		return AST_TEST_FAIL;
    	}
    
    	ast_str_reset(buf);
    	snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s,single,2)", "test_sorcery", "test", "blah", "bob");
    	if (!ast_func_read2(NULL, expression, &buf, 16)) {
    		ast_free(buf);
    		ast_test_status_update(test, "Got a second 'bob' and shouldn't have\n");
    		return AST_TEST_FAIL;
    	}
    
    	/* 444 is already the first item in the list */
    	jim_handler(NULL, ast_variable_new("jim", "555", ""), obj);
    	jim_handler(NULL, ast_variable_new("jim", "666", ""), obj);
    
    	ast_str_reset(buf);
    	snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s)", "test_sorcery", "test", "blah", "jim");
    	if (ast_func_read2(NULL, expression, &buf, 16)) {
    		ast_free(buf);
    		ast_test_status_update(test, "Couldn't retrieve 'jim'\n");
    		return AST_TEST_FAIL;
    	}
    	if (strcmp(ast_str_buffer(buf), "444,555,666")) {
    		ast_free(buf);
    		ast_test_status_update(test, "Failed retrieve jim.  Got '%s', should be '444,555,666'\n", ast_str_buffer(buf));
    		return AST_TEST_FAIL;
    	}
    
    	ast_str_reset(buf);
    	snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s,single,2)", "test_sorcery", "test", "blah", "jim");
    	if (ast_func_read2(NULL, expression, &buf, 16)) {
    		ast_free(buf);
    		ast_test_status_update(test, "Couldn't retrieve 2nd jim\n");
    		return AST_TEST_FAIL;
    	}
    	if (strcmp(ast_str_buffer(buf), "555")) {
    		ast_free(buf);
    		ast_test_status_update(test, "Failed retrieve 2nd jim.  Got '%s', should be '555'\n", ast_str_buffer(buf));
    		return AST_TEST_FAIL;
    	}
    
    	ast_str_reset(buf);
    	snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s,concat,|)", "test_sorcery", "test", "blah", "jim");
    	if (ast_func_read2(NULL, expression, &buf, 16)) {
    		ast_free(buf);
    		ast_test_status_update(test, "Couldn't retrieve any 'jim'\n");
    		return AST_TEST_FAIL;
    	}
    	if (strcmp(ast_str_buffer(buf), "444|555|666")) {
    		ast_free(buf);
    		ast_test_status_update(test, "Failed retrieve 'jim'.  Got '%s', should be '444|555|666'\n", ast_str_buffer(buf));
    		return AST_TEST_FAIL;
    	}
    
    	ast_str_reset(buf);
    	snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s,noconcat,3)", "test_sorcery", "test", "blah", "jim");
    	if (!ast_func_read2(NULL, expression, &buf, 16)) {
    		ast_free(buf);
    		ast_test_status_update(test, "Should have failed with invalid retrieval_type\n");
    		return AST_TEST_FAIL;
    	}
    
    	ast_str_reset(buf);
    	snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s,single,|)", "test_sorcery", "test", "blah", "jim");
    	if (!ast_func_read2(NULL, expression, &buf, 16)) {
    		ast_free(buf);
    		ast_test_status_update(test, "Should have failed with invalid occurrence_number\n");
    		return AST_TEST_FAIL;
    	}
    
    	ast_free(buf);
    
    	return AST_TEST_PASS;
    }
    
    
    AST_TEST_DEFINE(object_field_registered)
    {
    	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
    	RAII_VAR(struct ast_sorcery_object_type *, object_type, NULL, ao2_cleanup);
    
    	switch (cmd) {
    	case TEST_INIT:
    		info->name = "object_field_registered";
    		info->category = "/main/sorcery/";
    		info->summary = "ast_sorcery_is_object_field_registered unit test";
    		info->description =
    			"Test ast_sorcery_is_object_field_registered in sorcery";
    		return AST_TEST_NOT_RUN;
    	case TEST_EXECUTE:
    		break;
    	}
    
    	if (!(sorcery = alloc_and_initialize_sorcery())) {
    		ast_test_status_update(test, "Failed to open sorcery structure\n");
    		return AST_TEST_FAIL;
    	}
    
    	object_type = ast_sorcery_get_object_type(sorcery, "test");
    
    	ast_sorcery_object_fields_register(sorcery, "test", "^prefix/.", test_sorcery_regex_handler, test_sorcery_regex_fields);
    
    	ast_test_validate(test, ast_sorcery_is_object_field_registered(object_type, "joe"));
    	ast_test_validate(test, ast_sorcery_is_object_field_registered(object_type, "bob"));
    	ast_test_validate(test, ast_sorcery_is_object_field_registered(object_type, "@joebob"));
    	ast_test_validate(test, ast_sorcery_is_object_field_registered(object_type, "prefix/goober"));
    
    	ast_test_validate(test, !ast_sorcery_is_object_field_registered(object_type, "joebob"));
    	ast_test_validate(test, !ast_sorcery_is_object_field_registered(object_type, "prefix/"));
    	ast_test_validate(test, !ast_sorcery_is_object_field_registered(object_type, "goober"));
    
    	ast_sorcery_object_fields_register(sorcery, "test", "^", test_sorcery_regex_handler, test_sorcery_regex_fields);
    
    	ast_test_validate(test, ast_sorcery_is_object_field_registered(object_type, "goober"));
    
    	return AST_TEST_PASS;
    }
    
    
    3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451
    static int event_observed;
    
    static void wizard_observer(const char *name, const struct ast_sorcery_wizard *wizard)
    {
    	if (!strcmp(wizard->name, "test")) {
    		event_observed = 1;
    	}
    }
    
    static void instance_observer(const char *name, struct ast_sorcery *sorcery)
    {
    	if (!strcmp(name, "test_sorcery")) {
    		event_observed = 1;
    	}
    }
    
    AST_TEST_DEFINE(global_observation)
    {
    	RAII_VAR(struct ast_sorcery_wizard *, wizard, &test_wizard, ast_sorcery_wizard_unregister);
    	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
    	const struct ast_sorcery_global_observer observer = {
    		.wizard_registered = wizard_observer,
    		.instance_created = instance_observer,
    		.wizard_unregistering = wizard_observer,
    		.instance_destroying = instance_observer,
    	};
    
    	switch (cmd) {
    	case TEST_INIT:
    		info->name = "global_observation";
    		info->category = "/main/sorcery/";
    		info->summary = "global sorcery observation test";
    		info->description =
    			"Test observation of sorcery (global)";
    		return AST_TEST_NOT_RUN;
    	case TEST_EXECUTE:
    		break;
    	}
    
    	ast_sorcery_global_observer_add(&observer);
    
    	event_observed = 0;
    	ast_sorcery_wizard_register(wizard);
    	ast_test_validate(test, (event_observed == 1), "Wizard registered failed");
    
    	event_observed = 0;
    	ast_sorcery_wizard_unregister(wizard);
    	ast_test_validate(test, (event_observed == 1), "Wizard unregistered failed");
    
    	event_observed = 0;
    	sorcery = ast_sorcery_open();
    	ast_test_validate(test, (event_observed == 1), "Instance created failed");
    
    	event_observed = 0;
    	ast_sorcery_unref(sorcery);
    	sorcery = NULL;
    	ast_test_validate(test, (event_observed == 1), "Instance destroyed failed");
    
    	ast_sorcery_global_observer_remove(&observer);
    	event_observed = 0;
    	ast_sorcery_wizard_register(&test_wizard);
    	ast_test_validate(test, (event_observed == 0), "Observer removed failed");
    
    	return AST_TEST_PASS;
    }
    
    static void instance_loaded_observer(const char *name, const struct ast_sorcery *sorcery,
    	int reloaded)
    {
    	if (!strcmp(name, "test_sorcery") && !reloaded) {
    		event_observed++;
    	}
    }
    
    static void instance_reloaded_observer(const char *name,
    	const struct ast_sorcery *sorcery, int reloaded)
    {
    	if (!strcmp(name, "test_sorcery") && reloaded) {
    		event_observed++;
    	}
    }
    
    static void wizard_mapped_observer(const char *name, struct ast_sorcery *sorcery,
    	const char *object_type, struct ast_sorcery_wizard *wizard,
    	const char *wizard_args, void *wizard_data)
    {
    	if (!strcmp(name, "test_sorcery") && !strcmp(object_type, "test_object_type")
    		&& !strcmp(wizard->name, "memory") && !strcmp(wizard_args, "memwiz")) {
    		event_observed++;
    	}
    }
    
    static void object_type_registered_observer(const char *name,
    	struct ast_sorcery *sorcery, const char *object_type)
    {
    	if (!strcmp(name, "test_sorcery") && !strcmp(object_type, "test_object_type")) {
    		event_observed++;
    	}
    }
    
    static void object_type_loaded_observer(const char *name,
    	const struct ast_sorcery *sorcery, const char *object_type, int reloaded)
    {
    	if (!strcmp(name, "test_sorcery") && !strcmp(object_type, "test_object_type")
    		&& !reloaded) {
    		event_observed++;
    	}
    }
    
    static void object_type_reloaded_observer(const char *name,
    	const struct ast_sorcery *sorcery, const char *object_type, int reloaded)
    {
    	if (!strcmp(name, "test_sorcery") && !strcmp(object_type, "test_object_type")
    		&& reloaded) {
    		event_observed++;
    	}
    }
    
    AST_TEST_DEFINE(instance_observation)
    {
    	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
    	struct ast_sorcery_instance_observer observer = {
    		.wizard_mapped = wizard_mapped_observer,
    		.object_type_registered = object_type_registered_observer,
    	};
    
    	switch (cmd) {
    	case TEST_INIT:
    		info->name = "instance_observation";
    		info->category = "/main/sorcery/";
    		info->summary = "sorcery instance observation test";
    		info->description =
    			"Test observation of sorcery (instance)";
    		return AST_TEST_NOT_RUN;
    	case TEST_EXECUTE:
    		break;
    	}
    
    	/* Test instance load */
    	if (!(sorcery = ast_sorcery_open())) {
    		ast_test_status_update(test, "Failed to open a sorcery instance\n");
    		return AST_TEST_FAIL;
    	}
    	observer.instance_loading = instance_loaded_observer;
    	observer.instance_loaded = instance_loaded_observer;
    	ast_sorcery_instance_observer_add(sorcery, &observer);
    	event_observed = 0;
    	ast_sorcery_load(sorcery);
    	ast_test_validate(test, (event_observed == 2), "Instance loaded failed");
    	event_observed = 0;
    	ast_sorcery_reload(sorcery);
    	ast_test_validate(test, (event_observed == 0), "Instance reloaded failed");
    
    	/* Test instance reload */
    	ast_sorcery_instance_observer_remove(sorcery, &observer);
    	observer.instance_loading = instance_reloaded_observer;
    	observer.instance_loaded = instance_reloaded_observer;
    	ast_sorcery_instance_observer_add(sorcery, &observer);
    	event_observed = 0;
    	ast_sorcery_load(sorcery);
    	ast_test_validate(test, (event_observed == 0), "Instance loaded failed");
    	event_observed = 0;
    	ast_sorcery_reload(sorcery);
    	ast_test_validate(test, (event_observed == 2), "Instance reloaded failed");
    
    	/* Test wizard mapping */
    	event_observed = 0;
    	ast_sorcery_apply_default(sorcery, "test_object_type", "memory", "memwiz");
    	ast_test_validate(test, (event_observed == 1), "Wizard mapping failed");
    
    	/* Test object type register */
    	event_observed = 0;
    	ast_sorcery_internal_object_register(sorcery, "test_object_type",
    		test_sorcery_object_alloc, NULL, NULL);
    	ast_test_validate(test, (event_observed == 1), "Object type registered failed");
    
    	/* Test object type load */
    	ast_sorcery_instance_observer_remove(sorcery, &observer);
    	observer.object_type_loading = object_type_loaded_observer;
    	observer.object_type_loaded = object_type_loaded_observer;
    	ast_sorcery_instance_observer_add(sorcery, &observer);
    	event_observed = 0;
    	ast_sorcery_load_object(sorcery, "test_object_type");
    	ast_test_validate(test, (event_observed == 2), "Object type loaded failed");
    	event_observed = 0;
    	ast_sorcery_reload_object(sorcery, "test_object_type");
    	ast_test_validate(test, (event_observed == 0), "Object type reloaded failed");
    
    	/* Test object type reload */
    	ast_sorcery_instance_observer_remove(sorcery, &observer);
    	observer.object_type_loading = object_type_reloaded_observer;
    	observer.object_type_loaded = object_type_reloaded_observer;
    	ast_sorcery_instance_observer_add(sorcery, &observer);
    	event_observed = 0;
    	ast_sorcery_load_object(sorcery, "test_object_type");
    	ast_test_validate(test, (event_observed == 0), "Object type loaded failed");
    	event_observed = 0;
    	ast_sorcery_reload_object(sorcery, "test_object_type");
    	ast_test_validate(test, (event_observed == 2), "Object type reloaded failed");
    
    	ast_sorcery_instance_observer_remove(sorcery, &observer);
    	event_observed = 0;
    	ast_sorcery_apply_default(sorcery, "test_object_type", "memory", "memwiz");
    	ast_test_validate(test, (event_observed == 0), "Observer remove failed");
    
    	return AST_TEST_PASS;
    }
    
    static void wizard_loaded_observer(const char *name,
    	const struct ast_sorcery_wizard *wizard, const char *object_type, int reloaded)
    {
    	if (!strcmp(name, "test") && !strcmp(object_type, "test_object_type")
    		&& !reloaded) {
    		event_observed++;
    	}
    }
    
    static void sorcery_test_load(void *data, const struct ast_sorcery *sorcery, const char *type)
    {
    	return;
    }
    
    static void wizard_reloaded_observer(const char *name,
    	const struct ast_sorcery_wizard *wizard, const char *object_type, int reloaded)
    {
    	if (!strcmp(name, "test") && !strcmp(object_type, "test_object_type")
    		&& reloaded) {
    		event_observed++;
    	}
    }
    
    AST_TEST_DEFINE(wizard_observation)
    {
    	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
    	RAII_VAR(struct ast_sorcery_wizard *, wizard, &test_wizard, ast_sorcery_wizard_unregister);
    	struct ast_sorcery_wizard_observer observer = {
    		.wizard_loading = wizard_loaded_observer,
    		.wizard_loaded = wizard_loaded_observer,
    	};
    
    	switch (cmd) {
    	case TEST_INIT:
    		info->name = "wizard_observation";
    		info->category = "/main/sorcery/";
    		info->summary = "sorcery wizard observation test";
    		info->description =
    			"Test observation of sorcery (wizard)";
    		return AST_TEST_NOT_RUN;
    	case TEST_EXECUTE:
    		break;
    	}
    
    	wizard->load = sorcery_test_load;
    	wizard->reload = sorcery_test_load;
    
    	/* Test wizard observer remove and wizard unregister */
    	ast_sorcery_wizard_register(wizard);
    	ast_sorcery_wizard_observer_add(wizard, &observer);
    	ast_sorcery_wizard_observer_remove(wizard, &observer);
    	event_observed = 0;
    	ast_sorcery_wizard_unregister(wizard);
    	ast_test_validate(test, (event_observed == 0), "Wizard observer removed failed");
    
    	/* Setup for test loaded and reloaded */
    	if (!(sorcery = ast_sorcery_open())) {
    		ast_test_status_update(test, "Failed to open a sorcery instance\n");
    		return AST_TEST_FAIL;
    	}
    
    	ast_sorcery_wizard_register(wizard);
    	ast_sorcery_apply_default(sorcery, "test_object_type", "test", NULL);
    	ast_sorcery_internal_object_register(sorcery, "test_object_type",
    		test_sorcery_object_alloc, NULL, NULL);
    
    	/* Test wizard loading and loaded */
    	ast_sorcery_wizard_observer_add(wizard, &observer);
    
    	event_observed = 0;
    	ast_sorcery_load_object(sorcery, "test_object_type");
    	ast_test_validate(test, (event_observed == 2), "Wizard loaded failed");
    
    	event_observed = 0;
    	ast_sorcery_reload_object(sorcery, "test_object_type");
    	ast_sorcery_wizard_observer_remove(wizard, &observer);
    	ast_test_validate(test, (event_observed == 0), "Wizard reloaded failed");
    
    	/* Test wizard reloading and reloaded */
    	observer.wizard_loading = wizard_reloaded_observer;
    	observer.wizard_loaded = wizard_reloaded_observer;
    	ast_sorcery_wizard_observer_add(wizard, &observer);
    
    	event_observed = 0;
    	ast_sorcery_load_object(sorcery, "test_object_type");
    	ast_test_validate(test, (event_observed == 0), "Wizard loaded failed");
    
    	event_observed = 0;
    	ast_sorcery_reload_object(sorcery, "test_object_type");
    	ast_sorcery_wizard_observer_remove(wizard, &observer);
    	ast_test_validate(test, (event_observed == 2), "Wizard reloaded failed");
    
    	return AST_TEST_PASS;
    }
    
    
    AST_TEST_DEFINE(wizard_apply_and_insert)
    {
    	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
    	RAII_VAR(struct ast_sorcery_wizard *, wizard1, &test_wizard, ast_sorcery_wizard_unregister);
    	RAII_VAR(struct ast_sorcery_wizard *, wizard2, &test_wizard2, ast_sorcery_wizard_unregister);
    	RAII_VAR(struct ast_sorcery_wizard *, wizard, NULL, ao2_cleanup);
    	void *data;
    
    	switch (cmd) {
    	case TEST_INIT:
    		info->name = "wizard_apply_and_insert";
    		info->category = "/main/sorcery/";
    		info->summary = "sorcery wizard apply and insert test";
    		info->description =
    			"sorcery wizard apply and insert test";
    		return AST_TEST_NOT_RUN;
    	case TEST_EXECUTE:
    		break;
    	}
    
    	wizard1->load = sorcery_test_load;
    	wizard1->reload = sorcery_test_load;
    
    	wizard2->load = sorcery_test_load;
    	wizard2->reload = sorcery_test_load;
    
    	if (!(sorcery = ast_sorcery_open())) {
    		ast_test_status_update(test, "Failed to open a sorcery instance\n");
    		return AST_TEST_FAIL;
    	}
    
    	ast_sorcery_wizard_register(wizard1);
    	ast_sorcery_wizard_register(wizard2);
    
    	/* test_object_type isn't registered yet so count should return error */
    	ast_test_validate(test,
    		ast_sorcery_get_wizard_mapping_count(sorcery, "test_object_type") == -1);
    
    	ast_sorcery_apply_default(sorcery, "test_object_type", "test", NULL);
    
    	ast_test_validate(test,
    		ast_sorcery_get_wizard_mapping_count(sorcery, "test_object_type") == 1);
    
    	ast_test_validate(test,
    		ast_sorcery_get_wizard_mapping(sorcery, "test_object_type", 0, &wizard, NULL) == 0);
    	ast_test_validate(test, strcmp("test", wizard->name) == 0);
    	ao2_ref(wizard, -1);
    	wizard = NULL;
    
    	ast_test_validate(test,
    		ast_sorcery_insert_wizard_mapping(sorcery, "test_object_type", "test2", "test2data", 0, 0) == 0);
    
    	ast_test_validate(test,
    		ast_sorcery_insert_wizard_mapping(sorcery, "test_object_type", "test2", "test2data", 0, 0) != 0);
    
    	ast_test_validate(test,
    		ast_sorcery_get_wizard_mapping(sorcery, "test_object_type", 0, &wizard, &data) == 0);
    	ast_test_validate(test, strcmp("test2", wizard->name) == 0);
    	ast_test_validate(test, strcmp("test2data", data) == 0);
    	ao2_ref(wizard, -1);
    	wizard = NULL;
    
    	ast_test_validate(test,
    		ast_sorcery_get_wizard_mapping(sorcery, "test_object_type", 1, &wizard, NULL) == 0);
    	ast_test_validate(test, strcmp("test", wizard->name) == 0);
    	ao2_ref(wizard, -1);
    	wizard = NULL;
    
    	/* Test failures */
    	ast_test_validate(test,
    		ast_sorcery_get_wizard_mapping(sorcery, "non-existent-type", 0, &wizard, NULL) != 0);
    
    	ast_test_validate(test,
    		ast_sorcery_get_wizard_mapping(sorcery, "test_object_type", -1, &wizard, &data) != 0);
    
    	ast_test_validate(test,
    		ast_sorcery_get_wizard_mapping(sorcery, "test_object_type", 2, &wizard, NULL) != 0);
    
    	ast_test_validate(test,
    		ast_sorcery_get_wizard_mapping(sorcery, "test_object_type", 2, NULL, NULL) != 0);
    
    	/* Test remove */
    	/* Should fail */
    	ast_test_validate(test,
    		ast_sorcery_remove_wizard_mapping(sorcery, "non-existent-type", "somewizard") != 0);
    	ast_test_validate(test,
    		ast_sorcery_remove_wizard_mapping(sorcery, "test_object_type", "somewizard") != 0);
    
    	/* should work */
    	ast_test_validate(test,
    		ast_sorcery_remove_wizard_mapping(sorcery, "test_object_type", "test") == 0);
    
    	ast_test_validate(test,
    		ast_sorcery_get_wizard_mapping_count(sorcery, "test_object_type") == 1);
    
    	ast_test_validate(test,
    		ast_sorcery_get_wizard_mapping(sorcery, "test_object_type", 0, &wizard, &data) == 0);
    	ast_test_validate(test, strcmp("test2", wizard->name) == 0);
    	ast_test_validate(test, strcmp("test2data", data) == 0);
    	ao2_ref(wizard, -1);
    	wizard = NULL;
    
    	return AST_TEST_PASS;
    }
    
    
    static int unload_module(void)
    {
    	AST_TEST_UNREGISTER(wizard_registration);
    
    	AST_TEST_UNREGISTER(apply_default);
    	AST_TEST_UNREGISTER(apply_config);
    	AST_TEST_UNREGISTER(object_register);
    	AST_TEST_UNREGISTER(object_register_without_mapping);
    	AST_TEST_UNREGISTER(object_field_register);
    
    	AST_TEST_UNREGISTER(object_alloc_with_id);
    	AST_TEST_UNREGISTER(object_alloc_without_id);
    	AST_TEST_UNREGISTER(object_copy);
    
    	AST_TEST_UNREGISTER(object_copy_native);
    
    	AST_TEST_UNREGISTER(object_diff);
    
    	AST_TEST_UNREGISTER(object_diff_native);
    
    	AST_TEST_UNREGISTER(objectset_create);
    
    	AST_TEST_UNREGISTER(objectset_json_create);
    
    	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(extended_fields);
    
    	AST_TEST_UNREGISTER(changeset_create);
    	AST_TEST_UNREGISTER(changeset_create_unchanged);
    	AST_TEST_UNREGISTER(object_create);
    	AST_TEST_UNREGISTER(object_retrieve_id);
    	AST_TEST_UNREGISTER(object_retrieve_field);
    	AST_TEST_UNREGISTER(object_retrieve_multiple_all);
    	AST_TEST_UNREGISTER(object_retrieve_multiple_field);
    
    	AST_TEST_UNREGISTER(object_retrieve_regex);
    
    	AST_TEST_UNREGISTER(object_update);
    	AST_TEST_UNREGISTER(object_update_uncreated);
    	AST_TEST_UNREGISTER(object_delete);
    	AST_TEST_UNREGISTER(object_delete_uncreated);
    
    	AST_TEST_UNREGISTER(object_is_stale);
    
    	AST_TEST_UNREGISTER(caching_wizard_behavior);
    
    	AST_TEST_UNREGISTER(object_type_observer);
    
    	AST_TEST_UNREGISTER(configuration_file_wizard);
    	AST_TEST_UNREGISTER(configuration_file_wizard_with_file_integrity);
    	AST_TEST_UNREGISTER(configuration_file_wizard_with_criteria);
    	AST_TEST_UNREGISTER(configuration_file_wizard_retrieve_field);
    	AST_TEST_UNREGISTER(configuration_file_wizard_retrieve_multiple);
    	AST_TEST_UNREGISTER(configuration_file_wizard_retrieve_multiple_all);
    
    	AST_TEST_UNREGISTER(dialplan_function);
    
    	AST_TEST_UNREGISTER(object_field_registered);
    
    	AST_TEST_UNREGISTER(global_observation);
    	AST_TEST_UNREGISTER(instance_observation);
    	AST_TEST_UNREGISTER(wizard_observation);
    
    	AST_TEST_UNREGISTER(wizard_apply_and_insert);
    
    	return 0;
    }
    
    static int load_module(void)
    {
    
    	AST_TEST_REGISTER(wizard_apply_and_insert);
    
    	AST_TEST_REGISTER(wizard_registration);
    
    	AST_TEST_REGISTER(apply_default);
    	AST_TEST_REGISTER(apply_config);
    	AST_TEST_REGISTER(object_register);
    	AST_TEST_REGISTER(object_register_without_mapping);
    	AST_TEST_REGISTER(object_field_register);
    
    	AST_TEST_REGISTER(object_alloc_with_id);
    	AST_TEST_REGISTER(object_alloc_without_id);
    	AST_TEST_REGISTER(object_copy);
    
    	AST_TEST_REGISTER(object_copy_native);
    
    	AST_TEST_REGISTER(object_diff);
    
    	AST_TEST_REGISTER(object_diff_native);
    
    	AST_TEST_REGISTER(objectset_create);
    
    	AST_TEST_REGISTER(objectset_json_create);
    
    	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(extended_fields);
    
    	AST_TEST_REGISTER(changeset_create);
    	AST_TEST_REGISTER(changeset_create_unchanged);
    	AST_TEST_REGISTER(object_create);
    	AST_TEST_REGISTER(object_retrieve_id);
    	AST_TEST_REGISTER(object_retrieve_field);
    	AST_TEST_REGISTER(object_retrieve_multiple_all);
    	AST_TEST_REGISTER(object_retrieve_multiple_field);
    
    	AST_TEST_REGISTER(object_retrieve_regex);
    
    	AST_TEST_REGISTER(object_update);
    	AST_TEST_REGISTER(object_update_uncreated);
    	AST_TEST_REGISTER(object_delete);
    	AST_TEST_REGISTER(object_delete_uncreated);
    
    	AST_TEST_REGISTER(object_is_stale);
    
    	AST_TEST_REGISTER(caching_wizard_behavior);
    
    	AST_TEST_REGISTER(object_type_observer);
    
    	AST_TEST_REGISTER(configuration_file_wizard);
    	AST_TEST_REGISTER(configuration_file_wizard_with_file_integrity);
    	AST_TEST_REGISTER(configuration_file_wizard_with_criteria);
    	AST_TEST_REGISTER(configuration_file_wizard_retrieve_field);
    	AST_TEST_REGISTER(configuration_file_wizard_retrieve_multiple);
    	AST_TEST_REGISTER(configuration_file_wizard_retrieve_multiple_all);
    
    	AST_TEST_REGISTER(dialplan_function);
    
    	AST_TEST_REGISTER(object_field_registered);
    
    	AST_TEST_REGISTER(global_observation);
    	AST_TEST_REGISTER(instance_observation);
    	AST_TEST_REGISTER(wizard_observation);
    
    	return AST_MODULE_LOAD_SUCCESS;
    }
    
    AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Sorcery test module");