mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-04 01:18:34 +00:00
test cleanup
This commit is contained in:
1 parent
0f669af37c
commit
bf1f53ecaf
4 files changed
+909
-836
No files matched your search
+281
-263
@@ -212,303 +212,300 @@ mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
fn seedance2pro_builder() -> GenerateVideoRequestBuilder {
|
||||
GenerateVideoRequestBuilder {
|
||||
provider: Provider::Seedance2Pro,
|
||||
prompt: Some("a cat dancing".to_string()),
|
||||
duration_seconds: Some(5),
|
||||
video_batch_count: Some(1),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn unwrap_draft(result: Result<VideoGenerationDraftOrRequest, ArtcraftRouterError>) -> KinoviSeedance2p0DraftState {
|
||||
match result.expect("build should succeed") {
|
||||
VideoGenerationDraftOrRequest::Draft(
|
||||
VideoGenerationDraftRequest::KinoviSeedance2p0(draft)
|
||||
) => draft,
|
||||
_ => panic!("expected KinoviSeedance2p0 draft"),
|
||||
}
|
||||
}
|
||||
|
||||
// ── Materialized field conversions ──
|
||||
|
||||
#[test]
|
||||
fn prompt_is_passed_through() {
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(seedance2pro_builder()));
|
||||
assert_eq!(draft.prompt, "a cat dancing");
|
||||
}
|
||||
mod materialized_field_conversions {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn prompt_defaults_to_empty() {
|
||||
let builder = GenerateVideoRequestBuilder { prompt: None, ..seedance2pro_builder() };
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
assert_eq!(draft.prompt, "");
|
||||
}
|
||||
#[test]
|
||||
fn prompt_is_passed_through() {
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(seedance2pro_builder()));
|
||||
assert_eq!(draft.prompt, "a cat dancing");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn duration_seconds_converted() {
|
||||
let builder = GenerateVideoRequestBuilder { duration_seconds: Some(10), ..seedance2pro_builder() };
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
assert_eq!(draft.duration_seconds, 10);
|
||||
}
|
||||
#[test]
|
||||
fn prompt_defaults_to_empty() {
|
||||
let builder = GenerateVideoRequestBuilder { prompt: None, ..seedance2pro_builder() };
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
assert_eq!(draft.prompt, "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn duration_defaults_to_5() {
|
||||
let builder = GenerateVideoRequestBuilder { duration_seconds: None, ..seedance2pro_builder() };
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
assert_eq!(draft.duration_seconds, 5);
|
||||
}
|
||||
#[test]
|
||||
fn duration_seconds_converted() {
|
||||
let builder = GenerateVideoRequestBuilder { duration_seconds: Some(10), ..seedance2pro_builder() };
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
assert_eq!(draft.duration_seconds, 10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn duration_clamped_to_max() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
duration_seconds: Some(99),
|
||||
..seedance2pro_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
assert_eq!(draft.duration_seconds, 15);
|
||||
}
|
||||
#[test]
|
||||
fn duration_defaults_to_5() {
|
||||
let builder = GenerateVideoRequestBuilder { duration_seconds: None, ..seedance2pro_builder() };
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
assert_eq!(draft.duration_seconds, 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn batch_count_one() {
|
||||
let builder = GenerateVideoRequestBuilder { video_batch_count: Some(1), ..seedance2pro_builder() };
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
assert!(matches!(draft.batch_count, KinoviBatchCount::One));
|
||||
}
|
||||
#[test]
|
||||
fn duration_clamped_to_max() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
duration_seconds: Some(99),
|
||||
..seedance2pro_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
assert_eq!(draft.duration_seconds, 15);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn batch_count_two() {
|
||||
let builder = GenerateVideoRequestBuilder { video_batch_count: Some(2), ..seedance2pro_builder() };
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
assert!(matches!(draft.batch_count, KinoviBatchCount::Two));
|
||||
}
|
||||
#[test]
|
||||
fn batch_count_one() {
|
||||
let builder = GenerateVideoRequestBuilder { video_batch_count: Some(1), ..seedance2pro_builder() };
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
assert!(matches!(draft.batch_count, KinoviBatchCount::One));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn batch_count_four() {
|
||||
let builder = GenerateVideoRequestBuilder { video_batch_count: Some(4), ..seedance2pro_builder() };
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
assert!(matches!(draft.batch_count, KinoviBatchCount::Four));
|
||||
#[test]
|
||||
fn batch_count_two() {
|
||||
let builder = GenerateVideoRequestBuilder { video_batch_count: Some(2), ..seedance2pro_builder() };
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
assert!(matches!(draft.batch_count, KinoviBatchCount::Two));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn batch_count_four() {
|
||||
let builder = GenerateVideoRequestBuilder { video_batch_count: Some(4), ..seedance2pro_builder() };
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
assert!(matches!(draft.batch_count, KinoviBatchCount::Four));
|
||||
}
|
||||
}
|
||||
|
||||
// ── Aspect ratio conversions ──
|
||||
|
||||
#[test]
|
||||
fn aspect_ratio_wide() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::WideSixteenByNine),
|
||||
..seedance2pro_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
assert!(matches!(draft.aspect_ratio, KinoviAspectRatio::Landscape16x9));
|
||||
}
|
||||
mod aspect_ratio_conversions {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn aspect_ratio_tall() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::TallNineBySixteen),
|
||||
..seedance2pro_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
assert!(matches!(draft.aspect_ratio, KinoviAspectRatio::Portrait9x16));
|
||||
}
|
||||
#[test]
|
||||
fn aspect_ratio_wide() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::WideSixteenByNine),
|
||||
..seedance2pro_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
assert!(matches!(draft.aspect_ratio, KinoviAspectRatio::Landscape16x9));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn aspect_ratio_square() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::Square),
|
||||
..seedance2pro_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
assert!(matches!(draft.aspect_ratio, KinoviAspectRatio::Square1x1));
|
||||
}
|
||||
#[test]
|
||||
fn aspect_ratio_tall() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::TallNineBySixteen),
|
||||
..seedance2pro_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
assert!(matches!(draft.aspect_ratio, KinoviAspectRatio::Portrait9x16));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn aspect_ratio_defaults_to_landscape() {
|
||||
let builder = GenerateVideoRequestBuilder { aspect_ratio: None, ..seedance2pro_builder() };
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
assert!(matches!(draft.aspect_ratio, KinoviAspectRatio::Landscape16x9));
|
||||
#[test]
|
||||
fn aspect_ratio_square() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::Square),
|
||||
..seedance2pro_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
assert!(matches!(draft.aspect_ratio, KinoviAspectRatio::Square1x1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn aspect_ratio_defaults_to_landscape() {
|
||||
let builder = GenerateVideoRequestBuilder { aspect_ratio: None, ..seedance2pro_builder() };
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
assert!(matches!(draft.aspect_ratio, KinoviAspectRatio::Landscape16x9));
|
||||
}
|
||||
}
|
||||
|
||||
// ── Resolution conversions ──
|
||||
|
||||
#[test]
|
||||
fn resolution_480p() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
resolution: Some(CommonResolution::FourEightyP),
|
||||
..seedance2pro_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
assert!(matches!(draft.resolution, Some(KinoviOutputResolution::FourEightyP)));
|
||||
}
|
||||
mod resolution_conversions {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn resolution_720p() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
resolution: Some(CommonResolution::SevenTwentyP),
|
||||
..seedance2pro_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
assert!(matches!(draft.resolution, Some(KinoviOutputResolution::SevenTwentyP)));
|
||||
}
|
||||
#[test]
|
||||
fn resolution_480p() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
resolution: Some(CommonResolution::FourEightyP),
|
||||
..seedance2pro_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
assert!(matches!(draft.resolution, Some(KinoviOutputResolution::FourEightyP)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolution_1080p() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
resolution: Some(CommonResolution::TenEightyP),
|
||||
..seedance2pro_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
assert!(matches!(draft.resolution, Some(KinoviOutputResolution::TenEightyP)));
|
||||
}
|
||||
#[test]
|
||||
fn resolution_720p() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
resolution: Some(CommonResolution::SevenTwentyP),
|
||||
..seedance2pro_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
assert!(matches!(draft.resolution, Some(KinoviOutputResolution::SevenTwentyP)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolution_none() {
|
||||
let builder = GenerateVideoRequestBuilder { resolution: None, ..seedance2pro_builder() };
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
assert!(draft.resolution.is_none());
|
||||
}
|
||||
#[test]
|
||||
fn resolution_1080p() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
resolution: Some(CommonResolution::TenEightyP),
|
||||
..seedance2pro_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
assert!(matches!(draft.resolution, Some(KinoviOutputResolution::TenEightyP)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unsupported_resolution_error_out() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
resolution: Some(CommonResolution::FourK),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
|
||||
..seedance2pro_builder()
|
||||
};
|
||||
assert!(build_kinovi_seedance_2p0(builder).is_err());
|
||||
}
|
||||
#[test]
|
||||
fn resolution_none() {
|
||||
let builder = GenerateVideoRequestBuilder { resolution: None, ..seedance2pro_builder() };
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
assert!(draft.resolution.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unsupported_resolution_rounds_up() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
resolution: Some(CommonResolution::FourK),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
..seedance2pro_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
assert!(matches!(draft.resolution, Some(KinoviOutputResolution::TenEightyP)));
|
||||
#[test]
|
||||
fn unsupported_resolution_error_out() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
resolution: Some(CommonResolution::FourK),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
|
||||
..seedance2pro_builder()
|
||||
};
|
||||
assert!(build_kinovi_seedance_2p0(builder).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unsupported_resolution_rounds_up() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
resolution: Some(CommonResolution::FourK),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
..seedance2pro_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
assert!(matches!(draft.resolution, Some(KinoviOutputResolution::TenEightyP)));
|
||||
}
|
||||
}
|
||||
|
||||
// ── unhandled_request_state: media refs are placed there ──
|
||||
|
||||
#[test]
|
||||
fn unhandled_state_is_present() {
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(seedance2pro_builder()));
|
||||
assert!(draft.unhandled_request_state.is_some());
|
||||
}
|
||||
mod unhandled_request_state {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn start_frame_placed_in_unhandled() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
start_frame: Some(ImageRef::Url("https://example.com/start.jpg".to_string())),
|
||||
..seedance2pro_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
let remaining = draft.unhandled_request_state.unwrap();
|
||||
assert!(matches!(remaining.start_frame, Some(ImageRef::Url(url)) if url == "https://example.com/start.jpg"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn end_frame_placed_in_unhandled() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
end_frame: Some(ImageRef::Url("https://example.com/end.jpg".to_string())),
|
||||
..seedance2pro_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
let remaining = draft.unhandled_request_state.unwrap();
|
||||
assert!(matches!(remaining.end_frame, Some(ImageRef::Url(url)) if url == "https://example.com/end.jpg"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn start_frame_media_token_placed_in_unhandled() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
start_frame: Some(ImageRef::MediaFileToken(MediaFileToken::new("mf_test123".to_string()))),
|
||||
..seedance2pro_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
let remaining = draft.unhandled_request_state.unwrap();
|
||||
assert!(matches!(remaining.start_frame, Some(ImageRef::MediaFileToken(t)) if t.as_str() == "mf_test123"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reference_images_placed_in_unhandled() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
reference_images: Some(ImageListRef::Urls(vec![
|
||||
"https://example.com/ref1.jpg".to_string(),
|
||||
"https://example.com/ref2.jpg".to_string(),
|
||||
])),
|
||||
..seedance2pro_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
let remaining = draft.unhandled_request_state.unwrap();
|
||||
match remaining.reference_images {
|
||||
Some(ImageListRef::Urls(urls)) => {
|
||||
assert_eq!(urls.len(), 2);
|
||||
assert_eq!(urls[0], "https://example.com/ref1.jpg");
|
||||
assert_eq!(urls[1], "https://example.com/ref2.jpg");
|
||||
}
|
||||
_ => panic!("expected Urls variant"),
|
||||
#[test]
|
||||
fn unhandled_state_is_present() {
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(seedance2pro_builder()));
|
||||
assert!(draft.unhandled_request_state.is_some());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reference_videos_placed_in_unhandled() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
reference_videos: Some(VideoListRef::Urls(vec![
|
||||
"https://example.com/vid.mp4".to_string(),
|
||||
])),
|
||||
..seedance2pro_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
let remaining = draft.unhandled_request_state.unwrap();
|
||||
assert!(matches!(remaining.reference_videos, Some(VideoListRef::Urls(urls)) if urls.len() == 1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reference_audio_placed_in_unhandled() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
reference_audio: Some(AudioListRef::Urls(vec![
|
||||
"https://example.com/audio.mp3".to_string(),
|
||||
])),
|
||||
..seedance2pro_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
let remaining = draft.unhandled_request_state.unwrap();
|
||||
assert!(matches!(remaining.reference_audio, Some(AudioListRef::Urls(urls)) if urls.len() == 1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn character_tokens_placed_in_unhandled() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
reference_character_tokens: Some(CharacterListRef::CharacterTokens(vec![
|
||||
CharacterToken::new("char_abc".to_string()),
|
||||
CharacterToken::new("char_def".to_string()),
|
||||
])),
|
||||
..seedance2pro_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
let remaining = draft.unhandled_request_state.unwrap();
|
||||
match remaining.reference_character_tokens {
|
||||
Some(CharacterListRef::CharacterTokens(tokens)) => {
|
||||
assert_eq!(tokens.len(), 2);
|
||||
assert_eq!(tokens[0].as_str(), "char_abc");
|
||||
assert_eq!(tokens[1].as_str(), "char_def");
|
||||
}
|
||||
_ => panic!("expected CharacterTokens variant"),
|
||||
#[test]
|
||||
fn start_frame_placed_in_unhandled() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
start_frame: Some(ImageRef::Url("https://example.com/start.jpg".to_string())),
|
||||
..seedance2pro_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
let remaining = draft.unhandled_request_state.unwrap();
|
||||
assert!(matches!(remaining.start_frame, Some(ImageRef::Url(url)) if url == "https://example.com/start.jpg"));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_refs_are_none_in_unhandled() {
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(seedance2pro_builder()));
|
||||
let remaining = draft.unhandled_request_state.unwrap();
|
||||
assert!(remaining.start_frame.is_none());
|
||||
assert!(remaining.end_frame.is_none());
|
||||
assert!(remaining.reference_images.is_none());
|
||||
assert!(remaining.reference_videos.is_none());
|
||||
assert!(remaining.reference_audio.is_none());
|
||||
assert!(remaining.reference_character_tokens.is_none());
|
||||
#[test]
|
||||
fn end_frame_placed_in_unhandled() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
end_frame: Some(ImageRef::Url("https://example.com/end.jpg".to_string())),
|
||||
..seedance2pro_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
let remaining = draft.unhandled_request_state.unwrap();
|
||||
assert!(matches!(remaining.end_frame, Some(ImageRef::Url(url)) if url == "https://example.com/end.jpg"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn start_frame_media_token_placed_in_unhandled() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
start_frame: Some(ImageRef::MediaFileToken(MediaFileToken::new("mf_test123".to_string()))),
|
||||
..seedance2pro_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
let remaining = draft.unhandled_request_state.unwrap();
|
||||
assert!(matches!(remaining.start_frame, Some(ImageRef::MediaFileToken(t)) if t.as_str() == "mf_test123"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reference_images_placed_in_unhandled() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
reference_images: Some(ImageListRef::Urls(vec![
|
||||
"https://example.com/ref1.jpg".to_string(),
|
||||
"https://example.com/ref2.jpg".to_string(),
|
||||
])),
|
||||
..seedance2pro_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
let remaining = draft.unhandled_request_state.unwrap();
|
||||
match remaining.reference_images {
|
||||
Some(ImageListRef::Urls(urls)) => {
|
||||
assert_eq!(urls.len(), 2);
|
||||
assert_eq!(urls[0], "https://example.com/ref1.jpg");
|
||||
assert_eq!(urls[1], "https://example.com/ref2.jpg");
|
||||
}
|
||||
_ => panic!("expected Urls variant"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reference_videos_placed_in_unhandled() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
reference_videos: Some(VideoListRef::Urls(vec![
|
||||
"https://example.com/vid.mp4".to_string(),
|
||||
])),
|
||||
..seedance2pro_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
let remaining = draft.unhandled_request_state.unwrap();
|
||||
assert!(matches!(remaining.reference_videos, Some(VideoListRef::Urls(urls)) if urls.len() == 1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reference_audio_placed_in_unhandled() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
reference_audio: Some(AudioListRef::Urls(vec![
|
||||
"https://example.com/audio.mp3".to_string(),
|
||||
])),
|
||||
..seedance2pro_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
let remaining = draft.unhandled_request_state.unwrap();
|
||||
assert!(matches!(remaining.reference_audio, Some(AudioListRef::Urls(urls)) if urls.len() == 1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn character_tokens_placed_in_unhandled() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
reference_character_tokens: Some(CharacterListRef::CharacterTokens(vec![
|
||||
CharacterToken::new("char_abc".to_string()),
|
||||
CharacterToken::new("char_def".to_string()),
|
||||
])),
|
||||
..seedance2pro_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(builder));
|
||||
let remaining = draft.unhandled_request_state.unwrap();
|
||||
match remaining.reference_character_tokens {
|
||||
Some(CharacterListRef::CharacterTokens(tokens)) => {
|
||||
assert_eq!(tokens.len(), 2);
|
||||
assert_eq!(tokens[0].as_str(), "char_abc");
|
||||
assert_eq!(tokens[1].as_str(), "char_def");
|
||||
}
|
||||
_ => panic!("expected CharacterTokens variant"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_refs_are_none_in_unhandled() {
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0(seedance2pro_builder()));
|
||||
let remaining = draft.unhandled_request_state.unwrap();
|
||||
assert!(remaining.start_frame.is_none());
|
||||
assert!(remaining.end_frame.is_none());
|
||||
assert!(remaining.reference_images.is_none());
|
||||
assert!(remaining.reference_videos.is_none());
|
||||
assert!(remaining.reference_audio.is_none());
|
||||
assert!(remaining.reference_character_tokens.is_none());
|
||||
}
|
||||
}
|
||||
|
||||
// ── Full combination ──
|
||||
@@ -547,4 +544,25 @@ mod tests {
|
||||
assert!(remaining.reference_audio.is_some());
|
||||
assert!(remaining.reference_character_tokens.is_some());
|
||||
}
|
||||
|
||||
// ── Helpers ──
|
||||
|
||||
fn seedance2pro_builder() -> GenerateVideoRequestBuilder {
|
||||
GenerateVideoRequestBuilder {
|
||||
provider: Provider::Seedance2Pro,
|
||||
prompt: Some("a cat dancing".to_string()),
|
||||
duration_seconds: Some(5),
|
||||
video_batch_count: Some(1),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn unwrap_draft(result: Result<VideoGenerationDraftOrRequest, ArtcraftRouterError>) -> KinoviSeedance2p0DraftState {
|
||||
match result.expect("build should succeed") {
|
||||
VideoGenerationDraftOrRequest::Draft(
|
||||
VideoGenerationDraftRequest::KinoviSeedance2p0(draft)
|
||||
) => draft,
|
||||
_ => panic!("expected KinoviSeedance2p0 draft"),
|
||||
}
|
||||
}
|
||||
}
|
||||
+290
-261
@@ -84,7 +84,296 @@ mod tests {
|
||||
use crate::api::video_list_ref::VideoListRef;
|
||||
use crate::generate::generate_video::generate_video_request_builder::GenerateVideoRequestBuilder;
|
||||
|
||||
// ======================== Helpers ========================
|
||||
// ── 720p pricing ──
|
||||
|
||||
mod pricing_720p {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn cost_720p_batch_1() {
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::SevenTwentyP, 4, KinoviBatchCount::One), 64);
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::SevenTwentyP, 5, KinoviBatchCount::One), 80);
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::SevenTwentyP, 6, KinoviBatchCount::One), 96);
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::SevenTwentyP, 7, KinoviBatchCount::One), 112);
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::SevenTwentyP, 10, KinoviBatchCount::One), 160);
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::SevenTwentyP, 15, KinoviBatchCount::One), 240);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cost_720p_batch_2() {
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::SevenTwentyP, 4, KinoviBatchCount::Two), 128);
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::SevenTwentyP, 5, KinoviBatchCount::Two), 160);
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::SevenTwentyP, 15, KinoviBatchCount::Two), 480);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cost_720p_batch_4() {
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::SevenTwentyP, 4, KinoviBatchCount::Four), 256);
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::SevenTwentyP, 5, KinoviBatchCount::Four), 320);
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::SevenTwentyP, 15, KinoviBatchCount::Four), 960);
|
||||
}
|
||||
}
|
||||
|
||||
// ── 480p pricing ──
|
||||
|
||||
mod pricing_480p {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn cost_480p_batch_1() {
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::FourEightyP, 4, KinoviBatchCount::One), 31);
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::FourEightyP, 5, KinoviBatchCount::One), 39);
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::FourEightyP, 10, KinoviBatchCount::One), 78);
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::FourEightyP, 15, KinoviBatchCount::One), 117);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cost_480p_batch_2() {
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::FourEightyP, 5, KinoviBatchCount::Two), 78);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cost_480p_batch_4() {
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::FourEightyP, 5, KinoviBatchCount::Four), 155);
|
||||
}
|
||||
}
|
||||
|
||||
// ── 1080p pricing ──
|
||||
|
||||
mod pricing_1080p {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn cost_1080p_batch_1() {
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::TenEightyP, 4, KinoviBatchCount::One), 187);
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::TenEightyP, 5, KinoviBatchCount::One), 233);
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::TenEightyP, 10, KinoviBatchCount::One), 466);
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::TenEightyP, 15, KinoviBatchCount::One), 699);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cost_1080p_batch_2() {
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::TenEightyP, 5, KinoviBatchCount::Two), 466);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cost_1080p_batch_4() {
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::TenEightyP, 5, KinoviBatchCount::Four), 933);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Relative pricing ──
|
||||
|
||||
mod relative_pricing_tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn cost_480p_cheaper_than_720p_cheaper_than_1080p() {
|
||||
let c480 = usd_cents(KinoviOutputResolution::FourEightyP, 5, KinoviBatchCount::One);
|
||||
let c720 = usd_cents(KinoviOutputResolution::SevenTwentyP, 5, KinoviBatchCount::One);
|
||||
let c1080 = usd_cents(KinoviOutputResolution::TenEightyP, 5, KinoviBatchCount::One);
|
||||
assert!(c480 < c720, "480p ({}) should be cheaper than 720p ({})", c480, c720);
|
||||
assert!(c720 < c1080, "720p ({}) should be cheaper than 1080p ({})", c720, c1080);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cost_scales_with_duration() {
|
||||
let c4 = usd_cents(KinoviOutputResolution::SevenTwentyP, 4, KinoviBatchCount::One);
|
||||
let c10 = usd_cents(KinoviOutputResolution::SevenTwentyP, 10, KinoviBatchCount::One);
|
||||
let c15 = usd_cents(KinoviOutputResolution::SevenTwentyP, 15, KinoviBatchCount::One);
|
||||
assert!(c4 < c10);
|
||||
assert!(c10 < c15);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cost_scales_with_batch() {
|
||||
let b1 = usd_cents(KinoviOutputResolution::TenEightyP, 5, KinoviBatchCount::One);
|
||||
let b2 = usd_cents(KinoviOutputResolution::TenEightyP, 5, KinoviBatchCount::Two);
|
||||
let b4 = usd_cents(KinoviOutputResolution::TenEightyP, 5, KinoviBatchCount::Four);
|
||||
assert!(b1 < b2);
|
||||
assert!(b2 < b4);
|
||||
}
|
||||
}
|
||||
|
||||
// -- Video reference does NOT affect cost (yet) --
|
||||
|
||||
#[test]
|
||||
fn video_reference_does_not_affect_cost() {
|
||||
let base = KinoviSeedance2p0CostState {
|
||||
resolution: KinoviOutputResolution::SevenTwentyP,
|
||||
duration_seconds: 5,
|
||||
batch_count: KinoviBatchCount::One,
|
||||
has_video_reference: false,
|
||||
};
|
||||
let without = base.estimate_cost();
|
||||
let with = KinoviSeedance2p0CostState { has_video_reference: true, ..base }.estimate_cost();
|
||||
assert_eq!(without.cost_in_usd_cents, with.cost_in_usd_cents);
|
||||
assert_eq!(without.cost_in_credits, with.cost_in_credits);
|
||||
}
|
||||
|
||||
// ── from_request() tests ──
|
||||
|
||||
mod from_request_tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn from_request_720p() {
|
||||
let req = make_request_state(Some(KinoviOutputResolution::SevenTwentyP), 5, KinoviBatchCount::One, false);
|
||||
let cost = KinoviSeedance2p0CostState::from_request(&req);
|
||||
assert!(matches!(cost.resolution, KinoviOutputResolution::SevenTwentyP));
|
||||
assert_eq!(cost.duration_seconds, 5);
|
||||
assert!(matches!(cost.batch_count, KinoviBatchCount::One));
|
||||
assert!(!cost.has_video_reference);
|
||||
assert_eq!(cost.estimate_cost().cost_in_usd_cents, Some(80));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_request_none_defaults_to_720p() {
|
||||
let req = make_request_state(None, 5, KinoviBatchCount::One, false);
|
||||
let cost = KinoviSeedance2p0CostState::from_request(&req);
|
||||
assert!(matches!(cost.resolution, KinoviOutputResolution::SevenTwentyP));
|
||||
assert_eq!(cost.estimate_cost().cost_in_usd_cents, Some(80));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_request_480p() {
|
||||
let req = make_request_state(Some(KinoviOutputResolution::FourEightyP), 5, KinoviBatchCount::One, false);
|
||||
let cost = KinoviSeedance2p0CostState::from_request(&req);
|
||||
assert_eq!(cost.estimate_cost().cost_in_usd_cents, Some(39));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_request_1080p_batch_2() {
|
||||
let req = make_request_state(Some(KinoviOutputResolution::TenEightyP), 5, KinoviBatchCount::Two, false);
|
||||
let cost = KinoviSeedance2p0CostState::from_request(&req);
|
||||
assert_eq!(cost.estimate_cost().cost_in_usd_cents, Some(466));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_request_with_video_reference() {
|
||||
let req = make_request_state(Some(KinoviOutputResolution::SevenTwentyP), 5, KinoviBatchCount::One, true);
|
||||
let cost = KinoviSeedance2p0CostState::from_request(&req);
|
||||
assert!(cost.has_video_reference);
|
||||
// Video refs don't affect cost yet
|
||||
assert_eq!(cost.estimate_cost().cost_in_usd_cents, Some(80));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_request_without_video_reference() {
|
||||
let req = make_request_state(Some(KinoviOutputResolution::SevenTwentyP), 5, KinoviBatchCount::One, false);
|
||||
let cost = KinoviSeedance2p0CostState::from_request(&req);
|
||||
assert!(!cost.has_video_reference);
|
||||
}
|
||||
}
|
||||
|
||||
// ── from_draft() tests ──
|
||||
|
||||
mod from_draft_tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn from_draft_720p_default() {
|
||||
let draft = make_draft(5, 1, None, false);
|
||||
let cost = KinoviSeedance2p0CostState::from_draft(&draft);
|
||||
assert!(matches!(cost.resolution, KinoviOutputResolution::SevenTwentyP));
|
||||
assert_eq!(cost.duration_seconds, 5);
|
||||
assert!(matches!(cost.batch_count, KinoviBatchCount::One));
|
||||
assert!(!cost.has_video_reference);
|
||||
assert_eq!(cost.estimate_cost().cost_in_usd_cents, Some(80));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_draft_480p() {
|
||||
let draft = make_draft(5, 1, Some(CommonResolution::FourEightyP), false);
|
||||
let cost = KinoviSeedance2p0CostState::from_draft(&draft);
|
||||
assert!(matches!(cost.resolution, KinoviOutputResolution::FourEightyP));
|
||||
assert_eq!(cost.estimate_cost().cost_in_usd_cents, Some(39));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_draft_1080p_batch_4() {
|
||||
let draft = make_draft(5, 4, Some(CommonResolution::TenEightyP), false);
|
||||
let cost = KinoviSeedance2p0CostState::from_draft(&draft);
|
||||
assert!(matches!(cost.resolution, KinoviOutputResolution::TenEightyP));
|
||||
assert!(matches!(cost.batch_count, KinoviBatchCount::Four));
|
||||
assert_eq!(cost.estimate_cost().cost_in_usd_cents, Some(933));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_draft_with_video_reference() {
|
||||
let draft = make_draft(5, 1, None, true);
|
||||
let cost = KinoviSeedance2p0CostState::from_draft(&draft);
|
||||
assert!(cost.has_video_reference);
|
||||
// Video refs don't affect cost yet
|
||||
assert_eq!(cost.estimate_cost().cost_in_usd_cents, Some(80));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_draft_without_video_reference() {
|
||||
let draft = make_draft(5, 1, None, false);
|
||||
let cost = KinoviSeedance2p0CostState::from_draft(&draft);
|
||||
assert!(!cost.has_video_reference);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_draft_duration_15_batch_2() {
|
||||
let draft = make_draft(15, 2, Some(CommonResolution::SevenTwentyP), false);
|
||||
let cost = KinoviSeedance2p0CostState::from_draft(&draft);
|
||||
assert_eq!(cost.duration_seconds, 15);
|
||||
assert!(matches!(cost.batch_count, KinoviBatchCount::Two));
|
||||
assert_eq!(cost.estimate_cost().cost_in_usd_cents, Some(480));
|
||||
}
|
||||
}
|
||||
|
||||
// ── Cross-check: from_draft matches from_request ──
|
||||
|
||||
mod cross_check_tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn draft_and_request_produce_same_cost() {
|
||||
// 720p, 5s, batch 1
|
||||
let draft = make_draft(5, 1, Some(CommonResolution::SevenTwentyP), false);
|
||||
let req = make_request_state(Some(KinoviOutputResolution::SevenTwentyP), 5, KinoviBatchCount::One, false);
|
||||
let draft_cost = KinoviSeedance2p0CostState::from_draft(&draft).estimate_cost();
|
||||
let req_cost = KinoviSeedance2p0CostState::from_request(&req).estimate_cost();
|
||||
assert_eq!(draft_cost.cost_in_usd_cents, req_cost.cost_in_usd_cents);
|
||||
assert_eq!(draft_cost.cost_in_credits, req_cost.cost_in_credits);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn draft_and_request_produce_same_cost_1080p() {
|
||||
let draft = make_draft(10, 2, Some(CommonResolution::TenEightyP), false);
|
||||
let req = make_request_state(Some(KinoviOutputResolution::TenEightyP), 10, KinoviBatchCount::Two, false);
|
||||
let draft_cost = KinoviSeedance2p0CostState::from_draft(&draft).estimate_cost();
|
||||
let req_cost = KinoviSeedance2p0CostState::from_request(&req).estimate_cost();
|
||||
assert_eq!(draft_cost.cost_in_usd_cents, req_cost.cost_in_usd_cents);
|
||||
assert_eq!(draft_cost.cost_in_credits, req_cost.cost_in_credits);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Credits spot checks ──
|
||||
|
||||
mod credits_tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn credits_720p() {
|
||||
assert_eq!(credits(KinoviOutputResolution::SevenTwentyP, 5, KinoviBatchCount::One), 200);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn credits_480p() {
|
||||
assert_eq!(credits(KinoviOutputResolution::FourEightyP, 5, KinoviBatchCount::One), 75);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn credits_1080p() {
|
||||
assert_eq!(credits(KinoviOutputResolution::TenEightyP, 5, KinoviBatchCount::One), 450);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Helpers ──
|
||||
|
||||
fn usd_cents(
|
||||
resolution: KinoviOutputResolution,
|
||||
@@ -169,264 +458,4 @@ mod tests {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// ======================== Direct estimate_cost() tests ========================
|
||||
// These must match the reference implementation values exactly.
|
||||
|
||||
// -- 720p (legacy pricing: 250 credits/$1, 40 credits/sec) --
|
||||
|
||||
#[test]
|
||||
fn cost_720p_batch_1() {
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::SevenTwentyP, 4, KinoviBatchCount::One), 64);
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::SevenTwentyP, 5, KinoviBatchCount::One), 80);
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::SevenTwentyP, 6, KinoviBatchCount::One), 96);
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::SevenTwentyP, 7, KinoviBatchCount::One), 112);
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::SevenTwentyP, 10, KinoviBatchCount::One), 160);
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::SevenTwentyP, 15, KinoviBatchCount::One), 240);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cost_720p_batch_2() {
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::SevenTwentyP, 4, KinoviBatchCount::Two), 128);
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::SevenTwentyP, 5, KinoviBatchCount::Two), 160);
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::SevenTwentyP, 15, KinoviBatchCount::Two), 480);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cost_720p_batch_4() {
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::SevenTwentyP, 4, KinoviBatchCount::Four), 256);
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::SevenTwentyP, 5, KinoviBatchCount::Four), 320);
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::SevenTwentyP, 15, KinoviBatchCount::Four), 960);
|
||||
}
|
||||
|
||||
// -- 480p (new pricing: 193 credits/$1, 15 credits/sec) --
|
||||
|
||||
#[test]
|
||||
fn cost_480p_batch_1() {
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::FourEightyP, 4, KinoviBatchCount::One), 31);
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::FourEightyP, 5, KinoviBatchCount::One), 39);
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::FourEightyP, 10, KinoviBatchCount::One), 78);
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::FourEightyP, 15, KinoviBatchCount::One), 117);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cost_480p_batch_2() {
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::FourEightyP, 5, KinoviBatchCount::Two), 78);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cost_480p_batch_4() {
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::FourEightyP, 5, KinoviBatchCount::Four), 155);
|
||||
}
|
||||
|
||||
// -- 1080p (new pricing: 193 credits/$1, 90 credits/sec) --
|
||||
|
||||
#[test]
|
||||
fn cost_1080p_batch_1() {
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::TenEightyP, 4, KinoviBatchCount::One), 187);
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::TenEightyP, 5, KinoviBatchCount::One), 233);
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::TenEightyP, 10, KinoviBatchCount::One), 466);
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::TenEightyP, 15, KinoviBatchCount::One), 699);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cost_1080p_batch_2() {
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::TenEightyP, 5, KinoviBatchCount::Two), 466);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cost_1080p_batch_4() {
|
||||
assert_eq!(usd_cents(KinoviOutputResolution::TenEightyP, 5, KinoviBatchCount::Four), 933);
|
||||
}
|
||||
|
||||
// -- Relative pricing --
|
||||
|
||||
#[test]
|
||||
fn cost_480p_cheaper_than_720p_cheaper_than_1080p() {
|
||||
let c480 = usd_cents(KinoviOutputResolution::FourEightyP, 5, KinoviBatchCount::One);
|
||||
let c720 = usd_cents(KinoviOutputResolution::SevenTwentyP, 5, KinoviBatchCount::One);
|
||||
let c1080 = usd_cents(KinoviOutputResolution::TenEightyP, 5, KinoviBatchCount::One);
|
||||
assert!(c480 < c720, "480p ({}) should be cheaper than 720p ({})", c480, c720);
|
||||
assert!(c720 < c1080, "720p ({}) should be cheaper than 1080p ({})", c720, c1080);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cost_scales_with_duration() {
|
||||
let c4 = usd_cents(KinoviOutputResolution::SevenTwentyP, 4, KinoviBatchCount::One);
|
||||
let c10 = usd_cents(KinoviOutputResolution::SevenTwentyP, 10, KinoviBatchCount::One);
|
||||
let c15 = usd_cents(KinoviOutputResolution::SevenTwentyP, 15, KinoviBatchCount::One);
|
||||
assert!(c4 < c10);
|
||||
assert!(c10 < c15);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cost_scales_with_batch() {
|
||||
let b1 = usd_cents(KinoviOutputResolution::TenEightyP, 5, KinoviBatchCount::One);
|
||||
let b2 = usd_cents(KinoviOutputResolution::TenEightyP, 5, KinoviBatchCount::Two);
|
||||
let b4 = usd_cents(KinoviOutputResolution::TenEightyP, 5, KinoviBatchCount::Four);
|
||||
assert!(b1 < b2);
|
||||
assert!(b2 < b4);
|
||||
}
|
||||
|
||||
// -- Video reference does NOT affect cost (yet) --
|
||||
|
||||
#[test]
|
||||
fn video_reference_does_not_affect_cost() {
|
||||
let base = KinoviSeedance2p0CostState {
|
||||
resolution: KinoviOutputResolution::SevenTwentyP,
|
||||
duration_seconds: 5,
|
||||
batch_count: KinoviBatchCount::One,
|
||||
has_video_reference: false,
|
||||
};
|
||||
let without = base.estimate_cost();
|
||||
let with = KinoviSeedance2p0CostState { has_video_reference: true, ..base }.estimate_cost();
|
||||
assert_eq!(without.cost_in_usd_cents, with.cost_in_usd_cents);
|
||||
assert_eq!(without.cost_in_credits, with.cost_in_credits);
|
||||
}
|
||||
|
||||
// ======================== from_request() tests ========================
|
||||
|
||||
#[test]
|
||||
fn from_request_720p() {
|
||||
let req = make_request_state(Some(KinoviOutputResolution::SevenTwentyP), 5, KinoviBatchCount::One, false);
|
||||
let cost = KinoviSeedance2p0CostState::from_request(&req);
|
||||
assert!(matches!(cost.resolution, KinoviOutputResolution::SevenTwentyP));
|
||||
assert_eq!(cost.duration_seconds, 5);
|
||||
assert!(matches!(cost.batch_count, KinoviBatchCount::One));
|
||||
assert!(!cost.has_video_reference);
|
||||
assert_eq!(cost.estimate_cost().cost_in_usd_cents, Some(80));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_request_none_defaults_to_720p() {
|
||||
let req = make_request_state(None, 5, KinoviBatchCount::One, false);
|
||||
let cost = KinoviSeedance2p0CostState::from_request(&req);
|
||||
assert!(matches!(cost.resolution, KinoviOutputResolution::SevenTwentyP));
|
||||
assert_eq!(cost.estimate_cost().cost_in_usd_cents, Some(80));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_request_480p() {
|
||||
let req = make_request_state(Some(KinoviOutputResolution::FourEightyP), 5, KinoviBatchCount::One, false);
|
||||
let cost = KinoviSeedance2p0CostState::from_request(&req);
|
||||
assert_eq!(cost.estimate_cost().cost_in_usd_cents, Some(39));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_request_1080p_batch_2() {
|
||||
let req = make_request_state(Some(KinoviOutputResolution::TenEightyP), 5, KinoviBatchCount::Two, false);
|
||||
let cost = KinoviSeedance2p0CostState::from_request(&req);
|
||||
assert_eq!(cost.estimate_cost().cost_in_usd_cents, Some(466));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_request_with_video_reference() {
|
||||
let req = make_request_state(Some(KinoviOutputResolution::SevenTwentyP), 5, KinoviBatchCount::One, true);
|
||||
let cost = KinoviSeedance2p0CostState::from_request(&req);
|
||||
assert!(cost.has_video_reference);
|
||||
// Video refs don't affect cost yet
|
||||
assert_eq!(cost.estimate_cost().cost_in_usd_cents, Some(80));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_request_without_video_reference() {
|
||||
let req = make_request_state(Some(KinoviOutputResolution::SevenTwentyP), 5, KinoviBatchCount::One, false);
|
||||
let cost = KinoviSeedance2p0CostState::from_request(&req);
|
||||
assert!(!cost.has_video_reference);
|
||||
}
|
||||
|
||||
// ======================== from_draft() tests ========================
|
||||
|
||||
#[test]
|
||||
fn from_draft_720p_default() {
|
||||
let draft = make_draft(5, 1, None, false);
|
||||
let cost = KinoviSeedance2p0CostState::from_draft(&draft);
|
||||
assert!(matches!(cost.resolution, KinoviOutputResolution::SevenTwentyP));
|
||||
assert_eq!(cost.duration_seconds, 5);
|
||||
assert!(matches!(cost.batch_count, KinoviBatchCount::One));
|
||||
assert!(!cost.has_video_reference);
|
||||
assert_eq!(cost.estimate_cost().cost_in_usd_cents, Some(80));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_draft_480p() {
|
||||
let draft = make_draft(5, 1, Some(CommonResolution::FourEightyP), false);
|
||||
let cost = KinoviSeedance2p0CostState::from_draft(&draft);
|
||||
assert!(matches!(cost.resolution, KinoviOutputResolution::FourEightyP));
|
||||
assert_eq!(cost.estimate_cost().cost_in_usd_cents, Some(39));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_draft_1080p_batch_4() {
|
||||
let draft = make_draft(5, 4, Some(CommonResolution::TenEightyP), false);
|
||||
let cost = KinoviSeedance2p0CostState::from_draft(&draft);
|
||||
assert!(matches!(cost.resolution, KinoviOutputResolution::TenEightyP));
|
||||
assert!(matches!(cost.batch_count, KinoviBatchCount::Four));
|
||||
assert_eq!(cost.estimate_cost().cost_in_usd_cents, Some(933));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_draft_with_video_reference() {
|
||||
let draft = make_draft(5, 1, None, true);
|
||||
let cost = KinoviSeedance2p0CostState::from_draft(&draft);
|
||||
assert!(cost.has_video_reference);
|
||||
// Video refs don't affect cost yet
|
||||
assert_eq!(cost.estimate_cost().cost_in_usd_cents, Some(80));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_draft_without_video_reference() {
|
||||
let draft = make_draft(5, 1, None, false);
|
||||
let cost = KinoviSeedance2p0CostState::from_draft(&draft);
|
||||
assert!(!cost.has_video_reference);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_draft_duration_15_batch_2() {
|
||||
let draft = make_draft(15, 2, Some(CommonResolution::SevenTwentyP), false);
|
||||
let cost = KinoviSeedance2p0CostState::from_draft(&draft);
|
||||
assert_eq!(cost.duration_seconds, 15);
|
||||
assert!(matches!(cost.batch_count, KinoviBatchCount::Two));
|
||||
assert_eq!(cost.estimate_cost().cost_in_usd_cents, Some(480));
|
||||
}
|
||||
|
||||
// ======================== Cross-check: from_draft matches from_request ========================
|
||||
|
||||
#[test]
|
||||
fn draft_and_request_produce_same_cost() {
|
||||
// 720p, 5s, batch 1
|
||||
let draft = make_draft(5, 1, Some(CommonResolution::SevenTwentyP), false);
|
||||
let req = make_request_state(Some(KinoviOutputResolution::SevenTwentyP), 5, KinoviBatchCount::One, false);
|
||||
let draft_cost = KinoviSeedance2p0CostState::from_draft(&draft).estimate_cost();
|
||||
let req_cost = KinoviSeedance2p0CostState::from_request(&req).estimate_cost();
|
||||
assert_eq!(draft_cost.cost_in_usd_cents, req_cost.cost_in_usd_cents);
|
||||
assert_eq!(draft_cost.cost_in_credits, req_cost.cost_in_credits);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn draft_and_request_produce_same_cost_1080p() {
|
||||
let draft = make_draft(10, 2, Some(CommonResolution::TenEightyP), false);
|
||||
let req = make_request_state(Some(KinoviOutputResolution::TenEightyP), 10, KinoviBatchCount::Two, false);
|
||||
let draft_cost = KinoviSeedance2p0CostState::from_draft(&draft).estimate_cost();
|
||||
let req_cost = KinoviSeedance2p0CostState::from_request(&req).estimate_cost();
|
||||
assert_eq!(draft_cost.cost_in_usd_cents, req_cost.cost_in_usd_cents);
|
||||
assert_eq!(draft_cost.cost_in_credits, req_cost.cost_in_credits);
|
||||
}
|
||||
|
||||
// ======================== Credits spot checks ========================
|
||||
|
||||
#[test]
|
||||
fn credits_720p() {
|
||||
assert_eq!(credits(KinoviOutputResolution::SevenTwentyP, 5, KinoviBatchCount::One), 200);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn credits_480p() {
|
||||
assert_eq!(credits(KinoviOutputResolution::FourEightyP, 5, KinoviBatchCount::One), 75);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn credits_1080p() {
|
||||
assert_eq!(credits(KinoviOutputResolution::TenEightyP, 5, KinoviBatchCount::One), 450);
|
||||
}
|
||||
}
|
||||
+302
-284
@@ -229,326 +229,322 @@ mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
fn seedance2pro_fast_builder() -> GenerateVideoRequestBuilder {
|
||||
GenerateVideoRequestBuilder {
|
||||
model: CommonVideoModel::Seedance2p0Fast,
|
||||
provider: Provider::Seedance2Pro,
|
||||
prompt: Some("a cat dancing".to_string()),
|
||||
duration_seconds: Some(5),
|
||||
video_batch_count: Some(1),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn unwrap_draft(result: Result<VideoGenerationDraftOrRequest, ArtcraftRouterError>) -> KinoviSeedance2p0FastDraftState {
|
||||
match result.expect("build should succeed") {
|
||||
VideoGenerationDraftOrRequest::Draft(
|
||||
VideoGenerationDraftRequest::KinoviSeedance2p0Fast(draft)
|
||||
) => draft,
|
||||
_ => panic!("expected KinoviSeedance2p0Fast draft"),
|
||||
}
|
||||
}
|
||||
|
||||
// ── Materialized field conversions ──
|
||||
|
||||
#[test]
|
||||
fn prompt_is_passed_through() {
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(seedance2pro_fast_builder()));
|
||||
assert_eq!(draft.prompt, "a cat dancing");
|
||||
}
|
||||
mod materialized_field_conversions {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn prompt_defaults_to_empty() {
|
||||
let builder = GenerateVideoRequestBuilder { prompt: None, ..seedance2pro_fast_builder() };
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
assert_eq!(draft.prompt, "");
|
||||
}
|
||||
#[test]
|
||||
fn prompt_is_passed_through() {
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(seedance2pro_fast_builder()));
|
||||
assert_eq!(draft.prompt, "a cat dancing");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn duration_seconds_converted() {
|
||||
let builder = GenerateVideoRequestBuilder { duration_seconds: Some(10), ..seedance2pro_fast_builder() };
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
assert_eq!(draft.duration_seconds, 10);
|
||||
}
|
||||
#[test]
|
||||
fn prompt_defaults_to_empty() {
|
||||
let builder = GenerateVideoRequestBuilder { prompt: None, ..seedance2pro_fast_builder() };
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
assert_eq!(draft.prompt, "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn duration_defaults_to_5() {
|
||||
let builder = GenerateVideoRequestBuilder { duration_seconds: None, ..seedance2pro_fast_builder() };
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
assert_eq!(draft.duration_seconds, 5);
|
||||
}
|
||||
#[test]
|
||||
fn duration_seconds_converted() {
|
||||
let builder = GenerateVideoRequestBuilder { duration_seconds: Some(10), ..seedance2pro_fast_builder() };
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
assert_eq!(draft.duration_seconds, 10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn duration_clamped_to_max() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
duration_seconds: Some(99),
|
||||
..seedance2pro_fast_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
assert_eq!(draft.duration_seconds, 15);
|
||||
}
|
||||
#[test]
|
||||
fn duration_defaults_to_5() {
|
||||
let builder = GenerateVideoRequestBuilder { duration_seconds: None, ..seedance2pro_fast_builder() };
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
assert_eq!(draft.duration_seconds, 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn batch_count_one() {
|
||||
let builder = GenerateVideoRequestBuilder { video_batch_count: Some(1), ..seedance2pro_fast_builder() };
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
assert!(matches!(draft.batch_count, KinoviBatchCount::One));
|
||||
}
|
||||
#[test]
|
||||
fn duration_clamped_to_max() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
duration_seconds: Some(99),
|
||||
..seedance2pro_fast_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
assert_eq!(draft.duration_seconds, 15);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn batch_count_two() {
|
||||
let builder = GenerateVideoRequestBuilder { video_batch_count: Some(2), ..seedance2pro_fast_builder() };
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
assert!(matches!(draft.batch_count, KinoviBatchCount::Two));
|
||||
}
|
||||
#[test]
|
||||
fn batch_count_one() {
|
||||
let builder = GenerateVideoRequestBuilder { video_batch_count: Some(1), ..seedance2pro_fast_builder() };
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
assert!(matches!(draft.batch_count, KinoviBatchCount::One));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn batch_count_four() {
|
||||
let builder = GenerateVideoRequestBuilder { video_batch_count: Some(4), ..seedance2pro_fast_builder() };
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
assert!(matches!(draft.batch_count, KinoviBatchCount::Four));
|
||||
#[test]
|
||||
fn batch_count_two() {
|
||||
let builder = GenerateVideoRequestBuilder { video_batch_count: Some(2), ..seedance2pro_fast_builder() };
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
assert!(matches!(draft.batch_count, KinoviBatchCount::Two));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn batch_count_four() {
|
||||
let builder = GenerateVideoRequestBuilder { video_batch_count: Some(4), ..seedance2pro_fast_builder() };
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
assert!(matches!(draft.batch_count, KinoviBatchCount::Four));
|
||||
}
|
||||
}
|
||||
|
||||
// ── Aspect ratio conversions ──
|
||||
|
||||
#[test]
|
||||
fn aspect_ratio_wide() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::WideSixteenByNine),
|
||||
..seedance2pro_fast_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
assert!(matches!(draft.aspect_ratio, KinoviAspectRatio::Landscape16x9));
|
||||
}
|
||||
mod aspect_ratio_conversions {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn aspect_ratio_tall() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::TallNineBySixteen),
|
||||
..seedance2pro_fast_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
assert!(matches!(draft.aspect_ratio, KinoviAspectRatio::Portrait9x16));
|
||||
}
|
||||
#[test]
|
||||
fn aspect_ratio_wide() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::WideSixteenByNine),
|
||||
..seedance2pro_fast_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
assert!(matches!(draft.aspect_ratio, KinoviAspectRatio::Landscape16x9));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn aspect_ratio_square() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::Square),
|
||||
..seedance2pro_fast_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
assert!(matches!(draft.aspect_ratio, KinoviAspectRatio::Square1x1));
|
||||
}
|
||||
#[test]
|
||||
fn aspect_ratio_tall() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::TallNineBySixteen),
|
||||
..seedance2pro_fast_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
assert!(matches!(draft.aspect_ratio, KinoviAspectRatio::Portrait9x16));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn aspect_ratio_defaults_to_landscape() {
|
||||
let builder = GenerateVideoRequestBuilder { aspect_ratio: None, ..seedance2pro_fast_builder() };
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
assert!(matches!(draft.aspect_ratio, KinoviAspectRatio::Landscape16x9));
|
||||
#[test]
|
||||
fn aspect_ratio_square() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::Square),
|
||||
..seedance2pro_fast_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
assert!(matches!(draft.aspect_ratio, KinoviAspectRatio::Square1x1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn aspect_ratio_defaults_to_landscape() {
|
||||
let builder = GenerateVideoRequestBuilder { aspect_ratio: None, ..seedance2pro_fast_builder() };
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
assert!(matches!(draft.aspect_ratio, KinoviAspectRatio::Landscape16x9));
|
||||
}
|
||||
}
|
||||
|
||||
// ── Resolution conversions ──
|
||||
|
||||
#[test]
|
||||
fn resolution_480p() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
resolution: Some(CommonResolution::FourEightyP),
|
||||
..seedance2pro_fast_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
assert!(matches!(draft.resolution, Some(KinoviOutputResolution::FourEightyP)));
|
||||
}
|
||||
mod resolution_conversions {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn resolution_720p() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
resolution: Some(CommonResolution::SevenTwentyP),
|
||||
..seedance2pro_fast_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
assert!(matches!(draft.resolution, Some(KinoviOutputResolution::SevenTwentyP)));
|
||||
}
|
||||
#[test]
|
||||
fn resolution_480p() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
resolution: Some(CommonResolution::FourEightyP),
|
||||
..seedance2pro_fast_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
assert!(matches!(draft.resolution, Some(KinoviOutputResolution::FourEightyP)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolution_1080p_downgrades_to_720p() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
resolution: Some(CommonResolution::TenEightyP),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::PayLessDowngrade,
|
||||
..seedance2pro_fast_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
assert!(matches!(draft.resolution, Some(KinoviOutputResolution::SevenTwentyP)));
|
||||
}
|
||||
#[test]
|
||||
fn resolution_720p() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
resolution: Some(CommonResolution::SevenTwentyP),
|
||||
..seedance2pro_fast_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
assert!(matches!(draft.resolution, Some(KinoviOutputResolution::SevenTwentyP)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolution_1080p_upgrade_also_downgrades_to_720p() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
resolution: Some(CommonResolution::TenEightyP),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
..seedance2pro_fast_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
assert!(matches!(draft.resolution, Some(KinoviOutputResolution::SevenTwentyP)));
|
||||
}
|
||||
#[test]
|
||||
fn resolution_1080p_downgrades_to_720p() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
resolution: Some(CommonResolution::TenEightyP),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::PayLessDowngrade,
|
||||
..seedance2pro_fast_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
assert!(matches!(draft.resolution, Some(KinoviOutputResolution::SevenTwentyP)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolution_1080p_error_out() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
resolution: Some(CommonResolution::TenEightyP),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
|
||||
..seedance2pro_fast_builder()
|
||||
};
|
||||
assert!(build_kinovi_seedance_2p0_fast(builder).is_err());
|
||||
}
|
||||
#[test]
|
||||
fn resolution_1080p_upgrade_also_downgrades_to_720p() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
resolution: Some(CommonResolution::TenEightyP),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
..seedance2pro_fast_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
assert!(matches!(draft.resolution, Some(KinoviOutputResolution::SevenTwentyP)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolution_none() {
|
||||
let builder = GenerateVideoRequestBuilder { resolution: None, ..seedance2pro_fast_builder() };
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
assert!(draft.resolution.is_none());
|
||||
}
|
||||
#[test]
|
||||
fn resolution_1080p_error_out() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
resolution: Some(CommonResolution::TenEightyP),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
|
||||
..seedance2pro_fast_builder()
|
||||
};
|
||||
assert!(build_kinovi_seedance_2p0_fast(builder).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unsupported_resolution_error_out() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
resolution: Some(CommonResolution::FourK),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
|
||||
..seedance2pro_fast_builder()
|
||||
};
|
||||
assert!(build_kinovi_seedance_2p0_fast(builder).is_err());
|
||||
}
|
||||
#[test]
|
||||
fn resolution_none() {
|
||||
let builder = GenerateVideoRequestBuilder { resolution: None, ..seedance2pro_fast_builder() };
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
assert!(draft.resolution.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unsupported_resolution_rounds_to_720p() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
resolution: Some(CommonResolution::FourK),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
..seedance2pro_fast_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
assert!(matches!(draft.resolution, Some(KinoviOutputResolution::SevenTwentyP)));
|
||||
#[test]
|
||||
fn unsupported_resolution_error_out() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
resolution: Some(CommonResolution::FourK),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
|
||||
..seedance2pro_fast_builder()
|
||||
};
|
||||
assert!(build_kinovi_seedance_2p0_fast(builder).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unsupported_resolution_rounds_to_720p() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
resolution: Some(CommonResolution::FourK),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
..seedance2pro_fast_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
assert!(matches!(draft.resolution, Some(KinoviOutputResolution::SevenTwentyP)));
|
||||
}
|
||||
}
|
||||
|
||||
// ── unhandled_request_state: media refs are placed there ──
|
||||
|
||||
#[test]
|
||||
fn unhandled_state_is_present() {
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(seedance2pro_fast_builder()));
|
||||
assert!(draft.unhandled_request_state.is_some());
|
||||
}
|
||||
mod unhandled_request_state {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn start_frame_placed_in_unhandled() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
start_frame: Some(ImageRef::Url("https://example.com/start.jpg".to_string())),
|
||||
..seedance2pro_fast_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
let remaining = draft.unhandled_request_state.unwrap();
|
||||
assert!(matches!(remaining.start_frame, Some(ImageRef::Url(url)) if url == "https://example.com/start.jpg"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn end_frame_placed_in_unhandled() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
end_frame: Some(ImageRef::Url("https://example.com/end.jpg".to_string())),
|
||||
..seedance2pro_fast_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
let remaining = draft.unhandled_request_state.unwrap();
|
||||
assert!(matches!(remaining.end_frame, Some(ImageRef::Url(url)) if url == "https://example.com/end.jpg"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn start_frame_media_token_placed_in_unhandled() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
start_frame: Some(ImageRef::MediaFileToken(MediaFileToken::new("mf_test123".to_string()))),
|
||||
..seedance2pro_fast_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
let remaining = draft.unhandled_request_state.unwrap();
|
||||
assert!(matches!(remaining.start_frame, Some(ImageRef::MediaFileToken(t)) if t.as_str() == "mf_test123"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reference_images_placed_in_unhandled() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
reference_images: Some(ImageListRef::Urls(vec![
|
||||
"https://example.com/ref1.jpg".to_string(),
|
||||
"https://example.com/ref2.jpg".to_string(),
|
||||
])),
|
||||
..seedance2pro_fast_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
let remaining = draft.unhandled_request_state.unwrap();
|
||||
match remaining.reference_images {
|
||||
Some(ImageListRef::Urls(urls)) => {
|
||||
assert_eq!(urls.len(), 2);
|
||||
assert_eq!(urls[0], "https://example.com/ref1.jpg");
|
||||
assert_eq!(urls[1], "https://example.com/ref2.jpg");
|
||||
}
|
||||
_ => panic!("expected Urls variant"),
|
||||
#[test]
|
||||
fn unhandled_state_is_present() {
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(seedance2pro_fast_builder()));
|
||||
assert!(draft.unhandled_request_state.is_some());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reference_videos_placed_in_unhandled() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
reference_videos: Some(VideoListRef::Urls(vec![
|
||||
"https://example.com/vid.mp4".to_string(),
|
||||
])),
|
||||
..seedance2pro_fast_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
let remaining = draft.unhandled_request_state.unwrap();
|
||||
assert!(matches!(remaining.reference_videos, Some(VideoListRef::Urls(urls)) if urls.len() == 1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reference_audio_placed_in_unhandled() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
reference_audio: Some(AudioListRef::Urls(vec![
|
||||
"https://example.com/audio.mp3".to_string(),
|
||||
])),
|
||||
..seedance2pro_fast_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
let remaining = draft.unhandled_request_state.unwrap();
|
||||
assert!(matches!(remaining.reference_audio, Some(AudioListRef::Urls(urls)) if urls.len() == 1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn character_tokens_placed_in_unhandled() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
reference_character_tokens: Some(CharacterListRef::CharacterTokens(vec![
|
||||
CharacterToken::new("char_abc".to_string()),
|
||||
CharacterToken::new("char_def".to_string()),
|
||||
])),
|
||||
..seedance2pro_fast_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
let remaining = draft.unhandled_request_state.unwrap();
|
||||
match remaining.reference_character_tokens {
|
||||
Some(CharacterListRef::CharacterTokens(tokens)) => {
|
||||
assert_eq!(tokens.len(), 2);
|
||||
assert_eq!(tokens[0].as_str(), "char_abc");
|
||||
assert_eq!(tokens[1].as_str(), "char_def");
|
||||
}
|
||||
_ => panic!("expected CharacterTokens variant"),
|
||||
#[test]
|
||||
fn start_frame_placed_in_unhandled() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
start_frame: Some(ImageRef::Url("https://example.com/start.jpg".to_string())),
|
||||
..seedance2pro_fast_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
let remaining = draft.unhandled_request_state.unwrap();
|
||||
assert!(matches!(remaining.start_frame, Some(ImageRef::Url(url)) if url == "https://example.com/start.jpg"));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_refs_are_none_in_unhandled() {
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(seedance2pro_fast_builder()));
|
||||
let remaining = draft.unhandled_request_state.unwrap();
|
||||
assert!(remaining.start_frame.is_none());
|
||||
assert!(remaining.end_frame.is_none());
|
||||
assert!(remaining.reference_images.is_none());
|
||||
assert!(remaining.reference_videos.is_none());
|
||||
assert!(remaining.reference_audio.is_none());
|
||||
assert!(remaining.reference_character_tokens.is_none());
|
||||
#[test]
|
||||
fn end_frame_placed_in_unhandled() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
end_frame: Some(ImageRef::Url("https://example.com/end.jpg".to_string())),
|
||||
..seedance2pro_fast_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
let remaining = draft.unhandled_request_state.unwrap();
|
||||
assert!(matches!(remaining.end_frame, Some(ImageRef::Url(url)) if url == "https://example.com/end.jpg"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn start_frame_media_token_placed_in_unhandled() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
start_frame: Some(ImageRef::MediaFileToken(MediaFileToken::new("mf_test123".to_string()))),
|
||||
..seedance2pro_fast_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
let remaining = draft.unhandled_request_state.unwrap();
|
||||
assert!(matches!(remaining.start_frame, Some(ImageRef::MediaFileToken(t)) if t.as_str() == "mf_test123"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reference_images_placed_in_unhandled() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
reference_images: Some(ImageListRef::Urls(vec![
|
||||
"https://example.com/ref1.jpg".to_string(),
|
||||
"https://example.com/ref2.jpg".to_string(),
|
||||
])),
|
||||
..seedance2pro_fast_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
let remaining = draft.unhandled_request_state.unwrap();
|
||||
match remaining.reference_images {
|
||||
Some(ImageListRef::Urls(urls)) => {
|
||||
assert_eq!(urls.len(), 2);
|
||||
assert_eq!(urls[0], "https://example.com/ref1.jpg");
|
||||
assert_eq!(urls[1], "https://example.com/ref2.jpg");
|
||||
}
|
||||
_ => panic!("expected Urls variant"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reference_videos_placed_in_unhandled() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
reference_videos: Some(VideoListRef::Urls(vec![
|
||||
"https://example.com/vid.mp4".to_string(),
|
||||
])),
|
||||
..seedance2pro_fast_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
let remaining = draft.unhandled_request_state.unwrap();
|
||||
assert!(matches!(remaining.reference_videos, Some(VideoListRef::Urls(urls)) if urls.len() == 1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reference_audio_placed_in_unhandled() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
reference_audio: Some(AudioListRef::Urls(vec![
|
||||
"https://example.com/audio.mp3".to_string(),
|
||||
])),
|
||||
..seedance2pro_fast_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
let remaining = draft.unhandled_request_state.unwrap();
|
||||
assert!(matches!(remaining.reference_audio, Some(AudioListRef::Urls(urls)) if urls.len() == 1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn character_tokens_placed_in_unhandled() {
|
||||
let builder = GenerateVideoRequestBuilder {
|
||||
reference_character_tokens: Some(CharacterListRef::CharacterTokens(vec![
|
||||
CharacterToken::new("char_abc".to_string()),
|
||||
CharacterToken::new("char_def".to_string()),
|
||||
])),
|
||||
..seedance2pro_fast_builder()
|
||||
};
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(builder));
|
||||
let remaining = draft.unhandled_request_state.unwrap();
|
||||
match remaining.reference_character_tokens {
|
||||
Some(CharacterListRef::CharacterTokens(tokens)) => {
|
||||
assert_eq!(tokens.len(), 2);
|
||||
assert_eq!(tokens[0].as_str(), "char_abc");
|
||||
assert_eq!(tokens[1].as_str(), "char_def");
|
||||
}
|
||||
_ => panic!("expected CharacterTokens variant"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_refs_are_none_in_unhandled() {
|
||||
let draft = unwrap_draft(build_kinovi_seedance_2p0_fast(seedance2pro_fast_builder()));
|
||||
let remaining = draft.unhandled_request_state.unwrap();
|
||||
assert!(remaining.start_frame.is_none());
|
||||
assert!(remaining.end_frame.is_none());
|
||||
assert!(remaining.reference_images.is_none());
|
||||
assert!(remaining.reference_videos.is_none());
|
||||
assert!(remaining.reference_audio.is_none());
|
||||
assert!(remaining.reference_character_tokens.is_none());
|
||||
}
|
||||
}
|
||||
|
||||
// ── Full combination ──
|
||||
@@ -587,4 +583,26 @@ mod tests {
|
||||
assert!(remaining.reference_audio.is_some());
|
||||
assert!(remaining.reference_character_tokens.is_some());
|
||||
}
|
||||
|
||||
// ── Helpers ──
|
||||
|
||||
fn seedance2pro_fast_builder() -> GenerateVideoRequestBuilder {
|
||||
GenerateVideoRequestBuilder {
|
||||
model: CommonVideoModel::Seedance2p0Fast,
|
||||
provider: Provider::Seedance2Pro,
|
||||
prompt: Some("a cat dancing".to_string()),
|
||||
duration_seconds: Some(5),
|
||||
video_batch_count: Some(1),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn unwrap_draft(result: Result<VideoGenerationDraftOrRequest, ArtcraftRouterError>) -> KinoviSeedance2p0FastDraftState {
|
||||
match result.expect("build should succeed") {
|
||||
VideoGenerationDraftOrRequest::Draft(
|
||||
VideoGenerationDraftRequest::KinoviSeedance2p0Fast(draft)
|
||||
) => draft,
|
||||
_ => panic!("expected KinoviSeedance2p0Fast draft"),
|
||||
}
|
||||
}
|
||||
}
|
||||
+36
-28
@@ -138,29 +138,33 @@ mod tests {
|
||||
|
||||
// -- Relative pricing --
|
||||
|
||||
#[test]
|
||||
fn cost_480p_cheaper_than_720p() {
|
||||
let c480 = usd_cents(KinoviOutputResolution::FourEightyP, 5, KinoviBatchCount::One);
|
||||
let c720 = usd_cents(KinoviOutputResolution::SevenTwentyP, 5, KinoviBatchCount::One);
|
||||
assert!(c480 < c720, "480p ({}) should be cheaper than 720p ({})", c480, c720);
|
||||
}
|
||||
mod relative_pricing_tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn cost_scales_with_duration() {
|
||||
let c4 = usd_cents(KinoviOutputResolution::SevenTwentyP, 4, KinoviBatchCount::One);
|
||||
let c10 = usd_cents(KinoviOutputResolution::SevenTwentyP, 10, KinoviBatchCount::One);
|
||||
let c15 = usd_cents(KinoviOutputResolution::SevenTwentyP, 15, KinoviBatchCount::One);
|
||||
assert!(c4 < c10);
|
||||
assert!(c10 < c15);
|
||||
}
|
||||
#[test]
|
||||
fn cost_480p_cheaper_than_720p() {
|
||||
let c480 = usd_cents(KinoviOutputResolution::FourEightyP, 5, KinoviBatchCount::One);
|
||||
let c720 = usd_cents(KinoviOutputResolution::SevenTwentyP, 5, KinoviBatchCount::One);
|
||||
assert!(c480 < c720, "480p ({}) should be cheaper than 720p ({})", c480, c720);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cost_scales_with_batch() {
|
||||
let b1 = usd_cents(KinoviOutputResolution::SevenTwentyP, 5, KinoviBatchCount::One);
|
||||
let b2 = usd_cents(KinoviOutputResolution::SevenTwentyP, 5, KinoviBatchCount::Two);
|
||||
let b4 = usd_cents(KinoviOutputResolution::SevenTwentyP, 5, KinoviBatchCount::Four);
|
||||
assert!(b1 < b2);
|
||||
assert!(b2 < b4);
|
||||
#[test]
|
||||
fn cost_scales_with_duration() {
|
||||
let c4 = usd_cents(KinoviOutputResolution::SevenTwentyP, 4, KinoviBatchCount::One);
|
||||
let c10 = usd_cents(KinoviOutputResolution::SevenTwentyP, 10, KinoviBatchCount::One);
|
||||
let c15 = usd_cents(KinoviOutputResolution::SevenTwentyP, 15, KinoviBatchCount::One);
|
||||
assert!(c4 < c10);
|
||||
assert!(c10 < c15);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cost_scales_with_batch() {
|
||||
let b1 = usd_cents(KinoviOutputResolution::SevenTwentyP, 5, KinoviBatchCount::One);
|
||||
let b2 = usd_cents(KinoviOutputResolution::SevenTwentyP, 5, KinoviBatchCount::Two);
|
||||
let b4 = usd_cents(KinoviOutputResolution::SevenTwentyP, 5, KinoviBatchCount::Four);
|
||||
assert!(b1 < b2);
|
||||
assert!(b2 < b4);
|
||||
}
|
||||
}
|
||||
|
||||
// -- Video reference does NOT affect cost (yet) --
|
||||
@@ -306,14 +310,18 @@ mod tests {
|
||||
|
||||
// ── Credits spot checks ──
|
||||
|
||||
#[test]
|
||||
fn credits_720p() {
|
||||
assert_eq!(credits(KinoviOutputResolution::SevenTwentyP, 5, KinoviBatchCount::One), 140);
|
||||
}
|
||||
mod credits_tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn credits_480p() {
|
||||
assert_eq!(credits(KinoviOutputResolution::FourEightyP, 5, KinoviBatchCount::One), 50);
|
||||
#[test]
|
||||
fn credits_720p() {
|
||||
assert_eq!(credits(KinoviOutputResolution::SevenTwentyP, 5, KinoviBatchCount::One), 140);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn credits_480p() {
|
||||
assert_eq!(credits(KinoviOutputResolution::FourEightyP, 5, KinoviBatchCount::One), 50);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Helpers ──
|
||||
|
||||
Reference in new issue
Block a user