@@ -175,5 +175,166 @@ public void Invoke_WithMultipleSources_ExecutesAllOperationsToSink()
175175 sourceExtension . Verify ( se => se . ReadAsync ( It . IsAny < IConfiguration > ( ) , It . IsAny < ILogger > ( ) , It . IsAny < CancellationToken > ( ) ) , Times . Exactly ( 3 ) ) ;
176176 sinkExtension . Verify ( se => se . WriteAsync ( It . IsAny < IAsyncEnumerable < IDataItem > > ( ) , It . Is < IConfiguration > ( c => c [ "FilePath" ] == targetFile ) , sourceExtension . Object , It . IsAny < ILogger > ( ) , It . IsAny < CancellationToken > ( ) ) , Times . Exactly ( 3 ) ) ;
177177 }
178+
179+ [ TestMethod ]
180+ public void Invoke_WithEmptySourceAndSink_ReturnsError ( )
181+ {
182+ IConfigurationRoot configuration = new ConfigurationBuilder ( )
183+ . AddInMemoryCollection ( new Dictionary < string , string ? >
184+ {
185+ { "Source" , "" } ,
186+ { "Sink" , "" } ,
187+ } )
188+ . Build ( ) ;
189+ var loader = new Mock < IExtensionLoader > ( ) ;
190+ loader
191+ . Setup ( l => l . LoadExtensions < IDataSourceExtension > ( It . IsAny < CompositionContainer > ( ) ) )
192+ . Returns ( new List < IDataSourceExtension > ( ) ) ;
193+ loader
194+ . Setup ( l => l . LoadExtensions < IDataSinkExtension > ( It . IsAny < CompositionContainer > ( ) ) )
195+ . Returns ( new List < IDataSinkExtension > ( ) ) ;
196+
197+ var handler = new RunCommand . CommandHandler ( loader . Object ,
198+ configuration ,
199+ NullLoggerFactory . Instance ) ;
200+
201+ var parseResult = new RootCommand ( ) . Parse ( Array . Empty < string > ( ) ) ;
202+ var result = handler . Invoke ( new InvocationContext ( parseResult ) ) ;
203+
204+ // Should return error code when source/sink are not configured
205+ Assert . AreEqual ( 1 , result ) ;
206+ }
207+
208+ [ TestMethod ]
209+ public void Invoke_WithMissingSource_ReturnsError ( )
210+ {
211+ const string sink = "testSink" ;
212+ IConfigurationRoot configuration = new ConfigurationBuilder ( )
213+ . AddInMemoryCollection ( new Dictionary < string , string ? >
214+ {
215+ { "Sink" , sink } ,
216+ } )
217+ . Build ( ) ;
218+ var loader = new Mock < IExtensionLoader > ( ) ;
219+ var sinkExtension = new Mock < IDataSinkExtension > ( ) ;
220+ sinkExtension . SetupGet ( ds => ds . DisplayName ) . Returns ( sink ) ;
221+ loader
222+ . Setup ( l => l . LoadExtensions < IDataSourceExtension > ( It . IsAny < CompositionContainer > ( ) ) )
223+ . Returns ( new List < IDataSourceExtension > ( ) ) ;
224+ loader
225+ . Setup ( l => l . LoadExtensions < IDataSinkExtension > ( It . IsAny < CompositionContainer > ( ) ) )
226+ . Returns ( new List < IDataSinkExtension > { sinkExtension . Object } ) ;
227+
228+ var handler = new RunCommand . CommandHandler ( loader . Object ,
229+ configuration ,
230+ NullLoggerFactory . Instance ) ;
231+
232+ var parseResult = new RootCommand ( ) . Parse ( Array . Empty < string > ( ) ) ;
233+ var result = handler . Invoke ( new InvocationContext ( parseResult ) ) ;
234+
235+ // Should return error code when source is not configured
236+ Assert . AreEqual ( 1 , result ) ;
237+ }
238+
239+ [ TestMethod ]
240+ public void Invoke_WithMissingSink_ReturnsError ( )
241+ {
242+ const string source = "testSource" ;
243+ IConfigurationRoot configuration = new ConfigurationBuilder ( )
244+ . AddInMemoryCollection ( new Dictionary < string , string ? >
245+ {
246+ { "Source" , source } ,
247+ } )
248+ . Build ( ) ;
249+ var loader = new Mock < IExtensionLoader > ( ) ;
250+ var sourceExtension = new Mock < IDataSourceExtension > ( ) ;
251+ sourceExtension . SetupGet ( ds => ds . DisplayName ) . Returns ( source ) ;
252+ loader
253+ . Setup ( l => l . LoadExtensions < IDataSourceExtension > ( It . IsAny < CompositionContainer > ( ) ) )
254+ . Returns ( new List < IDataSourceExtension > { sourceExtension . Object } ) ;
255+ loader
256+ . Setup ( l => l . LoadExtensions < IDataSinkExtension > ( It . IsAny < CompositionContainer > ( ) ) )
257+ . Returns ( new List < IDataSinkExtension > ( ) ) ;
258+
259+ var handler = new RunCommand . CommandHandler ( loader . Object ,
260+ configuration ,
261+ NullLoggerFactory . Instance ) ;
262+
263+ var parseResult = new RootCommand ( ) . Parse ( Array . Empty < string > ( ) ) ;
264+ var result = handler . Invoke ( new InvocationContext ( parseResult ) ) ;
265+
266+ // Should return error code when sink is not configured
267+ Assert . AreEqual ( 1 , result ) ;
268+ }
269+
270+ [ TestMethod ]
271+ public void Invoke_WithInvalidSourceExtension_ThrowsException ( )
272+ {
273+ const string source = "invalidSource" ;
274+ const string sink = "testSink" ;
275+ IConfigurationRoot configuration = new ConfigurationBuilder ( )
276+ . AddInMemoryCollection ( new Dictionary < string , string ? >
277+ {
278+ { "Source" , source } ,
279+ { "Sink" , sink } ,
280+ } )
281+ . Build ( ) ;
282+ var loader = new Mock < IExtensionLoader > ( ) ;
283+ var sourceExtension = new Mock < IDataSourceExtension > ( ) ;
284+ sourceExtension . SetupGet ( ds => ds . DisplayName ) . Returns ( "differentSource" ) ;
285+ loader
286+ . Setup ( l => l . LoadExtensions < IDataSourceExtension > ( It . IsAny < CompositionContainer > ( ) ) )
287+ . Returns ( new List < IDataSourceExtension > { sourceExtension . Object } ) ;
288+
289+ var sinkExtension = new Mock < IDataSinkExtension > ( ) ;
290+ sinkExtension . SetupGet ( ds => ds . DisplayName ) . Returns ( sink ) ;
291+ loader
292+ . Setup ( l => l . LoadExtensions < IDataSinkExtension > ( It . IsAny < CompositionContainer > ( ) ) )
293+ . Returns ( new List < IDataSinkExtension > { sinkExtension . Object } ) ;
294+
295+ var handler = new RunCommand . CommandHandler ( loader . Object ,
296+ configuration ,
297+ NullLoggerFactory . Instance ) ;
298+
299+ var parseResult = new RootCommand ( ) . Parse ( Array . Empty < string > ( ) ) ;
300+
301+ // Should throw exception when source extension is not found
302+ Assert . ThrowsException < InvalidOperationException > ( ( ) => handler . Invoke ( new InvocationContext ( parseResult ) ) ) ;
303+ }
304+
305+ [ TestMethod ]
306+ public void Invoke_WithInvalidSinkExtension_ThrowsException ( )
307+ {
308+ const string source = "testSource" ;
309+ const string sink = "invalidSink" ;
310+ IConfigurationRoot configuration = new ConfigurationBuilder ( )
311+ . AddInMemoryCollection ( new Dictionary < string , string ? >
312+ {
313+ { "Source" , source } ,
314+ { "Sink" , sink } ,
315+ } )
316+ . Build ( ) ;
317+ var loader = new Mock < IExtensionLoader > ( ) ;
318+ var sourceExtension = new Mock < IDataSourceExtension > ( ) ;
319+ sourceExtension . SetupGet ( ds => ds . DisplayName ) . Returns ( source ) ;
320+ loader
321+ . Setup ( l => l . LoadExtensions < IDataSourceExtension > ( It . IsAny < CompositionContainer > ( ) ) )
322+ . Returns ( new List < IDataSourceExtension > { sourceExtension . Object } ) ;
323+
324+ var sinkExtension = new Mock < IDataSinkExtension > ( ) ;
325+ sinkExtension . SetupGet ( ds => ds . DisplayName ) . Returns ( "differentSink" ) ;
326+ loader
327+ . Setup ( l => l . LoadExtensions < IDataSinkExtension > ( It . IsAny < CompositionContainer > ( ) ) )
328+ . Returns ( new List < IDataSinkExtension > { sinkExtension . Object } ) ;
329+
330+ var handler = new RunCommand . CommandHandler ( loader . Object ,
331+ configuration ,
332+ NullLoggerFactory . Instance ) ;
333+
334+ var parseResult = new RootCommand ( ) . Parse ( Array . Empty < string > ( ) ) ;
335+
336+ // Should throw exception when sink extension is not found
337+ Assert . ThrowsException < InvalidOperationException > ( ( ) => handler . Invoke ( new InvocationContext ( parseResult ) ) ) ;
338+ }
178339 }
179340}
0 commit comments