mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-04 01:18:34 +00:00
seedream test
This commit is contained in:
1 parent
2452e065f5
commit
d2fc71cfe9
3 files changed
+623
-8
No files matched your search
+9
-8
@@ -46,9 +46,10 @@ fn resolve_image_list_ref<'a>(
|
||||
match image_list_ref {
|
||||
None => Ok(None),
|
||||
Some(ImageListRef::MediaFileTokens(tokens)) => Ok(Some(tokens)),
|
||||
Some(ImageListRef::Urls(_)) => {
|
||||
Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens))
|
||||
}
|
||||
// Omni-gen distillation hydrates media tokens to URLs before running the
|
||||
// Artcraft cost path. Cost only depends on num_images, so URL-form inputs
|
||||
// are accepted and dropped.
|
||||
Some(ImageListRef::Urls(_)) => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -351,16 +352,16 @@ mod tests {
|
||||
// ── Image inputs ──────────────────────────────────────────────────────────
|
||||
|
||||
#[test]
|
||||
fn url_image_inputs_returns_error() {
|
||||
fn url_image_inputs_are_accepted_for_cost_path() {
|
||||
let urls = vec!["https://example.com/image.jpg".to_string()];
|
||||
let request = GenerateImageRequest {
|
||||
image_inputs: Some(ImageListRef::Urls(&urls)),
|
||||
..base_seedream_4_image_request()
|
||||
};
|
||||
assert!(matches!(
|
||||
request.build(),
|
||||
Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens))
|
||||
));
|
||||
let ImageGenerationPlan::ArtcraftSeedream4(plan) = request.build().unwrap() else {
|
||||
panic!("expected ArtcraftSeedream4")
|
||||
};
|
||||
assert!(plan.image_inputs.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
+1
@@ -7,3 +7,4 @@ mod test_gpt_image_1p5;
|
||||
mod test_nano_banana;
|
||||
mod test_nano_banana_2;
|
||||
mod test_nano_banana_pro;
|
||||
mod test_seedream_4;
|
||||
+613
@@ -0,0 +1,613 @@
|
||||
//! Tests for omni-gen against the Seedream 4 model.
|
||||
//!
|
||||
//! Seedream 4 is multi-function: text-to-image and image-to-image (edit).
|
||||
//!
|
||||
//! Artcraft-tier pricing: flat 3¢/image regardless of size, quality, or mode.
|
||||
//!
|
||||
//! The Fal execution plan maps aspect ratios to Seedream-native image sizes:
|
||||
//! Square, SquareHd, LandscapeFourThree, LandscapeSixteenNine,
|
||||
//! PortraitFourThree, PortraitSixteenNine, Auto, Auto2k, Auto4k.
|
||||
//! Auto in t2i mode falls back to Square; in edit mode it passes through.
|
||||
//! Unsupported ratios (5:4, 3:2, 21:9, 4:5, 2:3, 9:21) fall back under
|
||||
//! PayMoreUpgrade to the nearest 16:9 or 9:16 variant.
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::collections::HashMap;
|
||||
|
||||
use artcraft_api_defs::omni_gen::cost_and_generate_requests::omni_gen_image_cost_and_generate_request::OmniGenImageCostAndGenerateRequest;
|
||||
use enums::common::generation::common_aspect_ratio::CommonAspectRatio;
|
||||
use enums::common::generation::common_image_model::CommonImageModel;
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
use url::Url;
|
||||
|
||||
use crate::http_server::endpoints::omni_gen::generate::image::distill_image_request::{
|
||||
distill_image_request, DistilledImageRequest,
|
||||
};
|
||||
|
||||
// ── Helpers ────────────────────────────────────────────────────────────────
|
||||
|
||||
fn make_request(
|
||||
prompt: Option<&str>,
|
||||
aspect_ratio: Option<CommonAspectRatio>,
|
||||
image_batch_count: Option<u16>,
|
||||
image_media_tokens: Option<Vec<MediaFileToken>>,
|
||||
) -> OmniGenImageCostAndGenerateRequest {
|
||||
OmniGenImageCostAndGenerateRequest {
|
||||
idempotency_token: Some("11111111-1111-1111-1111-111111111111".to_string()),
|
||||
model: Some(CommonImageModel::Seedream4),
|
||||
prompt: prompt.map(|s| s.to_string()),
|
||||
image_media_tokens,
|
||||
resolution: None,
|
||||
aspect_ratio,
|
||||
quality: None,
|
||||
image_batch_count,
|
||||
horizontal_angle: None,
|
||||
vertical_angle: None,
|
||||
zoom: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn fake_image_refs(n: usize) -> (Vec<MediaFileToken>, HashMap<MediaFileToken, Url>) {
|
||||
let mut tokens = Vec::with_capacity(n);
|
||||
let mut map = HashMap::with_capacity(n);
|
||||
for i in 0..n {
|
||||
let token = MediaFileToken::new_from_str(&format!("mf_test{:028}", i));
|
||||
let url = Url::parse(&format!("https://fake.example.com/img{}.png", i)).unwrap();
|
||||
map.insert(token.clone(), url);
|
||||
tokens.push(token);
|
||||
}
|
||||
(tokens, map)
|
||||
}
|
||||
|
||||
fn distill_text(request: &OmniGenImageCostAndGenerateRequest) -> DistilledImageRequest {
|
||||
let empty: HashMap<MediaFileToken, Url> = HashMap::new();
|
||||
distill_image_request(request, Some(&empty))
|
||||
.expect("distill_image_request should succeed for Seedream 4 (text)")
|
||||
}
|
||||
|
||||
fn distill_edit(
|
||||
request: &OmniGenImageCostAndGenerateRequest,
|
||||
hydration: &HashMap<MediaFileToken, Url>,
|
||||
) -> DistilledImageRequest {
|
||||
distill_image_request(request, Some(hydration))
|
||||
.expect("distill_image_request should succeed for Seedream 4 (edit)")
|
||||
}
|
||||
|
||||
// ────────────────────────────────────────────────────────────────────────────
|
||||
// COST — flat 3¢/image
|
||||
// ────────────────────────────────────────────────────────────────────────────
|
||||
mod cost {
|
||||
use super::*;
|
||||
|
||||
mod text {
|
||||
use super::*;
|
||||
|
||||
fn cost_for_batch(batch: Option<u16>) -> u64 {
|
||||
let request = make_request(Some("p"), None, batch, None);
|
||||
distill_text(&request).cost.cost_in_usd_cents.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn default_batch_costs_3_cents() {
|
||||
assert_eq!(cost_for_batch(None), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn batch_of_one_costs_3() { assert_eq!(cost_for_batch(Some(1)), 3); }
|
||||
|
||||
#[test]
|
||||
fn batch_of_two_costs_6() { assert_eq!(cost_for_batch(Some(2)), 6); }
|
||||
|
||||
#[test]
|
||||
fn batch_of_three_costs_9() { assert_eq!(cost_for_batch(Some(3)), 9); }
|
||||
|
||||
#[test]
|
||||
fn batch_of_four_costs_12() { assert_eq!(cost_for_batch(Some(4)), 12); }
|
||||
|
||||
#[test]
|
||||
fn batch_above_max_clamps_to_12() { assert_eq!(cost_for_batch(Some(7)), 12); }
|
||||
|
||||
#[test]
|
||||
fn cost_is_independent_of_aspect_ratio() {
|
||||
let ars = [
|
||||
None,
|
||||
Some(CommonAspectRatio::Square),
|
||||
Some(CommonAspectRatio::SquareHd),
|
||||
Some(CommonAspectRatio::WideSixteenByNine),
|
||||
Some(CommonAspectRatio::WideFourByThree),
|
||||
Some(CommonAspectRatio::TallNineBySixteen),
|
||||
Some(CommonAspectRatio::TallThreeByFour),
|
||||
Some(CommonAspectRatio::Auto),
|
||||
Some(CommonAspectRatio::Auto2k),
|
||||
Some(CommonAspectRatio::Auto4k),
|
||||
];
|
||||
for ar in ars {
|
||||
let request = make_request(Some("p"), ar, Some(2), None);
|
||||
assert_eq!(
|
||||
distill_text(&request).cost.cost_in_usd_cents.unwrap(), 6,
|
||||
"expected 6¢ regardless of aspect ratio {:?}", ar,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cost_is_independent_of_prompt() {
|
||||
let a = distill_text(&make_request(Some("a cat"), None, Some(1), None));
|
||||
let b = distill_text(&make_request(None, None, Some(1), None));
|
||||
assert_eq!(a.cost.cost_in_usd_cents, b.cost.cost_in_usd_cents);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cost_metadata_flags_are_default() {
|
||||
let d = distill_text(&make_request(Some("p"), None, Some(1), None));
|
||||
assert!(!d.cost.is_free);
|
||||
assert!(!d.cost.is_unlimited);
|
||||
assert!(!d.cost.is_rate_limited);
|
||||
assert!(!d.cost.has_watermark);
|
||||
}
|
||||
}
|
||||
|
||||
mod edit {
|
||||
use super::*;
|
||||
|
||||
fn cost_edit(batch: Option<u16>, num_refs: usize) -> u64 {
|
||||
let (tokens, hydration) = fake_image_refs(num_refs);
|
||||
let request = make_request(Some("p"), None, batch, Some(tokens));
|
||||
distill_edit(&request, &hydration).cost.cost_in_usd_cents.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn default_batch_costs_3() { assert_eq!(cost_edit(None, 1), 3); }
|
||||
|
||||
#[test]
|
||||
fn batch_of_one_costs_3() { assert_eq!(cost_edit(Some(1), 1), 3); }
|
||||
|
||||
#[test]
|
||||
fn batch_of_two_costs_6() { assert_eq!(cost_edit(Some(2), 1), 6); }
|
||||
|
||||
#[test]
|
||||
fn batch_of_four_costs_12() { assert_eq!(cost_edit(Some(4), 1), 12); }
|
||||
|
||||
#[test]
|
||||
fn batch_above_max_clamps_to_12() { assert_eq!(cost_edit(Some(9), 1), 12); }
|
||||
|
||||
#[test]
|
||||
fn cost_independent_of_input_image_count() {
|
||||
for num_refs in [1usize, 2, 3, 5] {
|
||||
assert_eq!(cost_edit(Some(2), num_refs), 6, "expected 6¢ regardless of {} input images", num_refs);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn edit_and_text_cost_match() {
|
||||
for batch in [1u16, 2, 3, 4] {
|
||||
let text = distill_text(&make_request(Some("p"), None, Some(batch), None))
|
||||
.cost.cost_in_usd_cents.unwrap();
|
||||
let (tokens, hydration) = fake_image_refs(1);
|
||||
let edit = distill_edit(
|
||||
&make_request(Some("p"), None, Some(batch), Some(tokens)),
|
||||
&hydration,
|
||||
).cost.cost_in_usd_cents.unwrap();
|
||||
assert_eq!(text, edit, "text/edit cost diverged at batch={}", batch);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cost_metadata_flags_are_default() {
|
||||
let (tokens, hydration) = fake_image_refs(1);
|
||||
let d = distill_edit(&make_request(Some("p"), None, Some(1), Some(tokens)), &hydration);
|
||||
assert!(!d.cost.is_free);
|
||||
assert!(!d.cost.is_unlimited);
|
||||
assert!(!d.cost.is_rate_limited);
|
||||
assert!(!d.cost.has_watermark);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ────────────────────────────────────────────────────────────────────────────
|
||||
// PLAN
|
||||
// ────────────────────────────────────────────────────────────────────────────
|
||||
mod plan {
|
||||
use super::*;
|
||||
|
||||
use artcraft_router::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use artcraft_router::generate::generate_image::plan::fal::plan_generate_image_fal_seedream_4::{
|
||||
FalSeedream4ImageSize, FalSeedream4NumImages, PlanFalSeedream4,
|
||||
};
|
||||
|
||||
fn with_text_plan<F: FnOnce(&PlanFalSeedream4<'_>)>(
|
||||
request: &OmniGenImageCostAndGenerateRequest,
|
||||
assertion: F,
|
||||
) {
|
||||
let distilled = distill_text(request);
|
||||
match distilled.plan() {
|
||||
ImageGenerationPlan::FalSeedream4(plan) => assertion(plan),
|
||||
other => panic!("expected FalSeedream4, got {:?}", other),
|
||||
}
|
||||
}
|
||||
|
||||
fn with_edit_plan<F: FnOnce(&PlanFalSeedream4<'_>)>(
|
||||
request: &OmniGenImageCostAndGenerateRequest,
|
||||
hydration: &HashMap<MediaFileToken, Url>,
|
||||
assertion: F,
|
||||
) {
|
||||
let distilled = distill_edit(request, hydration);
|
||||
match distilled.plan() {
|
||||
ImageGenerationPlan::FalSeedream4(plan) => assertion(plan),
|
||||
other => panic!("expected FalSeedream4, got {:?}", other),
|
||||
}
|
||||
}
|
||||
|
||||
mod text {
|
||||
use super::*;
|
||||
|
||||
// ── Mode detection ────────────────────────────────────────────────────
|
||||
|
||||
#[test]
|
||||
fn text_mode_has_empty_image_urls() {
|
||||
with_text_plan(&make_request(Some("p"), None, Some(1), None), |plan| {
|
||||
assert!(plan.image_urls.is_empty());
|
||||
});
|
||||
}
|
||||
|
||||
// ── Image size: direct mappings ───────────────────────────────────────
|
||||
|
||||
#[test]
|
||||
fn default_image_size_is_none() {
|
||||
with_text_plan(&make_request(Some("p"), None, Some(1), None), |plan| {
|
||||
assert!(plan.image_size.is_none());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn square_yields_square() {
|
||||
with_text_plan(&make_request(Some("p"), Some(CommonAspectRatio::Square), Some(1), None), |plan| {
|
||||
assert!(matches!(plan.image_size, Some(FalSeedream4ImageSize::Square)));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn square_hd_yields_square_hd() {
|
||||
with_text_plan(&make_request(Some("p"), Some(CommonAspectRatio::SquareHd), Some(1), None), |plan| {
|
||||
assert!(matches!(plan.image_size, Some(FalSeedream4ImageSize::SquareHd)));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wide_16x9_yields_landscape_sixteen_nine() {
|
||||
with_text_plan(&make_request(Some("p"), Some(CommonAspectRatio::WideSixteenByNine), Some(1), None), |plan| {
|
||||
assert!(matches!(plan.image_size, Some(FalSeedream4ImageSize::LandscapeSixteenNine)));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wide_alias_yields_landscape_sixteen_nine() {
|
||||
with_text_plan(&make_request(Some("p"), Some(CommonAspectRatio::Wide), Some(1), None), |plan| {
|
||||
assert!(matches!(plan.image_size, Some(FalSeedream4ImageSize::LandscapeSixteenNine)));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wide_4x3_yields_landscape_four_three() {
|
||||
with_text_plan(&make_request(Some("p"), Some(CommonAspectRatio::WideFourByThree), Some(1), None), |plan| {
|
||||
assert!(matches!(plan.image_size, Some(FalSeedream4ImageSize::LandscapeFourThree)));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tall_9x16_yields_portrait_sixteen_nine() {
|
||||
with_text_plan(&make_request(Some("p"), Some(CommonAspectRatio::TallNineBySixteen), Some(1), None), |plan| {
|
||||
assert!(matches!(plan.image_size, Some(FalSeedream4ImageSize::PortraitSixteenNine)));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tall_alias_yields_portrait_sixteen_nine() {
|
||||
with_text_plan(&make_request(Some("p"), Some(CommonAspectRatio::Tall), Some(1), None), |plan| {
|
||||
assert!(matches!(plan.image_size, Some(FalSeedream4ImageSize::PortraitSixteenNine)));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tall_3x4_yields_portrait_four_three() {
|
||||
with_text_plan(&make_request(Some("p"), Some(CommonAspectRatio::TallThreeByFour), Some(1), None), |plan| {
|
||||
assert!(matches!(plan.image_size, Some(FalSeedream4ImageSize::PortraitFourThree)));
|
||||
});
|
||||
}
|
||||
|
||||
// ── Image size: Auto variants ─────────────────────────────────────────
|
||||
|
||||
#[test]
|
||||
fn auto_in_text_mode_yields_square() {
|
||||
with_text_plan(&make_request(Some("p"), Some(CommonAspectRatio::Auto), Some(1), None), |plan| {
|
||||
assert!(matches!(plan.image_size, Some(FalSeedream4ImageSize::Square)));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn auto_2k_yields_auto_2k() {
|
||||
with_text_plan(&make_request(Some("p"), Some(CommonAspectRatio::Auto2k), Some(1), None), |plan| {
|
||||
assert!(matches!(plan.image_size, Some(FalSeedream4ImageSize::Auto2k)));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn auto_4k_yields_auto_4k() {
|
||||
with_text_plan(&make_request(Some("p"), Some(CommonAspectRatio::Auto4k), Some(1), None), |plan| {
|
||||
assert!(matches!(plan.image_size, Some(FalSeedream4ImageSize::Auto4k)));
|
||||
});
|
||||
}
|
||||
|
||||
// ── Image size: fallbacks (unsupported → nearest under PayMoreUpgrade)
|
||||
|
||||
#[test]
|
||||
fn wide_5x4_falls_back_to_landscape_sixteen_nine() {
|
||||
with_text_plan(&make_request(Some("p"), Some(CommonAspectRatio::WideFiveByFour), Some(1), None), |plan| {
|
||||
assert!(matches!(plan.image_size, Some(FalSeedream4ImageSize::LandscapeSixteenNine)));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wide_3x2_falls_back_to_landscape_sixteen_nine() {
|
||||
with_text_plan(&make_request(Some("p"), Some(CommonAspectRatio::WideThreeByTwo), Some(1), None), |plan| {
|
||||
assert!(matches!(plan.image_size, Some(FalSeedream4ImageSize::LandscapeSixteenNine)));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wide_21x9_falls_back_to_landscape_sixteen_nine() {
|
||||
with_text_plan(&make_request(Some("p"), Some(CommonAspectRatio::WideTwentyOneByNine), Some(1), None), |plan| {
|
||||
assert!(matches!(plan.image_size, Some(FalSeedream4ImageSize::LandscapeSixteenNine)));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tall_4x5_falls_back_to_portrait_sixteen_nine() {
|
||||
with_text_plan(&make_request(Some("p"), Some(CommonAspectRatio::TallFourByFive), Some(1), None), |plan| {
|
||||
assert!(matches!(plan.image_size, Some(FalSeedream4ImageSize::PortraitSixteenNine)));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tall_2x3_falls_back_to_portrait_sixteen_nine() {
|
||||
with_text_plan(&make_request(Some("p"), Some(CommonAspectRatio::TallTwoByThree), Some(1), None), |plan| {
|
||||
assert!(matches!(plan.image_size, Some(FalSeedream4ImageSize::PortraitSixteenNine)));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tall_9x21_falls_back_to_portrait_sixteen_nine() {
|
||||
with_text_plan(&make_request(Some("p"), Some(CommonAspectRatio::TallNineByTwentyOne), Some(1), None), |plan| {
|
||||
assert!(matches!(plan.image_size, Some(FalSeedream4ImageSize::PortraitSixteenNine)));
|
||||
});
|
||||
}
|
||||
|
||||
// ── Num images ────────────────────────────────────────────────────────
|
||||
|
||||
#[test]
|
||||
fn default_batch_count_is_one() {
|
||||
with_text_plan(&make_request(Some("p"), None, None, None), |plan| {
|
||||
assert!(matches!(plan.num_images, FalSeedream4NumImages::One));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn batch_direct_mapping() {
|
||||
for (count, expected) in [
|
||||
(1u16, FalSeedream4NumImages::One), (2, FalSeedream4NumImages::Two),
|
||||
(3, FalSeedream4NumImages::Three), (4, FalSeedream4NumImages::Four),
|
||||
] {
|
||||
with_text_plan(&make_request(Some("p"), None, Some(count), None), |plan| {
|
||||
assert!(std::mem::discriminant(&plan.num_images) == std::mem::discriminant(&expected));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn batch_above_four_clamps_to_four() {
|
||||
with_text_plan(&make_request(Some("p"), None, Some(9), None), |plan| {
|
||||
assert!(matches!(plan.num_images, FalSeedream4NumImages::Four));
|
||||
});
|
||||
}
|
||||
|
||||
// ── Prompt passthrough ────────────────────────────────────────────────
|
||||
|
||||
#[test]
|
||||
fn prompt_is_passed_through() {
|
||||
with_text_plan(&make_request(Some("a corgi in a hat"), None, Some(1), None), |plan| {
|
||||
assert_eq!(plan.prompt, Some("a corgi in a hat"));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_prompt_is_none() {
|
||||
with_text_plan(&make_request(None, None, Some(1), None), |plan| {
|
||||
assert_eq!(plan.prompt, None);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
mod edit {
|
||||
use super::*;
|
||||
|
||||
// ── Mode detection / image-url passthrough ────────────────────────────
|
||||
|
||||
#[test]
|
||||
fn edit_mode_populates_image_urls() {
|
||||
let (tokens, hydration) = fake_image_refs(1);
|
||||
with_edit_plan(
|
||||
&make_request(Some("p"), None, Some(1), Some(tokens)),
|
||||
&hydration,
|
||||
|plan| {
|
||||
assert_eq!(plan.image_urls.len(), 1);
|
||||
assert!(plan.image_urls[0].starts_with("https://fake.example.com/"));
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn edit_mode_with_three_image_refs() {
|
||||
let (tokens, hydration) = fake_image_refs(3);
|
||||
with_edit_plan(
|
||||
&make_request(Some("p"), None, Some(1), Some(tokens)),
|
||||
&hydration,
|
||||
|plan| { assert_eq!(plan.image_urls.len(), 3); },
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn edit_mode_with_five_image_refs() {
|
||||
let (tokens, hydration) = fake_image_refs(5);
|
||||
with_edit_plan(
|
||||
&make_request(Some("p"), None, Some(1), Some(tokens)),
|
||||
&hydration,
|
||||
|plan| { assert_eq!(plan.image_urls.len(), 5); },
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn edit_image_urls_are_hydrated_from_map() {
|
||||
let (tokens, hydration) = fake_image_refs(3);
|
||||
let expected: Vec<String> = tokens.iter()
|
||||
.map(|t| hydration.get(t).unwrap().to_string())
|
||||
.collect();
|
||||
with_edit_plan(
|
||||
&make_request(Some("p"), None, Some(1), Some(tokens.clone())),
|
||||
&hydration,
|
||||
|plan| { assert_eq!(plan.image_urls, expected); },
|
||||
);
|
||||
}
|
||||
|
||||
// ── Auto in edit mode yields Auto (not Square) ────────────────────────
|
||||
|
||||
#[test]
|
||||
fn auto_in_edit_mode_yields_auto() {
|
||||
let (tokens, hydration) = fake_image_refs(1);
|
||||
with_edit_plan(
|
||||
&make_request(Some("p"), Some(CommonAspectRatio::Auto), Some(1), Some(tokens)),
|
||||
&hydration,
|
||||
|plan| {
|
||||
assert!(matches!(plan.image_size, Some(FalSeedream4ImageSize::Auto)));
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// ── Image size direct mappings in edit mode ───────────────────────────
|
||||
|
||||
#[test]
|
||||
fn edit_default_image_size_is_none() {
|
||||
let (tokens, hydration) = fake_image_refs(1);
|
||||
with_edit_plan(
|
||||
&make_request(Some("p"), None, Some(1), Some(tokens)),
|
||||
&hydration,
|
||||
|plan| { assert!(plan.image_size.is_none()); },
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn edit_square_yields_square() {
|
||||
let (tokens, hydration) = fake_image_refs(1);
|
||||
with_edit_plan(
|
||||
&make_request(Some("p"), Some(CommonAspectRatio::Square), Some(1), Some(tokens)),
|
||||
&hydration,
|
||||
|plan| { assert!(matches!(plan.image_size, Some(FalSeedream4ImageSize::Square))); },
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn edit_wide_16x9_yields_landscape_sixteen_nine() {
|
||||
let (tokens, hydration) = fake_image_refs(1);
|
||||
with_edit_plan(
|
||||
&make_request(Some("p"), Some(CommonAspectRatio::WideSixteenByNine), Some(1), Some(tokens)),
|
||||
&hydration,
|
||||
|plan| { assert!(matches!(plan.image_size, Some(FalSeedream4ImageSize::LandscapeSixteenNine))); },
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn edit_tall_9x16_yields_portrait_sixteen_nine() {
|
||||
let (tokens, hydration) = fake_image_refs(1);
|
||||
with_edit_plan(
|
||||
&make_request(Some("p"), Some(CommonAspectRatio::TallNineBySixteen), Some(1), Some(tokens)),
|
||||
&hydration,
|
||||
|plan| { assert!(matches!(plan.image_size, Some(FalSeedream4ImageSize::PortraitSixteenNine))); },
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn edit_auto_2k() {
|
||||
let (tokens, hydration) = fake_image_refs(1);
|
||||
with_edit_plan(
|
||||
&make_request(Some("p"), Some(CommonAspectRatio::Auto2k), Some(1), Some(tokens)),
|
||||
&hydration,
|
||||
|plan| { assert!(matches!(plan.image_size, Some(FalSeedream4ImageSize::Auto2k))); },
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn edit_auto_4k() {
|
||||
let (tokens, hydration) = fake_image_refs(1);
|
||||
with_edit_plan(
|
||||
&make_request(Some("p"), Some(CommonAspectRatio::Auto4k), Some(1), Some(tokens)),
|
||||
&hydration,
|
||||
|plan| { assert!(matches!(plan.image_size, Some(FalSeedream4ImageSize::Auto4k))); },
|
||||
);
|
||||
}
|
||||
|
||||
// ── Num images in edit mode ───────────────────────────────────────────
|
||||
|
||||
#[test]
|
||||
fn edit_default_batch_count_is_one() {
|
||||
let (tokens, hydration) = fake_image_refs(1);
|
||||
with_edit_plan(
|
||||
&make_request(Some("p"), None, None, Some(tokens)),
|
||||
&hydration,
|
||||
|plan| { assert!(matches!(plan.num_images, FalSeedream4NumImages::One)); },
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn edit_batch_of_four_yields_four() {
|
||||
let (tokens, hydration) = fake_image_refs(1);
|
||||
with_edit_plan(
|
||||
&make_request(Some("p"), None, Some(4), Some(tokens)),
|
||||
&hydration,
|
||||
|plan| { assert!(matches!(plan.num_images, FalSeedream4NumImages::Four)); },
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn edit_batch_above_four_clamps_to_four() {
|
||||
let (tokens, hydration) = fake_image_refs(1);
|
||||
with_edit_plan(
|
||||
&make_request(Some("p"), None, Some(9), Some(tokens)),
|
||||
&hydration,
|
||||
|plan| { assert!(matches!(plan.num_images, FalSeedream4NumImages::Four)); },
|
||||
);
|
||||
}
|
||||
|
||||
// ── Prompt passthrough ────────────────────────────────────────────────
|
||||
|
||||
#[test]
|
||||
fn edit_prompt_is_passed_through() {
|
||||
let (tokens, hydration) = fake_image_refs(1);
|
||||
with_edit_plan(
|
||||
&make_request(Some("make it shiny"), None, Some(1), Some(tokens)),
|
||||
&hydration,
|
||||
|plan| { assert_eq!(plan.prompt, Some("make it shiny")); },
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn edit_missing_prompt_is_none() {
|
||||
let (tokens, hydration) = fake_image_refs(1);
|
||||
with_edit_plan(
|
||||
&make_request(None, None, Some(1), Some(tokens)),
|
||||
&hydration,
|
||||
|plan| { assert_eq!(plan.prompt, None); },
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user