@@ -279,71 +279,124 @@ end
279279 empty! (results)
280280 cset = ConditionSet (" hello" )
281281 spec = FilterSpec (cset)
282- @test filterchunkrev! (results, entries, spec) == 0
282+ seen = Set {Tuple{Symbol,String}} ()
283+ @test filterchunkrev! (results, entries, spec, seen) == 0
283284 @test results == [entries[1 ], entries[7 ]]
284285 empty! (results)
285286 cset2 = ConditionSet (" world" )
286287 spec2 = FilterSpec (cset2)
287- @test filterchunkrev! (results, entries, spec2) == 0
288+ empty! (seen)
289+ @test filterchunkrev! (results, entries, spec2, seen) == 0
288290 @test results == [entries[1 ], entries[7 ]]
289291 empty! (results)
290292 cset3 = ConditionSet (" World" )
291293 spec3 = FilterSpec (cset3)
292- @test filterchunkrev! (results, entries, spec3) == 0
294+ empty! (seen)
295+ @test filterchunkrev! (results, entries, spec3, seen) == 0
293296 @test results == [entries[7 ]]
294297 end
295298 @testset " Exact" begin
296299 empty! (results)
297300 cset = ConditionSet (" =test" )
298301 spec = FilterSpec (cset)
299- @test filterchunkrev! (results, entries, spec, maxresults = 2 ) == 5
302+ seen = Set {Tuple{Symbol,String}} ()
303+ @test filterchunkrev! (results, entries, spec, seen; maxresults = 2 ) == 5
300304 @test results == [entries[6 ], entries[9 ]]
301305 empty! (results)
302306 cset2 = ConditionSet (" =test case" )
303307 spec2 = FilterSpec (cset2)
304- @test filterchunkrev! (results, entries, spec2) == 0
308+ empty! (seen)
309+ @test filterchunkrev! (results, entries, spec2, seen) == 0
305310 @test results == [entries[3 ]]
306311 end
307312 @testset " Negative" begin
308313 empty! (results)
309314 cset = ConditionSet (" !hello ; !test;! cos" )
310315 spec = FilterSpec (cset)
311- @test filterchunkrev! (results, entries, spec) == 0
316+ seen = Set {Tuple{Symbol,String}} ()
317+ @test filterchunkrev! (results, entries, spec, seen) == 0
312318 @test results == [entries[2 ], entries[7 ], entries[8 ]]
313319 end
314320 @testset " Initialism" begin
315321 empty! (results)
316322 cset = ConditionSet (" `tc" )
317323 spec = FilterSpec (cset)
318- @test filterchunkrev! (results, entries, spec) == 0
324+ seen = Set {Tuple{Symbol,String}} ()
325+ @test filterchunkrev! (results, entries, spec, seen) == 0
319326 @test results == [entries[3 ]]
320327 empty! (results)
321328 cset2 = ConditionSet (" `fb" )
322329 spec2 = FilterSpec (cset2)
323- @test filterchunkrev! (results, entries, spec2) == 0
330+ empty! (seen)
331+ @test filterchunkrev! (results, entries, spec2, seen) == 0
324332 @test results == [entries[8 ]]
325333 end
326334 @testset " Regexp" begin
327335 empty! (results)
328336 cset = ConditionSet (" /^c.s\\ b" )
329337 spec = FilterSpec (cset)
330- @test filterchunkrev! (results, entries, spec) == 0
338+ seen = Set {Tuple{Symbol,String}} ()
339+ @test filterchunkrev! (results, entries, spec, seen) == 0
331340 @test results == [entries[4 ], entries[5 ]]
332341 end
333342 @testset " Mode" begin
334343 empty! (results)
335344 cset = ConditionSet (" >shell" )
336345 spec = FilterSpec (cset)
337- @test filterchunkrev! (results, entries, spec) == 0
346+ seen = Set {Tuple{Symbol,String}} ()
347+ @test filterchunkrev! (results, entries, spec, seen) == 0
338348 @test results == [entries[7 ]]
339349 end
340350 @testset " Fuzzy" begin
341351 empty! (results)
342352 cset = ConditionSet (" ~cs" )
343353 spec = FilterSpec (cset)
344- @test filterchunkrev! (results, entries, spec) == 0
354+ seen = Set {Tuple{Symbol,String}} ()
355+ @test filterchunkrev! (results, entries, spec, seen) == 0
345356 @test results == entries[3 : 6 ]
346357 end
358+ @testset " Uniqueness" begin
359+ empty! (results)
360+ # Create entries with duplicate content in the same mode
361+ dup_entries = [
362+ HistEntry (:julia , now (UTC), " println(\" hello\" )" , 1 ),
363+ HistEntry (:julia , now (UTC), " cos(2π)" , 2 ),
364+ HistEntry (:julia , now (UTC), " println(\" hello\" )" , 3 ), # duplicate
365+ HistEntry (:julia , now (UTC), " sin(π)" , 4 ),
366+ HistEntry (:julia , now (UTC), " cos(2π)" , 5 ), # duplicate
367+ HistEntry (:julia , now (UTC), " println(\" hello\" )" , 6 ), # duplicate
368+ HistEntry (:julia , now (UTC), " tan(π/4)" , 7 ),
369+ ]
370+ # When filtering with seen Set, duplicates are removed
371+ cset = ConditionSet (" cos" )
372+ spec = FilterSpec (cset)
373+ seen = Set {Tuple{Symbol,String}} ()
374+ @test filterchunkrev! (results, dup_entries, spec, seen) == 0
375+ # Should only get unique entries matching the filter
376+ # Since we iterate in reverse (7->1), we keep the most recent occurrence of each unique content
377+ @test length (results) == 1
378+ @test results[1 ] == dup_entries[5 ] # cos(2π) - most recent
379+ # When browsing without filtering, duplicates are kept
380+ empty! (results)
381+ append! (results, dup_entries)
382+ @test length (results) == 7 # All entries, including duplicates
383+ @test results == dup_entries
384+ # Test that same content in different modes is NOT deduplicated
385+ empty! (results)
386+ mode_entries = [
387+ HistEntry (:julia , now (UTC), " ls" , 1 ),
388+ HistEntry (:shell , now (UTC), " ls" , 2 ),
389+ HistEntry (:julia , now (UTC), " ls" , 3 ), # duplicate in :julia mode
390+ HistEntry (:shell , now (UTC), " pwd" , 4 ),
391+ ]
392+ empty! (seen)
393+ cset3 = ConditionSet (" ls" )
394+ spec3 = FilterSpec (cset3)
395+ @test filterchunkrev! (results, mode_entries, spec3, seen) == 0
396+ @test length (results) == 2 # "ls" from :julia and "ls" from :shell
397+ @test results[1 ] == mode_entries[2 ] # :shell ls
398+ @test results[2 ] == mode_entries[3 ] # :julia ls (most recent)
399+ end
347400 end
348401 @testset " Strictness comparison" begin
349402 c1 = ConditionSet (" hello world" )
0 commit comments