Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
test_image_repository.c
Go to the documentation of this file.
1/*
2 This file is part of Ansel,
3 Copyright (C) 2026 Aurélien PIERRE.
4
5 Ansel is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 Ansel is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with Ansel. If not, see <http://www.gnu.org/licenses/>.
17*/
18
27#include "testdb.h"
28
29
30// an arbitrary flag bit with no side meaning in these tests
31#define TEST_FLAG 2048
32
34{
35 (void)state;
36 const int32_t film = testdb_make_film("/testdb/filmroll");
37 assert_true(film > 0);
38 const int32_t a = testdb_make_image(film, "a.raw");
39 const int32_t b = testdb_make_image(film, "b.raw");
40 const int32_t c = testdb_make_image(film, "c.raw");
41 assert_true(a > 0 && b > 0 && c > 0);
42
45
46 // set the flag on TWO images at once -- the case the old IN (?) binding silently dropped
48
54
55 // a single-element list keeps working (the only case the old binding handled)
61
62 // an empty set asks about nothing
64
68}
69
70/* dt_image_repository_set_flags_masked() writes the mask's bits and nothing else.
71 *
72 * The XMP crawler reads an image's whole `flags` word, then lists a directory -- a
73 * filesystem round-trip -- before deciding what to write back. Anything the user changes in
74 * that window (a star rating, a colour label) shares the word, so the crawl must write only
75 * the two bits it owns. This pins that. */
77{
78 (void)state;
79 const int32_t film = testdb_make_film("/testdb/masked");
80 assert_true(film > 0);
81 const int32_t img = testdb_make_image(film, "masked.raw");
82 assert_true(img > 0);
83
84 // two bits the write will own, and one standing in for the rating the user sets meanwhile
85 const int owned_a = 1 << 4;
86 const int owned_b = 1 << 5;
87 const int mask = owned_a | owned_b;
88
90
91 // start with owned_a set and owned_b clear, plus the unrelated bit
93
94 // the crawl's write: clear owned_a, set owned_b, say nothing about the rest
96
100
102
103 // the bit outside the mask survived -- this is the whole point
107
108 // an empty mask writes nothing and says so, rather than clearing the word
113
115}
116
117static void test_full_paths(void **state)
118{
119 (void)state;
120 const int32_t film = testdb_make_film("/testdb/paths");
121 const int32_t a = testdb_make_image(film, "a.raw");
122 const int32_t b = testdb_make_image(film, "b.raw");
123 assert_true(a > 0 && b > 0);
124
128 assert_string_equal((const char *)paths->data, "/testdb/paths/a.raw");
129 assert_string_equal((const char *)paths->next->data, "/testdb/paths/b.raw");
131 g_list_free(ids);
132}
133
134static void test_id_range(void **state)
135{
136 (void)state;
137 const int32_t film = testdb_make_film("/testdb/range");
138 const int32_t a = testdb_make_image(film, "a.raw");
139 const int32_t b = testdb_make_image(film, "b.raw");
140 const int32_t c = testdb_make_image(film, "c.raw");
141 assert_true(a > 0 && c > a);
142
146}
147
149{
150 (void)state;
151 const int32_t film = testdb_make_film("/testdb/ts");
152 const int32_t a = testdb_make_image(film, "a.raw");
153 assert_true(a > 0);
154
155 // 2100-01-01: overflows a 32-bit time_t. The caller this setter replaced bound the
156 // timestamp with sqlite3_bind_int(), which truncates in 2038.
157 const int64_t year2100 = 4102444800LL;
160}
161
162static void test_group_member_rows(void **state)
163{
164 (void)state;
165 const int32_t film = testdb_make_film("/testdb/group");
166 const int32_t a = testdb_make_image(film, "a.raw");
167 const int32_t b = testdb_make_image(film, "b.raw");
168 assert_true(a > 0 && b > 0);
171
174 const dt_image_group_member_t *first = (const dt_image_group_member_t *)members->data;
175 const dt_image_group_member_t *second = (const dt_image_group_member_t *)members->next->data;
176 assert_int_equal(first->imgid, a);
177 assert_string_equal(first->filename, "a.raw");
178 assert_int_equal(second->imgid, b);
179 assert_string_equal(second->filename, "b.raw");
181}
182
184{
185 (void)state;
186 const int32_t film = testdb_make_film("/testdb/distinct");
187 const int32_t a = testdb_make_image(film, "a.raw");
188 const int32_t b = testdb_make_image(film, "b.raw");
189 assert_true(a > 0 && b > 0);
190
194
195 assert_int_equal(counts[DT_IMAGE_FIELD_FILM_ROLL], 1); // same film -> agree
196 assert_int_equal(counts[DT_IMAGE_FIELD_FILENAME], 2); // different names -> disagree
197 assert_int_equal(counts[DT_IMAGE_FIELD_IMGID], 2); // ids differ by definition
198 assert_int_equal(counts[DT_IMAGE_FIELD_VERSION], 1); // both imported at version 0
199
200 free(counts);
201 g_list_free(ids);
202
203 // the empty set answers nothing rather than something
205}
206
207static gboolean _count_two_rows(const int32_t imgid, const int64_t write_timestamp,
208 const int version, const char *image_path, const int flags,
209 void *user_data)
210{
211 (void)imgid;
213 (void)version;
214 (void)image_path;
215 (void)flags;
216 int *seen = (int *)user_data;
217 (*seen)++;
218 return *seen < 2; // refuse the second row
219}
220
221/* The walk ends at the first row the callback refuses. That is how the XMP crawler stops when
222 * Ansel quits; a walk that went on regardless would hold the quit up until the last image. */
224{
225 (void)state;
226 const int32_t film = testdb_make_film("/testdb/walk");
227 assert_true(film > 0);
228 assert_true(testdb_make_image(film, "w0.raw") > 0);
229 assert_true(testdb_make_image(film, "w1.raw") > 0);
230 assert_true(testdb_make_image(film, "w2.raw") > 0);
231
232 int seen = 0;
235}
236
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
int dt_image_repository_count_in_id_range(const int32_t min_imgid, const int32_t max_imgid)
How many images have an id in [min_imgid, max_imgid]. -1 when unreadable.
gboolean dt_image_repository_set_flags_masked(const int32_t imgid, const int mask, const int value)
Write only mask's bits of imgid's flags, taking them from value.
GList * dt_image_repository_get_ids_with_flag_among(GList *imgids, const int flag)
Of the images in imgids, those whose flags carry flag, in row order.
int64_t dt_image_repository_get_write_timestamp(const int32_t imgid)
main.images.write_timestamp for imgid, or 0.
gboolean dt_image_repository_set_group(const int32_t imgid, const int32_t group_id)
Set imgid's group_id.
gboolean dt_image_repository_set_write_timestamp(const int32_t imgid, const int64_t timestamp)
Set write_timestamp of imgid to timestamp (seconds since the epoch). Bound as a 64-bit integer; the c...
void dt_image_group_member_free(gpointer data)
Free one dt_image_group_member_t. Suits g_list_free_full().
GList * dt_image_repository_get_group_member_rows(const int32_t group_id)
Every member of group_id, in row order, named. Free with g_list_free_full(list, dt_image_group_member...
void dt_image_repository_foreach_with_path(dt_image_repository_path_row_cb cb, void *user_data)
Walk every image in the library, film roll by film roll, filename within each.
gboolean dt_image_repository_set_flag_among(GList *imgids, const int flag)
Set flag on every image in imgids.
GList * dt_image_repository_get_full_paths(GList *imgids)
"<folder>/<filename>" for every image in imgids, distinct, in row order. Caller owns the strings.
int * dt_image_repository_count_distinct_fields(GList *imgids)
How many DISTINCT values each dt_image_field_t takes over imgids.
@ DT_IMAGE_FIELD_VERSION
@ DT_IMAGE_FIELD_FILENAME
@ DT_IMAGE_FIELD_FILM_ROLL
@ DT_IMAGE_FIELD_IMGID
dt_mipmap_buffer_dsc_flags flags
Definition mipmap_cache.c:4
const float uint32_t state[4]
One member of a group, with what a tooltip needs to name it.
static void test_flag_among_multi_image(void **state)
static void test_foreach_with_path_stops_when_asked(void **state)
static void test_write_timestamp_is_64bit(void **state)
static void test_set_flags_masked_leaves_other_bits(void **state)
static void test_group_member_rows(void **state)
int main(void)
static gboolean _count_two_rows(const int32_t imgid, const int64_t write_timestamp, const int version, const char *image_path, const int flags, void *user_data)
static void test_count_distinct_fields(void **state)
static void test_full_paths(void **state)
static void test_id_range(void **state)
#define TEST_FLAG
Shared fixture for the src/database repository tests.
static int testdb_setup(void **state)
Definition testdb.h:55
static int32_t testdb_make_film(const char *folder)
Definition testdb.h:85
static int testdb_teardown(void **state)
Definition testdb.h:66
static int32_t testdb_make_image(const int32_t film_id, const char *filename)
Definition testdb.h:92