Params-Validate-Strict

 view release on metacpan or  search on metacpan

t/function.t  view on Meta::CPAN

				type     => 'stringref',
				callback => sub { 0 },
			} },
			input => { x => \$s },
		},
		qr/failed custom validation/,
		'croaks when stringref callback returns false'
	);
};

# ── stringref × transform returning non-string ───────────────────────────────
# The early-deref block validates the SCALAR ref and derefs $value; transform
# then runs on the plain string.  If transform returns a reference, the
# stringref dispatch arm must catch it — the no-op stub that existed before
# was a confirmed bug.

subtest 'validate_strict: type stringref × transform returning hashref → croaks' => sub {
	my $s = 'hello';
	_vs_throws(
		{
			schema => { x => { type => 'stringref', transform => sub { {} } } },
			input  => { x => \$s },
		},
		qr/stringref transform must return a plain string/,
		'croaks when transform returns a hashref for a stringref parameter'
	);
};

subtest 'validate_strict: type stringref × transform returning arrayref → croaks' => sub {
	my $s = 'hello';
	_vs_throws(
		{
			schema => { x => { type => 'stringref', transform => sub { [] } } },
			input  => { x => \$s },
		},
		qr/stringref transform must return a plain string/,
		'croaks when transform returns an arrayref for a stringref parameter'
	);
};

subtest 'validate_strict: type stringref × transform returning plain string → ok' => sub {
	my $s = 'hello';
	my $r = _vs({
		schema => { x => { type => 'stringref', transform => sub { uc($_[0]) } } },
		input  => { x => \$s },
	});
	is($r->{x}, 'HELLO', 'transform returning a plain string is accepted normally');
};

# ── stringref × optional => CODE receives original SCALAR ref ────────────────
# The early-deref mutates $value to a plain string before optional => CODE is
# evaluated.  The fix captures the original ref so the coderef sees what the
# caller actually passed, not the module's internal representation.

subtest 'validate_strict: type stringref × optional CODE receives original SCALAR ref' => sub {
	my $received;
	my $s = 'world';
	_vs({
		schema => { x => {
			type     => 'stringref',
			optional => sub { $received = $_[0]; 0 },	# 0 = required; just capture
		} },
		input => { x => \$s },
	});
	ok(ref($received) eq 'SCALAR', 'optional coderef receives the original SCALAR ref');
	is(${$received}, 'world',      'the ref still points to the correct string value');
};

subtest 'validate_strict: type stringref × optional CODE returning true — param treated as optional' => sub {
	# Confirm the coderef return value is honoured even though the value is a ref.
	my $s = 'ignored';
	my $r = _vs({
		schema => {
			x => { type => 'stringref', optional => sub { 1 } },
		},
		input => { x => \$s },
	});
	# optional => 1 means the key is present but the parameter is optional;
	# when the value IS provided it is still validated and returned.
	ok(exists($r->{x}), 'present stringref value returned even when optional coderef returns true');
};

# ── stringref in union types ──────────────────────────────────────────────────

subtest 'validate_strict: union [string, stringref] — plain string takes string branch' => sub {
	my $r = _vs({
		schema => { x => { type => ['string', 'stringref'] } },
		input  => { x => 'plain' },
	});
	is($r->{x}, 'plain', 'plain string accepted via string branch of union');
};

subtest 'validate_strict: union [string, stringref] — string ref takes stringref branch, deref returned' => sub {
	my $s = 'wrapped';
	my $r = _vs({
		schema => { x => { type => ['string', 'stringref'] } },
		input  => { x => \$s },
	});
	is($r->{x}, 'wrapped', 'string ref accepted via stringref branch; dereferenced string returned');
	ok(!ref($r->{x}),       'returned value is a plain scalar, not a ref');
};

subtest 'validate_strict: union [string, stringref] — arrayref rejected by both branches' => sub {
	_vs_throws(
		{ schema => { x => { type => ['string', 'stringref'] } }, input => { x => [1, 2] } },
		qr/must be one of/,
		'croaks when arrayref fails both string and stringref branches'
	);
};

subtest 'validate_strict: union [string, stringref] — hashref rejected by both branches' => sub {
	_vs_throws(
		{ schema => { x => { type => ['string', 'stringref'] } }, input => { x => { a => 1 } } },
		qr/must be one of/,
		'croaks when hashref fails both string and stringref branches'
	);
};

done_testing;



( run in 1.805 second using v1.01-cache-2.11-cpan-6aa56a78535 )