use c3p0::{IdType, VersionType};
use crate::error::ErrorDetails;
use crate::service::auth::Owned;
pub const WRONG_OWNER: &str = "WRONG_OWNER";
pub const WRONG_ID: &str = "WRONG_ID";
pub const WRONG_VERSION: &str = "WRONG_VERSION";
pub trait WithIdAndVersion<Id> {
fn get_id(&self) -> &Id;
fn get_version(&self) -> VersionType;
}
impl<Id, Data> WithIdAndVersion<Id> for c3p0::Model<Id, Data> {
fn get_id(&self) -> &Id {
&self.id
}
fn get_version(&self) -> VersionType {
self.version
}
}
pub fn validate_ownership<Id: Eq, F: Owned<Id>, S: Owned<Id>>(error_details: &mut ErrorDetails, owner: &F, owned: &S) {
if owner.get_owner_id() != owned.get_owner_id() {
error_details.add_detail("owner_id", WRONG_OWNER)
}
}
pub fn validate_id_and_version<F: WithIdAndVersion<Id>, S: WithIdAndVersion<Id>, Id: IdType>(
error_details: &mut ErrorDetails,
first: &F,
second: &S,
) {
if first.get_version() != second.get_version() {
error_details.add_detail("version", WRONG_VERSION)
}
if first.get_id() != second.get_id() {
error_details.add_detail("id", WRONG_ID)
}
}
pub fn validate_ownership_id_and_version<
Id: IdType,
F: Owned<Id> + WithIdAndVersion<Id>,
S: Owned<Id> + WithIdAndVersion<Id>,
>(
error_details: &mut ErrorDetails,
first: &F,
second: &S,
) {
validate_ownership(error_details, first, second);
validate_id_and_version(error_details, first, second);
}
#[cfg(test)]
mod tests {
use super::*;
use crate::error::{ErrorDetail, ErrorDetails};
struct Data(i32);
impl Owned<i32> for Data {
fn get_owner_id(&self) -> &i32 {
&self.0
}
}
#[test]
fn should_validate_ownership_1() {
let mut error_details = ErrorDetails::default();
let first = Data(61);
let second = Data(61);
validate_ownership(&mut error_details, &first, &second);
assert!(error_details.details().is_empty())
}
#[test]
fn should_validate_ownership_2() {
let mut error_details = ErrorDetails::default();
let first =
c3p0::Model { id: 13, version: 1, data: Data(1000), update_epoch_millis: 0, create_epoch_millis: 0 };
let second =
c3p0::Model { id: 12, version: 0, data: Data(1000), update_epoch_millis: 0, create_epoch_millis: 0 };
validate_ownership(&mut error_details, &first, &second);
assert!(error_details.details().is_empty())
}
#[test]
fn should_fail_validate_ownership() {
let mut error_details = ErrorDetails::default();
let first =
c3p0::Model { id: 13, version: 1, data: Data(1001), update_epoch_millis: 0, create_epoch_millis: 0 };
let second =
c3p0::Model { id: 12, version: 0, data: Data(1000), update_epoch_millis: 0, create_epoch_millis: 0 };
validate_ownership(&mut error_details, &first, &second);
assert_eq!(1, error_details.details().len());
assert_eq!(ErrorDetail::new(WRONG_OWNER, vec![]), error_details.details()["owner_id"][0])
}
#[test]
fn should_validate_id_and_version() {
let mut error_details = ErrorDetails::default();
let first =
c3p0::Model { id: 12, version: 0, data: Data(1001), update_epoch_millis: 0, create_epoch_millis: 0 };
let second =
c3p0::Model { id: 12, version: 0, data: Data(1000), update_epoch_millis: 0, create_epoch_millis: 0 };
validate_id_and_version(&mut error_details, &first, &second);
assert!(error_details.details().is_empty())
}
#[test]
fn should_fail_validate_id_and_version() {
let mut error_details = ErrorDetails::default();
let first =
c3p0::Model { id: 13, version: 1, data: Data(1001), update_epoch_millis: 0, create_epoch_millis: 0 };
let second =
c3p0::Model { id: 12, version: 0, data: Data(1000), update_epoch_millis: 0, create_epoch_millis: 0 };
validate_id_and_version(&mut error_details, &first, &second);
assert_eq!(2, error_details.details().len());
assert_eq!(ErrorDetail::new(WRONG_ID, vec![]), error_details.details()["id"][0]);
assert_eq!(ErrorDetail::new(WRONG_VERSION, vec![]), error_details.details()["version"][0]);
}
#[test]
fn should_validate_ownership_id_and_version() {
let mut error_details = ErrorDetails::default();
let first =
c3p0::Model { id: 12, version: 0, data: Data(1000), update_epoch_millis: 0, create_epoch_millis: 0 };
let second =
c3p0::Model { id: 12, version: 0, data: Data(1000), update_epoch_millis: 0, create_epoch_millis: 0 };
validate_ownership_id_and_version(&mut error_details, &first, &second);
assert!(error_details.details().is_empty())
}
#[test]
fn should_fail_validate_ownership_id_and_version_if_bad_id() {
let mut error_details = ErrorDetails::default();
let first =
c3p0::Model { id: 13, version: 0, data: Data(1000), update_epoch_millis: 0, create_epoch_millis: 0 };
let second =
c3p0::Model { id: 12, version: 0, data: Data(1000), update_epoch_millis: 0, create_epoch_millis: 0 };
validate_ownership_id_and_version(&mut error_details, &first, &second);
assert_eq!(1, error_details.details().len());
assert_eq!(ErrorDetail::new(WRONG_ID, vec![]), error_details.details()["id"][0]);
}
#[test]
fn should_fail_validate_ownership_id_and_version_if_bad_version() {
let mut error_details = ErrorDetails::default();
let first =
c3p0::Model { id: 12, version: 1, data: Data(1000), update_epoch_millis: 0, create_epoch_millis: 0 };
let second =
c3p0::Model { id: 12, version: 0, data: Data(1000), update_epoch_millis: 0, create_epoch_millis: 0 };
validate_ownership_id_and_version(&mut error_details, &first, &second);
assert_eq!(1, error_details.details().len());
assert_eq!(ErrorDetail::new(WRONG_VERSION, vec![]), error_details.details()["version"][0]);
}
#[test]
fn should_fail_validate_ownership_id_and_version_if_bad_owner() {
let mut error_details = ErrorDetails::default();
let first =
c3p0::Model { id: 12, version: 0, data: Data(1001), update_epoch_millis: 0, create_epoch_millis: 0 };
let second =
c3p0::Model { id: 12, version: 0, data: Data(1000), update_epoch_millis: 0, create_epoch_millis: 0 };
validate_ownership_id_and_version(&mut error_details, &first, &second);
assert_eq!(1, error_details.details().len());
assert_eq!(ErrorDetail::new(WRONG_OWNER, vec![]), error_details.details()["owner_id"][0]);
}
}