1use anyhow::{Context, Result};
26use clap::{Parser, Subcommand};
27use std::path::PathBuf;
28
29use crate::{extract, to_format, Format};
30
31#[derive(Parser, Debug)]
33#[command(author, version, about, long_about = None)]
34pub struct Cli {
35 #[command(subcommand)]
36 command: Commands,
37}
38
39#[derive(Subcommand, Debug)]
41enum Commands {
42 Extract {
44 #[arg(required = true)]
46 input: PathBuf,
47
48 #[arg(short, long, default_value = "yaml")]
50 format: String,
51
52 #[arg(short, long)]
54 output: Option<PathBuf>,
55 },
56
57 Validate {
59 #[arg(required = true)]
61 input: PathBuf,
62
63 #[arg(short, long)]
65 required: Option<String>,
66 },
67}
68
69impl Cli {
70 pub async fn process(&self) -> Result<()> {
80 match &self.command {
81 Commands::Extract {
82 input,
83 format,
84 output,
85 } => process_extract(input, format, output).await,
86 Commands::Validate { input, required } => {
87 process_validate(input, required).await
88 }
89 }
90 }
91}
92
93async fn process_extract(
109 input: &PathBuf,
110 format: &str,
111 output: &Option<PathBuf>,
112) -> Result<()> {
113 let content =
115 tokio::fs::read_to_string(input).await.with_context(|| {
116 format!("Failed to read input file: {}", input.display())
117 })?;
118
119 let (frontmatter, remaining) = extract(&content)
121 .with_context(|| "Failed to extract frontmatter")?;
122
123 let output_format = match format.to_lowercase().as_str() {
125 "yaml" => Format::Yaml,
126 "toml" => Format::Toml,
127 "json" => Format::Json,
128 _ => {
129 return Err(anyhow::anyhow!(
130 "Unsupported format: {}",
131 format
132 ))
133 }
134 };
135
136 let formatted = to_format(&frontmatter, output_format)
137 .with_context(|| "Failed to format frontmatter")?;
138
139 if let Some(output_path) = output {
141 tokio::fs::write(output_path, formatted)
142 .await
143 .with_context(|| {
144 format!(
145 "Failed to write to output file: {}",
146 output_path.display()
147 )
148 })?;
149 log::info!(
150 "Frontmatter extracted to `{}`",
151 output_path.display()
152 );
153 } else {
154 log::info!(
155 "Extracted Frontmatter as {}\n\n{}\n\n",
156 output_format,
157 formatted
158 );
159 log::info!("Remaining Markdown Content\n\n{}\n\n", remaining);
160 }
161
162 Ok(())
163}
164
165async fn process_validate(
179 input: &PathBuf,
180 required: &Option<String>,
181) -> Result<()> {
182 let content =
184 tokio::fs::read_to_string(input).await.with_context(|| {
185 format!("Failed to read input file: {}", input.display())
186 })?;
187
188 let (frontmatter, _) = extract(&content)
190 .with_context(|| "Failed to extract frontmatter")?;
191
192 if let Some(required_fields) = required {
194 let fields: Vec<&str> = required_fields.split(',').collect();
195 for field in fields {
196 if !frontmatter.contains_key(field) {
197 return Err(anyhow::anyhow!(
198 "Missing required field: {}",
199 field
200 ));
201 }
202 }
203 }
204
205 println!("Validation successful!");
206 Ok(())
207}
208
209#[cfg(test)]
210mod tests {
211 use super::*;
212 use std::fs::File;
213 use std::io::Write;
214 use tempfile::tempdir;
215
216 mod extract_tests {
218 use super::*;
219
220 #[tokio::test]
221 async fn test_extract_command_default_format() -> Result<()> {
222 let dir = tempdir()?;
223 let input_path = dir.path().join("test.md");
224 let output_path = dir.path().join("output.yaml");
225
226 let content = r#"---
228title: "Test"
229date: "2024-01-01"
230---
231Content here"#;
232
233 let mut file = File::create(&input_path)?;
234 writeln!(file, "{}", content)?;
235
236 let args = vec![
238 "program",
239 "extract",
240 input_path.to_str().unwrap(),
241 "--output",
242 output_path.to_str().unwrap(),
243 ];
244 let cli = Cli::parse_from(args);
245 let result = cli.process().await;
246 assert!(result.is_ok());
247
248 let output_content =
250 tokio::fs::read_to_string(&output_path).await?;
251 assert!(output_content.contains("title:"));
252 assert!(output_content.contains("Test"));
253
254 Ok(())
255 }
256
257 #[tokio::test]
258 async fn test_extract_command_uppercase_format() -> Result<()> {
259 let dir = tempdir()?;
260 let input_path = dir.path().join("test.md");
261 let output_path = dir.path().join("output.yaml");
262
263 let content = r#"---
265title: "Test"
266date: "2024-01-01"
267---
268Content here"#;
269
270 let mut file = File::create(&input_path)?;
271 writeln!(file, "{}", content)?;
272
273 let result = process_extract(
275 &input_path,
276 "YAML",
277 &Some(output_path.clone()),
278 )
279 .await;
280 assert!(result.is_ok());
281
282 let output_content =
284 tokio::fs::read_to_string(&output_path).await?;
285 assert!(output_content.contains("title:"));
286 assert!(output_content.contains("Test"));
287
288 Ok(())
289 }
290
291 #[tokio::test]
292 async fn test_extract_command_invalid_format() -> Result<()> {
293 let dir = tempdir()?;
294 let input_path = dir.path().join("test.md");
295
296 let content = r#"---
298title: "Test"
299---
300Content here"#;
301
302 let mut file = File::create(&input_path)?;
303 writeln!(file, "{}", content)?;
304
305 let result =
307 process_extract(&input_path, "invalid_format", &None)
308 .await;
309 assert!(result.is_err());
310 if let Err(e) = result {
311 assert!(e.to_string().contains("Unsupported format"));
312 }
313
314 Ok(())
315 }
316
317 #[tokio::test]
318 async fn test_extract_command() -> Result<()> {
319 let dir = tempdir()?;
320 let input_path = dir.path().join("test.md");
321 let output_path = dir.path().join("output.yaml");
322
323 let content = r#"---
325title: "Test"
326date: "2024-01-01"
327---
328Content here"#;
329 let mut file = File::create(&input_path)?;
330 writeln!(file, "{}", content)?;
331
332 process_extract(
334 &input_path,
335 "yaml",
336 &Some(output_path.clone()),
337 )
338 .await?;
339
340 let output_content =
342 tokio::fs::read_to_string(&output_path).await?;
343 log::debug!("Generated YAML content:\n{}", output_content);
344
345 assert!(
347 output_content.contains("title:"),
348 "title field not found in output"
349 );
350 assert!(
351 output_content.contains("Test"),
352 "Test value not found in output"
353 );
354 assert!(
355 output_content.contains("date:"),
356 "date field not found in output"
357 );
358 assert!(
359 output_content.contains("2024-01-01"),
360 "date value not found in output"
361 );
362
363 Ok(())
364 }
365
366 #[tokio::test]
367 async fn test_extract_command_invalid_input_file() -> Result<()>
368 {
369 let input_path = PathBuf::from("nonexistent.md");
370 let output_path = None;
371 let result =
372 process_extract(&input_path, "yaml", &output_path)
373 .await;
374 assert!(result.is_err());
375 if let Err(e) = result {
376 assert!(e
377 .to_string()
378 .contains("Failed to read input file"));
379 }
380 Ok(())
381 }
382
383 #[tokio::test]
384 async fn test_extract_command_unsupported_format() -> Result<()>
385 {
386 let dir = tempdir()?;
387 let input_path = dir.path().join("test.md");
388
389 let content = r"---
391title: Test
392date: 2024-01-01
393---
394Content here";
395 let mut file = File::create(&input_path)?;
396 writeln!(file, "{}", content)?;
397
398 let result =
399 process_extract(&input_path, "xml", &None).await;
400 assert!(result.is_err());
401 if let Err(e) = result {
402 assert!(e.to_string().contains("Unsupported format"));
403 }
404 Ok(())
405 }
406
407 #[tokio::test]
408 async fn test_extract_command_no_frontmatter() -> Result<()> {
409 let dir = tempdir()?;
410 let input_path = dir.path().join("test.md");
411
412 let content = "Content here without frontmatter";
414 let mut file = File::create(&input_path)?;
415 writeln!(file, "{}", content)?;
416
417 let result =
418 process_extract(&input_path, "yaml", &None).await;
419 assert!(result.is_err());
420 if let Err(e) = result {
421 assert!(e
422 .to_string()
423 .contains("Failed to extract frontmatter"));
424 }
425 Ok(())
426 }
427
428 #[tokio::test]
429 async fn test_extract_command_invalid_frontmatter() -> Result<()>
430 {
431 let dir = tempdir()?;
432 let input_path = dir.path().join("test.md");
433
434 let content = r#"---
436title: "Test
437date: 2024-01-01
438---
439Content here"#; let mut file = File::create(&input_path)?;
442 writeln!(file, "{}", content)?;
443
444 let result =
445 process_extract(&input_path, "yaml", &None).await;
446 assert!(result.is_err());
447 if let Err(e) = result {
448 assert!(e
449 .to_string()
450 .contains("Failed to extract frontmatter"));
451 }
452 Ok(())
453 }
454
455 #[cfg(unix)]
456 #[tokio::test]
457 async fn test_extract_command_output_write_error() -> Result<()>
458 {
459 let dir = tempdir()?;
460 let input_path = dir.path().join("test.md");
461 let output_dir = dir.path().join("readonly_dir");
462
463 let content = r#"---
465title: "Test"
466date: "2024-01-01"
467---
468Content here"#;
469 let mut file = File::create(&input_path)?;
470 writeln!(file, "{}", content)?;
471
472 tokio::fs::create_dir(&output_dir).await?;
474 let mut perms =
475 tokio::fs::metadata(&output_dir).await?.permissions();
476 perms.set_readonly(true);
477 tokio::fs::set_permissions(&output_dir, perms).await?;
478
479 let output_path = output_dir.join("output.yaml");
480
481 let result = process_extract(
483 &input_path,
484 "yaml",
485 &Some(output_path.clone()),
486 )
487 .await;
488 assert!(result.is_err());
489 if let Err(e) = result {
490 assert!(e
491 .to_string()
492 .contains("Failed to write to output file"));
493 }
494
495 Ok(())
496 }
497
498 #[tokio::test]
499 async fn test_extract_command_toml_format() -> Result<()> {
500 let dir = tempdir()?;
501 let input_path = dir.path().join("test.md");
502 let output_path = dir.path().join("output.toml");
503
504 let content = r#"---
506title: "Test"
507date: "2024-01-01"
508---
509Content here"#;
510
511 let mut file = File::create(&input_path)?;
512 writeln!(file, "{}", content)?;
513
514 let result = process_extract(
515 &input_path,
516 "toml",
517 &Some(output_path.clone()),
518 )
519 .await;
520 assert!(result.is_ok());
521
522 let output_content =
524 tokio::fs::read_to_string(&output_path).await?;
525 log::debug!("Generated TOML content:\n{}", output_content);
526
527 assert!(output_content.contains("title = "));
529 assert!(output_content.contains("Test"));
530 assert!(output_content.contains("date = "));
531 assert!(output_content.contains("2024-01-01"));
532
533 Ok(())
534 }
535
536 #[tokio::test]
537 async fn test_extract_command_json_format() -> Result<()> {
538 let dir = tempdir()?;
539 let input_path = dir.path().join("test.md");
540 let output_path = dir.path().join("output.json");
541
542 let content = r#"---
544title: "Test"
545date: "2024-01-01"
546---
547Content here"#;
548
549 let mut file = File::create(&input_path)?;
550 writeln!(file, "{}", content)?;
551
552 let result = process_extract(
553 &input_path,
554 "json",
555 &Some(output_path.clone()),
556 )
557 .await;
558 assert!(result.is_ok());
559
560 let output_content =
562 tokio::fs::read_to_string(&output_path).await?;
563 log::debug!("Generated JSON content:\n{}", output_content);
564
565 assert!(output_content.contains("\"title\":"));
567 assert!(output_content.contains("Test"));
568 assert!(output_content.contains("\"date\":"));
569 assert!(output_content.contains("2024-01-01"));
570
571 Ok(())
572 }
573
574 #[tokio::test]
575 async fn test_extract_command_no_output_file() -> Result<()> {
576 let dir = tempdir()?;
577 let input_path = dir.path().join("test.md");
578
579 let content = r#"---
581title: "Test"
582date: "2024-01-01"
583---
584Content here"#;
585
586 let mut file = File::create(&input_path)?;
587 writeln!(file, "{}", content)?;
588
589 let result =
590 process_extract(&input_path, "yaml", &None).await;
591 assert!(result.is_ok());
592
593 Ok(())
597 }
598 }
599
600 mod validate_tests {
602 use super::*;
603
604 #[tokio::test]
605 async fn test_validate_command_required_fields_whitespace_only(
606 ) -> Result<()> {
607 let dir = tempdir()?;
608 let input_path = dir.path().join("test.md");
609
610 let content = r#"---
612title: "Test"
613date: "2024-01-01"
614---
615Content here"#;
616
617 let mut file = File::create(&input_path)?;
618 writeln!(file, "{}", content)?;
619
620 let result =
622 process_validate(&input_path, &Some(" ".to_string()))
623 .await;
624 assert!(result.is_err());
625 if let Err(e) = result {
626 assert!(e
627 .to_string()
628 .contains("Missing required field: "));
629 }
630
631 Ok(())
632 }
633
634 #[tokio::test]
635 async fn test_cli_process_with_invalid_subcommand() {
636 let result =
637 Cli::try_parse_from(["program", "invalid_command"]);
638 assert!(result.is_err());
639 }
640
641 #[tokio::test]
642 async fn test_validate_command_missing_required_field(
643 ) -> Result<()> {
644 let dir = tempdir()?;
645 let input_path = dir.path().join("test.md");
646
647 let content = r#"---
649title: "Test"
650date: "2024-01-01"
651---
652Content here"#;
653
654 let mut file = File::create(&input_path)?;
655 writeln!(file, "{}", content)?;
656
657 let result = process_validate(
659 &input_path,
660 &Some("author".to_string()),
661 )
662 .await;
663 assert!(result.is_err());
664 if let Err(e) = result {
665 assert!(e
666 .to_string()
667 .contains("Missing required field: author"));
668 }
669
670 Ok(())
671 }
672
673 #[tokio::test]
674 async fn test_extract_command_output_is_directory() -> Result<()>
675 {
676 let dir = tempdir()?;
677 let input_path = dir.path().join("test.md");
678 let output_path = dir.path(); let content = r#"---
682title: "Test"
683date: "2024-01-01"
684---
685Content here"#;
686
687 let mut file = File::create(&input_path)?;
688 writeln!(file, "{}", content)?;
689
690 let result = process_extract(
691 &input_path,
692 "yaml",
693 &Some(output_path.to_path_buf()),
694 )
695 .await;
696 assert!(result.is_err());
697 if let Err(e) = result {
698 assert!(e
699 .to_string()
700 .contains("Failed to write to output file"));
701 }
702
703 Ok(())
704 }
705
706 #[tokio::test]
707 async fn test_extract_command_with_empty_frontmatter(
708 ) -> Result<()> {
709 let dir = tempdir()?;
710 let input_path = dir.path().join("test.md");
711 let output_path = dir.path().join("output.yaml");
712
713 let content = r"---
715---
716Content here";
717
718 let mut file = File::create(&input_path)?;
719 writeln!(file, "{}", content)?;
720
721 let result = process_extract(
722 &input_path,
723 "yaml",
724 &Some(output_path.clone()),
725 )
726 .await;
727 assert!(result.is_err());
728 if let Err(e) = result {
729 assert!(e
730 .to_string()
731 .contains("Failed to extract frontmatter"));
732 }
733
734 Ok(())
735 }
736
737 #[tokio::test]
738 async fn test_validate_command() -> Result<()> {
739 let dir = tempdir()?;
740 let input_path = dir.path().join("test.md");
741
742 let content = r"---
744title: Test
745date: 2024-01-01
746---
747Content here";
748 let mut file = File::create(&input_path)?;
749 writeln!(file, "{}", content)?;
750
751 process_validate(
753 &input_path,
754 &Some("title,date".to_string()),
755 )
756 .await?;
757
758 let result = process_validate(
760 &input_path,
761 &Some("title,author".to_string()),
762 )
763 .await;
764 assert!(result.is_err());
765
766 Ok(())
767 }
768
769 #[tokio::test]
770 async fn test_validate_command_invalid_input_file() -> Result<()>
771 {
772 let input_path = PathBuf::from("nonexistent.md");
773
774 let result = process_validate(
775 &input_path,
776 &Some("title".to_string()),
777 )
778 .await;
779 assert!(result.is_err());
780 if let Err(e) = result {
781 assert!(e
782 .to_string()
783 .contains("Failed to read input file"));
784 }
785
786 Ok(())
787 }
788
789 #[tokio::test]
790 async fn test_validate_command_no_frontmatter() -> Result<()> {
791 let dir = tempdir()?;
792 let input_path = dir.path().join("test.md");
793
794 let content = "Content here without frontmatter";
796 let mut file = File::create(&input_path)?;
797 writeln!(file, "{}", content)?;
798
799 let result = process_validate(
800 &input_path,
801 &Some("title".to_string()),
802 )
803 .await;
804 assert!(result.is_err());
805 if let Err(e) = result {
806 assert!(e
807 .to_string()
808 .contains("Failed to extract frontmatter"));
809 }
810
811 Ok(())
812 }
813
814 #[tokio::test]
815 async fn test_validate_command_invalid_frontmatter(
816 ) -> Result<()> {
817 let dir = tempdir()?;
818 let input_path = dir.path().join("test.md");
819
820 let content = r"---
822title: 'Test
823date: 2024-01-01
824---
825Content here";
826
827 let mut file = File::create(&input_path)?;
828 writeln!(file, "{}", content)?;
829
830 let result = process_validate(
831 &input_path,
832 &Some("title".to_string()),
833 )
834 .await;
835 assert!(result.is_err());
836 if let Err(e) = result {
837 assert!(e
838 .to_string()
839 .contains("Failed to extract frontmatter"));
840 }
841
842 Ok(())
843 }
844
845 #[tokio::test]
846 async fn test_validate_command_no_required_fields() -> Result<()>
847 {
848 let dir = tempdir()?;
849 let input_path = dir.path().join("test.md");
850
851 let content = r"---
853title: Test
854date: 2024-01-01
855---
856Content here";
857
858 let mut file = File::create(&input_path)?;
859 writeln!(file, "{}", content)?;
860
861 let result = process_validate(&input_path, &None).await;
863 assert!(result.is_ok());
864
865 Ok(())
866 }
867 }
868
869 mod cli_parsing_tests {
871 use super::*;
872 use clap::Parser;
873
874 #[test]
875 fn test_cli_parsing_extract_default_format() {
876 let args =
878 Cli::parse_from(["program", "extract", "input.md"]);
879 match args.command {
880 Commands::Extract { input, format, .. } => {
881 assert_eq!(input, PathBuf::from("input.md"));
882 assert_eq!(format, "yaml"); }
884 _ => panic!("Expected Extract command"),
885 }
886 }
887
888 #[test]
889 fn test_cli_parsing_invalid_command() {
890 let result =
892 Cli::try_parse_from(["program", "invalid", "input.md"]);
893 assert!(result.is_err());
894 }
895
896 #[test]
897 fn test_cli_parsing() {
898 let args = Cli::parse_from([
900 "program", "extract", "input.md", "--format", "yaml",
901 ]);
902 match args.command {
903 Commands::Extract { input, format, .. } => {
904 assert_eq!(input, PathBuf::from("input.md"));
905 assert_eq!(format, "yaml");
906 }
907 _ => panic!("Expected Extract command"),
908 }
909
910 let args = Cli::parse_from([
912 "program",
913 "validate",
914 "input.md",
915 "--required",
916 "title,date",
917 ]);
918 match args.command {
919 Commands::Validate { input, required } => {
920 assert_eq!(input, PathBuf::from("input.md"));
921 assert_eq!(
922 required,
923 Some("title,date".to_string())
924 );
925 }
926 _ => panic!("Expected Validate command"),
927 }
928 }
929 }
930
931 mod cli_process_tests {
933 use super::*;
934
935 #[tokio::test]
936 async fn test_cli_process_extract() -> Result<()> {
937 let dir = tempdir()?;
938 let input_path = dir.path().join("test.md");
939 let output_path = dir.path().join("output.yaml");
940
941 let content = r"---
943title: Test
944date: 2024-01-01
945---
946Content here";
947
948 let mut file = File::create(&input_path)?;
949 writeln!(file, "{}", content)?;
950
951 let cli = Cli {
952 command: Commands::Extract {
953 input: input_path.clone(),
954 format: "yaml".to_string(),
955 output: Some(output_path.clone()),
956 },
957 };
958
959 let result = cli.process().await;
960 assert!(result.is_ok());
961
962 let output_content =
964 tokio::fs::read_to_string(&output_path).await?;
965 assert!(output_content.contains("title:"));
966 assert!(output_content.contains("Test"));
967
968 Ok(())
969 }
970
971 #[tokio::test]
972 async fn test_cli_process_validate() -> Result<()> {
973 let dir = tempdir()?;
974 let input_path = dir.path().join("test.md");
975
976 let content = r"---
978title: Test
979date: 2024-01-01
980---
981Content here";
982 let mut file = File::create(&input_path)?;
983 writeln!(file, "{}", content)?;
984
985 let cli = Cli {
986 command: Commands::Validate {
987 input: input_path.clone(),
988 required: Some("title,date".to_string()),
989 },
990 };
991
992 let result = cli.process().await;
993 assert!(result.is_ok());
994
995 Ok(())
996 }
997 }
998
999 #[tokio::test]
1000 async fn test_extract_command_empty_format() -> Result<()> {
1001 let dir = tempdir()?;
1002 let input_path = dir.path().join("test.md");
1003
1004 let content = r"---
1006title: 'Test'
1007---
1008Content here";
1009
1010 let mut file = File::create(&input_path)?;
1011 writeln!(file, "{}", content)?;
1012
1013 let result = process_extract(&input_path, "", &None).await;
1015 assert!(result.is_err());
1016 if let Err(e) = result {
1017 assert!(e.to_string().contains("Unsupported format"));
1018 }
1019
1020 Ok(())
1021 }
1022
1023 #[tokio::test]
1024 async fn test_validate_command_required_fields_with_whitespace(
1025 ) -> Result<()> {
1026 let dir = tempdir()?;
1027 let input_path = dir.path().join("test.md");
1028
1029 let content = r"---
1031title: 'Test'
1032date: '2024-01-01'
1033---
1034Content here";
1035
1036 let mut file = File::create(&input_path)?;
1037 writeln!(file, "{}", content)?;
1038
1039 let result = process_validate(
1041 &input_path,
1042 &Some(" title , date ".to_string()),
1043 )
1044 .await;
1045 assert!(result.is_err());
1046 if let Err(e) = result {
1047 assert!(e
1048 .to_string()
1049 .contains("Missing required field: title "));
1050 }
1051
1052 Ok(())
1053 }
1054
1055 #[tokio::test]
1056 async fn test_validate_command_duplicate_required_fields(
1057 ) -> Result<()> {
1058 let dir = tempdir()?;
1059 let input_path = dir.path().join("test.md");
1060
1061 let content = r"---
1063title: 'Test'
1064date: '2024-01-01'
1065---
1066Content here";
1067
1068 let mut file = File::create(&input_path)?;
1069 writeln!(file, "{}", content)?;
1070
1071 let result = process_validate(
1073 &input_path,
1074 &Some("title,date,title".to_string()),
1075 )
1076 .await;
1077 assert!(result.is_ok());
1078
1079 Ok(())
1080 }
1081
1082 #[tokio::test]
1083 async fn test_extract_command_with_complex_data() -> Result<()> {
1084 let dir = tempdir()?;
1085 let input_path = dir.path().join("test.md");
1086 let output_path = dir.path().join("output.json");
1087
1088 let content = r"---
1090title: 'Test'
1091tags:
1092 - rust
1093 - cli
1094nested:
1095 level1:
1096 level2: 'deep value'
1097---
1098Content here";
1099
1100 let mut file = File::create(&input_path)?;
1101 writeln!(file, "{}", content)?;
1102
1103 let result = process_extract(
1105 &input_path,
1106 "json",
1107 &Some(output_path.clone()),
1108 )
1109 .await;
1110 assert!(result.is_ok());
1111
1112 let output_content =
1114 tokio::fs::read_to_string(&output_path).await?;
1115 let json_output: serde_json::Value =
1116 serde_json::from_str(&output_content)?;
1117 assert_eq!(json_output["title"], "Test");
1118 assert_eq!(json_output["tags"][0], "rust");
1119 assert_eq!(
1120 json_output["nested"]["level1"]["level2"],
1121 "deep value"
1122 );
1123
1124 Ok(())
1125 }
1126}