@@ -231,6 +231,237 @@ public async Task DoesNotBuildsUriForInvalidQueryParameterAsync()
231231 Assert . Equal ( "Unknown equality filter clause field name 'fooBar', must be one of answerCount,cc,freshness,mkt,promote,responseFilter,safeSearch,setLang,textDecorations,textFormat,contains,ext,filetype,inanchor,inbody,intitle,ip,language,loc,location,prefer,site,feed,hasfeed,url (Parameter 'searchOptions')" , e . Message ) ;
232232 }
233233
234+ #region Generic ITextSearch<BingWebPage> Interface Tests
235+
236+ [ Fact ]
237+ public async Task GenericSearchAsyncWithLanguageEqualityFilterProducesCorrectBingQueryAsync ( )
238+ {
239+ // Arrange
240+ this . _messageHandlerStub . AddJsonResponse ( File . ReadAllText ( WhatIsTheSKResponseJson ) ) ;
241+ ITextSearch < BingWebPage > textSearch = new BingTextSearch ( apiKey : "ApiKey" , options : new ( ) { HttpClient = this . _httpClient } ) ;
242+
243+ // Act
244+ var searchOptions = new TextSearchOptions < BingWebPage >
245+ {
246+ Top = 4 ,
247+ Skip = 0 ,
248+ Filter = page => page . Language == "en"
249+ } ;
250+ KernelSearchResults < string > result = await textSearch . SearchAsync ( "What is the Semantic Kernel?" , searchOptions ) ;
251+
252+ // Assert - Verify LINQ expression converted to Bing's language: operator
253+ var requestUris = this . _messageHandlerStub . RequestUris ;
254+ Assert . Single ( requestUris ) ;
255+ Assert . NotNull ( requestUris [ 0 ] ) ;
256+ Assert . Contains ( "language%3Aen" , requestUris [ 0 ] ! . AbsoluteUri ) ;
257+ Assert . Contains ( "count=4" , requestUris [ 0 ] ! . AbsoluteUri ) ;
258+ Assert . Contains ( "offset=0" , requestUris [ 0 ] ! . AbsoluteUri ) ;
259+ }
260+
261+ [ Fact ]
262+ public async Task GenericSearchAsyncWithLanguageInequalityFilterProducesCorrectBingQueryAsync ( )
263+ {
264+ // Arrange
265+ this . _messageHandlerStub . AddJsonResponse ( File . ReadAllText ( WhatIsTheSKResponseJson ) ) ;
266+ ITextSearch < BingWebPage > textSearch = new BingTextSearch ( apiKey : "ApiKey" , options : new ( ) { HttpClient = this . _httpClient } ) ;
267+
268+ // Act
269+ var searchOptions = new TextSearchOptions < BingWebPage >
270+ {
271+ Top = 4 ,
272+ Skip = 0 ,
273+ Filter = page => page . Language != "fr"
274+ } ;
275+ KernelSearchResults < string > result = await textSearch . SearchAsync ( "What is the Semantic Kernel?" , searchOptions ) ;
276+
277+ // Assert - Verify LINQ inequality expression converted to Bing's negation syntax (-language:fr)
278+ var requestUris = this . _messageHandlerStub . RequestUris ;
279+ Assert . Single ( requestUris ) ;
280+ Assert . NotNull ( requestUris [ 0 ] ) ;
281+ Assert . Contains ( "-language%3Afr" , requestUris [ 0 ] ! . AbsoluteUri ) ;
282+ }
283+
284+ [ Fact ]
285+ public async Task GenericSearchAsyncWithContainsFilterProducesCorrectBingQueryAsync ( )
286+ {
287+ // Arrange
288+ this . _messageHandlerStub . AddJsonResponse ( File . ReadAllText ( WhatIsTheSKResponseJson ) ) ;
289+ ITextSearch < BingWebPage > textSearch = new BingTextSearch ( apiKey : "ApiKey" , options : new ( ) { HttpClient = this . _httpClient } ) ;
290+
291+ // Act
292+ var searchOptions = new TextSearchOptions < BingWebPage >
293+ {
294+ Top = 4 ,
295+ Skip = 0 ,
296+ Filter = page => page . Name . Contains ( "Microsoft" )
297+ } ;
298+ KernelSearchResults < string > result = await textSearch . SearchAsync ( "What is the Semantic Kernel?" , searchOptions ) ;
299+
300+ // Assert - Verify LINQ Contains() converted to Bing's intitle: operator
301+ var requestUris = this . _messageHandlerStub . RequestUris ;
302+ Assert . Single ( requestUris ) ;
303+ Assert . NotNull ( requestUris [ 0 ] ) ;
304+ Assert . Contains ( "intitle%3AMicrosoft" , requestUris [ 0 ] ! . AbsoluteUri ) ;
305+ }
306+
307+ [ Fact ]
308+ public async Task GenericSearchAsyncWithComplexAndFilterProducesCorrectBingQueryAsync ( )
309+ {
310+ // Arrange
311+ this . _messageHandlerStub . AddJsonResponse ( File . ReadAllText ( WhatIsTheSKResponseJson ) ) ;
312+ ITextSearch < BingWebPage > textSearch = new BingTextSearch ( apiKey : "ApiKey" , options : new ( ) { HttpClient = this . _httpClient } ) ;
313+
314+ // Act
315+ var searchOptions = new TextSearchOptions < BingWebPage >
316+ {
317+ Top = 4 ,
318+ Skip = 0 ,
319+ Filter = page => page . Language == "en" && page . Name . Contains ( "AI" )
320+ } ;
321+ KernelSearchResults < string > result = await textSearch . SearchAsync ( "What is the Semantic Kernel?" , searchOptions ) ;
322+
323+ // Assert - Verify LINQ AND expression produces both Bing operators
324+ var requestUris = this . _messageHandlerStub . RequestUris ;
325+ Assert . Single ( requestUris ) ;
326+ Assert . NotNull ( requestUris [ 0 ] ) ;
327+ Assert . Contains ( "language%3Aen" , requestUris [ 0 ] ! . AbsoluteUri ) ;
328+ Assert . Contains ( "intitle%3AAI" , requestUris [ 0 ] ! . AbsoluteUri ) ;
329+ }
330+
331+ [ Fact ]
332+ public async Task GenericGetTextSearchResultsAsyncWithUrlFilterProducesCorrectBingQueryAsync ( )
333+ {
334+ // Arrange
335+ this . _messageHandlerStub . AddJsonResponse ( File . ReadAllText ( WhatIsTheSKResponseJson ) ) ;
336+ ITextSearch < BingWebPage > textSearch = new BingTextSearch ( apiKey : "ApiKey" , options : new ( ) { HttpClient = this . _httpClient } ) ;
337+
338+ // Act
339+ var searchOptions = new TextSearchOptions < BingWebPage >
340+ {
341+ Top = 4 ,
342+ Skip = 0 ,
343+ Filter = page => page . Url . Contains ( "microsoft.com" )
344+ } ;
345+ KernelSearchResults < TextSearchResult > result = await textSearch . GetTextSearchResultsAsync ( "What is the Semantic Kernel?" , searchOptions ) ;
346+
347+ // Assert - Verify LINQ Url.Contains() converted to Bing's url: operator
348+ var requestUris = this . _messageHandlerStub . RequestUris ;
349+ Assert . Single ( requestUris ) ;
350+ Assert . NotNull ( requestUris [ 0 ] ) ;
351+ Assert . Contains ( "url%3Amicrosoft.com" , requestUris [ 0 ] ! . AbsoluteUri ) ;
352+
353+ // Also verify result structure
354+ Assert . NotNull ( result ) ;
355+ Assert . NotNull ( result . Results ) ;
356+ }
357+
358+ [ Fact ]
359+ public async Task GenericGetSearchResultsAsyncWithSnippetContainsFilterProducesCorrectBingQueryAsync ( )
360+ {
361+ // Arrange
362+ this . _messageHandlerStub . AddJsonResponse ( File . ReadAllText ( WhatIsTheSKResponseJson ) ) ;
363+ ITextSearch < BingWebPage > textSearch = new BingTextSearch ( apiKey : "ApiKey" , options : new ( ) { HttpClient = this . _httpClient } ) ;
364+
365+ // Act
366+ var searchOptions = new TextSearchOptions < BingWebPage >
367+ {
368+ Top = 4 ,
369+ Skip = 0 ,
370+ Filter = page => page . Snippet . Contains ( "semantic" )
371+ } ;
372+ KernelSearchResults < object > result = await textSearch . GetSearchResultsAsync ( "What is the Semantic Kernel?" , searchOptions ) ;
373+
374+ // Assert - Verify LINQ Snippet.Contains() converted to Bing's inbody: operator
375+ var requestUris = this . _messageHandlerStub . RequestUris ;
376+ Assert . Single ( requestUris ) ;
377+ Assert . NotNull ( requestUris [ 0 ] ) ;
378+ Assert . Contains ( "inbody%3Asemantic" , requestUris [ 0 ] ! . AbsoluteUri ) ;
379+
380+ // Verify result structure
381+ Assert . NotNull ( result ) ;
382+ Assert . NotNull ( result . Results ) ;
383+ }
384+
385+ [ Fact ]
386+ public async Task GenericSearchAsyncWithDisplayUrlEqualityFilterProducesCorrectBingQueryAsync ( )
387+ {
388+ // Arrange
389+ this . _messageHandlerStub . AddJsonResponse ( File . ReadAllText ( SiteFilterDevBlogsResponseJson ) ) ;
390+ ITextSearch < BingWebPage > textSearch = new BingTextSearch ( apiKey : "ApiKey" , options : new ( ) { HttpClient = this . _httpClient } ) ;
391+
392+ // Act
393+ var searchOptions = new TextSearchOptions < BingWebPage >
394+ {
395+ Top = 4 ,
396+ Skip = 0 ,
397+ Filter = page => page . DisplayUrl == "devblogs.microsoft.com"
398+ } ;
399+ KernelSearchResults < string > result = await textSearch . SearchAsync ( "What is the Semantic Kernel?" , searchOptions ) ;
400+
401+ // Assert - Verify LINQ DisplayUrl equality converted to Bing's site: operator
402+ var requestUris = this . _messageHandlerStub . RequestUris ;
403+ Assert . Single ( requestUris ) ;
404+ Assert . NotNull ( requestUris [ 0 ] ) ;
405+ Assert . Contains ( "site%3Adevblogs.microsoft.com" , requestUris [ 0 ] ! . AbsoluteUri ) ;
406+ }
407+
408+ [ Fact ]
409+ public async Task GenericSearchAsyncWithMultipleAndConditionsProducesCorrectBingQueryAsync ( )
410+ {
411+ // Arrange
412+ this . _messageHandlerStub . AddJsonResponse ( File . ReadAllText ( WhatIsTheSKResponseJson ) ) ;
413+ ITextSearch < BingWebPage > textSearch = new BingTextSearch ( apiKey : "ApiKey" , options : new ( ) { HttpClient = this . _httpClient } ) ;
414+
415+ // Act
416+ var searchOptions = new TextSearchOptions < BingWebPage >
417+ {
418+ Top = 4 ,
419+ Skip = 0 ,
420+ Filter = page => page . Language == "en" && page . DisplayUrl . Contains ( "microsoft.com" ) && page . Name . Contains ( "Semantic" )
421+ } ;
422+ KernelSearchResults < string > result = await textSearch . SearchAsync ( "What is the Semantic Kernel?" , searchOptions ) ;
423+
424+ // Assert - Verify all LINQ conditions converted correctly
425+ var requestUris = this . _messageHandlerStub . RequestUris ;
426+ Assert . Single ( requestUris ) ;
427+ Assert . NotNull ( requestUris [ 0 ] ) ;
428+ string uri = requestUris [ 0 ] ! . AbsoluteUri ;
429+ Assert . Contains ( "language%3Aen" , uri ) ;
430+ Assert . Contains ( "site%3Amicrosoft.com" , uri ) ; // DisplayUrl.Contains() → site: operator
431+ Assert . Contains ( "intitle%3ASemantic" , uri ) ;
432+ }
433+
434+ [ Fact ]
435+ public async Task GenericSearchAsyncWithNoFilterReturnsResultsSuccessfullyAsync ( )
436+ {
437+ // Arrange
438+ this . _messageHandlerStub . AddJsonResponse ( File . ReadAllText ( WhatIsTheSKResponseJson ) ) ;
439+ ITextSearch < BingWebPage > textSearch = new BingTextSearch ( apiKey : "ApiKey" , options : new ( ) { HttpClient = this . _httpClient } ) ;
440+
441+ // Act - No filter specified
442+ var searchOptions = new TextSearchOptions < BingWebPage >
443+ {
444+ Top = 10 ,
445+ Skip = 0
446+ } ;
447+ KernelSearchResults < string > result = await textSearch . SearchAsync ( "What is the Semantic Kernel?" , searchOptions ) ;
448+
449+ // Assert - Verify basic query without filter operators
450+ var requestUris = this . _messageHandlerStub . RequestUris ;
451+ Assert . Single ( requestUris ) ;
452+ Assert . NotNull ( requestUris [ 0 ] ) ;
453+ Assert . DoesNotContain ( "language%3A" , requestUris [ 0 ] ! . AbsoluteUri ) ;
454+ Assert . DoesNotContain ( "intitle%3A" , requestUris [ 0 ] ! . AbsoluteUri ) ;
455+
456+ // Verify results
457+ Assert . NotNull ( result ) ;
458+ Assert . NotNull ( result . Results ) ;
459+ var resultList = await result . Results . ToListAsync ( ) ;
460+ Assert . Equal ( 10 , resultList . Count ) ;
461+ }
462+
463+ #endregion
464+
234465 /// <inheritdoc/>
235466 public void Dispose ( )
236467 {
0 commit comments