Compare commits

..

No commits in common. "908e0031e22abf3139d1bbb65b31d860705d005a" and "51cf212bb64f671fd76f56cdc19dac3f7bb9f81d" have entirely different histories.

5 changed files with 96 additions and 245 deletions

19
.vscode/tasks.json vendored
View file

@ -27,24 +27,15 @@
"group": "none"
},
{
"label": "Clippy All Targets",
"type": "cargo",
"command": "clippy",
"args": [
"--all-targets",
"--",
"-Wclippy::pedantic"
],
"problemMatcher": "$rustc",
"group": "build"
},
{
"label": "Clippy Fix All Targets",
"label": "Clippy Fix Project",
"type": "cargo",
"command": "clippy",
"args": [
"--fix",
"--all-targets",
"--lib",
"--bin",
"shrupl",
"--allow-dirty",
"--allow-staged",
"--",
"-Wclippy::pedantic"

View file

@ -38,7 +38,7 @@ pub const DATA_LENGTHS_BAD: [u64; 8] = [36, 12, 1, 0, 9, 24, 13, 10];
/// known good hashes of the test dataset
///
/// using `BLAKE2b`, 512 bit, with unpadded Base64 (standard variant)
/// using BLAKE2b, 512 bit, with unpadded Base64 (standard variant)
pub const HASHES_STD_GOOD: [&str; 8] = [
// empty slice
"eGoC90IBWQPGxv2FJVLScpEvR0DhWEdhiobiF/cfVBnSXhAxr+5YUxOJZESTTrBLkDpoWxRIt1XVb3Aa/pvizg",
@ -101,7 +101,7 @@ pub const HASHES_STD_BAD: [&str; 8] = [
// ];
pub fn data() -> impl Iterator<Item = &'static [u8]> {
DATA.iter().copied()
DATA.iter().map(|item| *item)
}
pub fn cases() -> impl Iterator<Item = (&'static [u8], u64)> {

View file

@ -1,124 +1,26 @@
use std::{
cell::{RefCell, RefMut},
collections::{HashMap, hash_map::Entry},
};
use crate::{
Error, Result,
file::{self, FileTrait},
sharry::{AliasID, Client, FileID, ShareID, Uri, json},
file,
sharry::{self, AliasID, FileID, ShareID, Uri},
test_util::mock_ids,
};
use super::mock_ids::CheckID;
pub struct MockClient;
#[derive(Debug)]
pub struct MockClient {
shares: RefCell<HashMap<String, MockShare>>,
}
#[derive(Debug, Default)]
struct MockShare {
files: HashMap<String, MockFile>,
}
#[derive(Debug)]
struct MockFile {
name: String,
size: u64,
offset: u64,
}
impl MockClient {
fn insert_share(&self, share_id: &ShareID) -> Result<()> {
let mut shares = self.shares.borrow_mut();
let Entry::Vacant(entry) = shares.entry(share_id.to_string()) else {
return Err(Error::response(format_args!(
"Can't create share {share_id:?}!"
)));
};
entry.insert(MockShare::default());
Ok(())
}
fn insert_file(
&self,
share_id: &ShareID,
file_id: &FileID,
name: String,
size: u64,
) -> Result<()> {
let mut share = self.get_share_mut(share_id)?;
let Entry::Vacant(entry) = share.files.entry(file_id.to_string()) else {
return Err(Error::response(format_args!(
"Can't create file {file_id:?}!"
)));
};
entry.insert(MockFile {
name,
size,
offset: 0,
});
Ok(())
}
fn get_share_mut<'t>(&'t self, share_id: &ShareID) -> Result<RefMut<'t, MockShare>> {
let share_id = &share_id.to_string();
let shares = self.shares.borrow_mut();
shares
.get(share_id)
.ok_or_else(|| Error::response(format_args!("Can't find share {share_id:?}!")))?;
// share exists
Ok(RefMut::map(shares, |shares| {
shares.get_mut(share_id).expect("checked but None!")
}))
}
fn get_file_mut<'t>(
&'t self,
share_id: &ShareID,
file_id: &FileID,
) -> Result<RefMut<'t, MockFile>> {
let file_id = &file_id.to_string();
let share = self.get_share_mut(share_id)?;
share
.files
.get(file_id)
.ok_or_else(|| Error::response(format_args!("Can't find file {file_id:?}!")))?;
// file exists
Ok(RefMut::map(share, move |share| {
share.files.get_mut(file_id).expect("checked but None!")
}))
}
}
impl Client for MockClient {
impl sharry::Client for MockClient {
fn share_create(
&self,
uri: &Uri,
alias_id: &AliasID,
_: json::NewShareRequest,
) -> Result<ShareID> {
(uri, alias_id).check()?;
_: sharry::json::NewShareRequest,
) -> crate::Result<ShareID> {
mock_ids::check_alias(uri, alias_id)?;
let share_id = true.into();
self.insert_share(&share_id)?;
Ok(share_id)
Ok(true.into())
}
fn share_notify(&self, uri: &Uri, alias_id: &AliasID, share_id: &ShareID) -> crate::Result<()> {
(uri, alias_id).check()?;
share_id.check()?;
mock_ids::check_alias(uri, alias_id)?;
mock_ids::check_share(share_id)?;
Ok(())
}
@ -128,20 +30,12 @@ impl Client for MockClient {
uri: &Uri,
alias_id: &AliasID,
share_id: &ShareID,
file: &file::Checked,
) -> Result<FileID> {
(uri, alias_id).check()?;
share_id.check()?;
_: &file::Checked,
) -> crate::Result<FileID> {
mock_ids::check_alias(uri, alias_id)?;
mock_ids::check_share(share_id)?;
let file_id = true.into();
self.insert_file(
share_id,
&file_id,
file.get_name().to_string(),
file.get_size(),
)?;
Ok(file_id)
Ok(true.into())
}
fn file_patch(
@ -150,15 +44,14 @@ impl Client for MockClient {
alias_id: &AliasID,
share_id: &ShareID,
chunk: &file::Chunk,
) -> Result<()> {
(uri, alias_id).check()?;
(share_id, chunk.get_file_id()).check()?;
) -> crate::Result<()> {
mock_ids::check_alias(uri, alias_id)?;
mock_ids::check_file(share_id, chunk.get_file_id())?;
// TODO: `chunk` must align to a full MiB
let file = self.get_file_mut(share_id, chunk.get_file_id())?;
todo!()
// Ok(())
todo!()
}
}

View file

@ -1,12 +1,45 @@
use crate::{
Result,
sharry::{AliasID, FileID, ShareID, Uri},
};
use crate::sharry::{AliasID, FileID, ShareID, Uri};
const VALID_URI: &str = "scheme://valid.uri";
const VALID_ALIAS: &str = "valid-alias";
const VALID_SHARE: &str = "valid-share";
const VALID_FILE: &str = "valid-file";
const VALID_URI: &'static str = "scheme://valid.uri";
const VALID_ALIAS: &'static str = "valid-alias";
const VALID_SHARE: &'static str = "valid-share";
const VALID_FILE: &'static str = "valid-file";
pub fn check_uri(uri: &Uri) -> crate::Result<&Uri> {
if uri.to_string() != VALID_URI {
Err(uri.into())
} else {
Ok(uri)
}
}
pub fn check_alias<'t>(uri: &Uri, alias_id: &'t AliasID) -> crate::Result<&'t AliasID> {
check_uri(uri)?;
if alias_id.as_ref() != VALID_ALIAS {
Err(alias_id.into())
} else {
Ok(alias_id)
}
}
pub fn check_share(share_id: &ShareID) -> crate::Result<&ShareID> {
if share_id.to_string() != VALID_SHARE {
Err(share_id.into())
} else {
Ok(share_id)
}
}
pub fn check_file<'t>(share_id: &ShareID, file_id: &'t FileID) -> crate::Result<&'t FileID> {
check_share(share_id)?;
if file_id.to_string() != VALID_FILE {
Err(file_id.into())
} else {
Ok(file_id)
}
}
fn make_invalid(valid: &str) -> String {
let invalid = valid.replace("valid", "invalid");
@ -15,80 +48,38 @@ fn make_invalid(valid: &str) -> String {
invalid
}
pub trait CheckID {
fn check(self) -> Result<()>;
}
impl CheckID for (&Uri, &AliasID) {
fn check(self) -> Result<()> {
if self.0.to_string() == make_invalid(VALID_URI) {
Err(self.0.into())
} else if self.1.as_ref() == make_invalid(VALID_ALIAS) {
Err(self.1.into())
} else {
Ok(())
}
}
}
impl CheckID for &ShareID {
fn check(self) -> Result<()> {
if self.to_string() == make_invalid(VALID_SHARE) {
Err(self.into())
} else {
Ok(())
}
}
}
impl CheckID for (&ShareID, &FileID) {
fn check(self) -> Result<()> {
self.0.check()?;
if self.1.to_string() == make_invalid(VALID_FILE) {
Err(self.1.into())
} else {
Ok(())
}
}
}
impl From<bool> for Uri {
fn from(value: bool) -> Self {
if value {
Self::from(VALID_URI.to_string())
} else {
Self::from(make_invalid(VALID_URI))
match value {
true => Self::from(VALID_URI.to_string()),
false => Self::from(make_invalid(VALID_URI)),
}
}
}
impl From<bool> for AliasID {
fn from(value: bool) -> Self {
if value {
Self::from(VALID_ALIAS.to_string())
} else {
Self::from(make_invalid(VALID_ALIAS))
match value {
true => Self::from(VALID_ALIAS.to_string()),
false => Self::from(make_invalid(VALID_ALIAS)),
}
}
}
impl From<bool> for ShareID {
fn from(value: bool) -> Self {
if value {
Self::from(VALID_SHARE.to_string())
} else {
Self::from(make_invalid(VALID_SHARE))
match value {
true => Self::from(VALID_SHARE.to_string()),
false => Self::from(make_invalid(VALID_SHARE)),
}
}
}
impl From<bool> for FileID {
fn from(value: bool) -> Self {
if value {
Self::new_test(VALID_FILE)
} else {
Self::new_test(make_invalid(VALID_FILE))
match value {
true => Self::new_test(VALID_FILE),
false => Self::new_test(make_invalid(VALID_FILE)),
}
}
}
@ -101,65 +92,41 @@ mod tests {
#[test]
fn true_makes_valids() {
let uri = Uri::from(true);
let alias_id = AliasID::from(true);
let share_id = ShareID::from(true);
let file_id = FileID::from(true);
assert!(matches!((&uri, &alias_id).check(), Ok(())));
assert!(matches!(share_id.check(), Ok(())));
assert!(matches!((&share_id, &file_id).check(), Ok(())));
}
#[test]
fn default_is_valid() {
let uri = Uri::default();
let share_id = ShareID::default();
let file_id = FileID::default();
assert!(matches!((&uri, &AliasID::from(true)).check(), Ok(())));
assert!(matches!(share_id.check(), Ok(())));
assert!(matches!((&share_id, &file_id).check(), Ok(())));
assert!(check_uri(&true.into()).is_ok());
assert!(check_alias(&true.into(), &true.into()).is_ok());
assert!(check_share(&true.into()).is_ok());
assert!(check_file(&true.into(), &true.into()).is_ok());
}
#[test]
fn false_makes_invalids() {
let uri = Uri::from(true);
let alias_id = AliasID::from(true);
let share_id = ShareID::from(true);
let file_id = FileID::from(true);
let uri_i = Uri::from(false);
let alias_id_i = AliasID::from(false);
let share_id_i = ShareID::from(false);
let file_id_i = FileID::from(false);
// invalid Uri
let check = check_uri(&false.into()).expect_err("should be invalid");
let p = check.get_invalid_param().expect("should be InvalidParam");
assert!(matches!(p, Parameter::Uri(_)));
// invalid Uri, valid alias
let check = (&uri_i, &alias_id).check().expect_err("should be invalid");
let check = check_alias(&false.into(), &true.into()).expect_err("should be invalid");
let p = check.get_invalid_param().expect("should be InvalidParam");
assert!(matches!(p, Parameter::Uri(_)));
// valid Uri, invalid alias
let check = (&uri, &alias_id_i).check().expect_err("should be invalid");
let check = check_alias(&true.into(), &false.into()).expect_err("should be invalid");
let p = check.get_invalid_param().expect("should be InvalidParam");
assert!(matches!(p, Parameter::AliasID(_)));
// invalid share
let check = share_id_i.check().expect_err("should be invalid");
let check = check_share(&false.into()).expect_err("should be invalid");
let p = check.get_invalid_param().expect("should be InvalidParam");
assert!(matches!(p, Parameter::ShareID(_)));
// invalid share, valid file
let check = (&share_id_i, &file_id)
.check()
.expect_err("should be invalid");
let check = check_file(&false.into(), &true.into()).expect_err("should be invalid");
let p = check.get_invalid_param().expect("should be InvalidParam");
assert!(matches!(p, Parameter::ShareID(_)));
// valid share, invalid file
let check = (&share_id, &file_id_i)
.check()
.expect_err("should be invalid");
let check = check_file(&true.into(), &false.into()).expect_err("should be invalid");
let p = check.get_invalid_param().expect("should be InvalidParam");
assert!(matches!(p, Parameter::FileID(_)));
}

View file

@ -8,7 +8,6 @@ use std::{fmt, io::Write};
use tempfile::NamedTempFile;
#[allow(clippy::needless_pass_by_value)]
pub fn check_trait<A, E>(actual: A, expected: E, tr: &str, ty: &str)
where
A: fmt::Debug + PartialEq<E>,
@ -16,7 +15,8 @@ where
{
assert_eq!(
actual, expected,
"`impl {tr} for {ty}` expected: {expected:?}, actual: {actual:?}",
"`impl {tr} for {ty}` expected: {:?}, actual: {:?}",
expected, actual,
);
}