1use crate::generator::Generator;
10use crate::oracle::{
11 diff_results, DiffOptions, DiffResult, ExecutionResult, Executor, PythonExecutor, RustExecutor,
12 SandboxedPythonExecutor,
13};
14use crate::Language;
15
16use super::Transpiler;
17
18#[derive(Debug, Clone)]
20pub struct TranspilerVerification {
21 pub source_code: String,
23 pub target_code: Option<String>,
25 pub source_result: Option<ExecutionResult>,
27 pub target_result: Option<ExecutionResult>,
29 pub diff: Option<DiffResult>,
31 pub verdict: TranspilerVerdict,
33 pub input: String,
35}
36
37#[derive(Debug, Clone, PartialEq, Eq)]
39pub enum TranspilerVerdict {
40 Pass,
42 TranspileError(String),
44 SourceError(String),
46 TargetError(String),
48 OutputMismatch,
50 Timeout,
52}
53
54#[derive(Debug, Clone, Default)]
56pub struct VerificationStats {
57 pub total: usize,
59 pub passed: usize,
61 pub transpile_errors: usize,
63 pub source_errors: usize,
65 pub target_errors: usize,
67 pub mismatches: usize,
69 pub timeouts: usize,
71}
72
73impl VerificationStats {
74 #[must_use]
76 pub fn pass_rate(&self) -> f64 {
77 if self.total == 0 {
78 return 0.0;
79 }
80 (self.passed as f64 / self.total as f64) * 100.0
81 }
82
83 #[must_use]
85 pub fn transpile_rate(&self) -> f64 {
86 if self.total == 0 {
87 return 0.0;
88 }
89 let successful = self.total - self.transpile_errors;
90 (successful as f64 / self.total as f64) * 100.0
91 }
92}
93
94pub struct TranspilerOracle<T: Transpiler> {
96 transpiler: T,
97 source_executor: Box<dyn Executor>,
98 target_executor: Box<dyn Executor>,
99 diff_options: DiffOptions,
100 timeout_ms: u64,
101 use_sandbox: bool,
102}
103
104impl<T: Transpiler> TranspilerOracle<T> {
105 pub fn new(transpiler: T) -> Self {
107 let source_executor: Box<dyn Executor> = match transpiler.source_language() {
108 Language::Python => Box::new(SandboxedPythonExecutor::new()),
109 _ => Box::new(PythonExecutor::new()), };
111
112 let target_executor: Box<dyn Executor> = match transpiler.target_language() {
113 Language::Python => Box::new(PythonExecutor::new()),
114 _ => Box::new(RustExecutor::new()),
116 };
117
118 Self {
119 transpiler,
120 source_executor,
121 target_executor,
122 diff_options: DiffOptions::default(),
123 timeout_ms: 5000,
124 use_sandbox: true,
125 }
126 }
127
128 #[must_use]
130 pub fn with_timeout(mut self, timeout_ms: u64) -> Self {
131 self.timeout_ms = timeout_ms;
132 self
133 }
134
135 #[must_use]
137 pub fn with_diff_options(mut self, options: DiffOptions) -> Self {
138 self.diff_options = options;
139 self
140 }
141
142 #[must_use]
144 pub fn without_sandbox(mut self) -> Self {
145 self.use_sandbox = false;
146 if matches!(self.transpiler.source_language(), Language::Python) {
147 self.source_executor = Box::new(PythonExecutor::new());
148 }
149 self
150 }
151
152 pub fn verify(&self, source: &str, input: &str) -> TranspilerVerification {
154 let target_code = match self.transpiler.transpile(source) {
156 Ok(code) => code,
157 Err(e) => {
158 return TranspilerVerification {
159 source_code: source.to_string(),
160 target_code: None,
161 source_result: None,
162 target_result: None,
163 diff: None,
164 verdict: TranspilerVerdict::TranspileError(e.to_string()),
165 input: input.to_string(),
166 };
167 }
168 };
169
170 let source_result = match self.source_executor.execute(source, input, self.timeout_ms) {
172 Ok(result) => result,
173 Err(e) => {
174 let msg = e.to_string();
175 let verdict = if msg.contains("timeout") || msg.contains("timed out") {
176 TranspilerVerdict::Timeout
177 } else {
178 TranspilerVerdict::SourceError(msg)
179 };
180 return TranspilerVerification {
181 source_code: source.to_string(),
182 target_code: Some(target_code),
183 source_result: None,
184 target_result: None,
185 diff: None,
186 verdict,
187 input: input.to_string(),
188 };
189 }
190 };
191
192 let target_result = match self
194 .target_executor
195 .execute(&target_code, input, self.timeout_ms)
196 {
197 Ok(result) => result,
198 Err(e) => {
199 let msg = e.to_string();
200 let verdict = if msg.contains("timeout") || msg.contains("timed out") {
201 TranspilerVerdict::Timeout
202 } else {
203 TranspilerVerdict::TargetError(msg)
204 };
205 return TranspilerVerification {
206 source_code: source.to_string(),
207 target_code: Some(target_code),
208 source_result: Some(source_result),
209 target_result: None,
210 diff: None,
211 verdict,
212 input: input.to_string(),
213 };
214 }
215 };
216
217 let diff = diff_results(&source_result, &target_result, &self.diff_options);
219 let verdict = if diff.matches {
220 TranspilerVerdict::Pass
221 } else {
222 TranspilerVerdict::OutputMismatch
223 };
224
225 TranspilerVerification {
226 source_code: source.to_string(),
227 target_code: Some(target_code),
228 source_result: Some(source_result),
229 target_result: Some(target_result),
230 diff: Some(diff),
231 verdict,
232 input: input.to_string(),
233 }
234 }
235
236 pub fn verify_batch(
238 &self,
239 sources: &[(String, String)],
240 ) -> (Vec<TranspilerVerification>, VerificationStats) {
241 let mut results = Vec::with_capacity(sources.len());
242 let mut stats = VerificationStats::default();
243
244 for (source, input) in sources {
245 let verification = self.verify(source, input);
246 stats.total += 1;
247
248 match &verification.verdict {
249 TranspilerVerdict::Pass => stats.passed += 1,
250 TranspilerVerdict::TranspileError(_) => stats.transpile_errors += 1,
251 TranspilerVerdict::SourceError(_) => stats.source_errors += 1,
252 TranspilerVerdict::TargetError(_) => stats.target_errors += 1,
253 TranspilerVerdict::OutputMismatch => stats.mismatches += 1,
254 TranspilerVerdict::Timeout => stats.timeouts += 1,
255 }
256
257 results.push(verification);
258 }
259
260 (results, stats)
261 }
262
263 pub fn verify_generated(
265 &self,
266 count: usize,
267 max_depth: usize,
268 ) -> (Vec<TranspilerVerification>, VerificationStats) {
269 let generator = Generator::new(self.transpiler.source_language());
270 let programs = generator.generate_exhaustive(max_depth);
271
272 let sources: Vec<_> = programs
273 .into_iter()
274 .take(count)
275 .map(|p| (p.code, String::new())) .collect();
277
278 self.verify_batch(&sources)
279 }
280
281 #[must_use]
283 pub fn transpiler(&self) -> &T {
284 &self.transpiler
285 }
286}
287
288impl<T: Transpiler> std::fmt::Debug for TranspilerOracle<T> {
289 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
290 f.debug_struct("TranspilerOracle")
291 .field("source_language", &self.transpiler.source_language())
292 .field("target_language", &self.transpiler.target_language())
293 .field("timeout_ms", &self.timeout_ms)
294 .field("use_sandbox", &self.use_sandbox)
295 .field("diff_options", &self.diff_options)
296 .finish_non_exhaustive()
297 }
298}
299
300#[cfg(test)]
301mod tests {
302 use super::*;
303 use crate::grammar::{grammar_for, Grammar};
304 use crate::{Error, Result};
305
306 struct MockTranspiler {
308 source: Language,
309 target: Language,
310 }
311
312 impl MockTranspiler {
313 fn new(source: Language, target: Language) -> Self {
314 Self { source, target }
315 }
316 }
317
318 impl Transpiler for MockTranspiler {
319 fn source_language(&self) -> Language {
320 self.source
321 }
322
323 fn target_language(&self) -> Language {
324 self.target
325 }
326
327 fn transpile(&self, source: &str) -> Result<String> {
328 if source.contains("print") {
330 if let Some(start) = source.find("print(") {
332 let rest = &source[start + 6..];
333 if let Some(end) = rest.find(')') {
334 let arg = &rest[..end];
335 if arg.starts_with('\'') || arg.starts_with('"') {
337 let content = &arg[1..arg.len() - 1];
338 return Ok(format!("fn main() {{\n println!(\"{}\");\n}}", content));
339 }
340 return Ok(format!(
342 "fn main() {{\n println!(\"{{}}\", {});\n}}",
343 arg
344 ));
345 }
346 }
347 }
348 Ok(format!("fn main() {{\n // {}\n}}", source))
350 }
351
352 fn grammar(&self) -> &dyn Grammar {
353 Box::leak(grammar_for(self.source))
356 }
357
358 fn version(&self) -> &str {
359 "0.1.0-mock"
360 }
361 }
362
363 #[test]
364 fn test_verification_stats() {
365 let stats = VerificationStats {
366 total: 100,
367 passed: 80,
368 transpile_errors: 5,
369 source_errors: 5,
370 target_errors: 5,
371 mismatches: 3,
372 timeouts: 2,
373 };
374
375 assert!((stats.pass_rate() - 80.0).abs() < 0.001);
376 assert!((stats.transpile_rate() - 95.0).abs() < 0.001);
377 }
378
379 #[test]
380 fn test_verification_stats_empty() {
381 let stats = VerificationStats::default();
382 assert!((stats.pass_rate() - 0.0).abs() < 0.001);
383 }
384
385 #[test]
386 fn test_transpiler_verdict_eq() {
387 assert_eq!(TranspilerVerdict::Pass, TranspilerVerdict::Pass);
388 assert_ne!(TranspilerVerdict::Pass, TranspilerVerdict::OutputMismatch);
389 }
390
391 #[test]
392 fn test_mock_transpiler() {
393 let transpiler = MockTranspiler::new(Language::Python, Language::Rust);
394 assert_eq!(transpiler.source_language(), Language::Python);
395 assert_eq!(transpiler.target_language(), Language::Rust);
396
397 let result = transpiler.transpile("print('hello')");
398 assert!(result.is_ok());
399 let code = result.unwrap();
400 assert!(code.contains("println!"));
401 assert!(code.contains("hello"));
402 }
403
404 #[test]
405 fn test_transpiler_oracle_creation() {
406 let transpiler = MockTranspiler::new(Language::Python, Language::Rust);
407 let oracle = TranspilerOracle::new(transpiler);
408
409 assert_eq!(oracle.transpiler().source_language(), Language::Python);
410 assert_eq!(oracle.transpiler().target_language(), Language::Rust);
411 }
412
413 #[test]
414 fn test_transpiler_oracle_verify_transpile_error() {
415 struct FailingTranspiler;
416
417 impl Transpiler for FailingTranspiler {
418 fn source_language(&self) -> Language {
419 Language::Python
420 }
421 fn target_language(&self) -> Language {
422 Language::Rust
423 }
424 fn transpile(&self, _source: &str) -> Result<String> {
425 Err(Error::Transpile("Unsupported syntax".to_string()))
426 }
427 fn grammar(&self) -> &dyn Grammar {
428 Box::leak(grammar_for(Language::Python))
429 }
430 fn version(&self) -> &str {
431 "0.0.0"
432 }
433 }
434
435 let oracle = TranspilerOracle::new(FailingTranspiler);
436 let result = oracle.verify("invalid code", "");
437
438 assert!(matches!(
439 result.verdict,
440 TranspilerVerdict::TranspileError(_)
441 ));
442 }
443
444 #[test]
445 fn test_transpiler_oracle_with_timeout() {
446 let transpiler = MockTranspiler::new(Language::Python, Language::Rust);
447 let oracle = TranspilerOracle::new(transpiler).with_timeout(1000);
448 assert_eq!(oracle.timeout_ms, 1000);
449 }
450
451 #[test]
452 fn test_transpiler_oracle_with_diff_options() {
453 let transpiler = MockTranspiler::new(Language::Python, Language::Rust);
454 let options = DiffOptions {
455 normalize_whitespace: true,
456 ignore_trailing_whitespace: true,
457 ignore_case: false,
458 float_tolerance: Some(0.001),
459 ignore_stderr: false,
460 ignore_exit_code: false,
461 };
462 let oracle = TranspilerOracle::new(transpiler).with_diff_options(options);
463 assert!(oracle.diff_options.normalize_whitespace);
464 }
465
466 #[test]
467 fn test_transpiler_oracle_without_sandbox() {
468 let transpiler = MockTranspiler::new(Language::Python, Language::Rust);
469 let oracle = TranspilerOracle::new(transpiler).without_sandbox();
470 assert!(!oracle.use_sandbox);
471 }
472
473 #[test]
474 fn test_transpiler_oracle_debug() {
475 let transpiler = MockTranspiler::new(Language::Python, Language::Rust);
476 let oracle = TranspilerOracle::new(transpiler);
477 let debug = format!("{:?}", oracle);
478 assert!(debug.contains("TranspilerOracle"));
479 assert!(debug.contains("Python"));
480 assert!(debug.contains("Rust"));
481 }
482
483 #[test]
484 fn test_transpiler_verification_clone() {
485 let verification = TranspilerVerification {
486 source_code: "print(1)".to_string(),
487 target_code: Some("fn main() {}".to_string()),
488 source_result: None,
489 target_result: None,
490 diff: None,
491 verdict: TranspilerVerdict::Pass,
492 input: String::new(),
493 };
494 let cloned = verification.clone();
495 assert_eq!(cloned.source_code, verification.source_code);
496 assert_eq!(cloned.verdict, verification.verdict);
497 }
498
499 #[test]
500 fn test_transpiler_verdict_debug() {
501 let verdict = TranspilerVerdict::TranspileError("test error".to_string());
502 let debug = format!("{:?}", verdict);
503 assert!(debug.contains("TranspileError"));
504 }
505
506 #[test]
507 fn test_transpiler_verdict_source_error() {
508 let verdict = TranspilerVerdict::SourceError("runtime error".to_string());
509 assert!(matches!(verdict, TranspilerVerdict::SourceError(_)));
510 }
511
512 #[test]
513 fn test_transpiler_verdict_target_error() {
514 let verdict = TranspilerVerdict::TargetError("compilation error".to_string());
515 assert!(matches!(verdict, TranspilerVerdict::TargetError(_)));
516 }
517
518 #[test]
519 fn test_transpiler_verdict_output_mismatch() {
520 let verdict = TranspilerVerdict::OutputMismatch;
521 assert_eq!(verdict, TranspilerVerdict::OutputMismatch);
522 }
523
524 #[test]
525 fn test_transpiler_verdict_timeout() {
526 let verdict = TranspilerVerdict::Timeout;
527 assert_eq!(verdict, TranspilerVerdict::Timeout);
528 }
529
530 #[test]
531 fn test_verification_stats_default() {
532 let stats = VerificationStats::default();
533 assert_eq!(stats.total, 0);
534 assert_eq!(stats.passed, 0);
535 assert_eq!(stats.transpile_errors, 0);
536 }
537
538 #[test]
539 fn test_verification_stats_transpile_rate() {
540 let stats = VerificationStats {
541 total: 100,
542 passed: 80,
543 transpile_errors: 10,
544 source_errors: 5,
545 target_errors: 3,
546 mismatches: 1,
547 timeouts: 1,
548 };
549 assert!((stats.transpile_rate() - 90.0).abs() < 0.001);
550 }
551
552 #[test]
553 fn test_verification_stats_debug() {
554 let stats = VerificationStats {
555 total: 10,
556 passed: 8,
557 transpile_errors: 1,
558 source_errors: 0,
559 target_errors: 0,
560 mismatches: 1,
561 timeouts: 0,
562 };
563 let debug = format!("{:?}", stats);
564 assert!(debug.contains("VerificationStats"));
565 }
566
567 #[test]
568 fn test_verification_stats_clone() {
569 let stats = VerificationStats {
570 total: 50,
571 passed: 40,
572 transpile_errors: 5,
573 source_errors: 2,
574 target_errors: 1,
575 mismatches: 1,
576 timeouts: 1,
577 };
578 let cloned = stats.clone();
579 assert_eq!(cloned.total, stats.total);
580 assert_eq!(cloned.passed, stats.passed);
581 }
582
583 #[test]
584 fn test_transpiler_oracle_verify_batch_empty() {
585 let transpiler = MockTranspiler::new(Language::Python, Language::Rust);
586 let oracle = TranspilerOracle::new(transpiler);
587 let (results, stats) = oracle.verify_batch(&[]);
588 assert!(results.is_empty());
589 assert_eq!(stats.total, 0);
590 }
591
592 #[test]
593 fn test_mock_transpiler_numeric_expression() {
594 let transpiler = MockTranspiler::new(Language::Python, Language::Rust);
595 let result = transpiler.transpile("print(1 + 2)");
596 assert!(result.is_ok());
597 let code = result.unwrap();
598 assert!(code.contains("println!"));
599 assert!(code.contains("1 + 2"));
600 }
601
602 #[test]
603 fn test_mock_transpiler_non_print() {
604 let transpiler = MockTranspiler::new(Language::Python, Language::Rust);
605 let result = transpiler.transpile("x = 5");
606 assert!(result.is_ok());
607 let code = result.unwrap();
608 assert!(code.contains("fn main()"));
609 assert!(code.contains("x = 5"));
610 }
611
612 #[test]
613 fn test_mock_transpiler_version() {
614 let transpiler = MockTranspiler::new(Language::Python, Language::Rust);
615 assert_eq!(transpiler.version(), "0.1.0-mock");
616 }
617
618 #[test]
619 fn test_mock_transpiler_grammar() {
620 let transpiler = MockTranspiler::new(Language::Python, Language::Rust);
621 let grammar = transpiler.grammar();
622 assert_eq!(grammar.language(), Language::Python);
623 }
624
625 #[test]
626 fn test_verification_stats_transpile_rate_zero_total() {
627 let stats = VerificationStats::default();
628 assert!((stats.transpile_rate() - 0.0).abs() < 0.001);
629 }
630
631 #[test]
632 fn test_transpiler_oracle_verify_pass() {
633 use crate::oracle::PythonExecutor;
634 let executor = PythonExecutor::new();
635 if !executor.is_available() {
636 eprintln!("Python not available, skipping test");
637 return;
638 }
639
640 struct PassingTranspiler;
642
643 impl Transpiler for PassingTranspiler {
644 fn source_language(&self) -> Language {
645 Language::Python
646 }
647 fn target_language(&self) -> Language {
648 Language::Python
649 }
650 fn transpile(&self, source: &str) -> Result<String> {
651 Ok(source.to_string())
653 }
654 fn grammar(&self) -> &dyn Grammar {
655 Box::leak(grammar_for(Language::Python))
656 }
657 fn version(&self) -> &str {
658 "1.0.0"
659 }
660 }
661
662 let oracle = TranspilerOracle::new(PassingTranspiler);
663 let result = oracle.verify("print('hello')", "");
664
665 assert_eq!(result.verdict, TranspilerVerdict::Pass);
666 assert!(result.source_result.is_some());
667 assert!(result.target_result.is_some());
668 assert!(result.diff.is_some());
669 }
670
671 #[test]
672 fn test_transpiler_oracle_verify_mismatch() {
673 use crate::oracle::PythonExecutor;
674 let executor = PythonExecutor::new();
675 if !executor.is_available() {
676 eprintln!("Python not available, skipping test");
677 return;
678 }
679
680 struct MismatchTranspiler;
682
683 impl Transpiler for MismatchTranspiler {
684 fn source_language(&self) -> Language {
685 Language::Python
686 }
687 fn target_language(&self) -> Language {
688 Language::Python
689 }
690 fn transpile(&self, _source: &str) -> Result<String> {
691 Ok("print('goodbye')".to_string())
693 }
694 fn grammar(&self) -> &dyn Grammar {
695 Box::leak(grammar_for(Language::Python))
696 }
697 fn version(&self) -> &str {
698 "1.0.0"
699 }
700 }
701
702 let oracle = TranspilerOracle::new(MismatchTranspiler);
703 let result = oracle.verify("print('hello')", "");
704
705 assert_eq!(result.verdict, TranspilerVerdict::OutputMismatch);
706 }
707
708 #[test]
709 fn test_transpiler_oracle_verify_target_execution_error() {
710 use crate::oracle::PythonExecutor;
711 let executor = PythonExecutor::new();
712 if !executor.is_available() {
713 eprintln!("Python not available, skipping test");
714 return;
715 }
716
717 struct TargetErrorTranspiler;
719
720 impl Transpiler for TargetErrorTranspiler {
721 fn source_language(&self) -> Language {
722 Language::Python
723 }
724 fn target_language(&self) -> Language {
725 Language::Python
726 }
727 fn transpile(&self, _source: &str) -> Result<String> {
728 Ok("this is not valid python syntax !!@#$".to_string())
730 }
731 fn grammar(&self) -> &dyn Grammar {
732 Box::leak(grammar_for(Language::Python))
733 }
734 fn version(&self) -> &str {
735 "1.0.0"
736 }
737 }
738
739 let oracle = TranspilerOracle::new(TargetErrorTranspiler);
740 let result = oracle.verify("print('hello')", "");
741
742 assert!(matches!(
745 result.verdict,
746 TranspilerVerdict::TargetError(_) | TranspilerVerdict::OutputMismatch
747 ));
748 }
749
750 #[test]
751 fn test_transpiler_oracle_verify_batch() {
752 use crate::oracle::PythonExecutor;
753 let executor = PythonExecutor::new();
754 if !executor.is_available() {
755 eprintln!("Python not available, skipping test");
756 return;
757 }
758
759 struct PassthroughTranspiler;
761
762 impl Transpiler for PassthroughTranspiler {
763 fn source_language(&self) -> Language {
764 Language::Python
765 }
766 fn target_language(&self) -> Language {
767 Language::Python
768 }
769 fn transpile(&self, source: &str) -> Result<String> {
770 Ok(source.to_string())
771 }
772 fn grammar(&self) -> &dyn Grammar {
773 Box::leak(grammar_for(Language::Python))
774 }
775 fn version(&self) -> &str {
776 "1.0.0"
777 }
778 }
779
780 let oracle = TranspilerOracle::new(PassthroughTranspiler);
781 let sources = vec![
782 ("print(1)".to_string(), String::new()),
783 ("print(2)".to_string(), String::new()),
784 ("print(3)".to_string(), String::new()),
785 ];
786 let (results, stats) = oracle.verify_batch(&sources);
787
788 assert_eq!(results.len(), 3);
789 assert_eq!(stats.total, 3);
790 assert_eq!(stats.passed, 3);
791 }
792
793 #[test]
794 fn test_transpiler_oracle_verify_batch_mixed() {
795 struct MixedTranspiler;
797
798 impl Transpiler for MixedTranspiler {
799 fn source_language(&self) -> Language {
800 Language::Python
801 }
802 fn target_language(&self) -> Language {
803 Language::Python
804 }
805 fn transpile(&self, source: &str) -> Result<String> {
806 if source.contains("FAIL") {
807 Err(Error::Transpile("intentional failure".to_string()))
808 } else {
809 Ok(source.to_string())
810 }
811 }
812 fn grammar(&self) -> &dyn Grammar {
813 Box::leak(grammar_for(Language::Python))
814 }
815 fn version(&self) -> &str {
816 "1.0.0"
817 }
818 }
819
820 let oracle = TranspilerOracle::new(MixedTranspiler);
821 let sources = vec![
822 ("print(1)".to_string(), String::new()),
823 ("FAIL".to_string(), String::new()),
824 ];
825 let (results, stats) = oracle.verify_batch(&sources);
826
827 assert_eq!(results.len(), 2);
828 assert_eq!(stats.total, 2);
829 assert_eq!(stats.transpile_errors, 1);
830 }
831
832 #[test]
833 fn test_transpiler_oracle_verify_generated() {
834 use crate::oracle::PythonExecutor;
835 let executor = PythonExecutor::new();
836 if !executor.is_available() {
837 eprintln!("Python not available, skipping test");
838 return;
839 }
840
841 struct GeneratedTranspiler;
842
843 impl Transpiler for GeneratedTranspiler {
844 fn source_language(&self) -> Language {
845 Language::Python
846 }
847 fn target_language(&self) -> Language {
848 Language::Python
849 }
850 fn transpile(&self, source: &str) -> Result<String> {
851 Ok(source.to_string())
852 }
853 fn grammar(&self) -> &dyn Grammar {
854 Box::leak(grammar_for(Language::Python))
855 }
856 fn version(&self) -> &str {
857 "1.0.0"
858 }
859 }
860
861 let oracle = TranspilerOracle::new(GeneratedTranspiler);
862 let (results, stats) = oracle.verify_generated(5, 2);
863
864 assert!(results.len() <= 5);
866 assert!(stats.total <= 5);
867 }
868
869 #[test]
870 fn test_transpiler_oracle_new_with_rust_source() {
871 struct RustSourceTranspiler;
873
874 impl Transpiler for RustSourceTranspiler {
875 fn source_language(&self) -> Language {
876 Language::Rust
877 }
878 fn target_language(&self) -> Language {
879 Language::Python
880 }
881 fn transpile(&self, _source: &str) -> Result<String> {
882 Ok("print('hi')".to_string())
883 }
884 fn grammar(&self) -> &dyn Grammar {
885 Box::leak(grammar_for(Language::Python))
886 }
887 fn version(&self) -> &str {
888 "1.0.0"
889 }
890 }
891
892 let oracle = TranspilerOracle::new(RustSourceTranspiler);
893 assert_eq!(oracle.transpiler().source_language(), Language::Rust);
894 }
895}