Compare commits
No commits in common. "61d62d731e34de660bc6b474c326ce40df903be7" and "ea453da43376b621173ba17b851ef2c84730c6e5" have entirely different histories.
61d62d731e
...
ea453da433
10 changed files with 45 additions and 269 deletions
99
Cargo.lock
generated
99
Cargo.lock
generated
|
|
@ -85,6 +85,12 @@ version = "0.22.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "base64ct"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.9.1"
|
||||
|
|
@ -344,22 +350,6 @@ version = "1.0.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.1"
|
||||
|
|
@ -393,19 +383,7 @@ checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
|
|||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"r-efi",
|
||||
"wasi 0.14.2+wasi-0.2.4",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -628,12 +606,6 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
|
||||
|
||||
[[package]]
|
||||
name = "litemap"
|
||||
version = "0.8.0"
|
||||
|
|
@ -757,19 +729,13 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "r-efi"
|
||||
version = "5.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
|
||||
dependencies = [
|
||||
"getrandom 0.2.16",
|
||||
"getrandom",
|
||||
"libredox",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
|
@ -811,25 +777,12 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
|
|||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"getrandom 0.2.16",
|
||||
"getrandom",
|
||||
"libc",
|
||||
"untrusted",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.23.27"
|
||||
|
|
@ -928,7 +881,7 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
|||
name = "shrupl"
|
||||
version = "0.1.0-alpha"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"base64ct",
|
||||
"blake2b_simd",
|
||||
"clap",
|
||||
"console",
|
||||
|
|
@ -941,7 +894,6 @@ dependencies = [
|
|||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tempfile",
|
||||
"thiserror 2.0.12",
|
||||
"ureq",
|
||||
]
|
||||
|
|
@ -992,19 +944,6 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"getrandom 0.3.3",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.69"
|
||||
|
|
@ -1178,15 +1117,6 @@ version = "0.11.0+wasi-snapshot-preview1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.14.2+wasi-0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
|
||||
dependencies = [
|
||||
"wit-bindgen-rt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.100"
|
||||
|
|
@ -1376,15 +1306,6 @@ version = "0.52.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rt"
|
||||
version = "0.39.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "writeable"
|
||||
version = "0.6.1"
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ edition = "2024"
|
|||
description = "ShrUpl is a tool to upload files to a Sharry Instance through a public Alias, leveraging the tus protocol"
|
||||
|
||||
[dependencies]
|
||||
base64 = { version = "0.22.1", default-features = false }
|
||||
base64ct = { version = "1.8.0", default-features = false, features = ["alloc"] }
|
||||
blake2b_simd = "1.0.3"
|
||||
clap = { version = "4.5.38", features = ["derive"] }
|
||||
console = { version = "0.15.11", default-features = false }
|
||||
|
|
@ -21,9 +21,6 @@ serde_json = "1.0.140"
|
|||
thiserror = "2.0.12"
|
||||
ureq = { version = "3.0.11", features = ["json"] }
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.20.0"
|
||||
|
||||
[profile.release]
|
||||
# Optimize for speed even more aggressively
|
||||
opt-level = "z"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::{convert::Infallible, fmt, io, time::Duration};
|
||||
|
||||
use base64::prelude::{BASE64_URL_SAFE_NO_PAD as BASE64URL, Engine};
|
||||
use base64ct::{Base64UrlUnpadded, Encoding};
|
||||
use blake2b_simd::Params as Blake2b;
|
||||
use clap::{Parser, builder::TypedValueParser, value_parser};
|
||||
use log::LevelFilter;
|
||||
|
|
@ -154,6 +154,6 @@ impl Cli {
|
|||
hasher.update(chk.as_ref());
|
||||
}
|
||||
|
||||
BASE64URL.encode(hasher.finalize())
|
||||
Base64UrlUnpadded::encode_string(hasher.finalize().as_bytes())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
12
src/error.rs
12
src/error.rs
|
|
@ -121,18 +121,6 @@ impl Error {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn is_mismatch<E, A>(&self, has_expected: E, has_actual: A) -> bool
|
||||
where
|
||||
String: PartialEq<E> + PartialEq<A>,
|
||||
{
|
||||
matches!(
|
||||
self,
|
||||
Self::Mismatch { expected, actual }
|
||||
if *expected == has_expected
|
||||
&& *actual == has_actual
|
||||
)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn get_invalid_param(&self) -> Option<&Parameter> {
|
||||
if let Self::InvalidParameter(p) = self {
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ impl Checked {
|
|||
return Err(crate::Error::mismatch("unhashed file", self.path.display()));
|
||||
}
|
||||
|
||||
self.hash = Some(super::compute_hash(&self.path, self.size, f)?);
|
||||
self.hash = Some(super::compute_file_hash(&self.path, self.size, f)?);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -100,11 +100,6 @@ impl<'t> FileTrait<'t> for Checked {
|
|||
}
|
||||
|
||||
fn check_hash(&self, on_progress: impl Fn(u64)) -> crate::Result<()> {
|
||||
super::check_hash(
|
||||
&self.path,
|
||||
self.size,
|
||||
self.hash.as_ref().map(String::as_str),
|
||||
on_progress,
|
||||
)
|
||||
super::check_file_hash(&self.path, self.size, self.hash.as_ref(), on_progress)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
144
src/file/mod.rs
144
src/file/mod.rs
|
|
@ -4,7 +4,7 @@ mod uploading;
|
|||
|
||||
use std::{ffi::OsStr, fs, io::Read, path::Path};
|
||||
|
||||
use base64::prelude::{BASE64_STANDARD_NO_PAD as BASE64, Engine};
|
||||
use base64ct::{Base64, Encoding};
|
||||
use blake2b_simd::Params as Blake2b;
|
||||
|
||||
pub use checked::Checked;
|
||||
|
|
@ -12,14 +12,12 @@ pub use chunk::Chunk;
|
|||
use log::{debug, warn};
|
||||
pub use uploading::Uploading;
|
||||
|
||||
fn compute_hash(path: &Path, size: u64, mut on_progress: impl FnMut(u64)) -> crate::Result<String> {
|
||||
let mut file = fs::File::open(path)?;
|
||||
|
||||
// Blake2b-512 hasher (64 * 8 bit)
|
||||
fn compute_file_hash(path: &Path, size: u64, on_progress: impl Fn(u64)) -> crate::Result<String> {
|
||||
let mut file = fs::File::open(path)?;
|
||||
let mut hasher = Blake2b::new().hash_length(64).to_state();
|
||||
|
||||
// buffer (4 MiB)
|
||||
let mut buf = vec![0; 4 * 1024 * 1024];
|
||||
let mut buf = vec![0u8; 4 * 1024 * 1024];
|
||||
let mut bytes_read = 0;
|
||||
|
||||
loop {
|
||||
|
|
@ -29,7 +27,6 @@ fn compute_hash(path: &Path, size: u64, mut on_progress: impl FnMut(u64)) -> cra
|
|||
}
|
||||
hasher.update(&buf[..n]);
|
||||
|
||||
// `buf` size must be < 2 EiB
|
||||
bytes_read += n as u64;
|
||||
on_progress(n as u64);
|
||||
}
|
||||
|
|
@ -38,22 +35,22 @@ fn compute_hash(path: &Path, size: u64, mut on_progress: impl FnMut(u64)) -> cra
|
|||
return Err(crate::Error::mismatch(size, bytes_read));
|
||||
}
|
||||
|
||||
let result = BASE64.encode(hasher.finalize());
|
||||
let result = Base64::encode_string(hasher.finalize().as_bytes());
|
||||
debug!("hashed {:?}: {result:?}", path.display());
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn check_hash(
|
||||
fn check_file_hash(
|
||||
path: &Path,
|
||||
size: u64,
|
||||
hash: Option<&str>,
|
||||
on_progress: impl FnMut(u64),
|
||||
hash: Option<&String>,
|
||||
on_progress: impl Fn(u64),
|
||||
) -> crate::Result<()> {
|
||||
let Some(expected) = hash else {
|
||||
return Err(crate::Error::mismatch("hash", path.display()));
|
||||
};
|
||||
|
||||
let actual = &compute_hash(path, size, on_progress)?;
|
||||
let actual = &compute_file_hash(path, size, on_progress)?;
|
||||
|
||||
if expected == actual {
|
||||
debug!("hash matches {expected:?}");
|
||||
|
|
@ -84,126 +81,3 @@ pub trait FileTrait<'t> {
|
|||
|
||||
fn check_hash(&self, on_progress: impl Fn(u64)) -> crate::Result<()>;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::io::Write;
|
||||
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
use super::*;
|
||||
|
||||
/// Helper to create a temp file from `data`
|
||||
fn create_file(data: &[u8]) -> NamedTempFile {
|
||||
let mut tmp = NamedTempFile::new().expect("creating temp file");
|
||||
tmp.write_all(data).expect("writing to tempfile");
|
||||
tmp
|
||||
}
|
||||
|
||||
static CASES: [(&[u8], u64); 8] = [
|
||||
(b"The quick brown fox jumps over the lazy dog", 43), // common pangram
|
||||
(b"hello world", 11), // simple greeting
|
||||
(b"", 0), // empty slice
|
||||
(b"x", 1), // single-byte
|
||||
(b"0123456789", 10), // numeric ASCII
|
||||
(b"!@#$%^&*()_+-=[]{};':,.<>/?", 27), // punctuation
|
||||
(b"RustLang1337", 12), // mixed alphanumeric
|
||||
(b"foo\0bar\0baz", 11), // embedded nulls
|
||||
];
|
||||
|
||||
static HASHES: [&str; 8] = [
|
||||
"qK3Uvd39k+SHfSdG5igXsRY2Sh+nvBSNlQkLxzM7NnP4JAHPeqLkyx7NkCluPxTLVBP47Xe+cwRbE5FM3NapGA", // common pangram
|
||||
"Ahzth5kpbOylV4MquUGlC0oR+DR4zxQfUfkz9lOrn7zAWgN83b7QbjCb8zSULE5YzfGkbiN5EczX/Pl4fLx/0A", // simple greeting
|
||||
"eGoC90IBWQPGxv2FJVLScpEvR0DhWEdhiobiF/cfVBnSXhAxr+5YUxOJZESTTrBLkDpoWxRIt1XVb3Aa/pvizg", // empty slice
|
||||
"CQk3etNREMr7KQnhhWcrfyco0fUJT4rWjW+sYnS/H0mUhagOo2TATtAG0pRZ6jy3xgAoDi+D4DJSmQb4iuMNCg", // single-byte
|
||||
"UqCSwAW2Ib1X5QGgrtlQp2/vuwDQeqQ9rdb1NALMJUE3SfDTxi6MoKfbrjRIQa3qUdU/i2HZaaFdSmMYtXa4rA", // numeric ASCII
|
||||
"Sr91qmX4R/Ly4HsJh5eiG3S1tuO81kwV0KPfRpn1j4jjrQoGL2I+SeKfcGvpXu3l/rfhGdJHF8ei775ZzdgK3Q", // punctuation
|
||||
"Ox+zobaUmB8Ps410/TGOtjjLIJKaMUCwG/iFLNXjwRShuJAmtvQcK9Ahc9+SfD4Ci67HyPPorl7NGjN6LRrmlQ", // mixed alphanumeric
|
||||
"a3rsGWE2kfvN6e2sVhioWP9NOmwLK9trzjc/GKXTPvvsiagiRSHMjlg5jy+bMepip68Pv69dY8TvTSFZES5Jzw", // embedded nulls
|
||||
];
|
||||
|
||||
#[test]
|
||||
fn compute_hash_as_expected() {
|
||||
for (&(content, size), expected_hash) in CASES.iter().zip(HASHES) {
|
||||
// to capture progress updates from `compute_hash`
|
||||
let file = create_file(content);
|
||||
let mut read_total = 0;
|
||||
let callback = |n| read_total += n;
|
||||
|
||||
let hash = compute_hash(file.path(), size, callback).expect("hash should succeed");
|
||||
|
||||
assert_eq!(hash, expected_hash);
|
||||
assert_eq!(read_total, size);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hash_size_mismatch() {
|
||||
let bad_sizes = [
|
||||
36, // common pangram
|
||||
12, // simple greeting
|
||||
1, // empty slice
|
||||
0, // single-byte
|
||||
9, // numeric ASCII
|
||||
24, // punctuation
|
||||
13, // mixed alphanumeric
|
||||
10, // embedded nulls
|
||||
];
|
||||
|
||||
for (&(content, good_size), bad_size) in CASES.iter().zip(bad_sizes) {
|
||||
let file = create_file(content);
|
||||
let callback = drop;
|
||||
|
||||
{
|
||||
let err = compute_hash(file.path(), bad_size, callback)
|
||||
.expect_err("compute_hash should report a mismatch");
|
||||
|
||||
// check error
|
||||
assert!(err.is_mismatch(bad_size.to_string(), good_size.to_string()));
|
||||
}
|
||||
|
||||
{
|
||||
let err = check_hash(file.path(), bad_size, Some("foobar"), callback)
|
||||
.expect_err("check_hash should report a mismatch");
|
||||
|
||||
// check error
|
||||
assert!(err.is_mismatch(bad_size.to_string(), good_size.to_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hash_value_none() {
|
||||
for (content, size) in CASES {
|
||||
let file = create_file(content);
|
||||
let callback = drop;
|
||||
|
||||
let err = check_hash(file.path(), size, None, callback)
|
||||
.expect_err("check_hash should report a mismatch");
|
||||
|
||||
// check error
|
||||
assert!(err.is_mismatch("hash", file.path().display().to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hash_value_mismatch() {
|
||||
let bad_hashes = [
|
||||
"invalid9k+SHfSdG5igXsRY2Sh+nvBSNlQkLxzM7NnP4JAHPeqLkyx7NkCluPxTLVBP47Xe+cwRbE5FM3NapGA", // common pangram
|
||||
"", // simple greeting
|
||||
"eGoC90IBWQPGxv2FJVLScpEvR0DhWEdhiobiG/cfVBnSXhAxr+5YUxOJZESTTrBLkDpoWxRIt1XVb3Aa/pvizg", // empty slice
|
||||
"Hash", // single-byte
|
||||
];
|
||||
|
||||
for ((&(content, size), good_hash), bad_hash) in CASES.iter().zip(HASHES).zip(bad_hashes) {
|
||||
let file = create_file(content);
|
||||
let callback = drop;
|
||||
|
||||
let err = check_hash(file.path(), size, Some(bad_hash), callback)
|
||||
.expect_err("check_hash should report a mismatch");
|
||||
|
||||
// check error
|
||||
assert!(err.is_mismatch(bad_hash, good_hash));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -107,11 +107,6 @@ impl<'t> FileTrait<'t> for Uploading {
|
|||
}
|
||||
|
||||
fn check_hash(&self, on_progress: impl Fn(u64)) -> crate::Result<()> {
|
||||
super::check_hash(
|
||||
&self.path,
|
||||
self.size,
|
||||
self.hash.as_ref().map(String::as_str),
|
||||
on_progress,
|
||||
)
|
||||
super::check_file_hash(&self.path, self.size, self.hash.as_ref(), on_progress)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn basic_traits_working() {
|
||||
let inputs = [
|
||||
let inputs = vec![
|
||||
"",
|
||||
"abcd",
|
||||
"12345",
|
||||
|
|
@ -142,7 +142,7 @@ mod tests {
|
|||
#[test]
|
||||
fn valid_urls_produce_expected_file_id() {
|
||||
// a handful of valid‐looking URLs
|
||||
let cases = [
|
||||
let cases = vec![
|
||||
(
|
||||
"http://example.com/api/v2/alias/upload/SID123/files/tus/FID456",
|
||||
"FID456",
|
||||
|
|
@ -169,7 +169,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn invalid_urls_return_error() {
|
||||
let bad_inputs = [
|
||||
let bad_inputs = vec![
|
||||
// missing /api/v2/alias/upload
|
||||
"http://example.com/files/tus/FID",
|
||||
// missing /files/tus
|
||||
|
|
@ -185,10 +185,16 @@ mod tests {
|
|||
for bad in bad_inputs {
|
||||
let err = FileID::try_from(bad.to_string()).expect_err("URL should not parse");
|
||||
// make sure it's the Mismatch variant, and that it contains the original input
|
||||
assert!(err.is_mismatch(
|
||||
"<proto>://<host>/api/v2/alias/upload/<share>/files/tus/<file>",
|
||||
bad
|
||||
));
|
||||
match err {
|
||||
crate::Error::Mismatch { expected, actual } => {
|
||||
assert_eq!(
|
||||
expected, "<proto>://<host>/api/v2/alias/upload/<share>/files/tus/<file>",
|
||||
"Error should output expected format"
|
||||
);
|
||||
assert_eq!(actual, bad, "Error should echo back the input");
|
||||
}
|
||||
_ => panic!("Expected Error::Mismatch for input `{bad}` but got {err:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn nsreq_new_sets_fields_correctly() {
|
||||
let cases = [
|
||||
let cases: Vec<(&str, u32)> = vec![
|
||||
// simple ASCII name, small view count
|
||||
("alice", 1),
|
||||
// underscores, mid-range views
|
||||
|
|
@ -95,7 +95,7 @@ mod tests {
|
|||
fn nsreq_new_allows_setting_description() {
|
||||
let longstr = "y".repeat(256);
|
||||
|
||||
let cases = [
|
||||
let cases = vec![
|
||||
// simple alphanumeric
|
||||
"A simple test user",
|
||||
// whitespace & punctuation
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ impl From<String> for Uri {
|
|||
SHARRY_URI_RE.captures(value).map(|caps| {
|
||||
let captured = |name| {
|
||||
caps.name(name)
|
||||
.unwrap_or_else(|| panic!("{name} not captured"))
|
||||
.expect(&format!("{name} not captured"))
|
||||
.as_str()
|
||||
.to_string()
|
||||
};
|
||||
|
|
@ -104,7 +104,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn basic_traits_working() {
|
||||
let cases = [
|
||||
let cases = vec![
|
||||
// simple http host
|
||||
"http://example.com",
|
||||
// https host with port
|
||||
|
|
@ -122,7 +122,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn valid_urls_produce_expected_uri() {
|
||||
let cases = [
|
||||
let cases = vec![
|
||||
// simple http host
|
||||
("http://example.com", "http://example.com"),
|
||||
// https host with port
|
||||
|
|
@ -143,7 +143,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn invalid_urls_passed_through() {
|
||||
let cases = [
|
||||
let cases = vec![
|
||||
// missing “://”
|
||||
"http:/example.com",
|
||||
// missing scheme
|
||||
|
|
@ -165,7 +165,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_endpoint() {
|
||||
let cases = [
|
||||
let cases = vec![
|
||||
// simple path
|
||||
("path/to/something", "/api/v2/path/to/something"),
|
||||
// underscores, hyphens, dots
|
||||
|
|
|
|||
Loading…
Reference in a new issue