@@ -507,6 +507,109 @@ mod find {
507507 ) ;
508508 Ok ( ( ) )
509509 }
510+
511+ #[ test]
512+ fn empty_blob_can_always_be_found ( ) -> crate :: Result {
513+ let repo = basic_repo ( ) ?;
514+ let empty_blob = gix:: hash:: ObjectId :: empty_blob ( repo. object_hash ( ) ) ;
515+ assert_eq ! ( repo. find_object( empty_blob) ?. into_blob( ) . data. len( ) , 0 ) ;
516+ assert ! ( repo. has_object( empty_blob) ) ;
517+ assert_eq ! (
518+ repo. find_header( empty_blob) ?,
519+ gix_odb:: find:: Header :: Loose {
520+ kind: gix_object:: Kind :: Blob ,
521+ size: 0 ,
522+ } ,
523+ "empty blob is considered a loose object"
524+ ) ;
525+ assert_eq ! (
526+ repo. try_find_object( empty_blob) ?
527+ . expect( "present" )
528+ . into_blob( )
529+ . data
530+ . len( ) ,
531+ 0
532+ ) ;
533+ assert_eq ! (
534+ repo. try_find_header( empty_blob) ?,
535+ Some ( gix_odb:: find:: Header :: Loose {
536+ kind: gix_object:: Kind :: Blob ,
537+ size: 0 ,
538+ } ) ,
539+ "empty blob is considered a loose object"
540+ ) ;
541+
542+ // Note: Unlike empty tree, empty blobs might actually exist in the repository.
543+ // The key point is that has_object() should always return true for empty blobs,
544+ // regardless of whether they are physically stored or not.
545+ Ok ( ( ) )
546+ }
547+ }
548+
549+ #[ test]
550+ fn empty_blob_is_always_considered_present ( ) -> crate :: Result {
551+ use gix_object:: Find ;
552+
553+ // Test with an empty in-memory repository to ensure empty blob is considered present
554+ // even when it doesn't physically exist
555+ let repo = empty_bare_in_memory_repo ( ) ?;
556+ let empty_blob = gix:: hash:: ObjectId :: empty_blob ( repo. object_hash ( ) ) ;
557+
558+ // The key behavior being tested: has_object should return true for empty blob
559+ assert ! ( repo. has_object( empty_blob) , "empty blob should always be considered present" ) ;
560+
561+ // Verify that the lower-level object database doesn't have it
562+ let mut buf = Vec :: new ( ) ;
563+ let lower_level_result = repo. objects . try_find ( & empty_blob, & mut buf) ?;
564+
565+ // Empty blob might or might not exist at the lower level - that's implementation dependent
566+ // But has_object should always return true regardless
567+ match lower_level_result {
568+ Some ( _) => {
569+ // If it exists at the lower level, that's fine
570+ }
571+ None => {
572+ // If it doesn't exist at the lower level, has_object should still return true
573+ // thanks to our special handling
574+ }
575+ }
576+
577+ Ok ( ( ) )
578+ }
579+
580+ #[ test]
581+ fn empty_blob_edge_cases ( ) -> crate :: Result {
582+ let repo = empty_bare_in_memory_repo ( ) ?;
583+ let empty_blob_id = gix:: hash:: ObjectId :: empty_blob ( repo. object_hash ( ) ) ;
584+
585+ // Test all the related methods for empty blobs
586+ assert ! ( repo. has_object( & empty_blob_id) , "has_object should return true" ) ;
587+
588+ // Test find_header
589+ let header = repo. find_header ( empty_blob_id) ?;
590+ assert_eq ! ( header. kind( ) , gix_object:: Kind :: Blob ) ;
591+ assert_eq ! ( header. size( ) , 0 ) ;
592+
593+ // Test try_find_header
594+ let header = repo. try_find_header ( empty_blob_id) ?. expect ( "should find header" ) ;
595+ assert_eq ! ( header. kind( ) , gix_object:: Kind :: Blob ) ;
596+ assert_eq ! ( header. size( ) , 0 ) ;
597+
598+ // Test find_object
599+ let obj = repo. find_object ( empty_blob_id) ?;
600+ assert_eq ! ( obj. kind, gix_object:: Kind :: Blob ) ;
601+ assert_eq ! ( obj. data. len( ) , 0 ) ;
602+
603+ // Test try_find_object
604+ let obj = repo. try_find_object ( empty_blob_id) ?. expect ( "should find object" ) ;
605+ assert_eq ! ( obj. kind, gix_object:: Kind :: Blob ) ;
606+ assert_eq ! ( obj. data. len( ) , 0 ) ;
607+
608+ // Test that we can get a blob from the object
609+ let blob = obj. into_blob ( ) ;
610+ assert_eq ! ( blob. data. len( ) , 0 ) ;
611+
612+ Ok ( ( ) )
510613}
511614
512615mod tag {
0 commit comments