1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
|
use std::process::{Command, Stdio};
use pretty_assertions::{assert_eq, assert_ne};
use rstest::rstest;
use select::document::Document;
mod fixtures;
mod utils;
use crate::fixtures::{server, Error, TestServer, DEEPLY_NESTED_FILE, DIRECTORIES};
use crate::utils::{get_link_from_text, get_link_hrefs_with_prefix};
#[rstest]
#[case("", "/")]
#[case("/dira", "/dira/")]
#[case("/dirb/", "/dirb/")]
#[case("/very/deeply/nested", "/very/deeply/nested/")]
/// Directories get a trailing slash.
fn index_gets_trailing_slash(
server: TestServer,
#[case] input: &str,
#[case] expected: &str,
) -> Result<(), Error> {
let resp = reqwest::blocking::get(server.url().join(input)?)?;
assert!(resp.url().as_str().ends_with(expected));
Ok(())
}
#[rstest]
/// Can't navigate up the root.
fn cant_navigate_up_the_root(server: TestServer) -> Result<(), Error> {
// We're using curl for this as it has the option `--path-as-is` which doesn't normalize
// invalid urls. A useful feature in this particular case.
let base_url = server.url();
let curl_successful = Command::new("curl")
.arg("-s")
.arg("--fail")
.arg("--path-as-is")
.arg(format!("{base_url}/../"))
.stdout(Stdio::null())
.status()?
.success();
assert!(curl_successful);
Ok(())
}
#[rstest]
/// We can navigate into directories and back using shown links.
fn can_navigate_into_dirs_and_back(server: TestServer) -> Result<(), Error> {
let base_url = server.url();
let initial_body = reqwest::blocking::get(base_url.as_str())?.error_for_status()?;
let initial_parsed = Document::from_read(initial_body)?;
for &directory in DIRECTORIES {
let dir_elem = get_link_from_text(&initial_parsed, directory).expect("Dir not found.");
let body = reqwest::blocking::get(format!("{base_url}{dir_elem}"))?.error_for_status()?;
let parsed = Document::from_read(body)?;
let back_link =
get_link_from_text(&parsed, "Parent directory").expect("Back link not found.");
let resp = reqwest::blocking::get(format!("{base_url}{back_link}"))?;
// Now check that we can actually get back to the original location we came from using the
// link.
assert_eq!(resp.url().as_str(), base_url.as_str());
}
Ok(())
}
#[rstest]
/// We can navigate deep into the file tree and back using shown links.
fn can_navigate_deep_into_dirs_and_back(server: TestServer) -> Result<(), Error> {
// Create a vector of directory names. We don't need to fetch the file and so we'll
// remove that part.
let dir_names = {
let mut comps = DEEPLY_NESTED_FILE
.split('/')
.map(|d| format!("{d}/"))
.collect::<Vec<String>>();
comps.pop();
comps
};
let base_url = server.url();
// First we'll go forwards through the directory tree and then we'll go backwards.
// In the end, we'll have to end up where we came from.
let mut next_url = base_url.clone();
for dir_name in dir_names.iter() {
let resp = reqwest::blocking::get(next_url.as_str())?;
let body = resp.error_for_status()?;
let parsed = Document::from_read(body)?;
let dir_elem = get_link_from_text(&parsed, dir_name).expect("Dir not found.");
next_url = next_url.join(&dir_elem)?;
}
assert_ne!(base_url, next_url);
// Now try to get out the tree again using links only.
while next_url != base_url {
let resp = reqwest::blocking::get(next_url.as_str())?;
let body = resp.error_for_status()?;
let parsed = Document::from_read(body)?;
let dir_elem =
get_link_from_text(&parsed, "Parent directory").expect("Back link not found.");
next_url = next_url.join(&dir_elem)?;
}
assert_eq!(base_url, next_url);
Ok(())
}
#[rstest]
#[case(server(&["--title", "some title"]), "some title")]
#[case(server(None::<&str>), format!("localhost:{}", server.port()))]
/// We can use breadcrumbs to navigate.
fn can_navigate_using_breadcrumbs(
#[case] server: TestServer,
#[case] title_name: String,
) -> Result<(), Error> {
// Create a vector of directory names. We don't need to fetch the file and so we'll
// remove that part.
let dir: String = {
let mut comps = DEEPLY_NESTED_FILE
.split('/')
.map(|d| format!("{d}/"))
.collect::<Vec<String>>();
comps.pop();
comps.join("")
};
let base_url = server.url();
let nested_url = base_url.join(&dir)?;
let resp = reqwest::blocking::get(nested_url.as_str())?;
let body = resp.error_for_status()?;
let parsed = Document::from_read(body)?;
// can go back to root dir by clicking title
let title_link = get_link_from_text(&parsed, &title_name).expect("Root dir link not found.");
assert_eq!("/", title_link);
// can go to intermediate dir
let intermediate_dir_link =
get_link_from_text(&parsed, "very").expect("Intermediate dir link not found.");
assert_eq!("/very/", intermediate_dir_link);
// current dir is not linked
let current_dir_link = get_link_from_text(&parsed, "nested");
assert_eq!(None, current_dir_link);
Ok(())
}
#[rstest]
#[case(server(&["--default-sorting-method", "name", "--default-sorting-order", "asc"]), "name", "asc")]
#[case(server(&["--default-sorting-method", "name", "--default-sorting-order", "desc"]), "name", "desc")]
/// We can specify the default sorting order
fn can_specify_default_sorting_order(
#[case] server: TestServer,
#[case] method: String,
#[case] order: String,
) -> Result<(), Error> {
let resp = reqwest::blocking::get(server.url())?;
let body = resp.error_for_status()?;
let parsed = Document::from_read(body)?;
let links = get_link_hrefs_with_prefix(&parsed, "/");
let dir_iter = server.path();
let mut dir_entries = dir_iter
.read_dir()
.unwrap()
.map(|x| x.unwrap().file_name().into_string().unwrap())
.map(|x| format!("/{x}"))
.collect::<Vec<_>>();
dir_entries.sort();
if method == "name" && order == "asc" {
assert_eq!(
*dir_entries.last().unwrap(),
*percent_encoding::percent_decode_str(links.first().unwrap()).decode_utf8_lossy()
);
} else if method == "name" && order == "desc" {
assert_eq!(
*dir_entries.first().unwrap(),
*percent_encoding::percent_decode_str(links.first().unwrap()).decode_utf8_lossy()
);
}
Ok(())
}
|