@@ -717,28 +717,49 @@ mod tests {
717717
718718 #[ test]
719719 fn test_fs_read_deser ( ) {
720- serde_json :: from_value :: < FsRead > ( serde_json :: json! ( { "path" : "/test_file.txt" , "mode" : "Line" } ) ) . unwrap ( ) ;
720+ // Test single operations (wrapped in operations array)
721721 serde_json:: from_value :: < FsRead > (
722- serde_json:: json!( { "path" : "/test_file.txt" , "mode" : "Line" , "end_line" : 5 } ) ,
722+ serde_json:: json!( { "operations" : [ { " path": "/test_file.txt" , "mode" : "Line" } ] } ) ,
723723 )
724724 . unwrap ( ) ;
725725 serde_json:: from_value :: < FsRead > (
726- serde_json:: json!( { "path" : "/test_file.txt" , "mode" : "Line" , "start_line " : - 1 } ) ,
726+ serde_json:: json!( { "operations" : [ { " path": "/test_file.txt" , "mode" : "Line" , "end_line " : 5 } ] } ) ,
727727 )
728728 . unwrap ( ) ;
729729 serde_json:: from_value :: < FsRead > (
730- serde_json:: json!( { "path" : "/test_file.txt" , "mode" : "Line" , "start_line" : None :: < usize > } ) ,
730+ serde_json:: json!( { "operations" : [ { " path": "/test_file.txt" , "mode" : "Line" , "start_line" : - 1 } ] } ) ,
731731 )
732732 . unwrap ( ) ;
733- serde_json:: from_value :: < FsRead > ( serde_json:: json!( { "path" : "/" , "mode" : "Directory" } ) ) . unwrap ( ) ;
734733 serde_json:: from_value :: < FsRead > (
735- serde_json:: json!( { "path" : "/test_file.txt" , "mode" : "Directory " , "depth " : 2 } ) ,
734+ serde_json:: json!( { "operations" : [ { " path": "/test_file.txt" , "mode" : "Line " , "start_line " : None :: < usize > } ] } ) ,
736735 )
737736 . unwrap ( ) ;
737+ serde_json:: from_value :: < FsRead > ( serde_json:: json!( { "operations" : [ { "path" : "/" , "mode" : "Directory" } ] } ) )
738+ . unwrap ( ) ;
738739 serde_json:: from_value :: < FsRead > (
739- serde_json:: json!( { "path" : "/test_file.txt" , "mode" : "Search " , "pattern " : "hello" } ) ,
740+ serde_json:: json!( { "operations" : [ { " path": "/test_file.txt" , "mode" : "Directory " , "depth " : 2 } ] } ) ,
740741 )
741742 . unwrap ( ) ;
743+ serde_json:: from_value :: < FsRead > (
744+ serde_json:: json!( { "operations" : [ { "path" : "/test_file.txt" , "mode" : "Search" , "pattern" : "hello" } ] } ) ,
745+ )
746+ . unwrap ( ) ;
747+ serde_json:: from_value :: < FsRead > ( serde_json:: json!( {
748+ "operations" : [ { "image_paths" : [ "/img1.png" , "/img2.jpg" ] , "mode" : "Image" } ]
749+ } ) )
750+ . unwrap ( ) ;
751+
752+ // Test mixed batch operations
753+ serde_json:: from_value :: < FsRead > ( serde_json:: json!( {
754+ "operations" : [
755+ { "path" : "/file.txt" , "mode" : "Line" } ,
756+ { "path" : "/dir" , "mode" : "Directory" , "depth" : 1 } ,
757+ { "path" : "/log.txt" , "mode" : "Search" , "pattern" : "warning" } ,
758+ { "image_paths" : [ "/photo.jpg" ] , "mode" : "Image" }
759+ ] ,
760+ "purpose" : "Comprehensive file analysis"
761+ } ) )
762+ . unwrap ( ) ;
742763 }
743764
744765 #[ tokio:: test]
@@ -750,10 +771,11 @@ mod tests {
750771 macro_rules! assert_lines {
751772 ( $start_line: expr, $end_line: expr, $expected: expr) => {
752773 let v = serde_json:: json!( {
774+ "operations" : [ {
753775 "path" : TEST_FILE_PATH ,
754776 "mode" : "Line" ,
755777 "start_line" : $start_line,
756- "end_line" : $end_line,
778+ "end_line" : $end_line, } ]
757779 } ) ;
758780 let output = serde_json:: from_value:: <FsRead >( v)
759781 . unwrap( )
@@ -783,11 +805,11 @@ mod tests {
783805 let os = setup_test_directory ( ) . await ;
784806 let mut stdout = std:: io:: stdout ( ) ;
785807 let v = serde_json:: json!( {
808+ "operations" : [ {
786809 "path" : TEST_FILE_PATH ,
787810 "mode" : "Line" ,
788811 "start_line" : 100 ,
789- "end_line" : None :: <i32 >,
790- } ) ;
812+ "end_line" : None :: <i32 >, } ] } ) ;
791813 assert ! (
792814 serde_json:: from_value:: <FsRead >( v)
793815 . unwrap( )
@@ -818,9 +840,10 @@ mod tests {
818840
819841 // Testing without depth
820842 let v = serde_json:: json!( {
843+ "operations" : [ {
821844 "mode" : "Directory" ,
822845 "path" : "/" ,
823- } ) ;
846+ } ] } ) ;
824847 let output = serde_json:: from_value :: < FsRead > ( v)
825848 . unwrap ( )
826849 . invoke ( & os, & mut stdout)
@@ -835,9 +858,10 @@ mod tests {
835858
836859 // Testing with depth level 1
837860 let v = serde_json:: json!( {
861+ "operations" : [ {
838862 "mode" : "Directory" ,
839863 "path" : "/" ,
840- "depth" : 1 ,
864+ "depth" : 1 , } ]
841865 } ) ;
842866 let output = serde_json:: from_value :: < FsRead > ( v)
843867 . unwrap ( )
@@ -880,9 +904,10 @@ mod tests {
880904 }
881905
882906 let matches = invoke_search ! ( {
907+ "operations" : [ {
883908 "mode" : "Search" ,
884909 "path" : TEST_FILE_PATH ,
885- "pattern" : "hello" ,
910+ "pattern" : "hello" , } ]
886911 } ) ;
887912 assert_eq ! ( matches. len( ) , 2 ) ;
888913 assert_eq ! ( matches[ 0 ] . line_number, 1 ) ;
@@ -907,8 +932,9 @@ mod tests {
907932 os. fs . write ( binary_file_path, & binary_data) . await . unwrap ( ) ;
908933
909934 let v = serde_json:: json!( {
935+ "operations" : [ {
910936 "path" : binary_file_path,
911- "mode" : "Line"
937+ "mode" : "Line" } ]
912938 } ) ;
913939 let output = serde_json:: from_value :: < FsRead > ( v)
914940 . unwrap ( )
@@ -938,8 +964,9 @@ mod tests {
938964 os. fs . write ( latin1_file_path, & latin1_data) . await . unwrap ( ) ;
939965
940966 let v = serde_json:: json!( {
967+ "operations" : [ {
941968 "path" : latin1_file_path,
942- "mode" : "Line"
969+ "mode" : "Line" } ]
943970 } ) ;
944971 let output = serde_json:: from_value :: < FsRead > ( v)
945972 . unwrap ( )
@@ -973,9 +1000,10 @@ mod tests {
9731000 os. fs . write ( mixed_file_path, & mixed_data) . await . unwrap ( ) ;
9741001
9751002 let v = serde_json:: json!( {
1003+ "operations" : [ {
9761004 "mode" : "Search" ,
9771005 "path" : mixed_file_path,
978- "pattern" : "hello"
1006+ "pattern" : "hello" } ]
9791007 } ) ;
9801008 let output = serde_json:: from_value :: < FsRead > ( v)
9811009 . unwrap ( )
@@ -996,9 +1024,10 @@ mod tests {
9961024 }
9971025
9981026 let v = serde_json:: json!( {
1027+ "operations" : [ {
9991028 "mode" : "Search" ,
10001029 "path" : mixed_file_path,
1001- "pattern" : "goodbye"
1030+ "pattern" : "goodbye" } ]
10021031 } ) ;
10031032 let output = serde_json:: from_value :: < FsRead > ( v)
10041033 . unwrap ( )
@@ -1033,8 +1062,9 @@ mod tests {
10331062 os. fs . write ( windows1252_file_path, & windows1252_data) . await . unwrap ( ) ;
10341063
10351064 let v = serde_json:: json!( {
1065+ "operations" : [ {
10361066 "path" : windows1252_file_path,
1037- "mode" : "Line"
1067+ "mode" : "Line" } ]
10381068 } ) ;
10391069 let output = serde_json:: from_value :: < FsRead > ( v)
10401070 . unwrap ( )
@@ -1071,9 +1101,10 @@ mod tests {
10711101 . unwrap ( ) ;
10721102
10731103 let v = serde_json:: json!( {
1104+ "operations" : [ {
10741105 "mode" : "Search" ,
10751106 "path" : invalid_utf8_file_path,
1076- "pattern" : "caf"
1107+ "pattern" : "caf" } ]
10771108 } ) ;
10781109 let output = serde_json:: from_value :: < FsRead > ( v)
10791110 . unwrap ( )
@@ -1101,8 +1132,9 @@ mod tests {
11011132 os. fs . write ( invalid_only_file_path, & invalid_only_data) . await . unwrap ( ) ;
11021133
11031134 let v = serde_json:: json!( {
1135+ "operations" : [ {
11041136 "path" : invalid_only_file_path,
1105- "mode" : "Line"
1137+ "mode" : "Line" } ]
11061138 } ) ;
11071139 let output = serde_json:: from_value :: < FsRead > ( v)
11081140 . unwrap ( )
@@ -1118,9 +1150,10 @@ mod tests {
11181150 }
11191151
11201152 let v = serde_json:: json!( {
1153+ "operations" : [ {
11211154 "mode" : "Search" ,
11221155 "path" : invalid_only_file_path,
1123- "pattern" : "test"
1156+ "pattern" : "test" } ]
11241157 } ) ;
11251158 let output = serde_json:: from_value :: < FsRead > ( v)
11261159 . unwrap ( )
@@ -1139,4 +1172,65 @@ mod tests {
11391172 panic ! ( "expected Text output" ) ;
11401173 }
11411174 }
1175+
1176+ #[ tokio:: test]
1177+ async fn test_fs_read_batch_mixed_operations ( ) {
1178+ let os = setup_test_directory ( ) . await ;
1179+ let mut stdout = Vec :: new ( ) ;
1180+
1181+ let v = serde_json:: json!( {
1182+ "operations" : [
1183+ { "path" : TEST_FILE_PATH , "mode" : "Line" , "start_line" : 1 , "end_line" : 2 } ,
1184+ { "path" : "/" , "mode" : "Directory" } ,
1185+ { "path" : TEST_FILE_PATH , "mode" : "Search" , "pattern" : "hello" }
1186+ ] ,
1187+ "purpose" : "Test mixed text operations"
1188+ } ) ;
1189+
1190+ let output = serde_json:: from_value :: < FsRead > ( v)
1191+ . unwrap ( )
1192+ . invoke ( & os, & mut stdout)
1193+ . await
1194+ . unwrap ( ) ;
1195+ print ! ( "output {:?}" , output) ;
1196+ // All text operations should return combined text
1197+ if let OutputKind :: Text ( text) = output. output {
1198+ // Check all operations are included
1199+ assert ! ( text. contains( "=== Operation 1 Result (Text) ===" ) ) ;
1200+ assert ! ( text. contains( "=== Operation 2 Result (Text) ===" ) ) ;
1201+ assert ! ( text. contains( "=== Operation 3 Result (Text) ===" ) ) ;
1202+
1203+ // Check operation 1 (Line mode)
1204+ assert ! ( text. contains( "Hello world!" ) ) ;
1205+ assert ! ( text. contains( "This is line 2" ) ) ;
1206+
1207+ // Check operation 2 (Directory mode)
1208+ assert ! ( text. contains( "test_file.txt" ) ) ;
1209+
1210+ // Check operation 3 (Search mode)
1211+ assert ! ( text. contains( "\" line_number\" :1" ) ) ;
1212+ } else {
1213+ panic ! ( "expected text output for batch operations" ) ;
1214+ }
1215+ }
1216+ #[ tokio:: test]
1217+ async fn test_fs_read_empty_operations ( ) {
1218+ let os = Os :: new ( ) . await . unwrap ( ) ;
1219+
1220+ // Test empty operations array
1221+ let v = serde_json:: json!( {
1222+ "operations" : [ ]
1223+ } ) ;
1224+
1225+ let mut fs_read = serde_json:: from_value :: < FsRead > ( v) . unwrap ( ) ;
1226+ let result = fs_read. validate ( & os) . await ;
1227+
1228+ assert ! ( result. is_err( ) ) ;
1229+ assert ! (
1230+ result
1231+ . unwrap_err( )
1232+ . to_string( )
1233+ . contains( "At least one operation must be provided" )
1234+ ) ;
1235+ }
11421236}
0 commit comments