| 803 | 803 | | assert_eq!(out.code, 0); |
| 804 | 804 | | assert!(out.stdout.contains("_g1t")); |
| 805 | 805 | | } |
| 806 | + | |
| 807 | + | #[test] |
| 808 | + | fn login_approves_a_code_in_the_browser() { |
| 809 | + | let polls = Arc::new(Mutex::new(0)); |
| 810 | + | let counter = polls.clone(); |
| 811 | + | let mock = Mock::start(move |r| match r.path() { |
| 812 | + | "/device/code" => ( |
| 813 | + | 200, |
| 814 | + | json!({ "device_code": "dev_1", "user_code": "WDJB-MJHT", "verification_uri": "https://g1t.sh/device", |
| 815 | + | "verification_uri_complete": "https://g1t.sh/device?code=WDJB-MJHT", "expires_in": 60, "interval": 1 }), |
| 816 | + | ), |
| 817 | + | "/device/token" => { |
| 818 | + | let mut n = counter.lock().unwrap(); |
| 819 | + | *n += 1; |
| 820 | + | if *n < 2 { |
| 821 | + | (200, json!({ "status": "pending" })) |
| 822 | + | } else { |
| 823 | + | ( |
| 824 | + | 200, |
| 825 | + | json!({ "status": "approved", "token": "g1t_device", "username": "ana" }), |
| 826 | + | ) |
| 827 | + | } |
| 828 | + | } |
| 829 | + | _ => (404, json!({ "error": { "message": "No such endpoint." } })), |
| 830 | + | }); |
| 831 | + | let dir = temp_dir("device"); |
| 832 | + | let out = g1t(&mock, &dir, &["auth", "login", "--no-browser"], None, None); |
| 833 | + | assert_eq!(out.code, 0, "{}", out.stderr); |
| 834 | + | assert!(out.stderr.contains("WDJB-MJHT"), "{}", out.stderr); |
| 835 | + | assert!( |
| 836 | + | out.stderr.contains("https://g1t.sh/device?code=WDJB-MJHT"), |
| 837 | + | "{}", |
| 838 | + | out.stderr |
| 839 | + | ); |
| 840 | + | let seen = mock.requests(); |
| 841 | + | assert!( |
| 842 | + | seen[0].json()["client_name"] |
| 843 | + | .as_str() |
| 844 | + | .unwrap() |
| 845 | + | .starts_with("g1t CLI on ") |
| 846 | + | ); |
| 847 | + | assert!( |
| 848 | + | seen.iter() |
| 849 | + | .filter(|r| r.path() == "/device/token") |
| 850 | + | .all(|r| r.json() == json!({ "device_code": "dev_1" })) |
| 851 | + | ); |
| 852 | + | let out = g1t(&mock, &dir, &["auth", "token"], None, None); |
| 853 | + | assert_eq!(out.stdout, "g1t_device\n"); |
| 854 | + | } |
| 855 | + | |
| 856 | + | #[test] |
| 857 | + | fn the_repository_comes_from_the_git_remote() { |
| 858 | + | let mock = Mock::start(|_| (200, json!([]))); |
| 859 | + | let dir = temp_dir("remote"); |
| 860 | + | let git = |args: &[&str]| { |
| 861 | + | let ok = Command::new("git") |
| 862 | + | .args(args) |
| 863 | + | .current_dir(&dir) |
| 864 | + | .output() |
| 865 | + | .unwrap() |
| 866 | + | .status |
| 867 | + | .success(); |
| 868 | + | assert!(ok, "git {args:?}"); |
| 869 | + | }; |
| 870 | + | git(&["init", "--quiet"]); |
| 871 | + | git(&["remote", "add", "mine", "https://g1t.sh/ana/web.git"]); |
| 872 | + | git(&["remote", "add", "origin", "git@g1t.sh:acme/web.git"]); |
| 873 | + | git(&[ |
| 874 | + | "remote", |
| 875 | + | "add", |
| 876 | + | "elsewhere", |
| 877 | + | "https://example.com/acme/other.git", |
| 878 | + | ]); |
| 879 | + | let out = g1t( |
| 880 | + | &mock, |
| 881 | + | &dir, |
| 882 | + | &["issue", "list", "--json"], |
| 883 | + | None, |
| 884 | + | Some("g1t_test"), |
| 885 | + | ); |
| 886 | + | assert_eq!(out.code, 0, "{}", out.stderr); |
| 887 | + | assert_eq!(out.stdout, "[]\n"); |
| 888 | + | assert_eq!(mock.requests()[0].path(), "/repos/acme/web/issues"); |
| 889 | + | // Outside any repository, and without --repo, it says what to do. |
| 890 | + | let bare = temp_dir("bare"); |
| 891 | + | let out = g1t(&mock, &bare, &["issue", "list"], None, Some("g1t_test")); |
| 892 | + | assert_eq!(out.code, 2); |
| 893 | + | assert!(out.stderr.contains("--repo"), "{}", out.stderr); |
| 894 | + | } |