Add some tests

This commit is contained in:
Marc Plano-Lesay 2024-11-06 14:36:46 +11:00
parent bc46df634d
commit c525f63660
Signed by: kernald
GPG key ID: 66A41B08CC62A6CF
6 changed files with 889 additions and 27 deletions

714
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -33,7 +33,13 @@ uuid = { version = "1.11.0", features = ["serde", "v4"] }
vcard4 = "0.5.2" vcard4 = "0.5.2"
[build-dependencies] [build-dependencies]
openapiv3 = "2.0.0"
prettyplease = "0.2.24" prettyplease = "0.2.24"
progenitor = "0.8.0" progenitor = "0.8.0"
serde_json = "1.0" serde_json = "1.0"
syn = "2.0" syn = "2.0"
[dev-dependencies]
httpmock = "0.7.0"
regex = "1.11.1"
serde_json = "1.0"

View file

@ -1,3 +1,4 @@
use openapiv3::OpenAPI;
use std::{ use std::{
env, env,
fs::{self, File}, fs::{self, File},
@ -6,17 +7,34 @@ use std::{
fn main() { fn main() {
let src = "./src/immich-openapi-specs.json"; let src = "./src/immich-openapi-specs.json";
println!("cargo:rerun-if-changed={}", src); let out_dir = Path::new(&env::var("OUT_DIR").unwrap()).to_path_buf();
let file = File::open(src).unwrap(); let file = File::open(src).unwrap();
let spec = serde_json::from_reader(file).unwrap(); let spec = serde_json::from_reader(file).unwrap();
let mut generator = progenitor::Generator::default();
let tokens = generator.generate_tokens(&spec).unwrap(); let client = generate_client(&spec);
let ast = syn::parse2(tokens).unwrap(); let client_dst = out_dir.join("client.rs");
let content = prettyplease::unparse(&ast); fs::write(&client_dst, client).unwrap();
let mut out_file = Path::new(&env::var("OUT_DIR").unwrap()).to_path_buf(); let mock = generate_mock(&spec);
out_file.push("codegen.rs"); let mock_dst = out_dir.join("mock.rs");
fs::write(&mock_dst, mock).unwrap();
fs::write(out_file, content).unwrap(); println!("cargo:rerun-if-changed={}", src);
println!("cargo:rerun-if-changed={}", client_dst.display());
println!("cargo:rerun-if-changed={}", mock_dst.display());
}
fn generate_client(spec: &OpenAPI) -> String {
let mut generator = progenitor::Generator::default();
let tokens = generator.generate_tokens(spec).unwrap();
let ast = syn::parse2(tokens).unwrap();
prettyplease::unparse(&ast)
}
fn generate_mock(spec: &OpenAPI) -> String {
let mut generator = progenitor::Generator::default();
let tokens = generator.httpmock(spec, "crate").unwrap();
let ast = syn::parse2(tokens).unwrap();
prettyplease::unparse(&ast)
} }

View file

@ -49,3 +49,111 @@ impl Action for UpdatePersonDateOfBirth {
Ok(()) Ok(())
} }
} }
#[cfg(test)]
mod tests {
use std::str::FromStr;
use crate::tests::apimock::MockServerExt;
use httpmock::MockServer;
use uuid::Uuid;
use crate::{types::PersonResponseDto, Client};
use super::*;
#[test]
fn test_describe() {
let person = Person {
id: Uuid::parse_str("123e4567-e89b-12d3-a456-426655440000").unwrap(),
name: String::from("John Doe"),
date_of_birth: None,
};
let date_of_birth = NaiveDate::from_ymd_opt(2000, 1, 1).unwrap();
let args = UpdatePersonDateOfBirthArgs {
person,
date_of_birth,
};
let action = UpdatePersonDateOfBirth::new(args);
let description = action.describe();
assert_eq!(
description,
"Updating John Doe's date of birth to 2000-01-01"
);
}
#[tokio::test]
async fn calls_server() {
let id = "123e4567-e89b-12d3-a456-426655440000";
let new_date_of_birth = NaiveDate::from_ymd_opt(2000, 1, 1).unwrap();
let server = MockServer::start();
let response = PersonResponseDto {
id: String::from(id),
name: String::from("John Doe"),
birth_date: Some(new_date_of_birth),
is_hidden: false,
thumbnail_path: String::from("/foo/bar.jpg"),
updated_at: None,
};
let mock = server.update_person(|when, then| {
when.id(&Uuid::from_str(id).unwrap())
.body(&PersonUpdateDto {
birth_date: Some(new_date_of_birth),
feature_face_asset_id: None,
is_hidden: None,
name: None,
});
then.ok(&response);
});
let client = Client::new(&server.url(""));
let ctx = Context::builder()
.client(client)
.dry_run(false)
.no_confirm(true)
.build();
UpdatePersonDateOfBirth::new(UpdatePersonDateOfBirthArgs {
person: Person {
id: Uuid::from_str(id).unwrap(),
name: String::from("John Doe"),
date_of_birth: None,
},
date_of_birth: new_date_of_birth,
})
.execute(&ctx)
.await
.unwrap();
mock.assert_async().await;
}
#[tokio::test]
async fn does_not_call_server_in_dry_run() {
let id = "123e4567-e89b-12d3-a456-426655440000";
let new_date_of_birth = NaiveDate::from_ymd_opt(2000, 1, 1).unwrap();
let server = MockServer::start();
let mock = server.update_person(|_when, _then| {});
let client = Client::new(&server.url(""));
let ctx = Context::builder()
.client(client)
.dry_run(true)
.no_confirm(true)
.build();
UpdatePersonDateOfBirth::new(UpdatePersonDateOfBirthArgs {
person: Person {
id: Uuid::from_str(id).unwrap(),
name: String::from("John Doe"),
date_of_birth: None,
},
date_of_birth: new_date_of_birth,
})
.execute(&ctx)
.await
.unwrap();
mock.assert_hits_async(0).await;
}
}

