//! The HTML site: listing, repository pages, and what stays hidden.
mod common;
use assert2::check;
use common::{Fixture, PUBLIC_URL};
use poem::{http::StatusCode, test::TestClient};
const README: &str = "# Widget\n\nA *widget* for testing.\n\n\n";
fn fixture() -> Fixture {
let fx = Fixture::new();
fx.repo(
"widget",
true,
"Widgets for everyone",
&[("README.md", README)],
);
fx.repo(
"secret",
false,
"Nobody's business",
&[("README.md", "# Secret\n")],
);
fx.repo("plain", true, "", &[("README", "Just text \n")]);
fx.repo("bare", true, "Nothing committed", &[]);
fx
}
#[tokio::test]
async fn index_lists_only_public_repositories() {
let fx = fixture();
let client = TestClient::new(fx.app.routes());
let resp = client.get("/").send().await;
resp.assert_status_is_ok();
let body = resp.0.into_body().into_string().await.unwrap();
check!(body.contains("href=\"/widget\""));
check!(body.contains("Widgets for everyone"));
check!(body.contains("href=\"/plain\""));
check!(body.contains("href=\"/bare\""));
check!(!body.contains("secret"));
check!(body.contains("Test Site"));
}
#[tokio::test]
async fn index_survives_a_repository_that_cannot_be_opened() {
let fx = fixture();
let broken = fx.dir.path().join("broken.git");
std::fs::create_dir(&broken).unwrap();
common::set_public(&broken, true);
let client = TestClient::new(fx.app.routes());
let resp = client.get("/").send().await;
resp.assert_status_is_ok();
let body = resp.0.into_body().into_string().await.unwrap();
check!(body.contains("href=\"/widget\""));
check!(!body.contains("broken"));
}
#[tokio::test]
async fn a_directory_named_dot_git_dot_git_is_not_a_second_listing() {
let fx = Fixture::new();
fx.repo("tool", true, "The tool", &[]);
fx.repo("tool.git", true, "Named with a suffix", &[]);
let client = TestClient::new(fx.app.routes());
let body = client
.get("/")
.send()
.await
.0
.into_body()
.into_string()
.await
.unwrap();
check!(body.matches("href=\"/tool\"").count() == 1);
check!(!body.contains("Named with a suffix"));
check!(client.get("/tool.git.git").send().await.0.status() == StatusCode::NOT_FOUND);
}
#[tokio::test]
async fn index_is_sorted_case_insensitively() {
let fx = Fixture::new();
for name in ["zeta", "Alpha", "beta", "Gamma"] {
fx.repo(name, true, "", &[]);
}
let client = TestClient::new(fx.app.routes());
let body = client
.get("/")
.send()
.await
.0
.into_body()
.into_string()
.await
.unwrap();
let position = |name: &str| body.find(&format!("href=\"/{name}\"")).expect(name);
check!(position("Alpha") < position("beta"));
check!(position("beta") < position("Gamma"));
check!(position("Gamma") < position("zeta"));
}
#[tokio::test]
async fn index_paginates_when_there_are_more_repositories_than_fit() {
let fx = Fixture::with_page_size(2);
for name in ["a", "b", "c", "d", "e"] {
fx.repo(name, true, "", &[]);
}
let client = TestClient::new(fx.app.routes());
let first = client
.get("/")
.send()
.await
.0
.into_body()
.into_string()
.await
.unwrap();
check!(first.contains("href=\"/a\"") && first.contains("href=\"/b\""));
check!(!first.contains("href=\"/c\""));
check!(first.contains("Page 1 of 3"));
check!(first.contains("href=\"/?page=2\""));
let last = client
.get("/?page=3")
.send()
.await
.0
.into_body()
.into_string()
.await
.unwrap();
check!(last.contains("href=\"/e\"") && !last.contains("href=\"/d\""));
check!(last.contains("href=\"/?page=2\"") && !last.contains("href=\"/?page=4\""));
let beyond = client.get("/?page=4").send().await;
check!(beyond.0.status() == StatusCode::NOT_FOUND);
}
#[tokio::test]
async fn index_has_no_pager_when_everything_fits() {
let fx = fixture();
let client = TestClient::new(fx.app.routes());
let body = client
.get("/")
.send()
.await
.0
.into_body()
.into_string()
.await
.unwrap();
check!(!body.contains("class=\"pager\""));
}
#[tokio::test]
async fn repository_page_shows_readme_and_clone_url() {
let fx = fixture();
let client = TestClient::new(fx.app.routes());
let resp = client.get("/widget").send().await;
resp.assert_status_is_ok();
let body = resp.0.into_body().into_string().await.unwrap();
check!(body.contains("Widget
"));
check!(body.contains("widget"));
check!(!body.contains("