Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
test_conf_value_lifetime.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
44#include "common/conf.h"
45#include "darktable.h"
46
47#include <glib.h>
48#include <glib/gstdio.h>
49#include <stdarg.h>
50#include <stddef.h>
51#include <stdlib.h> // calloc/free, used directly below
52// cmocka.h declares `extern jmp_buf global_expect_assert_env' at file scope without including
53// <setjmp.h> itself. Same suppression as test_pipe_cache_policy.c, and for the same reason.
54#include <setjmp.h> // NOLINT(misc-include-cleaner)
55#include <stdint.h>
56#include <cmocka.h>
57
58#ifdef _WIN32
59#include "win/main_wrapper.h"
60#endif
61
63#define TEST_KEY "plugins/test/conf_value_lifetime"
64
65static char *_rcfile = NULL;
66
67static int _setup(void **state)
68{
69 (void)state;
70 // dt_conf_init() writes through the darktable.conf global, so it must point at the
71 // instance being initialised before the call -- exactly as dt_init() does it.
72 _rcfile = g_build_filename(g_get_tmp_dir(), "ansel_test_conf_lifetime.rc", NULL);
73 g_remove(_rcfile);
74 darktable.conf = (dt_conf_t *)calloc(1, sizeof(dt_conf_t));
76 return 0;
77}
78
79static int _teardown(void **state)
80{
81 (void)state;
83 free(darktable.conf);
84 darktable.conf = NULL;
85 g_remove(_rcfile);
86 g_free(_rcfile);
87 _rcfile = NULL;
88 return 0;
89}
90
93{
94 (void)state;
96
97 const char *borrowed = dt_conf_get_string_const(TEST_KEY);
98 assert_string_equal(borrowed, "first");
99
100 // The write that used to free `borrowed` out from under us.
101 dt_conf_set_string(TEST_KEY, "second");
102
103 // Still readable, and still the value it was read as. Under ASAN, a regression here is a
104 // heap-use-after-free rather than a failed assertion.
105 assert_string_equal(borrowed, "first");
106
107 // ... while a fresh read observes the new value. Stale, not wrong.
108 assert_string_equal(dt_conf_get_string_const(TEST_KEY), "second");
109}
110
113{
114 (void)state;
115 const char *held[8];
116
117 for(int i = 0; i < 8; i++)
118 {
119 char *value = g_strdup_printf("value-%d", i);
121 g_free(value);
123 }
124
125 // Every pointer taken along the way still reads as what it was when taken.
126 for(int i = 0; i < 8; i++)
127 {
128 char *expected = g_strdup_printf("value-%d", i);
129 assert_string_equal(held[i], expected);
130 g_free(expected);
131 }
132}
133
140{
141 (void)state;
142 dt_conf_set_string(TEST_KEY, "unchanged");
143 const char *before = dt_conf_get_string_const(TEST_KEY);
144
145 for(int i = 0; i < 16; i++) dt_conf_set_string(TEST_KEY, "unchanged");
146
147 // Same allocation, so nothing was displaced and nothing was retired.
148 assert_ptr_equal(before, dt_conf_get_string_const(TEST_KEY));
149 assert_string_equal(before, "unchanged");
150}
151
154{
155 (void)state;
157 const char *borrowed = dt_conf_get_string_const(TEST_KEY);
158 assert_string_equal(borrowed, "11");
159
161
162 assert_string_equal(borrowed, "11");
163 assert_int_equal(dt_conf_get_int_fast(TEST_KEY), 22);
164}
165
175{
176 (void)state;
178 const uint64_t after_first = dt_conf_generation();
179 assert_true(after_first > 0); // starts at 1, so 0 is usable as "nothing cached yet"
180
181 dt_conf_set_string(TEST_KEY, "second");
182 const uint64_t after_second = dt_conf_generation();
183 assert_true(after_second > after_first);
184
185 // An idle rewrite of the identical value must NOT move it.
186 for(int i = 0; i < 16; i++) dt_conf_set_string(TEST_KEY, "second");
187 assert_int_equal(dt_conf_generation(), after_second);
188
189 // The typed setters go through the same writer, so they advance it too.
191 const uint64_t after_int = dt_conf_generation();
192 assert_true(after_int > after_second);
193
195 assert_int_equal(dt_conf_generation(), after_int);
196
197 // And a plain read never moves it -- a cache that re-derived per read would be no cache.
200 assert_int_equal(dt_conf_generation(), after_int);
201}
202
203int main(int argc, char *argv[])
204{
205 const struct CMUnitTest tests[] = {
209 cmocka_unit_test(_typed_setters_retire_too),
211 };
212
213 return cmocka_run_group_tests(tests, _setup, _teardown);
214}
215
216// clang-format off
217// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
218// vim: shiftwidth=2 expandtab tabstop=2 cindent
219// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
220// clang-format on
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
void dt_conf_cleanup(dt_conf_t *cf)
Free everything cf owns. No dt_conf_*() call is valid afterwards.
void dt_conf_init(dt_conf_t *cf, const char *filename, GSList *override_entries)
Populate cf from filename and from the generated defaults.
uint64_t dt_conf_generation(void)
A counter that advances whenever a conf value actually changes.
int dt_conf_get_int_fast(const char *name)
Stored integer for name, NOT clamped to its declared bounds.
void dt_conf_set_int(const char *name, int val)
void dt_conf_set_string(const char *name, const char *val)
const char * dt_conf_get_string_const(const char *name)
Borrow the stored string for name without copying it.
darktable_t darktable
Definition darktable.c:213
int main()
Definition prova.c:47
static const dt_aligned_pixel_simd_t value
Definition simd.h:144
const float uint32_t state[4]
unsigned __int64 uint64_t
Definition strptime.c:75
struct dt_conf_t * conf
Definition darktable.h:184
The whole configuration state. One instance lives at darktable.conf.
static int _setup(void **state)
static int _teardown(void **state)
static void _borrowed_value_survives_being_replaced(void **state)
static void _every_displaced_value_stays_readable(void **state)
#define TEST_KEY
static char * _rcfile
static void _the_generation_advances_on_a_change_and_not_otherwise(void **state)
static void _typed_setters_retire_too(void **state)
static void _rewriting_the_same_value_retires_nothing(void **state)