summaryrefslogtreecommitdiffstats
path: root/vendor/gix-credentials/tests
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:41:41 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:41:41 +0000
commit10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87 (patch)
treebdffd5d80c26cf4a7a518281a204be1ace85b4c1 /vendor/gix-credentials/tests
parentReleasing progress-linux version 1.70.0+dfsg1-9~progress7.99u1. (diff)
downloadrustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.tar.xz
rustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.zip
Merging upstream version 1.70.0+dfsg2.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/gix-credentials/tests')
-rw-r--r--vendor/gix-credentials/tests/credentials.rs5
-rw-r--r--vendor/gix-credentials/tests/fixtures/all-but-credentials.sh6
-rwxr-xr-xvendor/gix-credentials/tests/fixtures/custom-helper.sh6
-rw-r--r--vendor/gix-credentials/tests/fixtures/fail.sh3
-rw-r--r--vendor/gix-credentials/tests/fixtures/last-pass.sh6
-rw-r--r--vendor/gix-credentials/tests/fixtures/password.sh3
-rw-r--r--vendor/gix-credentials/tests/fixtures/reflect.sh3
-rw-r--r--vendor/gix-credentials/tests/fixtures/url.sh7
-rw-r--r--vendor/gix-credentials/tests/fixtures/username.sh3
-rw-r--r--vendor/gix-credentials/tests/helper/cascade.rs174
-rw-r--r--vendor/gix-credentials/tests/helper/context.rs123
-rw-r--r--vendor/gix-credentials/tests/helper/invoke.rs134
-rw-r--r--vendor/gix-credentials/tests/helper/mod.rs39
-rw-r--r--vendor/gix-credentials/tests/program/from_custom_definition.rs42
-rw-r--r--vendor/gix-credentials/tests/program/mod.rs1
-rw-r--r--vendor/gix-credentials/tests/protocol/context.rs175
-rw-r--r--vendor/gix-credentials/tests/protocol/mod.rs1
17 files changed, 731 insertions, 0 deletions
diff --git a/vendor/gix-credentials/tests/credentials.rs b/vendor/gix-credentials/tests/credentials.rs
new file mode 100644
index 000000000..f94dfd05e
--- /dev/null
+++ b/vendor/gix-credentials/tests/credentials.rs
@@ -0,0 +1,5 @@
+pub use gix_testtools::Result;
+
+mod helper;
+mod program;
+mod protocol;
diff --git a/vendor/gix-credentials/tests/fixtures/all-but-credentials.sh b/vendor/gix-credentials/tests/fixtures/all-but-credentials.sh
new file mode 100644
index 000000000..0610a71b0
--- /dev/null
+++ b/vendor/gix-credentials/tests/fixtures/all-but-credentials.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+echo protocol=ftp
+echo host=example.com:8080
+echo path=/path/to/git/
+
diff --git a/vendor/gix-credentials/tests/fixtures/custom-helper.sh b/vendor/gix-credentials/tests/fixtures/custom-helper.sh
new file mode 100755
index 000000000..55d6b2f94
--- /dev/null
+++ b/vendor/gix-credentials/tests/fixtures/custom-helper.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+set -eu
+
+test "$1" = get && \
+echo username=user-script && \
+echo password=pass-script
diff --git a/vendor/gix-credentials/tests/fixtures/fail.sh b/vendor/gix-credentials/tests/fixtures/fail.sh
new file mode 100644
index 000000000..84b6391bc
--- /dev/null
+++ b/vendor/gix-credentials/tests/fixtures/fail.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+exit 42
diff --git a/vendor/gix-credentials/tests/fixtures/last-pass.sh b/vendor/gix-credentials/tests/fixtures/last-pass.sh
new file mode 100644
index 000000000..2f03f8986
--- /dev/null
+++ b/vendor/gix-credentials/tests/fixtures/last-pass.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+set -eu
+
+echo username=user
+echo password=pass
+echo quit=1
diff --git a/vendor/gix-credentials/tests/fixtures/password.sh b/vendor/gix-credentials/tests/fixtures/password.sh
new file mode 100644
index 000000000..f75c4bc02
--- /dev/null
+++ b/vendor/gix-credentials/tests/fixtures/password.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+echo password=pass
diff --git a/vendor/gix-credentials/tests/fixtures/reflect.sh b/vendor/gix-credentials/tests/fixtures/reflect.sh
new file mode 100644
index 000000000..e4079b793
--- /dev/null
+++ b/vendor/gix-credentials/tests/fixtures/reflect.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+cat
diff --git a/vendor/gix-credentials/tests/fixtures/url.sh b/vendor/gix-credentials/tests/fixtures/url.sh
new file mode 100644
index 000000000..1eb585859
--- /dev/null
+++ b/vendor/gix-credentials/tests/fixtures/url.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+echo protocol=ftp
+echo host=github.com
+echo path=byron/gitoxide
+echo url=http://example.com:8080/path/to/git/
+
diff --git a/vendor/gix-credentials/tests/fixtures/username.sh b/vendor/gix-credentials/tests/fixtures/username.sh
new file mode 100644
index 000000000..f2bab6c28
--- /dev/null
+++ b/vendor/gix-credentials/tests/fixtures/username.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+echo username=user
diff --git a/vendor/gix-credentials/tests/helper/cascade.rs b/vendor/gix-credentials/tests/helper/cascade.rs
new file mode 100644
index 000000000..f97a64dcb
--- /dev/null
+++ b/vendor/gix-credentials/tests/helper/cascade.rs
@@ -0,0 +1,174 @@
+mod invoke {
+ use std::convert::TryInto;
+
+ use bstr::{ByteSlice, ByteVec};
+ use gix_credentials::{
+ helper::{Action, Cascade},
+ program, protocol,
+ protocol::Context,
+ Program,
+ };
+ use gix_sec::identity::Account;
+ use gix_testtools::fixture_path;
+
+ #[test]
+ fn credentials_are_filled_in_one_by_one_and_stop_when_complete() {
+ let actual = invoke_cascade(["username", "password", "custom-helper"], action_get())
+ .unwrap()
+ .expect("credentials");
+ assert_eq!(actual.identity, identity("user", "pass"));
+ }
+
+ #[test]
+ fn usernames_in_urls_are_kept_if_the_helper_does_not_overwrite_it() {
+ let actual = invoke_cascade(
+ ["password", "custom-helper"],
+ Action::get_for_url("ssh://git@host.org/path"),
+ )
+ .unwrap()
+ .expect("credentials");
+ assert_eq!(actual.identity, identity("git", "pass"));
+ }
+
+ #[test]
+ fn partial_credentials_can_be_overwritten_by_complete_ones() {
+ let actual = invoke_cascade(["username", "custom-helper"], action_get())
+ .unwrap()
+ .expect("credentials");
+ assert_eq!(actual.identity, identity("user-script", "pass-script"));
+ }
+
+ #[test]
+ fn failing_helpers_for_filling_dont_interrupt() {
+ let actual = invoke_cascade(["fail", "custom-helper"], action_get())
+ .unwrap()
+ .expect("credentials");
+ assert_eq!(actual.identity, identity("user-script", "pass-script"));
+ }
+
+ #[test]
+ fn urls_are_split_in_get_to_support_scripts() {
+ let actual = invoke_cascade(
+ ["reflect", "custom-helper"],
+ Action::get_for_url("https://example.com:8080/path/git/"),
+ )
+ .unwrap()
+ .expect("credentials");
+
+ let ctx: Context = (&actual.next).try_into().unwrap();
+ assert_eq!(ctx.protocol.as_deref().expect("protocol"), "https");
+ assert_eq!(ctx.host.as_deref().expect("host"), "example.com:8080");
+ assert_eq!(ctx.path.as_deref().expect("path").as_bstr(), "path/git");
+ }
+
+ #[test]
+ fn urls_are_split_in_get_but_can_skip_the_path_in_host_only_urls() {
+ let actual = invoke_cascade(["reflect", "custom-helper"], Action::get_for_url("http://example.com"))
+ .unwrap()
+ .expect("credentials");
+
+ let ctx: Context = (&actual.next).try_into().unwrap();
+ assert_eq!(ctx.protocol.as_deref().expect("protocol"), "http");
+ assert_eq!(ctx.host.as_deref().expect("host"), "example.com");
+ assert_eq!(ctx.path, None);
+ }
+
+ #[test]
+ fn helpers_can_set_any_context_value() {
+ let actual = invoke_cascade(
+ ["all-but-credentials", "custom-helper"],
+ Action::get_for_url("http://github.com"),
+ )
+ .unwrap()
+ .expect("credentials");
+
+ let ctx: Context = (&actual.next).try_into().unwrap();
+ assert_eq!(ctx.protocol.as_deref().expect("protocol"), "ftp");
+ assert_eq!(ctx.host.as_deref().expect("host"), "example.com:8080");
+ assert_eq!(
+ ctx.path.expect("set by helper"),
+ "/path/to/git/",
+ "values are passed verbatim even if they would otherwise look different"
+ );
+ }
+
+ #[test]
+ fn helpers_can_set_any_context_value_using_the_url_only() {
+ let actual = invoke_cascade(["url", "custom-helper"], Action::get_for_url("http://github.com"))
+ .unwrap()
+ .expect("credentials");
+
+ let ctx: Context = (&actual.next).try_into().unwrap();
+ assert_eq!(
+ ctx.protocol.as_deref().expect("protocol"),
+ "http",
+ "url is processed last, it overwrites what came before"
+ );
+ assert_eq!(ctx.host.as_deref().expect("host"), "example.com:8080");
+ assert_eq!(
+ ctx.path.expect("set by helper"),
+ "path/to/git",
+ "the url is processed like any other"
+ );
+ }
+
+ #[test]
+ fn helpers_can_quit_and_their_creds_are_taken_if_complete() {
+ let actual = invoke_cascade(["last-pass", "custom-helper"], Action::get_for_url("http://github.com"))
+ .unwrap()
+ .expect("credentials");
+
+ assert_eq!(actual.identity, identity("user", "pass"));
+ }
+
+ #[test]
+ fn bogus_password_overrides_any_helper_and_helper_overrides_username_in_url() {
+ let actual = Cascade::default()
+ .query_user_only(true)
+ .extend(fixtures(["username", "password"]))
+ .invoke(
+ Action::get_for_url("ssh://git@host/repo"),
+ gix_prompt::Options {
+ mode: gix_prompt::Mode::Disable,
+ askpass: None,
+ },
+ )
+ .unwrap()
+ .expect("credentials");
+ assert_eq!(actual.identity, identity("user", ""));
+ }
+
+ fn action_get() -> Action {
+ Action::get_for_url("does/not/matter")
+ }
+
+ fn identity(user: &str, pass: &str) -> Account {
+ Account {
+ username: user.into(),
+ password: pass.into(),
+ }
+ }
+
+ #[allow(clippy::result_large_err)]
+ fn invoke_cascade<'a>(names: impl IntoIterator<Item = &'a str>, action: Action) -> protocol::Result {
+ Cascade::default().use_http_path(true).extend(fixtures(names)).invoke(
+ action,
+ gix_prompt::Options {
+ mode: gix_prompt::Mode::Disable,
+ askpass: None,
+ },
+ )
+ }
+
+ fn fixtures<'a>(names: impl IntoIterator<Item = &'a str>) -> Vec<Program> {
+ names
+ .into_iter()
+ .map(|name| gix_path::realpath(fixture_path(format!("{name}.sh"))).unwrap())
+ .map(|path| {
+ let mut script = gix_path::to_unix_separators_on_windows(gix_path::into_bstr(path)).into_owned();
+ script.insert_str(0, "sh ");
+ Program::from_kind(program::Kind::ExternalShellScript(script))
+ })
+ .collect()
+ }
+}
diff --git a/vendor/gix-credentials/tests/helper/context.rs b/vendor/gix-credentials/tests/helper/context.rs
new file mode 100644
index 000000000..6566c6c2b
--- /dev/null
+++ b/vendor/gix-credentials/tests/helper/context.rs
@@ -0,0 +1,123 @@
+use gix_credentials::protocol::Context;
+
+#[test]
+fn encode_decode_roundtrip_works_only_for_serializing_fields() {
+ for ctx in [
+ Context {
+ protocol: Some("https".into()),
+ host: Some("github.com".into()),
+ path: Some("byron/gitoxide".into()),
+ username: Some("user".into()),
+ password: Some("pass".into()),
+ url: Some("https://github.com/byron/gitoxide".into()),
+ ..Default::default()
+ },
+ Context::default(),
+ ] {
+ let mut buf = Vec::<u8>::new();
+ ctx.write_to(&mut buf).unwrap();
+ let actual = Context::from_bytes(&buf).unwrap();
+ assert_eq!(actual, ctx, "ctx should encode itself losslessly");
+ }
+}
+
+mod write_to {
+ use gix_credentials::protocol::Context;
+
+ #[test]
+ fn quit_is_not_serialized_but_can_be_parsed() {
+ let mut buf = Vec::<u8>::new();
+ Context {
+ quit: Some(true),
+ ..Default::default()
+ }
+ .write_to(&mut buf)
+ .unwrap();
+ assert_eq!(Context::from_bytes(&buf).unwrap(), Context::default());
+ assert_eq!(
+ Context::from_bytes(b"quit=true\nurl=https://example.com").unwrap(),
+ Context {
+ quit: Some(true),
+ url: Some("https://example.com".into()),
+ ..Default::default()
+ }
+ );
+ }
+
+ #[test]
+ fn null_bytes_and_newlines_are_invalid() {
+ for input in [&b"foo\0"[..], b"foo\n"] {
+ let ctx = Context {
+ path: Some(input.into()),
+ ..Default::default()
+ };
+ let mut buf = Vec::<u8>::new();
+ let err = ctx.write_to(&mut buf).unwrap_err();
+ assert_eq!(err.kind(), std::io::ErrorKind::Other);
+ }
+ }
+}
+
+mod from_bytes {
+ use gix_credentials::protocol::Context;
+
+ #[test]
+ fn empty_newlines_cause_skipping_remaining_input() {
+ let input = b"protocol=https
+host=example.com\n
+password=secr3t
+username=bob";
+ assert_eq!(
+ Context::from_bytes(input).unwrap(),
+ Context {
+ protocol: Some("https".into()),
+ host: Some("example.com".into()),
+ ..Default::default()
+ }
+ )
+ }
+
+ #[test]
+ fn unknown_field_names_are_skipped() {
+ let input = b"protocol=https
+unknown=value
+username=bob";
+ assert_eq!(
+ Context::from_bytes(input).unwrap(),
+ Context {
+ protocol: Some("https".into()),
+ username: Some("bob".into()),
+ ..Default::default()
+ }
+ )
+ }
+
+ #[test]
+ fn quit_supports_git_config_boolean_values() {
+ for true_value in ["1", "42", "-42", "true", "on", "yes"] {
+ let input = format!("quit={true_value}");
+ assert_eq!(
+ Context::from_bytes(input.as_bytes()).unwrap().quit,
+ Some(true),
+ "{input}"
+ )
+ }
+ for false_value in ["0", "false", "off", "no"] {
+ let input = format!("quit={false_value}");
+ assert_eq!(
+ Context::from_bytes(input.as_bytes()).unwrap().quit,
+ Some(false),
+ "{input}"
+ )
+ }
+ }
+
+ #[test]
+ fn null_bytes_when_decoding() {
+ let err = Context::from_bytes(b"url=https://foo\0").unwrap_err();
+ assert!(matches!(
+ err,
+ gix_credentials::protocol::context::decode::Error::Encoding(_)
+ ));
+ }
+}
diff --git a/vendor/gix-credentials/tests/helper/invoke.rs b/vendor/gix-credentials/tests/helper/invoke.rs
new file mode 100644
index 000000000..330048548
--- /dev/null
+++ b/vendor/gix-credentials/tests/helper/invoke.rs
@@ -0,0 +1,134 @@
+use bstr::{BString, ByteVec};
+use gix_credentials::{helper, protocol::Context, Program};
+use gix_testtools::fixture_path;
+
+#[test]
+fn get() {
+ let mut outcome = gix_credentials::helper::invoke(
+ &mut script_helper("last-pass"),
+ &helper::Action::get_for_url("https://github.com/byron/gitoxide"),
+ )
+ .unwrap()
+ .expect("mock provides credentials");
+ assert_eq!(
+ outcome.consume_identity().expect("complete"),
+ gix_sec::identity::Account {
+ username: "user".into(),
+ password: "pass".into()
+ }
+ );
+ assert_eq!(
+ outcome.next.store().payload().unwrap(),
+ "username=user\npassword=pass\nquit=1\n"
+ );
+}
+
+#[test]
+fn store_and_reject() {
+ let ctx = Context {
+ url: Some("https://github.com/byron/gitoxide".into()),
+ ..Default::default()
+ };
+ let ctxbuf = || -> BString {
+ let mut buf = Vec::<u8>::new();
+ ctx.write_to(&mut buf).expect("cannot fail");
+ buf.into()
+ };
+ for action in [helper::Action::Store(ctxbuf()), helper::Action::Erase(ctxbuf())] {
+ let outcome = gix_credentials::helper::invoke(&mut script_helper("last-pass"), &action).unwrap();
+ assert!(
+ outcome.is_none(),
+ "store and erase have no outcome, they just shouldn't fail"
+ );
+ }
+}
+
+mod program {
+ use gix_credentials::{helper, program::Kind, Program};
+
+ use crate::helper::invoke::script_helper;
+
+ #[test]
+ fn builtin() {
+ assert!(
+ matches!(
+ gix_credentials::helper::invoke(
+ &mut Program::from_kind(Kind::Builtin).suppress_stderr(),
+ &helper::Action::get_for_url("/path/without/scheme/fails/with/error"),
+ )
+ .unwrap_err(),
+ helper::Error::CredentialsHelperFailed { .. }
+ ),
+ "this failure indicates we could launch the helper, even though it wasn't happy which is fine. It doesn't like the URL"
+ );
+ }
+
+ #[test]
+ fn script() {
+ assert_eq!(
+ gix_credentials::helper::invoke(
+ &mut Program::from_custom_definition(
+ "!f() { test \"$1\" = get && echo \"password=pass\" && echo \"username=user\"; }; f"
+ ),
+ &helper::Action::get_for_url("/does/not/matter"),
+ )
+ .unwrap()
+ .expect("present")
+ .consume_identity()
+ .expect("complete"),
+ gix_sec::identity::Account {
+ username: "user".into(),
+ password: "pass".into()
+ }
+ );
+ }
+
+ #[cfg(unix)] // needs executable bits to work
+ #[test]
+ fn path_to_helper_script() -> crate::Result {
+ assert_eq!(
+ gix_credentials::helper::invoke(
+ &mut Program::from_custom_definition(
+ gix_path::into_bstr(gix_path::realpath(gix_testtools::fixture_path("custom-helper.sh"))?)
+ .into_owned()
+ ),
+ &helper::Action::get_for_url("/does/not/matter"),
+ )?
+ .expect("present")
+ .consume_identity()
+ .expect("complete"),
+ gix_sec::identity::Account {
+ username: "user-script".into(),
+ password: "pass-script".into()
+ }
+ );
+ Ok(())
+ }
+
+ #[test]
+ fn path_to_helper_as_script_to_workaround_executable_bits() -> crate::Result {
+ assert_eq!(
+ gix_credentials::helper::invoke(
+ &mut script_helper("custom-helper"),
+ &helper::Action::get_for_url("/does/not/matter")
+ )?
+ .expect("present")
+ .consume_identity()
+ .expect("complete"),
+ gix_sec::identity::Account {
+ username: "user-script".into(),
+ password: "pass-script".into()
+ }
+ );
+ Ok(())
+ }
+}
+
+pub fn script_helper(name: &str) -> Program {
+ let mut script = gix_path::to_unix_separators_on_windows(gix_path::into_bstr(
+ gix_path::realpath(fixture_path(format!("{name}.sh"))).unwrap(),
+ ))
+ .into_owned();
+ script.insert_str(0, "sh ");
+ Program::from_kind(gix_credentials::program::Kind::ExternalShellScript(script))
+}
diff --git a/vendor/gix-credentials/tests/helper/mod.rs b/vendor/gix-credentials/tests/helper/mod.rs
new file mode 100644
index 000000000..59c448065
--- /dev/null
+++ b/vendor/gix-credentials/tests/helper/mod.rs
@@ -0,0 +1,39 @@
+mod cascade;
+mod context;
+mod invoke;
+
+mod invoke_outcome_to_helper_result {
+ use gix_credentials::{helper, protocol, protocol::helper_outcome_to_result};
+
+ #[test]
+ fn missing_username_or_password_causes_failure_with_get_action() {
+ let action = helper::Action::get_for_url("does/not/matter");
+ let err = helper_outcome_to_result(
+ Some(helper::Outcome {
+ username: None,
+ password: None,
+ quit: false,
+ next: protocol::Context::default().into(),
+ }),
+ action,
+ )
+ .unwrap_err();
+ assert!(matches!(err, protocol::Error::IdentityMissing { .. }));
+ }
+
+ #[test]
+ fn quit_message_in_context_causes_special_error_ignoring_missing_identity() {
+ let action = helper::Action::get_for_url("does/not/matter");
+ let err = helper_outcome_to_result(
+ Some(helper::Outcome {
+ username: None,
+ password: None,
+ quit: true,
+ next: protocol::Context::default().into(),
+ }),
+ action,
+ )
+ .unwrap_err();
+ assert!(matches!(err, protocol::Error::Quit));
+ }
+}
diff --git a/vendor/gix-credentials/tests/program/from_custom_definition.rs b/vendor/gix-credentials/tests/program/from_custom_definition.rs
new file mode 100644
index 000000000..1b9d8a056
--- /dev/null
+++ b/vendor/gix-credentials/tests/program/from_custom_definition.rs
@@ -0,0 +1,42 @@
+use gix_credentials::{program::Kind, Program};
+
+#[test]
+fn script() {
+ assert!(
+ matches!(Program::from_custom_definition("!exe").kind, Kind::ExternalShellScript(script) if script == "exe")
+ );
+}
+
+#[test]
+fn name_with_args() {
+ let input = "name --arg --bar=\"a b\"";
+ let expected = "git credential-name --arg --bar=\"a b\"";
+ assert!(
+ matches!(Program::from_custom_definition(input).kind, Kind::ExternalName{name_and_args} if name_and_args == expected)
+ );
+}
+
+#[test]
+fn name() {
+ let input = "name";
+ let expected = "git credential-name";
+ assert!(
+ matches!(Program::from_custom_definition(input).kind, Kind::ExternalName{name_and_args} if name_and_args == expected)
+ );
+}
+
+#[test]
+fn path_with_args() {
+ let input = "/abs/name --arg --bar=\"a b\"";
+ assert!(
+ matches!(Program::from_custom_definition(input).kind, Kind::ExternalPath{path_and_args} if path_and_args == input)
+ );
+}
+
+#[test]
+fn path() {
+ let input = "/abs/name";
+ assert!(
+ matches!(Program::from_custom_definition(input).kind, Kind::ExternalPath{path_and_args} if path_and_args == input)
+ );
+}
diff --git a/vendor/gix-credentials/tests/program/mod.rs b/vendor/gix-credentials/tests/program/mod.rs
new file mode 100644
index 000000000..3672dd18e
--- /dev/null
+++ b/vendor/gix-credentials/tests/program/mod.rs
@@ -0,0 +1 @@
+mod from_custom_definition;
diff --git a/vendor/gix-credentials/tests/protocol/context.rs b/vendor/gix-credentials/tests/protocol/context.rs
new file mode 100644
index 000000000..3cfd850a3
--- /dev/null
+++ b/vendor/gix-credentials/tests/protocol/context.rs
@@ -0,0 +1,175 @@
+mod destructure_url_in_place {
+ use gix_credentials::protocol::Context;
+
+ fn url_ctx(url: &str) -> Context {
+ Context {
+ url: Some(url.into()),
+ ..Default::default()
+ }
+ }
+
+ fn assert_eq_parts(
+ url: &str,
+ proto: &str,
+ user: impl Into<Option<&'static str>>,
+ host: &str,
+ path: impl Into<Option<&'static str>>,
+ use_http_path: bool,
+ ) {
+ let mut ctx = url_ctx(url);
+ ctx.destructure_url_in_place(use_http_path).expect("splitting works");
+ assert_eq!(ctx.protocol.expect("set proto"), proto);
+ match user.into() {
+ Some(expected) => assert_eq!(ctx.username.expect("set user"), expected),
+ None => assert!(ctx.username.is_none()),
+ }
+ assert_eq!(ctx.host.expect("set host"), host);
+ match path.into() {
+ Some(expected) => assert_eq!(ctx.path.expect("set path"), expected),
+ None => assert!(ctx.path.is_none()),
+ }
+ }
+
+ #[test]
+ fn parts_are_verbatim_with_non_http_url() {
+ // path is always used for non-http
+ assert_eq_parts("ssh://user@host:21/path", "ssh", "user", "host:21", "path", false);
+ assert_eq_parts("ssh://host.org/path", "ssh", None, "host.org", "path", true);
+ }
+ #[test]
+ fn http_and_https_ignore_the_path_by_default() {
+ assert_eq_parts(
+ "http://user@example.com/path",
+ "http",
+ Some("user"),
+ "example.com",
+ None,
+ false,
+ );
+ assert_eq_parts(
+ "https://github.com/byron/gitoxide",
+ "https",
+ None,
+ "github.com",
+ None,
+ false,
+ );
+ assert_eq_parts(
+ "https://github.com/byron/gitoxide/",
+ "https",
+ None,
+ "github.com",
+ "byron/gitoxide",
+ true,
+ );
+ }
+}
+
+mod to_prompt {
+ use gix_credentials::protocol::Context;
+
+ #[test]
+ fn no_scheme_means_no_url() {
+ assert_eq!(Context::default().to_prompt("Username"), "Username: ");
+ }
+
+ #[test]
+ fn any_scheme_means_url_is_included() {
+ assert_eq!(
+ Context {
+ protocol: Some("https".into()),
+ host: Some("host".into()),
+ ..Default::default()
+ }
+ .to_prompt("Password"),
+ "Password for https://host: "
+ );
+ }
+}
+
+mod to_url {
+ use gix_credentials::protocol::Context;
+
+ #[test]
+ fn no_protocol_is_nothing() {
+ assert_eq!(Context::default().to_url(), None);
+ }
+ #[test]
+ fn protocol_alone_is_enough() {
+ assert_eq!(
+ Context {
+ protocol: Some("https".into()),
+ ..Default::default()
+ }
+ .to_url()
+ .unwrap(),
+ "https://"
+ );
+ }
+ #[test]
+ fn username_is_appended() {
+ assert_eq!(
+ Context {
+ protocol: Some("https".into()),
+ username: Some("user".into()),
+ ..Default::default()
+ }
+ .to_url()
+ .unwrap(),
+ "https://user@"
+ );
+ }
+ #[test]
+ fn host_is_appended() {
+ assert_eq!(
+ Context {
+ protocol: Some("https".into()),
+ host: Some("host".into()),
+ ..Default::default()
+ }
+ .to_url()
+ .unwrap(),
+ "https://host"
+ );
+ }
+ #[test]
+ fn path_is_appended_with_leading_slash_placed_as_needed() {
+ assert_eq!(
+ Context {
+ protocol: Some("file".into()),
+ path: Some("dir/git".into()),
+ ..Default::default()
+ }
+ .to_url()
+ .unwrap(),
+ "file:///dir/git"
+ );
+ assert_eq!(
+ Context {
+ protocol: Some("file".into()),
+ path: Some("/dir/git".into()),
+ ..Default::default()
+ }
+ .to_url()
+ .unwrap(),
+ "file:///dir/git"
+ );
+ }
+
+ #[test]
+ fn all_fields_with_port_but_password_is_never_shown() {
+ assert_eq!(
+ Context {
+ protocol: Some("https".into()),
+ username: Some("user".into()),
+ password: Some("secret".into()),
+ host: Some("example.com:8080".into()),
+ path: Some("Byron/gitoxide".into()),
+ ..Default::default()
+ }
+ .to_url()
+ .unwrap(),
+ "https://user@example.com:8080/Byron/gitoxide"
+ );
+ }
+}
diff --git a/vendor/gix-credentials/tests/protocol/mod.rs b/vendor/gix-credentials/tests/protocol/mod.rs
new file mode 100644
index 000000000..3d9885db8
--- /dev/null
+++ b/vendor/gix-credentials/tests/protocol/mod.rs
@@ -0,0 +1 @@
+mod context;