View file

@ -1,4 +1,12 @@
include!(concat!(env!("OUT_DIR"), "/codegen.rs")); include!(concat!(env!("OUT_DIR"), "/client.rs"));
#[cfg(test)]
mod tests {
#[allow(dead_code)]
pub mod apimock {
include!(concat!(env!("OUT_DIR"), "/mock.rs"));
}
}
use crate::args::Commands; use crate::args::Commands;
use args::{AssetsCommands, PeopleCommands, ServerCommands}; use args::{AssetsCommands, PeopleCommands, ServerCommands};

View file

@ -19,3 +19,47 @@ impl From<PersonResponseDto> for Person {
} }
} }
} }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn from_person_response_dto_success() {
let dto = PersonResponseDto {
id: String::from("123e4567-e89b-12d3-a456-426655440000"),
name: String::from("John Doe"),
birth_date: Some(NaiveDate::from_ymd_opt(2000, 1, 1).unwrap()),
is_hidden: false,
thumbnail_path: String::from("/foo/bar.jpg"),
updated_at: None,
};
let person = Person::from(dto);
assert_eq!(
person.id,
Uuid::parse_str("123e4567-e89b-12d3-a456-426655440000").unwrap()
);
assert_eq!(person.name, "John Doe".to_string());
assert_eq!(
person.date_of_birth,
Some(NaiveDate::from_ymd_opt(2000, 1, 1).unwrap())
);
}
#[test]
#[should_panic]
fn from_person_response_dto_invalid_uuid_panics() {
let dto = PersonResponseDto {
id: String::from("invalid_uuid"),
name: String::from("John Doe"),
birth_date: Some(NaiveDate::from_ymd_opt(2000, 1, 1).unwrap()),
is_hidden: false,
thumbnail_path: String::from("/foo/bar.jpg"),
updated_at: None,
};
let _ = Person::from(dto);
}
}