1use crate::config::test_service::TestConfigService;
7use crate::config::{Config, OverflowStrategy};
8
9pub struct TestConfigBuilder {
26 config: Config,
27}
28
29impl TestConfigBuilder {
30 pub fn new() -> Self {
32 Self {
33 config: Config::default(),
34 }
35 }
36
37 pub fn with_ai_provider(mut self, provider: &str) -> Self {
45 self.config.ai.provider = provider.to_string();
46 self
47 }
48
49 pub fn with_ai_model(mut self, model: &str) -> Self {
55 self.config.ai.model = model.to_string();
56 self
57 }
58
59 pub fn with_ai_api_key(mut self, api_key: &str) -> Self {
65 self.config.ai.api_key = Some(api_key.to_string());
66 self
67 }
68
69 pub fn with_ai_base_url(mut self, base_url: &str) -> Self {
75 self.config.ai.base_url = base_url.to_string();
76 self
77 }
78
79 pub fn with_max_sample_length(mut self, length: usize) -> Self {
85 self.config.ai.max_sample_length = length;
86 self
87 }
88
89 pub fn with_ai_temperature(mut self, temperature: f32) -> Self {
95 self.config.ai.temperature = temperature;
96 self
97 }
98
99 pub fn with_ai_max_tokens(mut self, max_tokens: u32) -> Self {
105 self.config.ai.max_tokens = max_tokens;
106 self
107 }
108
109 pub fn with_ai_retry(mut self, attempts: u32, delay_ms: u64) -> Self {
116 self.config.ai.retry_attempts = attempts;
117 self.config.ai.retry_delay_ms = delay_ms;
118 self
119 }
120
121 pub fn with_ai_request_timeout(mut self, timeout_seconds: u64) -> Self {
127 self.config.ai.request_timeout_seconds = timeout_seconds;
128 self
129 }
130
131 pub fn with_sync_method(mut self, method: &str) -> Self {
139 self.config.sync.default_method = method.to_string();
140 self
141 }
142
143 pub fn with_vad_enabled(mut self, enabled: bool) -> Self {
149 self.config.sync.vad.enabled = enabled;
150 self
151 }
152
153 pub fn with_vad_sensitivity(mut self, sensitivity: f32) -> Self {
159 self.config.sync.vad.sensitivity = sensitivity;
160 self
161 }
162
163 pub fn with_default_output_format(mut self, format: &str) -> Self {
171 self.config.formats.default_output = format.to_string();
172 self
173 }
174
175 pub fn with_preserve_styling(mut self, preserve: bool) -> Self {
181 self.config.formats.preserve_styling = preserve;
182 self
183 }
184
185 pub fn with_default_encoding(mut self, encoding: &str) -> Self {
191 self.config.formats.default_encoding = encoding.to_string();
192 self
193 }
194
195 pub fn with_encoding_detection_confidence(mut self, confidence: f32) -> Self {
201 self.config.formats.encoding_detection_confidence = confidence;
202 self
203 }
204
205 pub fn with_backup_enabled(mut self, enabled: bool) -> Self {
213 self.config.general.backup_enabled = enabled;
214 self
215 }
216
217 pub fn with_max_concurrent_jobs(mut self, jobs: usize) -> Self {
223 self.config.general.max_concurrent_jobs = jobs;
224 self
225 }
226
227 pub fn with_task_timeout(mut self, timeout_seconds: u64) -> Self {
233 self.config.general.task_timeout_seconds = timeout_seconds;
234 self
235 }
236
237 pub fn with_progress_bar(mut self, enabled: bool) -> Self {
243 self.config.general.enable_progress_bar = enabled;
244 self
245 }
246
247 pub fn with_worker_idle_timeout(mut self, timeout_seconds: u64) -> Self {
253 self.config.general.worker_idle_timeout_seconds = timeout_seconds;
254 self
255 }
256
257 pub fn with_task_queue_size(mut self, size: usize) -> Self {
265 self.config.parallel.task_queue_size = size;
266 self
267 }
268
269 pub fn with_task_priorities(mut self, enabled: bool) -> Self {
275 self.config.parallel.enable_task_priorities = enabled;
276 self
277 }
278
279 pub fn with_auto_balance_workers(mut self, enabled: bool) -> Self {
285 self.config.parallel.auto_balance_workers = enabled;
286 self
287 }
288
289 pub fn with_queue_overflow_strategy(mut self, strategy: OverflowStrategy) -> Self {
295 self.config.parallel.overflow_strategy = strategy;
296 self
297 }
298
299 pub fn with_parallel_settings(mut self, max_workers: usize, queue_size: usize) -> Self {
301 self.config.general.max_concurrent_jobs = max_workers;
302 self.config.parallel.task_queue_size = queue_size;
303 self
304 }
305
306 pub fn with_translation_batch_size(mut self, batch_size: usize) -> Self {
310 self.config.translation.batch_size = batch_size;
311 self
312 }
313
314 pub fn with_translation_default_target_language(mut self, language: &str) -> Self {
316 self.config.translation.default_target_language = Some(language.to_string());
317 self
318 }
319
320 pub fn without_translation_default_target_language(mut self) -> Self {
322 self.config.translation.default_target_language = None;
323 self
324 }
325
326 pub fn build_service(self) -> TestConfigService {
330 TestConfigService::new(self.config)
331 }
332
333 pub fn build_config(self) -> Config {
335 self.config
336 }
337
338 pub fn config(&self) -> &Config {
340 &self.config
341 }
342
343 pub fn config_mut(&mut self) -> &mut Config {
345 &mut self.config
346 }
347 pub fn with_mock_ai_server(mut self, mock_url: &str) -> Self {
366 self.config.ai.base_url = mock_url.to_string();
367 self.config.ai.api_key = Some("mock-api-key".to_string());
368 self
369 }
370}
371
372impl Default for TestConfigBuilder {
373 fn default() -> Self {
374 Self::new()
375 }
376}
377
378#[cfg(test)]
379mod tests {
380 use super::*;
381 use crate::config::service::ConfigService;
382
383 #[test]
384 fn test_builder_default() {
385 let config = TestConfigBuilder::new().build_config();
386 let default_config = Config::default();
387
388 assert_eq!(config.ai.provider, default_config.ai.provider);
389 assert_eq!(config.ai.model, default_config.ai.model);
390 }
391
392 #[test]
393 fn test_builder_ai_configuration() {
394 let config = TestConfigBuilder::new()
395 .with_ai_provider("anthropic")
396 .with_ai_model("claude-3")
397 .with_ai_api_key("test-key")
398 .with_max_sample_length(5000)
399 .with_ai_temperature(0.7)
400 .build_config();
401
402 assert_eq!(config.ai.provider, "anthropic");
403 assert_eq!(config.ai.model, "claude-3");
404 assert_eq!(config.ai.api_key, Some("test-key".to_string()));
405 assert_eq!(config.ai.max_sample_length, 5000);
406 assert_eq!(config.ai.temperature, 0.7);
407 }
408
409 #[test]
410 fn test_builder_sync_configuration() {
411 let config = TestConfigBuilder::new()
412 .with_sync_method("vad")
413 .with_vad_enabled(true)
414 .with_vad_sensitivity(0.8)
415 .build_config();
416
417 assert_eq!(config.sync.default_method, "vad");
418 assert!(config.sync.vad.enabled);
419 assert_eq!(config.sync.vad.sensitivity, 0.8);
420 }
421
422 #[test]
423 fn test_builder_service_creation() {
424 let service = TestConfigBuilder::new()
425 .with_ai_provider("test-provider")
426 .build_service();
427
428 let config = service.get_config().unwrap();
429 assert_eq!(config.ai.provider, "test-provider");
430 }
431
432 #[test]
433 fn test_builder_chaining() {
434 let config = TestConfigBuilder::new()
435 .with_ai_provider("openai")
436 .with_ai_model("gpt-4.1")
437 .with_sync_method("vad")
438 .with_vad_sensitivity(0.5)
439 .with_max_concurrent_jobs(8)
440 .with_task_queue_size(200)
441 .build_config();
442
443 assert_eq!(config.ai.provider, "openai");
444 assert_eq!(config.ai.model, "gpt-4.1");
445 assert_eq!(config.sync.default_method, "vad");
446 assert_eq!(config.sync.vad.sensitivity, 0.5);
447 assert_eq!(config.general.max_concurrent_jobs, 8);
448 assert_eq!(config.parallel.task_queue_size, 200);
449 }
450
451 #[test]
452 fn test_builder_ai_configuration_openrouter() {
453 let config = TestConfigBuilder::new()
454 .with_ai_provider("openrouter")
455 .with_ai_model("deepseek/deepseek-r1-0528:free")
456 .with_ai_api_key("test-openrouter-key")
457 .build_config();
458 assert_eq!(config.ai.provider, "openrouter");
459 assert_eq!(config.ai.model, "deepseek/deepseek-r1-0528:free");
460 assert_eq!(config.ai.api_key, Some("test-openrouter-key".to_string()));
461 }
462
463 #[test]
464 fn test_builder_default_trait() {
465 let config = TestConfigBuilder::default().build_config();
466 let default_config = Config::default();
467 assert_eq!(config.ai.provider, default_config.ai.provider);
468 assert_eq!(config.ai.model, default_config.ai.model);
469 assert_eq!(
470 config.formats.default_output,
471 default_config.formats.default_output
472 );
473 }
474
475 #[test]
476 fn test_builder_with_ai_base_url() {
477 let config = TestConfigBuilder::new()
478 .with_ai_base_url("https://custom.api.example.com/v2")
479 .build_config();
480 assert_eq!(config.ai.base_url, "https://custom.api.example.com/v2");
481 }
482
483 #[test]
484 fn test_builder_with_ai_max_tokens() {
485 let config = TestConfigBuilder::new()
486 .with_ai_max_tokens(4096)
487 .build_config();
488 assert_eq!(config.ai.max_tokens, 4096);
489 }
490
491 #[test]
492 fn test_builder_with_ai_retry() {
493 let config = TestConfigBuilder::new()
494 .with_ai_retry(5, 2000)
495 .build_config();
496 assert_eq!(config.ai.retry_attempts, 5);
497 assert_eq!(config.ai.retry_delay_ms, 2000);
498 }
499
500 #[test]
501 fn test_builder_with_ai_request_timeout() {
502 let config = TestConfigBuilder::new()
503 .with_ai_request_timeout(60)
504 .build_config();
505 assert_eq!(config.ai.request_timeout_seconds, 60);
506 }
507
508 #[test]
509 fn test_builder_with_default_output_format() {
510 let config = TestConfigBuilder::new()
511 .with_default_output_format("ass")
512 .build_config();
513 assert_eq!(config.formats.default_output, "ass");
514 }
515
516 #[test]
517 fn test_builder_with_preserve_styling_true() {
518 let config = TestConfigBuilder::new()
519 .with_preserve_styling(true)
520 .build_config();
521 assert!(config.formats.preserve_styling);
522 }
523
524 #[test]
525 fn test_builder_with_preserve_styling_false() {
526 let config = TestConfigBuilder::new()
527 .with_preserve_styling(false)
528 .build_config();
529 assert!(!config.formats.preserve_styling);
530 }
531
532 #[test]
533 fn test_builder_with_default_encoding() {
534 let config = TestConfigBuilder::new()
535 .with_default_encoding("gbk")
536 .build_config();
537 assert_eq!(config.formats.default_encoding, "gbk");
538 }
539
540 #[test]
541 fn test_builder_with_encoding_detection_confidence() {
542 let config = TestConfigBuilder::new()
543 .with_encoding_detection_confidence(0.95)
544 .build_config();
545 assert!((config.formats.encoding_detection_confidence - 0.95).abs() < f32::EPSILON);
546 }
547
548 #[test]
549 fn test_builder_with_backup_enabled_true() {
550 let config = TestConfigBuilder::new()
551 .with_backup_enabled(true)
552 .build_config();
553 assert!(config.general.backup_enabled);
554 }
555
556 #[test]
557 fn test_builder_with_backup_enabled_false() {
558 let config = TestConfigBuilder::new()
559 .with_backup_enabled(false)
560 .build_config();
561 assert!(!config.general.backup_enabled);
562 }
563
564 #[test]
565 fn test_builder_with_task_timeout() {
566 let config = TestConfigBuilder::new()
567 .with_task_timeout(600)
568 .build_config();
569 assert_eq!(config.general.task_timeout_seconds, 600);
570 }
571
572 #[test]
573 fn test_builder_with_progress_bar_enabled() {
574 let config = TestConfigBuilder::new()
575 .with_progress_bar(true)
576 .build_config();
577 assert!(config.general.enable_progress_bar);
578 }
579
580 #[test]
581 fn test_builder_with_progress_bar_disabled() {
582 let config = TestConfigBuilder::new()
583 .with_progress_bar(false)
584 .build_config();
585 assert!(!config.general.enable_progress_bar);
586 }
587
588 #[test]
589 fn test_builder_with_worker_idle_timeout() {
590 let config = TestConfigBuilder::new()
591 .with_worker_idle_timeout(120)
592 .build_config();
593 assert_eq!(config.general.worker_idle_timeout_seconds, 120);
594 }
595
596 #[test]
597 fn test_builder_with_task_priorities_enabled() {
598 let config = TestConfigBuilder::new()
599 .with_task_priorities(true)
600 .build_config();
601 assert!(config.parallel.enable_task_priorities);
602 }
603
604 #[test]
605 fn test_builder_with_task_priorities_disabled() {
606 let config = TestConfigBuilder::new()
607 .with_task_priorities(false)
608 .build_config();
609 assert!(!config.parallel.enable_task_priorities);
610 }
611
612 #[test]
613 fn test_builder_with_auto_balance_workers_enabled() {
614 let config = TestConfigBuilder::new()
615 .with_auto_balance_workers(true)
616 .build_config();
617 assert!(config.parallel.auto_balance_workers);
618 }
619
620 #[test]
621 fn test_builder_with_auto_balance_workers_disabled() {
622 let config = TestConfigBuilder::new()
623 .with_auto_balance_workers(false)
624 .build_config();
625 assert!(!config.parallel.auto_balance_workers);
626 }
627
628 #[test]
629 fn test_builder_with_queue_overflow_strategy_block() {
630 let config = TestConfigBuilder::new()
631 .with_queue_overflow_strategy(OverflowStrategy::Block)
632 .build_config();
633 assert_eq!(config.parallel.overflow_strategy, OverflowStrategy::Block);
634 }
635
636 #[test]
637 fn test_builder_with_queue_overflow_strategy_drop() {
638 let config = TestConfigBuilder::new()
639 .with_queue_overflow_strategy(OverflowStrategy::Drop)
640 .build_config();
641 assert_eq!(config.parallel.overflow_strategy, OverflowStrategy::Drop);
642 }
643
644 #[test]
645 fn test_builder_with_queue_overflow_strategy_expand() {
646 let config = TestConfigBuilder::new()
647 .with_queue_overflow_strategy(OverflowStrategy::Expand)
648 .build_config();
649 assert_eq!(config.parallel.overflow_strategy, OverflowStrategy::Expand);
650 }
651
652 #[test]
653 fn test_builder_with_queue_overflow_strategy_drop_oldest() {
654 let config = TestConfigBuilder::new()
655 .with_queue_overflow_strategy(OverflowStrategy::DropOldest)
656 .build_config();
657 assert_eq!(
658 config.parallel.overflow_strategy,
659 OverflowStrategy::DropOldest
660 );
661 }
662
663 #[test]
664 fn test_builder_with_queue_overflow_strategy_reject() {
665 let config = TestConfigBuilder::new()
666 .with_queue_overflow_strategy(OverflowStrategy::Reject)
667 .build_config();
668 assert_eq!(config.parallel.overflow_strategy, OverflowStrategy::Reject);
669 }
670
671 #[test]
672 fn test_builder_with_parallel_settings() {
673 let config = TestConfigBuilder::new()
674 .with_parallel_settings(16, 500)
675 .build_config();
676 assert_eq!(config.general.max_concurrent_jobs, 16);
677 assert_eq!(config.parallel.task_queue_size, 500);
678 }
679
680 #[test]
681 fn test_builder_config_ref() {
682 let builder = TestConfigBuilder::new().with_ai_provider("ref-provider");
683 let config_ref = builder.config();
684 assert_eq!(config_ref.ai.provider, "ref-provider");
685 }
686
687 #[test]
688 fn test_builder_config_mut() {
689 let mut builder = TestConfigBuilder::new();
690 builder.config_mut().ai.provider = "mutated-provider".to_string();
691 let config = builder.build_config();
692 assert_eq!(config.ai.provider, "mutated-provider");
693 }
694
695 #[test]
696 fn test_builder_with_mock_ai_server() {
697 let config = TestConfigBuilder::new()
698 .with_mock_ai_server("http://localhost:8080")
699 .build_config();
700 assert_eq!(config.ai.base_url, "http://localhost:8080");
701 assert_eq!(config.ai.api_key, Some("mock-api-key".to_string()));
702 }
703
704 #[test]
705 fn test_builder_override_preserves_other_fields() {
706 let config = TestConfigBuilder::new()
707 .with_ai_provider("openai")
708 .with_ai_model("gpt-4.1")
709 .with_ai_temperature(0.9)
710 .with_ai_provider("anthropic")
711 .build_config();
712 assert_eq!(config.ai.provider, "anthropic");
713 assert_eq!(config.ai.model, "gpt-4.1");
714 assert!((config.ai.temperature - 0.9).abs() < f32::EPSILON);
715 }
716
717 #[test]
718 fn test_builder_full_ai_configuration() {
719 let config = TestConfigBuilder::new()
720 .with_ai_provider("openai")
721 .with_ai_model("gpt-4.1")
722 .with_ai_api_key("sk-test-key")
723 .with_ai_base_url("https://api.openai.com/v1")
724 .with_max_sample_length(8000)
725 .with_ai_temperature(0.5)
726 .with_ai_max_tokens(2000)
727 .with_ai_retry(2, 500)
728 .with_ai_request_timeout(30)
729 .build_config();
730
731 assert_eq!(config.ai.provider, "openai");
732 assert_eq!(config.ai.model, "gpt-4.1");
733 assert_eq!(config.ai.api_key, Some("sk-test-key".to_string()));
734 assert_eq!(config.ai.base_url, "https://api.openai.com/v1");
735 assert_eq!(config.ai.max_sample_length, 8000);
736 assert!((config.ai.temperature - 0.5).abs() < f32::EPSILON);
737 assert_eq!(config.ai.max_tokens, 2000);
738 assert_eq!(config.ai.retry_attempts, 2);
739 assert_eq!(config.ai.retry_delay_ms, 500);
740 assert_eq!(config.ai.request_timeout_seconds, 30);
741 }
742
743 #[test]
744 fn test_builder_full_formats_configuration() {
745 let config = TestConfigBuilder::new()
746 .with_default_output_format("vtt")
747 .with_preserve_styling(true)
748 .with_default_encoding("utf-16")
749 .with_encoding_detection_confidence(0.75)
750 .build_config();
751
752 assert_eq!(config.formats.default_output, "vtt");
753 assert!(config.formats.preserve_styling);
754 assert_eq!(config.formats.default_encoding, "utf-16");
755 assert!((config.formats.encoding_detection_confidence - 0.75).abs() < f32::EPSILON);
756 }
757
758 #[test]
759 fn test_builder_full_general_configuration() {
760 let config = TestConfigBuilder::new()
761 .with_backup_enabled(true)
762 .with_max_concurrent_jobs(2)
763 .with_task_timeout(120)
764 .with_progress_bar(false)
765 .with_worker_idle_timeout(30)
766 .build_config();
767
768 assert!(config.general.backup_enabled);
769 assert_eq!(config.general.max_concurrent_jobs, 2);
770 assert_eq!(config.general.task_timeout_seconds, 120);
771 assert!(!config.general.enable_progress_bar);
772 assert_eq!(config.general.worker_idle_timeout_seconds, 30);
773 }
774
775 #[test]
776 fn test_builder_full_parallel_configuration() {
777 let config = TestConfigBuilder::new()
778 .with_task_queue_size(256)
779 .with_task_priorities(true)
780 .with_auto_balance_workers(false)
781 .with_queue_overflow_strategy(OverflowStrategy::Expand)
782 .build_config();
783
784 assert_eq!(config.parallel.task_queue_size, 256);
785 assert!(config.parallel.enable_task_priorities);
786 assert!(!config.parallel.auto_balance_workers);
787 assert_eq!(config.parallel.overflow_strategy, OverflowStrategy::Expand);
788 }
789
790 #[test]
791 fn test_builder_vad_disabled() {
792 let config = TestConfigBuilder::new()
793 .with_vad_enabled(false)
794 .build_config();
795 assert!(!config.sync.vad.enabled);
796 }
797
798 #[test]
799 fn test_builder_vad_sensitivity_boundary_zero() {
800 let config = TestConfigBuilder::new()
801 .with_vad_sensitivity(0.0)
802 .build_config();
803 assert!((config.sync.vad.sensitivity - 0.0).abs() < f32::EPSILON);
804 }
805
806 #[test]
807 fn test_builder_vad_sensitivity_boundary_one() {
808 let config = TestConfigBuilder::new()
809 .with_vad_sensitivity(1.0)
810 .build_config();
811 assert!((config.sync.vad.sensitivity - 1.0).abs() < f32::EPSILON);
812 }
813
814 #[test]
815 fn test_builder_service_returns_correct_config() {
816 let service = TestConfigBuilder::new()
817 .with_ai_provider("test-ai")
818 .with_ai_model("test-model")
819 .with_backup_enabled(true)
820 .build_service();
821
822 let config = service.get_config().unwrap();
823 assert_eq!(config.ai.provider, "test-ai");
824 assert_eq!(config.ai.model, "test-model");
825 assert!(config.general.backup_enabled);
826 }
827
828 #[test]
829 fn test_builder_parallel_settings_overrides_individual_methods() {
830 let config = TestConfigBuilder::new()
831 .with_max_concurrent_jobs(4)
832 .with_task_queue_size(100)
833 .with_parallel_settings(8, 200)
834 .build_config();
835 assert_eq!(config.general.max_concurrent_jobs, 8);
836 assert_eq!(config.parallel.task_queue_size, 200);
837 }
838}