LCOV - code coverage report
Current view: top level - src/tests - cache.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 116 116 100.0 %
Date: 2025-03-29 09:04:10 Functions: 3 3 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 83 162 51.2 %

           Branch data     Line data    Source code
       1                 :            : #include "utils.h"
       2                 :            : 
       3                 :            : #include <libplacebo/cache.h>
       4                 :            : 
       5                 :            : // Returns "foo" for even keys, "bar" for odd
       6                 :          2 : static pl_cache_obj lookup_foobar(void *priv, uint64_t key)
       7                 :            : {
       8                 :          2 :     return (pl_cache_obj) {
       9                 :            :         .key = 0xFFFF, // test key sanity
      10         [ +  + ]:          2 :         .data = (key & 1) ? "bar" : "foo",
      11                 :            :         .size = 3,
      12                 :            :     };
      13                 :            : }
      14                 :            : 
      15                 :          5 : static void update_count(void *priv, pl_cache_obj obj)
      16                 :            : {
      17                 :            :     int *count = priv;
      18         [ +  + ]:          5 :     *count += obj.size ? 1 : -1;
      19                 :          5 : }
      20                 :            : 
      21                 :            : enum {
      22                 :            :     KEY1 = 0x9c65575f419288f5,
      23                 :            :     KEY2 = 0x92da969be9b88086,
      24                 :            :     KEY3 = 0x7fcb62540b00bc8b,
      25                 :            :     KEY4 = 0x46c60ec11af9dde3,
      26                 :            :     KEY5 = 0xcb6760b98ece2477,
      27                 :            :     KEY6 = 0xf37dc72b7f9e5c88,
      28                 :            :     KEY7 = 0x30c18c962d82e5f5,
      29                 :            : };
      30                 :            : 
      31                 :          1 : int main()
      32                 :            : {
      33                 :          1 :     pl_log log = pl_test_logger();
      34                 :          1 :     pl_cache test = pl_cache_create(pl_cache_params(
      35                 :            :         .log             = log,
      36                 :            :         .max_object_size = 16,
      37                 :            :         .max_total_size  = 32,
      38                 :            :     ));
      39                 :            : 
      40                 :          1 :     pl_cache_obj obj1 = { .key  = KEY1, .data = "abc",  .size = 3 };
      41                 :          1 :     pl_cache_obj obj2 = { .key  = KEY2, .data = "de",   .size = 2 };
      42                 :          1 :     pl_cache_obj obj3 = { .key  = KEY3, .data = "xyzw", .size = 4 };
      43         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_signature(test), ==, 0x0, PRIu64);
      44                 :            : 
      45         [ -  + ]:          1 :     REQUIRE(pl_cache_try_set(test, &obj1));
      46         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_signature(test), ==, KEY1, PRIu64);
      47         [ -  + ]:          1 :     REQUIRE(pl_cache_try_set(test, &obj2));
      48         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_signature(test), ==, KEY1 ^ KEY2, PRIu64);
      49         [ -  + ]:          1 :     REQUIRE(pl_cache_try_set(test, &obj3));
      50         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_signature(test), ==, KEY1 ^ KEY2 ^ KEY3, PRIu64);
      51         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_size(test), ==, 9, "zu");
      52         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_objects(test), ==, 3, "d");
      53         [ -  + ]:          1 :     REQUIRE(pl_cache_try_set(test, &obj2)); // delete KEY2
      54         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_size(test), ==, 7, "zu");
      55         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_objects(test), ==, 2, "d");
      56         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_signature(test), ==, KEY1 ^ KEY3, PRIu64);
      57                 :            : 
      58         [ -  + ]:          1 :     REQUIRE(pl_cache_get(test, &obj1));
      59         [ -  + ]:          1 :     REQUIRE(!pl_cache_get(test, &obj2));
      60         [ -  + ]:          1 :     REQUIRE(pl_cache_get(test, &obj3));
      61         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_size(test), ==, 0, "zu");
      62         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_objects(test), ==, 0, "d");
      63                 :          1 :     REQUIRE_MEMEQ(obj1.data, "abc", 3);
      64                 :          1 :     REQUIRE_MEMEQ(obj3.data, "xyzw", 4);
      65                 :            : 
      66                 :            :     // Re-insert removed objects (in reversed order)
      67         [ -  + ]:          1 :     REQUIRE(pl_cache_try_set(test, &obj3));
      68         [ -  + ]:          1 :     REQUIRE(pl_cache_try_set(test, &obj1));
      69         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_size(test), ==, 7, "zu");
      70         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_objects(test), ==, 2, "d");
      71                 :            : 
      72                 :            :     uint8_t ref[72];
      73                 :            :     memset(ref, 0xbe, sizeof(ref));
      74                 :            :     uint8_t *refp = ref;
      75                 :            : 
      76                 :            : #define PAD_ALIGN(x) PL_ALIGN2(x, sizeof(uint32_t))
      77                 :            : #define W(type, ...)                                    \
      78                 :            :     do {                                                \
      79                 :            :         size_t sz = sizeof((type){__VA_ARGS__});        \
      80                 :            :         pl_assert(ref + sizeof(ref) - refp >= sz);      \
      81                 :            :         memcpy(refp, &(type){__VA_ARGS__}, sz);         \
      82                 :            :         refp += sz;                                     \
      83                 :            :         size_t pad_sz = PAD_ALIGN(sz) - sz;             \
      84                 :            :         pl_assert(ref + sizeof(ref) - refp >= pad_sz);  \
      85                 :            :         memcpy(refp, &(char[PAD_ALIGN(1)]){0}, pad_sz); \
      86                 :            :         refp += pad_sz;                                 \
      87                 :            :     } while (0)
      88                 :            : 
      89                 :            :     W(char[], 'p', 'l', '_', 'c', 'a', 'c', 'h', 'e');  // cache magic
      90                 :            :     W(uint32_t, 1);                                     // cache version
      91                 :            :     W(uint32_t, 2);                                     // number of objects
      92                 :            : 
      93                 :            :     // object 3
      94                 :            :     W(uint64_t, KEY3);                // key
      95                 :            :     W(uint64_t, 4);                   // size
      96                 :            : #ifdef PL_HAVE_XXHASH
      97                 :            :     W(uint64_t, 0xd43612ef3fbee8be);  // hash
      98                 :            : #else
      99                 :            :     W(uint64_t, 0xec18884e5e471117);  // hash
     100                 :            : #endif
     101                 :            :     W(char[], 'x', 'y', 'z', 'w');    // data
     102                 :            : 
     103                 :            :     // object 1
     104                 :            :     W(uint64_t, KEY1);                // key
     105                 :            :     W(uint64_t, 3);                   // size
     106                 :            : #ifdef PL_HAVE_XXHASH
     107                 :            :     W(uint64_t, 0x78af5f94892f3950);  // hash
     108                 :            : #else
     109                 :            :     W(uint64_t, 0x3a204d408a2e2d77);  // hash
     110                 :            : #endif
     111                 :            :     W(char[], 'a', 'b', 'c');         // data
     112                 :            : 
     113                 :            : #undef W
     114                 :            : #undef PAD_ALIGN
     115                 :            : 
     116                 :            :     uint8_t data[100];
     117                 :            :     pl_static_assert(sizeof(data) >= sizeof(ref));
     118         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_save(test, data, sizeof(data)), ==, sizeof(ref), "zu");
     119                 :          1 :     REQUIRE_MEMEQ(data, ref, sizeof(ref));
     120                 :            : 
     121                 :          1 :     pl_cache test2 = pl_cache_create(pl_cache_params( .log = log ));
     122         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_load(test2, data, sizeof(data)), ==, 2, "d");
     123         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_signature(test), ==, pl_cache_signature(test2), PRIu64);
     124         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_size(test2), ==, 7, "zu");
     125         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_save(test2, NULL, 0), ==, sizeof(ref), "zu");
     126         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_save(test2, data, sizeof(data)), ==, sizeof(ref), "zu");
     127                 :          1 :     REQUIRE_MEMEQ(data, ref, sizeof(ref));
     128                 :            : 
     129                 :            :     // Test loading invalid data
     130         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_load(test2, ref, 0),   <, 0, "d"); // empty file
     131         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_load(test2, ref, 5),   <, 0, "d"); // truncated header
     132         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_load(test2, ref, 64), ==, 1, "d"); // truncated object data
     133                 :          1 :     data[sizeof(ref) - 2] = 'X'; // corrupt data
     134         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_load(test2, data, sizeof(ref)), ==, 1, "d"); // bad checksum
     135                 :          1 :     pl_cache_destroy(&test2);
     136                 :            : 
     137                 :            :     // Inserting too large object should fail
     138                 :          1 :     uint8_t zero[32] = {0};
     139                 :          1 :     pl_cache_obj obj4 = { .key = KEY4, .data = zero, .size = 32 };
     140         [ -  + ]:          1 :     REQUIRE(!pl_cache_try_set(test, &obj4));
     141         [ -  + ]:          1 :     REQUIRE(!pl_cache_get(test, &obj4));
     142         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_size(test), ==, 7, "zu");
     143         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_objects(test), ==, 2, "d");
     144                 :            : 
     145                 :            :     // Inserting 16-byte object should succeed, and not purge old entries
     146                 :          1 :     obj4 = (pl_cache_obj) { .key = KEY4, .data = zero, .size = 16 };
     147         [ -  + ]:          1 :     REQUIRE(pl_cache_try_set(test, &obj4));
     148         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_size(test), ==, 23, "zu");
     149         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_objects(test), ==, 3, "d");
     150         [ -  + ]:          1 :     REQUIRE(pl_cache_get(test, &obj1));
     151         [ -  + ]:          1 :     REQUIRE(pl_cache_get(test, &obj3));
     152         [ -  + ]:          1 :     REQUIRE(pl_cache_get(test, &obj4));
     153                 :          1 :     pl_cache_set(test, &obj1);
     154                 :          1 :     pl_cache_set(test, &obj3);
     155                 :          1 :     pl_cache_set(test, &obj4);
     156         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_size(test), ==, 23, "zu");
     157         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_objects(test), ==, 3, "d");
     158                 :            : 
     159                 :            :     // Inserting another 10-byte object should purge entry KEY1
     160                 :          1 :     pl_cache_obj obj5 = { .key = KEY5, .data = zero, .size = 10 };
     161         [ -  + ]:          1 :     REQUIRE(pl_cache_try_set(test, &obj5));
     162         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_size(test), ==, 30, "zu");
     163         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_objects(test), ==, 3, "d");
     164         [ -  + ]:          1 :     REQUIRE(!pl_cache_get(test, &obj1));
     165         [ -  + ]:          1 :     REQUIRE(pl_cache_get(test, &obj3));
     166         [ -  + ]:          1 :     REQUIRE(pl_cache_get(test, &obj4));
     167         [ -  + ]:          1 :     REQUIRE(pl_cache_get(test, &obj5));
     168                 :          1 :     pl_cache_set(test, &obj3);
     169                 :          1 :     pl_cache_set(test, &obj4);
     170                 :          1 :     pl_cache_set(test, &obj5);
     171         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_size(test), ==, 30, "zu");
     172         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_objects(test), ==, 3, "d");
     173                 :            : 
     174                 :            :     // Inserting final 6-byte object should purge entry KEY3
     175                 :          1 :     pl_cache_obj obj6 = { .key = KEY6, .data = zero, .size = 6 };
     176         [ -  + ]:          1 :     REQUIRE(pl_cache_try_set(test, &obj6));
     177         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_size(test), ==, 32, "zu");
     178         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_objects(test), ==, 3, "d");
     179         [ -  + ]:          1 :     REQUIRE(!pl_cache_get(test, &obj3));
     180         [ -  + ]:          1 :     REQUIRE(pl_cache_get(test, &obj4));
     181         [ -  + ]:          1 :     REQUIRE(pl_cache_get(test, &obj5));
     182         [ -  + ]:          1 :     REQUIRE(pl_cache_get(test, &obj6));
     183         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_size(test), ==, 0, "zu");
     184         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_objects(test), ==, 0, "d");
     185                 :            :     pl_cache_obj_free(&obj4);
     186                 :            :     pl_cache_obj_free(&obj5);
     187                 :            :     pl_cache_obj_free(&obj6);
     188                 :            : 
     189                 :            :     // Test callback API
     190                 :          1 :     int num_objects = 0;
     191                 :          1 :     test2 = pl_cache_create(pl_cache_params(
     192                 :            :         .get  = lookup_foobar,
     193                 :            :         .set  = update_count,
     194                 :            :         .priv = &num_objects,
     195                 :            :     ));
     196                 :            : 
     197         [ -  + ]:          1 :     REQUIRE(pl_cache_get(test2, &obj1));
     198         [ -  + ]:          1 :     REQUIRE_CMP(obj1.key, ==, KEY1, PRIu64);
     199         [ -  + ]:          1 :     REQUIRE_CMP(obj1.size, ==, 3, "zu");
     200                 :          1 :     REQUIRE_MEMEQ(obj1.data, "bar", 3);
     201         [ -  + ]:          1 :     REQUIRE(pl_cache_get(test2, &obj2));
     202         [ -  + ]:          1 :     REQUIRE_CMP(obj2.key, ==, KEY2, PRIu64);
     203         [ -  + ]:          1 :     REQUIRE_CMP(obj2.size, ==, 3, "zu");
     204                 :          1 :     REQUIRE_MEMEQ(obj2.data, "foo", 3);
     205         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_objects(test2), ==, 0, "d");
     206         [ -  + ]:          1 :     REQUIRE_CMP(num_objects, ==, 0, "d");
     207         [ -  + ]:          1 :     REQUIRE(pl_cache_try_set(test2, &obj1));
     208         [ -  + ]:          1 :     REQUIRE(pl_cache_try_set(test2, &obj2));
     209         [ -  + ]:          1 :     REQUIRE(pl_cache_try_set(test2, &(pl_cache_obj) { .key = KEY7, .data = "abcde", .size = 5 }));
     210         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_objects(test2), ==, 3, "d");
     211         [ -  + ]:          1 :     REQUIRE_CMP(num_objects, ==, 3, "d");
     212         [ -  + ]:          1 :     REQUIRE(pl_cache_try_set(test2, &obj1));
     213         [ -  + ]:          1 :     REQUIRE(pl_cache_try_set(test2, &obj2));
     214         [ -  + ]:          1 :     REQUIRE_CMP(pl_cache_objects(test2), ==, 1, "d");
     215         [ -  + ]:          1 :     REQUIRE_CMP(num_objects, ==, 1, "d");
     216                 :          1 :     pl_cache_destroy(&test2);
     217                 :            : 
     218                 :          1 :     pl_cache_destroy(&test);
     219                 :          1 :     pl_log_destroy(&log);
     220                 :            :     return 0;
     221                 :            : }

Generated by: LCOV version 1.16