| #!/bin/sh | 
 |  | 
 | test_description='basic credential helper tests' | 
 | . ./test-lib.sh | 
 | . "$TEST_DIRECTORY"/lib-credential.sh | 
 |  | 
 | test_expect_success 'setup helper scripts' ' | 
 | 	cat >dump <<-\EOF && | 
 | 	whoami=$(echo $0 | sed s/.*git-credential-//) | 
 | 	echo >&2 "$whoami: $*" | 
 | 	OIFS=$IFS | 
 | 	IFS== | 
 | 	while read key value; do | 
 | 		echo >&2 "$whoami: $key=$value" | 
 | 		eval "$key=$value" | 
 | 	done | 
 | 	IFS=$OIFS | 
 | 	EOF | 
 |  | 
 | 	write_script git-credential-useless <<-\EOF && | 
 | 	. ./dump | 
 | 	exit 0 | 
 | 	EOF | 
 |  | 
 | 	write_script git-credential-quit <<-\EOF && | 
 | 	. ./dump | 
 | 	echo quit=1 | 
 | 	EOF | 
 |  | 
 | 	write_script git-credential-verbatim <<-\EOF && | 
 | 	user=$1; shift | 
 | 	pass=$1; shift | 
 | 	. ./dump | 
 | 	test -z "$user" || echo username=$user | 
 | 	test -z "$pass" || echo password=$pass | 
 | 	EOF | 
 |  | 
 | 	write_script git-credential-verbatim-with-expiry <<-\EOF && | 
 | 	user=$1; shift | 
 | 	pass=$1; shift | 
 | 	pexpiry=$1; shift | 
 | 	. ./dump | 
 | 	test -z "$user" || echo username=$user | 
 | 	test -z "$pass" || echo password=$pass | 
 | 	test -z "$pexpiry" || echo password_expiry_utc=$pexpiry | 
 | 	EOF | 
 |  | 
 | 	PATH="$PWD:$PATH" | 
 | ' | 
 |  | 
 | test_expect_success 'credential_fill invokes helper' ' | 
 | 	check fill "verbatim foo bar" <<-\EOF | 
 | 	protocol=http | 
 | 	host=example.com | 
 | 	-- | 
 | 	protocol=http | 
 | 	host=example.com | 
 | 	username=foo | 
 | 	password=bar | 
 | 	-- | 
 | 	verbatim: get | 
 | 	verbatim: protocol=http | 
 | 	verbatim: host=example.com | 
 | 	EOF | 
 | ' | 
 |  | 
 | test_expect_success 'credential_fill invokes multiple helpers' ' | 
 | 	check fill useless "verbatim foo bar" <<-\EOF | 
 | 	protocol=http | 
 | 	host=example.com | 
 | 	-- | 
 | 	protocol=http | 
 | 	host=example.com | 
 | 	username=foo | 
 | 	password=bar | 
 | 	-- | 
 | 	useless: get | 
 | 	useless: protocol=http | 
 | 	useless: host=example.com | 
 | 	verbatim: get | 
 | 	verbatim: protocol=http | 
 | 	verbatim: host=example.com | 
 | 	EOF | 
 | ' | 
 |  | 
 | test_expect_success 'credential_fill stops when we get a full response' ' | 
 | 	check fill "verbatim one two" "verbatim three four" <<-\EOF | 
 | 	protocol=http | 
 | 	host=example.com | 
 | 	-- | 
 | 	protocol=http | 
 | 	host=example.com | 
 | 	username=one | 
 | 	password=two | 
 | 	-- | 
 | 	verbatim: get | 
 | 	verbatim: protocol=http | 
 | 	verbatim: host=example.com | 
 | 	EOF | 
 | ' | 
 |  | 
 | test_expect_success 'credential_fill continues through partial response' ' | 
 | 	check fill "verbatim one \"\"" "verbatim two three" <<-\EOF | 
 | 	protocol=http | 
 | 	host=example.com | 
 | 	-- | 
 | 	protocol=http | 
 | 	host=example.com | 
 | 	username=two | 
 | 	password=three | 
 | 	-- | 
 | 	verbatim: get | 
 | 	verbatim: protocol=http | 
 | 	verbatim: host=example.com | 
 | 	verbatim: get | 
 | 	verbatim: protocol=http | 
 | 	verbatim: host=example.com | 
 | 	verbatim: username=one | 
 | 	EOF | 
 | ' | 
 |  | 
 | test_expect_success 'credential_fill populates password_expiry_utc' ' | 
 | 	check fill "verbatim-with-expiry one two 9999999999" <<-\EOF | 
 | 	protocol=http | 
 | 	host=example.com | 
 | 	-- | 
 | 	protocol=http | 
 | 	host=example.com | 
 | 	username=one | 
 | 	password=two | 
 | 	password_expiry_utc=9999999999 | 
 | 	-- | 
 | 	verbatim-with-expiry: get | 
 | 	verbatim-with-expiry: protocol=http | 
 | 	verbatim-with-expiry: host=example.com | 
 | 	EOF | 
 | ' | 
 |  | 
 | test_expect_success 'credential_fill ignores expired password' ' | 
 | 	check fill "verbatim-with-expiry one two 5" "verbatim three four" <<-\EOF | 
 | 	protocol=http | 
 | 	host=example.com | 
 | 	-- | 
 | 	protocol=http | 
 | 	host=example.com | 
 | 	username=three | 
 | 	password=four | 
 | 	-- | 
 | 	verbatim-with-expiry: get | 
 | 	verbatim-with-expiry: protocol=http | 
 | 	verbatim-with-expiry: host=example.com | 
 | 	verbatim: get | 
 | 	verbatim: protocol=http | 
 | 	verbatim: host=example.com | 
 | 	verbatim: username=one | 
 | 	EOF | 
 | ' | 
 |  | 
 | test_expect_success 'credential_fill passes along metadata' ' | 
 | 	check fill "verbatim one two" <<-\EOF | 
 | 	protocol=ftp | 
 | 	host=example.com | 
 | 	path=foo.git | 
 | 	-- | 
 | 	protocol=ftp | 
 | 	host=example.com | 
 | 	path=foo.git | 
 | 	username=one | 
 | 	password=two | 
 | 	-- | 
 | 	verbatim: get | 
 | 	verbatim: protocol=ftp | 
 | 	verbatim: host=example.com | 
 | 	verbatim: path=foo.git | 
 | 	EOF | 
 | ' | 
 |  | 
 | test_expect_success 'credential_approve calls all helpers' ' | 
 | 	check approve useless "verbatim one two" <<-\EOF | 
 | 	protocol=http | 
 | 	host=example.com | 
 | 	username=foo | 
 | 	password=bar | 
 | 	-- | 
 | 	-- | 
 | 	useless: store | 
 | 	useless: protocol=http | 
 | 	useless: host=example.com | 
 | 	useless: username=foo | 
 | 	useless: password=bar | 
 | 	verbatim: store | 
 | 	verbatim: protocol=http | 
 | 	verbatim: host=example.com | 
 | 	verbatim: username=foo | 
 | 	verbatim: password=bar | 
 | 	EOF | 
 | ' | 
 |  | 
 | test_expect_success 'credential_approve stores password expiry' ' | 
 | 	check approve useless <<-\EOF | 
 | 	protocol=http | 
 | 	host=example.com | 
 | 	username=foo | 
 | 	password=bar | 
 | 	password_expiry_utc=9999999999 | 
 | 	-- | 
 | 	-- | 
 | 	useless: store | 
 | 	useless: protocol=http | 
 | 	useless: host=example.com | 
 | 	useless: username=foo | 
 | 	useless: password=bar | 
 | 	useless: password_expiry_utc=9999999999 | 
 | 	EOF | 
 | ' | 
 |  | 
 | test_expect_success 'credential_approve stores oauth refresh token' ' | 
 | 	check approve useless <<-\EOF | 
 | 	protocol=http | 
 | 	host=example.com | 
 | 	username=foo | 
 | 	password=bar | 
 | 	oauth_refresh_token=xyzzy | 
 | 	-- | 
 | 	-- | 
 | 	useless: store | 
 | 	useless: protocol=http | 
 | 	useless: host=example.com | 
 | 	useless: username=foo | 
 | 	useless: password=bar | 
 | 	useless: oauth_refresh_token=xyzzy | 
 | 	EOF | 
 | ' | 
 |  | 
 | test_expect_success 'do not bother storing password-less credential' ' | 
 | 	check approve useless <<-\EOF | 
 | 	protocol=http | 
 | 	host=example.com | 
 | 	username=foo | 
 | 	-- | 
 | 	-- | 
 | 	EOF | 
 | ' | 
 |  | 
 | test_expect_success 'credential_approve does not store expired password' ' | 
 | 	check approve useless <<-\EOF | 
 | 	protocol=http | 
 | 	host=example.com | 
 | 	username=foo | 
 | 	password=bar | 
 | 	password_expiry_utc=5 | 
 | 	-- | 
 | 	-- | 
 | 	EOF | 
 | ' | 
 |  | 
 | test_expect_success 'credential_reject calls all helpers' ' | 
 | 	check reject useless "verbatim one two" <<-\EOF | 
 | 	protocol=http | 
 | 	host=example.com | 
 | 	username=foo | 
 | 	password=bar | 
 | 	-- | 
 | 	-- | 
 | 	useless: erase | 
 | 	useless: protocol=http | 
 | 	useless: host=example.com | 
 | 	useless: username=foo | 
 | 	useless: password=bar | 
 | 	verbatim: erase | 
 | 	verbatim: protocol=http | 
 | 	verbatim: host=example.com | 
 | 	verbatim: username=foo | 
 | 	verbatim: password=bar | 
 | 	EOF | 
 | ' | 
 |  | 
 | test_expect_success 'credential_reject erases credential regardless of expiry' ' | 
 | 	check reject useless <<-\EOF | 
 | 	protocol=http | 
 | 	host=example.com | 
 | 	username=foo | 
 | 	password=bar | 
 | 	password_expiry_utc=5 | 
 | 	-- | 
 | 	-- | 
 | 	useless: erase | 
 | 	useless: protocol=http | 
 | 	useless: host=example.com | 
 | 	useless: username=foo | 
 | 	useless: password=bar | 
 | 	useless: password_expiry_utc=5 | 
 | 	EOF | 
 | ' | 
 |  | 
 | test_expect_success 'usernames can be preserved' ' | 
 | 	check fill "verbatim \"\" three" <<-\EOF | 
 | 	protocol=http | 
 | 	host=example.com | 
 | 	username=one | 
 | 	-- | 
 | 	protocol=http | 
 | 	host=example.com | 
 | 	username=one | 
 | 	password=three | 
 | 	-- | 
 | 	verbatim: get | 
 | 	verbatim: protocol=http | 
 | 	verbatim: host=example.com | 
 | 	verbatim: username=one | 
 | 	EOF | 
 | ' | 
 |  | 
 | test_expect_success 'usernames can be overridden' ' | 
 | 	check fill "verbatim two three" <<-\EOF | 
 | 	protocol=http | 
 | 	host=example.com | 
 | 	username=one | 
 | 	-- | 
 | 	protocol=http | 
 | 	host=example.com | 
 | 	username=two | 
 | 	password=three | 
 | 	-- | 
 | 	verbatim: get | 
 | 	verbatim: protocol=http | 
 | 	verbatim: host=example.com | 
 | 	verbatim: username=one | 
 | 	EOF | 
 | ' | 
 |  | 
 | test_expect_success 'do not bother completing already-full credential' ' | 
 | 	check fill "verbatim three four" <<-\EOF | 
 | 	protocol=http | 
 | 	host=example.com | 
 | 	username=one | 
 | 	password=two | 
 | 	-- | 
 | 	protocol=http | 
 | 	host=example.com | 
 | 	username=one | 
 | 	password=two | 
 | 	-- | 
 | 	EOF | 
 | ' | 
 |  | 
 | # We can't test the basic terminal password prompt here because | 
 | # getpass() tries too hard to find the real terminal. But if our | 
 | # askpass helper is run, we know the internal getpass is working. | 
 | test_expect_success 'empty helper list falls back to internal getpass' ' | 
 | 	check fill <<-\EOF | 
 | 	protocol=http | 
 | 	host=example.com | 
 | 	-- | 
 | 	protocol=http | 
 | 	host=example.com | 
 | 	username=askpass-username | 
 | 	password=askpass-password | 
 | 	-- | 
 | 	askpass: Username for '\''http://example.com'\'': | 
 | 	askpass: Password for '\''http://askpass-username@example.com'\'': | 
 | 	EOF | 
 | ' | 
 |  | 
 | test_expect_success 'internal getpass does not ask for known username' ' | 
 | 	check fill <<-\EOF | 
 | 	protocol=http | 
 | 	host=example.com | 
 | 	username=foo | 
 | 	-- | 
 | 	protocol=http | 
 | 	host=example.com | 
 | 	username=foo | 
 | 	password=askpass-password | 
 | 	-- | 
 | 	askpass: Password for '\''http://foo@example.com'\'': | 
 | 	EOF | 
 | ' | 
 |  | 
 | test_expect_success 'git-credential respects core.askPass' ' | 
 | 	write_script alternate-askpass <<-\EOF && | 
 | 	echo >&2 "alternate askpass invoked" | 
 | 	echo alternate-value | 
 | 	EOF | 
 | 	test_config core.askpass "$PWD/alternate-askpass" && | 
 | 	( | 
 | 		# unset GIT_ASKPASS set by lib-credential.sh which would | 
 | 		# override our config, but do so in a subshell so that we do | 
 | 		# not interfere with other tests | 
 | 		sane_unset GIT_ASKPASS && | 
 | 		check fill <<-\EOF | 
 | 		protocol=http | 
 | 		host=example.com | 
 | 		-- | 
 | 		protocol=http | 
 | 		host=example.com | 
 | 		username=alternate-value | 
 | 		password=alternate-value | 
 | 		-- | 
 | 		alternate askpass invoked | 
 | 		alternate askpass invoked | 
 | 		EOF | 
 | 	) | 
 | ' | 
 |  | 
 | HELPER="!f() { | 
 | 		cat >/dev/null | 
 | 		echo username=foo | 
 | 		echo password=bar | 
 | 	}; f" | 
 | test_expect_success 'respect configured credentials' ' | 
 | 	test_config credential.helper "$HELPER" && | 
 | 	check fill <<-\EOF | 
 | 	protocol=http | 
 | 	host=example.com | 
 | 	-- | 
 | 	protocol=http | 
 | 	host=example.com | 
 | 	username=foo | 
 | 	password=bar | 
 | 	-- | 
 | 	EOF | 
 | ' | 
 |  | 
 | test_expect_success 'match configured credential' ' | 
 | 	test_config credential.https://example.com.helper "$HELPER" && | 
 | 	check fill <<-\EOF | 
 | 	protocol=https | 
 | 	host=example.com | 
 | 	path=repo.git | 
 | 	-- | 
 | 	protocol=https | 
 | 	host=example.com | 
 | 	username=foo | 
 | 	password=bar | 
 | 	-- | 
 | 	EOF | 
 | ' | 
 |  | 
 | test_expect_success 'do not match configured credential' ' | 
 | 	test_config credential.https://foo.helper "$HELPER" && | 
 | 	check fill <<-\EOF | 
 | 	protocol=https | 
 | 	host=bar | 
 | 	-- | 
 | 	protocol=https | 
 | 	host=bar | 
 | 	username=askpass-username | 
 | 	password=askpass-password | 
 | 	-- | 
 | 	askpass: Username for '\''https://bar'\'': | 
 | 	askpass: Password for '\''https://askpass-username@bar'\'': | 
 | 	EOF | 
 | ' | 
 |  | 
 | test_expect_success 'match multiple configured helpers' ' | 
 | 	test_config credential.helper "verbatim \"\" \"\"" && | 
 | 	test_config credential.https://example.com.helper "$HELPER" && | 
 | 	check fill <<-\EOF | 
 | 	protocol=https | 
 | 	host=example.com | 
 | 	path=repo.git | 
 | 	-- | 
 | 	protocol=https | 
 | 	host=example.com | 
 | 	username=foo | 
 | 	password=bar | 
 | 	-- | 
 | 	verbatim: get | 
 | 	verbatim: protocol=https | 
 | 	verbatim: host=example.com | 
 | 	EOF | 
 | ' | 
 |  | 
 | test_expect_success 'match multiple configured helpers with URLs' ' | 
 | 	test_config credential.https://example.com/repo.git.helper "verbatim \"\" \"\"" && | 
 | 	test_config credential.https://example.com.helper "$HELPER" && | 
 | 	check fill <<-\EOF | 
 | 	protocol=https | 
 | 	host=example.com | 
 | 	path=repo.git | 
 | 	-- | 
 | 	protocol=https | 
 | 	host=example.com | 
 | 	username=foo | 
 | 	password=bar | 
 | 	-- | 
 | 	verbatim: get | 
 | 	verbatim: protocol=https | 
 | 	verbatim: host=example.com | 
 | 	EOF | 
 | ' | 
 |  | 
 | test_expect_success 'match percent-encoded values' ' | 
 | 	test_config credential.https://example.com/%2566.git.helper "$HELPER" && | 
 | 	check fill <<-\EOF | 
 | 	url=https://example.com/%2566.git | 
 | 	-- | 
 | 	protocol=https | 
 | 	host=example.com | 
 | 	username=foo | 
 | 	password=bar | 
 | 	-- | 
 | 	EOF | 
 | ' | 
 |  | 
 | test_expect_success 'match percent-encoded UTF-8 values in path' ' | 
 | 	test_config credential.https://example.com.useHttpPath true && | 
 | 	test_config credential.https://example.com/perú.git.helper "$HELPER" && | 
 | 	check fill <<-\EOF | 
 | 	url=https://example.com/per%C3%BA.git | 
 | 	-- | 
 | 	protocol=https | 
 | 	host=example.com | 
 | 	path=perú.git | 
 | 	username=foo | 
 | 	password=bar | 
 | 	-- | 
 | 	EOF | 
 | ' | 
 |  | 
 | test_expect_success 'match percent-encoded values in username' ' | 
 | 	test_config credential.https://user%2fname@example.com/foo/bar.git.helper "$HELPER" && | 
 | 	check fill <<-\EOF | 
 | 	url=https://user%2fname@example.com/foo/bar.git | 
 | 	-- | 
 | 	protocol=https | 
 | 	host=example.com | 
 | 	username=foo | 
 | 	password=bar | 
 | 	-- | 
 | 	EOF | 
 | ' | 
 |  | 
 | test_expect_success 'fetch with multiple path components' ' | 
 | 	test_unconfig credential.helper && | 
 | 	test_config credential.https://example.com/foo/repo.git.helper "verbatim foo bar" && | 
 | 	check fill <<-\EOF | 
 | 	url=https://example.com/foo/repo.git | 
 | 	-- | 
 | 	protocol=https | 
 | 	host=example.com | 
 | 	username=foo | 
 | 	password=bar | 
 | 	-- | 
 | 	verbatim: get | 
 | 	verbatim: protocol=https | 
 | 	verbatim: host=example.com | 
 | 	EOF | 
 | ' | 
 |  | 
 | test_expect_success 'pull username from config' ' | 
 | 	test_config credential.https://example.com.username foo && | 
 | 	check fill <<-\EOF | 
 | 	protocol=https | 
 | 	host=example.com | 
 | 	-- | 
 | 	protocol=https | 
 | 	host=example.com | 
 | 	username=foo | 
 | 	password=askpass-password | 
 | 	-- | 
 | 	askpass: Password for '\''https://foo@example.com'\'': | 
 | 	EOF | 
 | ' | 
 |  | 
 | test_expect_success 'honors username from URL over helper (URL)' ' | 
 | 	test_config credential.https://example.com.username bob && | 
 | 	test_config credential.https://example.com.helper "verbatim \"\" bar" && | 
 | 	check fill <<-\EOF | 
 | 	url=https://alice@example.com | 
 | 	-- | 
 | 	protocol=https | 
 | 	host=example.com | 
 | 	username=alice | 
 | 	password=bar | 
 | 	-- | 
 | 	verbatim: get | 
 | 	verbatim: protocol=https | 
 | 	verbatim: host=example.com | 
 | 	verbatim: username=alice | 
 | 	EOF | 
 | ' | 
 |  | 
 | test_expect_success 'honors username from URL over helper (components)' ' | 
 | 	test_config credential.https://example.com.username bob && | 
 | 	test_config credential.https://example.com.helper "verbatim \"\" bar" && | 
 | 	check fill <<-\EOF | 
 | 	protocol=https | 
 | 	host=example.com | 
 | 	username=alice | 
 | 	-- | 
 | 	protocol=https | 
 | 	host=example.com | 
 | 	username=alice | 
 | 	password=bar | 
 | 	-- | 
 | 	verbatim: get | 
 | 	verbatim: protocol=https | 
 | 	verbatim: host=example.com | 
 | 	verbatim: username=alice | 
 | 	EOF | 
 | ' | 
 |  | 
 | test_expect_success 'last matching username wins' ' | 
 | 	test_config credential.https://example.com/path.git.username bob && | 
 | 	test_config credential.https://example.com.username alice && | 
 | 	test_config credential.https://example.com.helper "verbatim \"\" bar" && | 
 | 	check fill <<-\EOF | 
 | 	url=https://example.com/path.git | 
 | 	-- | 
 | 	protocol=https | 
 | 	host=example.com | 
 | 	username=alice | 
 | 	password=bar | 
 | 	-- | 
 | 	verbatim: get | 
 | 	verbatim: protocol=https | 
 | 	verbatim: host=example.com | 
 | 	verbatim: username=alice | 
 | 	EOF | 
 | ' | 
 |  | 
 | test_expect_success 'http paths can be part of context' ' | 
 | 	check fill "verbatim foo bar" <<-\EOF && | 
 | 	protocol=https | 
 | 	host=example.com | 
 | 	path=foo.git | 
 | 	-- | 
 | 	protocol=https | 
 | 	host=example.com | 
 | 	username=foo | 
 | 	password=bar | 
 | 	-- | 
 | 	verbatim: get | 
 | 	verbatim: protocol=https | 
 | 	verbatim: host=example.com | 
 | 	EOF | 
 | 	test_config credential.https://example.com.useHttpPath true && | 
 | 	check fill "verbatim foo bar" <<-\EOF | 
 | 	protocol=https | 
 | 	host=example.com | 
 | 	path=foo.git | 
 | 	-- | 
 | 	protocol=https | 
 | 	host=example.com | 
 | 	path=foo.git | 
 | 	username=foo | 
 | 	password=bar | 
 | 	-- | 
 | 	verbatim: get | 
 | 	verbatim: protocol=https | 
 | 	verbatim: host=example.com | 
 | 	verbatim: path=foo.git | 
 | 	EOF | 
 | ' | 
 |  | 
 | test_expect_success 'context uses urlmatch' ' | 
 | 	test_config "credential.https://*.org.useHttpPath" true && | 
 | 	check fill "verbatim foo bar" <<-\EOF | 
 | 	protocol=https | 
 | 	host=example.org | 
 | 	path=foo.git | 
 | 	-- | 
 | 	protocol=https | 
 | 	host=example.org | 
 | 	path=foo.git | 
 | 	username=foo | 
 | 	password=bar | 
 | 	-- | 
 | 	verbatim: get | 
 | 	verbatim: protocol=https | 
 | 	verbatim: host=example.org | 
 | 	verbatim: path=foo.git | 
 | 	EOF | 
 | ' | 
 |  | 
 | test_expect_success 'helpers can abort the process' ' | 
 | 	test_must_fail git \ | 
 | 		-c credential.helper=quit \ | 
 | 		-c credential.helper="verbatim foo bar" \ | 
 | 		credential fill >stdout 2>stderr <<-\EOF && | 
 | 	protocol=http | 
 | 	host=example.com | 
 | 	EOF | 
 | 	test_must_be_empty stdout && | 
 | 	cat >expect <<-\EOF && | 
 | 	quit: get | 
 | 	quit: protocol=http | 
 | 	quit: host=example.com | 
 | 	fatal: credential helper '\''quit'\'' told us to quit | 
 | 	EOF | 
 | 	test_cmp expect stderr | 
 | ' | 
 |  | 
 | test_expect_success 'empty helper spec resets helper list' ' | 
 | 	test_config credential.helper "verbatim file file" && | 
 | 	check fill "" "verbatim cmdline cmdline" <<-\EOF | 
 | 	protocol=http | 
 | 	host=example.com | 
 | 	-- | 
 | 	protocol=http | 
 | 	host=example.com | 
 | 	username=cmdline | 
 | 	password=cmdline | 
 | 	-- | 
 | 	verbatim: get | 
 | 	verbatim: protocol=http | 
 | 	verbatim: host=example.com | 
 | 	EOF | 
 | ' | 
 |  | 
 | test_expect_success 'url parser rejects embedded newlines' ' | 
 | 	test_must_fail git credential fill 2>stderr <<-\EOF && | 
 | 	url=https://one.example.com?%0ahost=two.example.com/ | 
 | 	EOF | 
 | 	cat >expect <<-\EOF && | 
 | 	warning: url contains a newline in its path component: https://one.example.com?%0ahost=two.example.com/ | 
 | 	fatal: credential url cannot be parsed: https://one.example.com?%0ahost=two.example.com/ | 
 | 	EOF | 
 | 	test_cmp expect stderr | 
 | ' | 
 |  | 
 | test_expect_success 'host-less URLs are parsed as empty host' ' | 
 | 	check fill "verbatim foo bar" <<-\EOF | 
 | 	url=cert:///path/to/cert.pem | 
 | 	-- | 
 | 	protocol=cert | 
 | 	host= | 
 | 	path=path/to/cert.pem | 
 | 	username=foo | 
 | 	password=bar | 
 | 	-- | 
 | 	verbatim: get | 
 | 	verbatim: protocol=cert | 
 | 	verbatim: host= | 
 | 	verbatim: path=path/to/cert.pem | 
 | 	EOF | 
 | ' | 
 |  | 
 | test_expect_success 'credential system refuses to work with missing host' ' | 
 | 	test_must_fail git credential fill 2>stderr <<-\EOF && | 
 | 	protocol=http | 
 | 	EOF | 
 | 	cat >expect <<-\EOF && | 
 | 	fatal: refusing to work with credential missing host field | 
 | 	EOF | 
 | 	test_cmp expect stderr | 
 | ' | 
 |  | 
 | test_expect_success 'credential system refuses to work with missing protocol' ' | 
 | 	test_must_fail git credential fill 2>stderr <<-\EOF && | 
 | 	host=example.com | 
 | 	EOF | 
 | 	cat >expect <<-\EOF && | 
 | 	fatal: refusing to work with credential missing protocol field | 
 | 	EOF | 
 | 	test_cmp expect stderr | 
 | ' | 
 |  | 
 | # usage: check_host_and_path <url> <expected-host> <expected-path> | 
 | check_host_and_path () { | 
 | 	# we always parse the path component, but we need this to make sure it | 
 | 	# is passed to the helper | 
 | 	test_config credential.useHTTPPath true && | 
 | 	check fill "verbatim user pass" <<-EOF | 
 | 	url=$1 | 
 | 	-- | 
 | 	protocol=https | 
 | 	host=$2 | 
 | 	path=$3 | 
 | 	username=user | 
 | 	password=pass | 
 | 	-- | 
 | 	verbatim: get | 
 | 	verbatim: protocol=https | 
 | 	verbatim: host=$2 | 
 | 	verbatim: path=$3 | 
 | 	EOF | 
 | } | 
 |  | 
 | test_expect_success 'url parser handles bare query marker' ' | 
 | 	check_host_and_path https://example.com?foo.git example.com ?foo.git | 
 | ' | 
 |  | 
 | test_expect_success 'url parser handles bare fragment marker' ' | 
 | 	check_host_and_path https://example.com#foo.git example.com "#foo.git" | 
 | ' | 
 |  | 
 | test_expect_success 'url parser not confused by encoded markers' ' | 
 | 	check_host_and_path https://example.com%23%3f%2f/foo.git \ | 
 | 		"example.com#?/" foo.git | 
 | ' | 
 |  | 
 | test_expect_success 'credential config with partial URLs' ' | 
 | 	echo "echo password=yep" | write_script git-credential-yep && | 
 | 	test_write_lines url=https://user@example.com/repo.git >stdin && | 
 | 	for partial in \ | 
 | 		example.com \ | 
 | 		user@example.com \ | 
 | 		https:// \ | 
 | 		https://example.com \ | 
 | 		https://example.com/ \ | 
 | 		https://user@example.com \ | 
 | 		https://user@example.com/ \ | 
 | 		https://example.com/repo.git \ | 
 | 		https://user@example.com/repo.git \ | 
 | 		/repo.git | 
 | 	do | 
 | 		git -c credential.$partial.helper=yep \ | 
 | 			credential fill <stdin >stdout && | 
 | 		grep yep stdout || | 
 | 		return 1 | 
 | 	done && | 
 |  | 
 | 	for partial in \ | 
 | 		dont.use.this \ | 
 | 		http:// \ | 
 | 		/repo | 
 | 	do | 
 | 		git -c credential.$partial.helper=yep \ | 
 | 			credential fill <stdin >stdout && | 
 | 		! grep yep stdout || | 
 | 		return 1 | 
 | 	done && | 
 |  | 
 | 	git -c credential.$partial.helper=yep \ | 
 | 		-c credential.with%0anewline.username=uh-oh \ | 
 | 		credential fill <stdin 2>stderr && | 
 | 	test_i18ngrep "skipping credential lookup for key" stderr | 
 | ' | 
 |  | 
 | test_done |