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