@@ -472,6 +472,47 @@ static bool test__cs_replace__out_of_bounds(void) {
472472 return true;
473473}
474474
475+ static bool test__cs_replace__add_fail_keeps_old_entry (void ) {
476+ _drop_ (teardown_test ) struct clip_store cs = setup_test ();
477+
478+ const char * old_content = "OLD_CONTENT" ;
479+ uint64_t old_hash ;
480+ int ret = cs_add (& cs , old_content , & old_hash , CS_DUPE_KEEP_ALL );
481+ t_assert (ret == 0 );
482+
483+ const char * new_content = "new" ;
484+ uint64_t new_hash = fnv1a_64_hash (new_content );
485+
486+ char hash_dir [CS_HASH_STR_MAX ];
487+ snprintf (hash_dir , sizeof (hash_dir ), PRI_HASH , new_hash );
488+ ret = mkdirat (cs .content_dir_fd , hash_dir , 0700 );
489+ t_assert (ret == 0 );
490+
491+ char fake_path [CS_HASH_STR_MAX + 3 ];
492+ snprintf (fake_path , sizeof (fake_path ), "%s/1" , hash_dir );
493+ _drop_ (close ) int fake_fd = openat (cs .content_dir_fd , fake_path ,
494+ O_WRONLY | O_CREAT | O_TRUNC , 0600 );
495+ t_assert (fake_fd >= 0 );
496+ t_assert (write (fake_fd , "X" , 1 ) == 1 );
497+
498+ ret = cs_replace (& cs , CS_ITER_NEWEST_FIRST , 0 , new_content , NULL );
499+ t_assert (ret == - EFAULT );
500+
501+ _drop_ (cs_content_unmap ) struct cs_content old_after ;
502+ ret = cs_content_get (& cs , old_hash , & old_after );
503+ t_assert (ret == 0 );
504+ t_assert ((size_t )old_after .size == strlen (old_content ));
505+ t_assert (strncmp (old_after .data , old_content , (size_t )old_after .size ) == 0 );
506+
507+ _drop_ (cs_unref ) struct ref_guard guard = cs_ref (& cs );
508+ struct cs_snip * snip = NULL ;
509+ t_assert (cs_snip_iter (& guard , CS_ITER_NEWEST_FIRST , & snip ));
510+ t_assert (snip -> hash == old_hash );
511+ t_assert (streq (snip -> line , old_content ));
512+
513+ return true;
514+ }
515+
475516static bool test__cs_snip__correct_nr_lines (void ) {
476517 _drop_ (teardown_test ) struct clip_store cs = setup_test ();
477518
@@ -728,6 +769,7 @@ int main(void) {
728769 t_run (test__cs_remove___empty );
729770 t_run (test__cs_add__around_alloc_batch_threshold );
730771 t_run (test__cs_replace__out_of_bounds );
772+ t_run (test__cs_replace__add_fail_keeps_old_entry );
731773 t_run (test__synchronisation );
732774 t_run (test__cs_trim__no_remove_when_still_referenced );
733775 t_run (test__cs_snip__correct_nr_lines );
0 commit comments