use super::*; use std::{ io::{Read, Write}, net::TcpListener, thread, }; fn commit(sha: &str, parents: &[&str]) -> models::Commit { models::Commit { sha: Some(sha.into()), parents: Some( parents .iter() .map(|sha| models::CommitMeta { sha: Some((*sha).into()), ..Default::default() }) .collect(), ), ..Default::default() } } #[test] fn lays_out_shared_commit_graph() { let rows = build_graph( vec![ ( 0, "main".into(), vec![ commit("merge", &["left", "right"]), commit("left", &["base"]), commit("base", &[]), ], ), ( 1, "feature".into(), vec![commit("right", &["base"]), commit("base", &[])], ), ], PullMetadata::default(), ); assert_eq!(rows.len(), 4); assert!(rows.iter().any(|row| row.refs == ["main"])); assert!(rows.iter().any(|row| row.refs == ["feature"])); let merge = rows .iter() .find(|row| row.commit.sha.as_deref() == Some("merge")) .unwrap(); assert_eq!(merge.node_lane, Some(0)); assert_eq!(merge.bottom_connections, [1]); let right = rows .iter() .find(|row| row.commit.sha.as_deref() == Some("right")) .unwrap(); assert_eq!(right.node_lane, Some(1)); let base = rows .iter() .find(|row| row.commit.sha.as_deref() == Some("base")) .unwrap(); assert_eq!(base.node_lane, Some(0)); assert_eq!(base.top_connections, [1]); } #[test] fn labels_first_commit_of_pull_branch() { let rows = build_graph( vec![( 0, "main".into(), vec![ commit("merge", &["main", "head"]), commit("head", &["first"]), commit("first", &["base"]), commit("main", &["base"]), commit("base", &[]), ], )], PullMetadata { tips: HashMap::from([("head".into(), vec!["feature".into()])]), starts: vec![PullBranch { head: "head".into(), base: "base".into(), label: "feature".into(), }], }, ); let first = rows .iter() .find(|row| row.commit.sha.as_deref() == Some("first")) .unwrap(); assert_eq!(first.branch_starts, ["feature"]); assert!( rows.iter() .find(|row| row.commit.sha.as_deref() == Some("head")) .unwrap() .refs .contains(&"feature".into()) ); } #[tokio::test] async fn reads_nested_directory_from_compatible_contents_endpoint() { let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let address = listener.local_addr().unwrap(); let server = thread::spawn(move || { let (mut stream, _) = listener.accept().unwrap(); let mut buffer = [0; 4096]; let length = stream.read(&mut buffer).unwrap(); let request = String::from_utf8_lossy(&buffer[..length]).into_owned(); let body = r#"[{"name":"guide.md","path":"docs/private guide/guide.md","type":"file"}]"#; write!( stream, "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: {}\r\nConnection: close\r\n\r\n{body}", body.len() ) .unwrap(); request }); let client = Client::with_provider(&format!("http://{address}"), None, crate::Provider::Forgejo) .unwrap(); let repository = RepositoryId::new("forgejo", "forgejo").unwrap(); let contents = client .repository_contents(&repository, "docs/private guide") .await .unwrap(); assert_eq!(contents.len(), 1); assert_eq!( contents[0].path.as_deref(), Some("docs/private guide/guide.md") ); assert!( server .join() .unwrap() .starts_with("GET /api/v1/repos/forgejo/forgejo/contents/docs%2Fprivate%20guide ") ); } #[tokio::test] async fn reads_file_with_spaces_from_raw_endpoint() { let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let address = listener.local_addr().unwrap(); let server = thread::spawn(move || { let (mut stream, _) = listener.accept().unwrap(); let mut buffer = [0; 4096]; let length = stream.read(&mut buffer).unwrap(); let request = String::from_utf8_lossy(&buffer[..length]).into_owned(); let body = "contents"; write!( stream, "HTTP/1.1 200 OK\r\nContent-Length: {}\r\nConnection: close\r\n\r\n{body}", body.len() ) .unwrap(); request }); let client = Client::new(&format!("http://{address}"), None).unwrap(); let repository = RepositoryId::new("gitea", "gitea").unwrap(); let contents = client .repository_file(&repository, "docs/private guide/read me.md") .await .unwrap(); assert_eq!(contents, b"contents"); assert!( server.join().unwrap().starts_with( "GET /api/v1/repos/gitea/gitea/raw/docs%2Fprivate%20guide%2Fread%20me.md " ) ); }