@@ -296,4 +296,196 @@ public async Task PurgeDeletedNotesFromIndexAsync_DeletedNotes_RemovesThem()
296296 req . RequestUri . ToString ( ) . Contains ( "json/delete" ) ) ,
297297 ItExpr . IsAny < CancellationToken > ( ) ) ;
298298 }
299+
300+ [ Test ]
301+ public async Task GetNoteIdsByKeywordAsync_IntegerQuery_FirstPage_UserOwnsNote_PrependsToResults ( )
302+ {
303+ // Arrange
304+ long userId = 1 ;
305+ string query = "123" ;
306+ int pageNumber = 1 ;
307+ int pageSize = 10 ;
308+
309+ // Mock regular search results
310+ _mockHandler . Protected ( )
311+ . Setup < Task < HttpResponseMessage > > ( "SendAsync" , ItExpr . IsAny < HttpRequestMessage > ( ) , ItExpr . IsAny < CancellationToken > ( ) )
312+ . ReturnsAsync ( new HttpResponseMessage
313+ {
314+ StatusCode = HttpStatusCode . OK ,
315+ Content = new StringContent ( "{\" took\" :0,\" timed_out\" :false,\" hits\" :{\" total\" :2,\" hits\" :[{\" _id\" :456,\" _source\" :{\" id\" :456}},{\" _id\" :789,\" _source\" :{\" id\" :789}}]}}" )
316+ } ) ;
317+
318+ // Mock database query to return user's note
319+ _mockDatabaseClient . Setup ( x => x . SqlQueryAsync < Note > (
320+ It . IsAny < string > ( ) ,
321+ It . IsAny < object > ( ) ) )
322+ . ReturnsAsync ( new List < Note > { new Note { Id = 123 , UserId = 1 } } ) ;
323+
324+ // Act
325+ var result = await _searchService . GetNoteIdsByKeywordAsync ( userId , query , pageNumber , pageSize ) ;
326+
327+ // Assert
328+ Assert . IsNotNull ( result ) ;
329+ Assert . That ( result . Item1 [ 0 ] , Is . EqualTo ( 123 ) ) ; // Note 123 should be first
330+ Assert . That ( result . Item1 . Count , Is . EqualTo ( 3 ) ) ; // Should have 3 notes total
331+ CollectionAssert . AreEqual ( new List < long > { 123 , 456 , 789 } , result . Item1 ) ;
332+ }
333+
334+ [ Test ]
335+ public async Task GetNoteIdsByKeywordAsync_IntegerQuery_FirstPage_UserDoesNotOwnNote_DoesNotPrepend ( )
336+ {
337+ // Arrange
338+ long userId = 1 ;
339+ string query = "123" ;
340+ int pageNumber = 1 ;
341+ int pageSize = 10 ;
342+
343+ // Mock regular search results
344+ _mockHandler . Protected ( )
345+ . Setup < Task < HttpResponseMessage > > ( "SendAsync" , ItExpr . IsAny < HttpRequestMessage > ( ) , ItExpr . IsAny < CancellationToken > ( ) )
346+ . ReturnsAsync ( new HttpResponseMessage
347+ {
348+ StatusCode = HttpStatusCode . OK ,
349+ Content = new StringContent ( "{\" took\" :0,\" timed_out\" :false,\" hits\" :{\" total\" :2,\" hits\" :[{\" _id\" :456,\" _source\" :{\" id\" :456}},{\" _id\" :789,\" _source\" :{\" id\" :789}}]}}" )
350+ } ) ;
351+
352+ // Mock database query to return note owned by different user
353+ _mockDatabaseClient . Setup ( x => x . SqlQueryAsync < Note > (
354+ It . IsAny < string > ( ) ,
355+ It . IsAny < object > ( ) ) )
356+ . ReturnsAsync ( new List < Note > { new Note { Id = 123 , UserId = 2 } } ) ; // Different user
357+
358+ // Act
359+ var result = await _searchService . GetNoteIdsByKeywordAsync ( userId , query , pageNumber , pageSize ) ;
360+
361+ // Assert
362+ Assert . IsNotNull ( result ) ;
363+ Assert . That ( result . Item1 . Count , Is . EqualTo ( 2 ) ) ; // Should remain 2 notes
364+ CollectionAssert . AreEqual ( new List < long > { 456 , 789 } , result . Item1 ) ;
365+ }
366+
367+ [ Test ]
368+ public async Task GetNoteIdsByKeywordAsync_IntegerQuery_SecondPage_DoesNotPrepend ( )
369+ {
370+ // Arrange
371+ long userId = 1 ;
372+ string query = "123" ;
373+ int pageNumber = 2 ; // Not first page
374+ int pageSize = 10 ;
375+
376+ // Mock regular search results
377+ _mockHandler . Protected ( )
378+ . Setup < Task < HttpResponseMessage > > ( "SendAsync" , ItExpr . IsAny < HttpRequestMessage > ( ) , ItExpr . IsAny < CancellationToken > ( ) )
379+ . ReturnsAsync ( new HttpResponseMessage
380+ {
381+ StatusCode = HttpStatusCode . OK ,
382+ Content = new StringContent ( "{\" took\" :0,\" timed_out\" :false,\" hits\" :{\" total\" :2,\" hits\" :[{\" _id\" :456,\" _source\" :{\" id\" :456}},{\" _id\" :789,\" _source\" :{\" id\" :789}}]}}" )
383+ } ) ;
384+
385+ // Act
386+ var result = await _searchService . GetNoteIdsByKeywordAsync ( userId , query , pageNumber , pageSize ) ;
387+
388+ // Assert
389+ Assert . IsNotNull ( result ) ;
390+ Assert . That ( result . Item1 . Count , Is . EqualTo ( 2 ) ) ; // Should remain 2 notes
391+ CollectionAssert . AreEqual ( new List < long > { 456 , 789 } , result . Item1 ) ;
392+ // Verify database was not called since it's not first page
393+ _mockDatabaseClient . Verify ( x => x . SqlQueryAsync < Note > ( It . IsAny < string > ( ) , It . IsAny < object > ( ) ) , Times . Never ) ;
394+ }
395+
396+ [ Test ]
397+ public async Task GetNoteIdsByKeywordAsync_IntegerQuery_NoteNotFound_DoesNotPrepend ( )
398+ {
399+ // Arrange
400+ long userId = 1 ;
401+ string query = "123" ;
402+ int pageNumber = 1 ;
403+ int pageSize = 10 ;
404+
405+ // Mock regular search results
406+ _mockHandler . Protected ( )
407+ . Setup < Task < HttpResponseMessage > > ( "SendAsync" , ItExpr . IsAny < HttpRequestMessage > ( ) , ItExpr . IsAny < CancellationToken > ( ) )
408+ . ReturnsAsync ( new HttpResponseMessage
409+ {
410+ StatusCode = HttpStatusCode . OK ,
411+ Content = new StringContent ( "{\" took\" :0,\" timed_out\" :false,\" hits\" :{\" total\" :2,\" hits\" :[{\" _id\" :456,\" _source\" :{\" id\" :456}},{\" _id\" :789,\" _source\" :{\" id\" :789}}]}}" )
412+ } ) ;
413+
414+ // Mock database query to return empty list (note not found)
415+ _mockDatabaseClient . Setup ( x => x . SqlQueryAsync < Note > (
416+ It . IsAny < string > ( ) ,
417+ It . IsAny < object > ( ) ) )
418+ . ReturnsAsync ( new List < Note > ( ) ) ;
419+
420+ // Act
421+ var result = await _searchService . GetNoteIdsByKeywordAsync ( userId , query , pageNumber , pageSize ) ;
422+
423+ // Assert
424+ Assert . IsNotNull ( result ) ;
425+ Assert . That ( result . Item1 . Count , Is . EqualTo ( 2 ) ) ; // Should remain 2 notes
426+ CollectionAssert . AreEqual ( new List < long > { 456 , 789 } , result . Item1 ) ;
427+ }
428+
429+ [ Test ]
430+ public async Task GetNoteIdsByKeywordAsync_IntegerQuery_FirstPage_NoteAlreadyInResults_DoesNotDuplicate ( )
431+ {
432+ // Arrange
433+ long userId = 1 ;
434+ string query = "123" ;
435+ int pageNumber = 1 ;
436+ int pageSize = 10 ;
437+
438+ // Mock regular search results including the note ID we're searching for
439+ _mockHandler . Protected ( )
440+ . Setup < Task < HttpResponseMessage > > ( "SendAsync" , ItExpr . IsAny < HttpRequestMessage > ( ) , ItExpr . IsAny < CancellationToken > ( ) )
441+ . ReturnsAsync ( new HttpResponseMessage
442+ {
443+ StatusCode = HttpStatusCode . OK ,
444+ Content = new StringContent ( "{\" took\" :0,\" timed_out\" :false,\" hits\" :{\" total\" :3,\" hits\" :[{\" _id\" :456,\" _source\" :{\" id\" :456}},{\" _id\" :123,\" _source\" :{\" id\" :123}},{\" _id\" :789,\" _source\" :{\" id\" :789}}]}}" )
445+ } ) ;
446+
447+ // Mock database query to return user's note
448+ _mockDatabaseClient . Setup ( x => x . SqlQueryAsync < Note > (
449+ It . IsAny < string > ( ) ,
450+ It . IsAny < object > ( ) ) )
451+ . ReturnsAsync ( new List < Note > { new Note { Id = 123 , UserId = 1 } } ) ;
452+
453+ // Act
454+ var result = await _searchService . GetNoteIdsByKeywordAsync ( userId , query , pageNumber , pageSize ) ;
455+
456+ // Assert
457+ Assert . IsNotNull ( result ) ;
458+ Assert . That ( result . Item1 [ 0 ] , Is . EqualTo ( 123 ) ) ; // Note 123 should be first
459+ Assert . That ( result . Item1 . Count , Is . EqualTo ( 3 ) ) ; // Should have 3 notes total (no duplication)
460+ CollectionAssert . AreEqual ( new List < long > { 123 , 456 , 789 } , result . Item1 ) ;
461+ }
462+
463+ [ Test ]
464+ public async Task GetNoteIdsByKeywordAsync_NonIntegerQuery_DoesNotPrepend ( )
465+ {
466+ // Arrange
467+ long userId = 1 ;
468+ string query = "test search" ;
469+ int pageNumber = 1 ;
470+ int pageSize = 10 ;
471+
472+ // Mock regular search results
473+ _mockHandler . Protected ( )
474+ . Setup < Task < HttpResponseMessage > > ( "SendAsync" , ItExpr . IsAny < HttpRequestMessage > ( ) , ItExpr . IsAny < CancellationToken > ( ) )
475+ . ReturnsAsync ( new HttpResponseMessage
476+ {
477+ StatusCode = HttpStatusCode . OK ,
478+ Content = new StringContent ( "{\" took\" :0,\" timed_out\" :false,\" hits\" :{\" total\" :2,\" hits\" :[{\" _id\" :456,\" _source\" :{\" id\" :456}},{\" _id\" :789,\" _source\" :{\" id\" :789}}]}}" )
479+ } ) ;
480+
481+ // Act
482+ var result = await _searchService . GetNoteIdsByKeywordAsync ( userId , query , pageNumber , pageSize ) ;
483+
484+ // Assert
485+ Assert . IsNotNull ( result ) ;
486+ Assert . That ( result . Item1 . Count , Is . EqualTo ( 2 ) ) ; // Should remain 2 notes
487+ CollectionAssert . AreEqual ( new List < long > { 456 , 789 } , result . Item1 ) ;
488+ // Verify database was not called since query is not an integer
489+ _mockDatabaseClient . Verify ( x => x . SqlQueryAsync < Note > ( It . IsAny < string > ( ) , It . IsAny < object > ( ) ) , Times . Never ) ;
490+ }
299491}
0 commit comments