Commit 3f48b137 authored by Mark Brown's avatar Mark Brown Committed by Takashi Iwai
Browse files

kselftest: alsa: Factor out check that values meet constraints



To simplify the code a bit and allow future reuse factor the checks that
values we read are valid out of test_ctl_get_value() into a separate
function which can be reused later. As part of this extend the test to
check all the values for the control, not just the first one.

Signed-off-by: default avatarMark Brown <broonie@kernel.org>
Reviewed-by: default avatarCezary Rojewski <cezary.rojewski@intel.com>
Link: https://lore.kernel.org/r/20211217130213.3893415-2-broonie@kernel.org


Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 0f7e5ee6
Loading
Loading
Loading
Loading
+82 −59
Original line number Diff line number Diff line
@@ -193,124 +193,147 @@ void find_controls(void)
	snd_config_delete(config);
}

/*
 * Check that we can read the default value and it is valid. Write
 * tests use the read value to restore the default.
 */
void test_ctl_get_value(struct ctl_data *ctl)
bool ctl_value_index_valid(struct ctl_data *ctl, snd_ctl_elem_value_t *val,
			   int index)
{
	int err;
	long int_val;
	long long int64_val;

	/* If the control is turned off let's be polite */
	if (snd_ctl_elem_info_is_inactive(ctl->info)) {
		ksft_print_msg("%s is inactive\n", ctl->name);
		ksft_test_result_skip("get_value.%d.%d\n",
				      ctl->card->card, ctl->elem);
		return;
	}

	/* Can't test reading on an unreadable control */
	if (!snd_ctl_elem_info_is_readable(ctl->info)) {
		ksft_print_msg("%s is not readable\n", ctl->name);
		ksft_test_result_skip("get_value.%d.%d\n",
				      ctl->card->card, ctl->elem);
		return;
	}

	err = snd_ctl_elem_read(ctl->card->handle, ctl->def_val);
	if (err < 0) {
		ksft_print_msg("snd_ctl_elem_read() failed: %s\n",
			       snd_strerror(err));
		goto out;
	}

	switch (snd_ctl_elem_info_get_type(ctl->info)) {
	case SND_CTL_ELEM_TYPE_NONE:
		ksft_print_msg("%s Invalid control type NONE\n", ctl->name);
		err = -1;
		break;
		ksft_print_msg("%s.%d Invalid control type NONE\n",
			       ctl->name, index);
		return false;

	case SND_CTL_ELEM_TYPE_BOOLEAN:
		int_val = snd_ctl_elem_value_get_boolean(ctl->def_val, 0);
		int_val = snd_ctl_elem_value_get_boolean(val, index);
		switch (int_val) {
		case 0:
		case 1:
			break;
		default:
			ksft_print_msg("%s Invalid boolean value %ld\n",
				       ctl->name, int_val);
			err = -1;
			break;
			ksft_print_msg("%s.%d Invalid boolean value %ld\n",
				       ctl->name, index, int_val);
			return false;
		}
		break;

	case SND_CTL_ELEM_TYPE_INTEGER:
		int_val = snd_ctl_elem_value_get_integer(ctl->def_val, 0);
		int_val = snd_ctl_elem_value_get_integer(val, index);

		if (int_val < snd_ctl_elem_info_get_min(ctl->info)) {
			ksft_print_msg("%s value %ld less than minimum %ld\n",
				       ctl->name, int_val,
			ksft_print_msg("%s.%d value %ld less than minimum %ld\n",
				       ctl->name, index, int_val,
				       snd_ctl_elem_info_get_min(ctl->info));
			err = -1;
			return false;
		}

		if (int_val > snd_ctl_elem_info_get_max(ctl->info)) {
			ksft_print_msg("%s value %ld more than maximum %ld\n",
				       ctl->name, int_val,
			ksft_print_msg("%s.%d value %ld more than maximum %ld\n",
				       ctl->name, index, int_val,
				       snd_ctl_elem_info_get_max(ctl->info));
			err = -1;
			return false;
		}

		/* Only check step size if there is one and we're in bounds */
		if (err >= 0 && snd_ctl_elem_info_get_step(ctl->info) &&
		if (snd_ctl_elem_info_get_step(ctl->info) &&
		    (int_val - snd_ctl_elem_info_get_min(ctl->info) %
		     snd_ctl_elem_info_get_step(ctl->info))) {
			ksft_print_msg("%s value %ld invalid for step %ld minimum %ld\n",
				       ctl->name, int_val,
			ksft_print_msg("%s.%d value %ld invalid for step %ld minimum %ld\n",
				       ctl->name, index, int_val,
				       snd_ctl_elem_info_get_step(ctl->info),
				       snd_ctl_elem_info_get_min(ctl->info));
			err = -1;
			return false;
		}
		break;

	case SND_CTL_ELEM_TYPE_INTEGER64:
		int64_val = snd_ctl_elem_value_get_integer64(ctl->def_val, 0);
		int64_val = snd_ctl_elem_value_get_integer64(val, index);

		if (int64_val < snd_ctl_elem_info_get_min64(ctl->info)) {
			ksft_print_msg("%s value %lld less than minimum %lld\n",
				       ctl->name, int64_val,
			ksft_print_msg("%s.%d value %lld less than minimum %lld\n",
				       ctl->name, index, int64_val,
				       snd_ctl_elem_info_get_min64(ctl->info));
			err = -1;
			return false;
		}

		if (int64_val > snd_ctl_elem_info_get_max64(ctl->info)) {
			ksft_print_msg("%s value %lld more than maximum %lld\n",
				       ctl->name, int64_val,
			ksft_print_msg("%s.%d value %lld more than maximum %lld\n",
				       ctl->name, index, int64_val,
				       snd_ctl_elem_info_get_max(ctl->info));
			err = -1;
			return false;
		}

		/* Only check step size if there is one and we're in bounds */
		if (err >= 0 && snd_ctl_elem_info_get_step64(ctl->info) &&
		if (snd_ctl_elem_info_get_step64(ctl->info) &&
		    (int64_val - snd_ctl_elem_info_get_min64(ctl->info)) %
		    snd_ctl_elem_info_get_step64(ctl->info)) {
			ksft_print_msg("%s value %lld invalid for step %lld minimum %lld\n",
				       ctl->name, int64_val,
			ksft_print_msg("%s.%d value %lld invalid for step %lld minimum %lld\n",
				       ctl->name, index, int64_val,
				       snd_ctl_elem_info_get_step64(ctl->info),
				       snd_ctl_elem_info_get_min64(ctl->info));
			err = -1;
			return false;
		}
		break;

	default:
		/* No tests for other types */
		break;
	}

	return true;
}

/*
 * Check that the provided value meets the constraints for the
 * provided control.
 */
bool ctl_value_valid(struct ctl_data *ctl, snd_ctl_elem_value_t *val)
{
	int i;
	bool valid = true;

	for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++)
		if (!ctl_value_index_valid(ctl, val, i))
			valid = false;

	return valid;
}

/*
 * Check that we can read the default value and it is valid. Write
 * tests use the read value to restore the default.
 */
void test_ctl_get_value(struct ctl_data *ctl)
{
	int err;

	/* If the control is turned off let's be polite */
	if (snd_ctl_elem_info_is_inactive(ctl->info)) {
		ksft_print_msg("%s is inactive\n", ctl->name);
		ksft_test_result_skip("get_value.%d.%d\n",
				      ctl->card->card, ctl->elem);
		return;
	}

	/* Can't test reading on an unreadable control */
	if (!snd_ctl_elem_info_is_readable(ctl->info)) {
		ksft_print_msg("%s is not readable\n", ctl->name);
		ksft_test_result_skip("get_value.%d.%d\n",
				      ctl->card->card, ctl->elem);
		return;
	}

	err = snd_ctl_elem_read(ctl->card->handle, ctl->def_val);
	if (err < 0) {
		ksft_print_msg("snd_ctl_elem_read() failed: %s\n",
			       snd_strerror(err));
		goto out;
	}

	if (!ctl_value_valid(ctl, ctl->def_val))
		err = -EINVAL;

out:
	ksft_test_result(err >= 0, "get_value.%d.%d\n",
			 ctl->card->card, ctl->elem);