Skip to content

Commit 707b18c

Browse files
committed
tests: Cover cs_replace add failure path
Add a regression test that forces cs_replace to hit the duplicate hash size mismatch path in cs_content_add.
1 parent 0d4a5b3 commit 707b18c

4 files changed

Lines changed: 58 additions & 17 deletions

File tree

src/store.c

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -338,23 +338,6 @@ static void _nonnull_ cs_snip_update(struct cs_snip *snip, uint64_t hash,
338338
snip->line[CS_SNIP_LINE_SIZE - 1] = '\0';
339339
}
340340

341-
/**
342-
* Computes a 64-bit FNV-1a hash for a given buffer.
343-
*
344-
* @buf: The input buffer to hash.
345-
*/
346-
static uint64_t fnv1a_64_hash(const char *buf) {
347-
const uint64_t fnv_offset_basis = 0xcbf29ce484222325ULL;
348-
const uint64_t fnv_prime = 0x100000001b3ULL;
349-
uint64_t hash = fnv_offset_basis;
350-
const uint8_t *src = (const uint8_t *)buf;
351-
while (*src) {
352-
hash ^= *src++;
353-
hash *= fnv_prime;
354-
}
355-
return hash;
356-
}
357-
358341
/**
359342
* Extracts the first non-empty line from a given text buffer and copies it to
360343
* the output buffer. Returns the total number of lines. A final line with no

src/util.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,3 +148,18 @@ bool debug_mode_enabled(void) {
148148
}
149149
return debug_enabled;
150150
}
151+
152+
/**
153+
* Compute a 64-bit FNV-1a hash for a NULL-terminated string.
154+
*/
155+
uint64_t fnv1a_64_hash(const char *buf) {
156+
const uint64_t fnv_offset_basis = 0xcbf29ce484222325ULL;
157+
const uint64_t fnv_prime = 0x100000001b3ULL;
158+
uint64_t hash = fnv_offset_basis;
159+
const uint8_t *src = (const uint8_t *)buf;
160+
while (*src) {
161+
hash ^= *src++;
162+
hash *= fnv_prime;
163+
}
164+
return hash;
165+
}

src/util.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ size_t _printf_(3, 4)
7272
snprintf_safe(char *buf, size_t len, const char *fmt, ...);
7373

7474
void run_clipserve(uint64_t hash, const struct selection *selections);
75+
uint64_t _nonnull_ fnv1a_64_hash(const char *buf);
7576

7677
/**
7778
* __attribute__((cleanup)) functions

tests/test_store.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
475516
static 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

Comments
 (0)