use crate::target::Target;
use std::io::{Cursor, Write};
use tempfile::TempDir;
use thunderstore_engine::client::ThunderstoreClient;
use zip::write::{FileOptions, ZipWriter};
pub fn mod_zip(version: &str) -> Vec<u8> {
mod_zip_with(version, "ModA.dll")
}
pub fn mod_zip_with(version: &str, dll_name: &str) -> Vec<u8> {
let mut zip = ZipWriter::new(Cursor::new(Vec::new()));
let options: FileOptions<'_, ()> =
FileOptions::default().compression_method(zip::CompressionMethod::Stored);
for (name, body) in [
(
"manifest.json".to_string(),
format!("{{\"version_number\":\"{version}\"}}").into_bytes(),
),
(format!("plugins/{dll_name}"), b"dll-bytes".to_vec()),
] {
zip.start_file(name, options).unwrap();
zip.write_all(&body).unwrap();
}
zip.finish().unwrap().into_inner()
}
pub fn index_json(server_url: &str) -> String {
let package = |owner: &str, name: &str, version: &str, dependencies: &str| {
format!(
r#"{{"name":"{name}","full_name":"{owner}-{name}","owner":"{owner}",
"package_url":"https://example.com/{name}",
"date_created":"2024-01-01T12:00:00Z","date_updated":"2024-01-02T12:00:00Z",
"uuid4":"pkg-{name}","rating_score":1,"is_pinned":false,
"is_deprecated":false,"has_nsfw_content":false,"categories":[],
"versions":[{{"name":"{name}","full_name":"{owner}-{name}",
"description":"A mod","icon":"icon.png","version_number":"{version}",
"dependencies":[{dependencies}],"download_url":"{server_url}/dl/{name}.zip",
"downloads":1,"date_created":"2024-01-01T12:00:00Z",
"website_url":"","is_active":true,"uuid4":"ver-{name}","file_size":1024}}]}}"#
)
};
format!(
"[{},{},{},{}]",
package("Owner", "ModA", "1.0.0", ""),
package("Owner", "ModB", "1.0.0", ""),
package("Owner", "ModC", "1.0.0", "\"Owner-ModA-1.0.0\""),
package("denikson", "BepInExPack_Valheim", "5.4.2200", "")
)
}
pub fn loader_zip() -> Vec<u8> {
let mut zip = ZipWriter::new(Cursor::new(Vec::new()));
let options: FileOptions<'_, ()> =
FileOptions::default().compression_method(zip::CompressionMethod::Stored);
for (name, body) in [
("manifest.json", &b"{\"version_number\":\"5.4.2200\"}"[..]),
("BepInExPack_Valheim/winhttp.dll", b"proxy"),
("BepInExPack_Valheim/BepInEx/core/BepInEx.dll", b"core"),
] {
zip.start_file(name, options).unwrap();
zip.write_all(body).unwrap();
}
zip.finish().unwrap().into_inner()
}
pub struct Fixture {
pub server: mockito::ServerGuard,
pub client: ThunderstoreClient,
pub base: TempDir,
pub game_dir: TempDir,
}
impl Fixture {
pub fn new() -> Self {
let mut server = mockito::Server::new();
let url = server.url();
server
.mock("GET", "/pkg/")
.with_status(200)
.with_header("Content-Type", "application/json")
.with_header("Last-Modified", "Wed, 21 Feb 2024 15:30:45 GMT")
.with_body(index_json(&url))
.create();
for (name, archive) in [
("ModA", mod_zip("1.0.0")),
("ModB", mod_zip_with("1.0.0", "ModB.dll")),
("ModC", mod_zip_with("1.0.0", "ModC.dll")),
("BepInExPack_Valheim", loader_zip()),
] {
server
.mock("GET", format!("/dl/{name}.zip").as_str())
.with_status(200)
.with_header("Content-Type", "application/zip")
.with_body(archive)
.create();
}
let base = TempDir::new().unwrap();
let game_dir = TempDir::new().unwrap();
let client = ThunderstoreClient::builder()
.package_index_url(format!("{url}/pkg/"))
.cache_dir(base.path())
.build()
.unwrap();
Self {
server,
client,
base,
game_dir,
}
}
pub fn target(&self) -> Target {
Target::resolve(
self.base.path().to_path_buf(),
self.game_dir.path().to_path_buf(),
crate::target::GAME,
None,
)
.unwrap()
}
pub fn profile_target(&self, name: &str) -> Target {
thunderstore_engine::profile::layout::create(self.base.path(), crate::target::GAME, name)
.unwrap();
Target::resolve(
self.base.path().to_path_buf(),
self.game_dir.path().to_path_buf(),
crate::target::GAME,
Some(name),
)
.unwrap()
}
}