29#include <glib/gstdio.h>
38#ifndef ANSEL_TEST_SOURCE_DIR
39#define ANSEL_TEST_SOURCE_DIR "."
42#ifndef ANSEL_TEST_BINARY_DIR
43#define ANSEL_TEST_BINARY_DIR "."
76static int test_fail(
const char *scenario,
const char *message,
char **failure_reason)
78 fprintf(stderr,
"[FAIL] %s: %s\n", scenario, message);
80 *failure_reason = g_strdup(message);
86 const char *
extension = strrchr(filename,
'.');
92 char *scenario = g_strdup(filename);
100 sqlite3_stmt *stmt = NULL;
102 sqlite3_bind_int(stmt, 1, imgid_a);
103 sqlite3_bind_int(stmt, 2, imgid_b);
104 const int value = (sqlite3_step(stmt) == SQLITE_ROW) ? sqlite3_column_int(stmt, 0) : -1;
105 sqlite3_finalize(stmt);
111 sqlite3_stmt *stmt = NULL;
114 const int value = (sqlite3_step(stmt) == SQLITE_ROW) ? sqlite3_column_int(stmt, 0) : 0;
115 sqlite3_finalize(stmt);
121 sqlite3_stmt *stmt = NULL;
123 "SELECT name FROM data.styles WHERE id > ?1 ORDER BY id DESC LIMIT 1", -1, &stmt,
125 sqlite3_bind_int(stmt, 1, before_import_style_id);
128 if(sqlite3_step(stmt) == SQLITE_ROW)
129 name = g_strdup((
const char *)sqlite3_column_text(stmt, 0));
131 sqlite3_finalize(stmt);
137 static int image_index = 0;
138 const char *
extension = strrchr(source_image_path,
'.');
139 char *filename = g_strdup_printf(
"style-test-%d%s", image_index++,
extension ?
extension :
".raw");
140 char *image_path = g_build_filename(
test_image_dir, filename, NULL);
142 GFile *source_file = g_file_new_for_path(source_image_path);
143 GFile *image_file = g_file_new_for_path(image_path);
144 GError *
error = NULL;
145 const gboolean copied = g_file_copy(source_file, image_file, G_FILE_COPY_OVERWRITE, NULL, NULL, NULL, &
error);
146 g_object_unref(source_file);
147 g_object_unref(image_file);
151 fprintf(stderr,
"[FAIL] copy test image: %s\n",
error ?
error->message :
"unknown error");
152 g_clear_error(&
error);
177 char **failure_reason)
179 if(!g_file_test(xmp_path, G_FILE_TEST_IS_REGULAR))
180 return test_fail(scenario,
"missing XMP fixture", failure_reason);
183 ?
test_fail(scenario,
"could not load XMP fixture", failure_reason)
188 const char *start_xmp_name,
char **failure_reason)
190 if(g_file_test(start_xmp_path, G_FILE_TEST_IS_REGULAR))
193 printf(
"[NOTE] %s: no %s fixture, using imported base history\n", scenario, start_xmp_name);
199 sqlite3_stmt *stmt = NULL;
201 "SELECT version, iop_list FROM main.module_order WHERE imgid=?1", -1, &stmt, NULL);
202 sqlite3_bind_int(stmt, 1, imgid);
204 if(sqlite3_step(stmt) == SQLITE_ROW)
206 const unsigned char *iop_list = sqlite3_column_text(stmt, 1);
207 fprintf(stderr,
" %s pipe order for image %d:\n", label, imgid);
208 fprintf(stderr,
" version=%d\n", sqlite3_column_int(stmt, 0));
209 fprintf(stderr,
" iop_list=%s\n", iop_list ? (
const char *)iop_list :
"(null)");
213 fprintf(stderr,
" %s pipe order for image %d: no module_order row\n", label, imgid);
216 sqlite3_finalize(stmt);
219static int compare_pipe_order(
const char *scenario,
const int32_t actual_imgid,
const int32_t expected_imgid,
220 char **failure_reason)
224 " (SELECT COUNT(*) FROM"
225 " (SELECT version, iop_list FROM main.module_order WHERE imgid=?1"
227 " SELECT version, iop_list FROM main.module_order WHERE imgid=?2))"
229 " (SELECT COUNT(*) FROM"
230 " (SELECT version, iop_list FROM main.module_order WHERE imgid=?2"
232 " SELECT version, iop_list FROM main.module_order WHERE imgid=?1))",
233 actual_imgid, expected_imgid);
237 test_fail(scenario,
"module order differs from expected XMP", failure_reason);
245 fprintf(stderr,
" %s enabled state for image %d:\n", label, imgid);
247 sqlite3_stmt *stmt = NULL;
250 "SELECT h.operation, h.multi_priority, IFNULL(h.multi_name, ''), h.enabled"
251 " FROM main.history h"
253 " AND h.num < (SELECT history_end FROM main.images WHERE id=?1)"
254 " AND h.num = (SELECT MAX(h2.num)"
255 " FROM main.history h2"
257 " AND h2.operation=h.operation"
258 " AND h2.multi_priority=h.multi_priority"
259 " AND h2.num < (SELECT history_end FROM main.images WHERE id=?1))"
260 " ORDER BY h.operation, h.multi_priority",
262 sqlite3_bind_int(stmt, 1, imgid);
264 while(sqlite3_step(stmt) == SQLITE_ROW)
266 const unsigned char *operation = sqlite3_column_text(stmt, 0);
267 const unsigned char *multi_name = sqlite3_column_text(stmt, 2);
268 fprintf(stderr,
" %-24s priority=%d name='%s' enabled=%d\n",
269 operation ? (
const char *)operation :
"", sqlite3_column_int(stmt, 1),
270 multi_name ? (
const char *)multi_name :
"", sqlite3_column_int(stmt, 3));
273 sqlite3_finalize(stmt);
277 const int32_t expected_imgid,
char **failure_reason)
281 " SELECT h.operation, h.multi_priority, IFNULL(h.multi_name, '') AS multi_name, h.enabled"
282 " FROM main.history h"
284 " AND h.num < (SELECT history_end FROM main.images WHERE id=?1)"
285 " AND h.num = (SELECT MAX(h2.num)"
286 " FROM main.history h2"
288 " AND h2.operation=h.operation"
289 " AND h2.multi_priority=h.multi_priority"
290 " AND h2.num < (SELECT history_end FROM main.images WHERE id=?1))"
292 " SELECT h.operation, h.multi_priority, IFNULL(h.multi_name, '') AS multi_name, h.enabled"
293 " FROM main.history h"
295 " AND h.num < (SELECT history_end FROM main.images WHERE id=?2)"
296 " AND h.num = (SELECT MAX(h2.num)"
297 " FROM main.history h2"
299 " AND h2.operation=h.operation"
300 " AND h2.multi_priority=h.multi_priority"
301 " AND h2.num < (SELECT history_end FROM main.images WHERE id=?2))"
304 " (SELECT COUNT(*) FROM (SELECT * FROM actual EXCEPT SELECT * FROM expected))"
306 " (SELECT COUNT(*) FROM (SELECT * FROM expected EXCEPT SELECT * FROM actual))",
307 actual_imgid, expected_imgid);
311 test_fail(scenario,
"final enabled states differ from expected XMP", failure_reason);
318 char **failure_reason)
322 return test_fail(scenario,
"imported style is missing from the database", failure_reason);
328 ?
test_fail(scenario,
"style application failed", failure_reason)
332static int run_style_scenario(
const char *scenario_dir,
const char *source_image_path,
const char *style_file,
333 char **failure_reason)
336 char *style_path = g_build_filename(scenario_dir, style_file, NULL);
337 char *start_xmp_name = g_strdup_printf(
"start_%s.xmp", scenario);
338 char *end_xmp_name = g_strdup_printf(
"end_%s.xmp", scenario);
339 char *start_xmp_path = g_build_filename(scenario_dir, start_xmp_name, NULL);
340 char *end_xmp_path = g_build_filename(scenario_dir, end_xmp_name, NULL);
342 printf(
"\n[STEP] %s\n", scenario);
348 if(
IS_NULL_PTR(style_name)) style_name = g_strdup(scenario);
353 if(actual_imgid <= 0 || expected_imgid <= 0)
355 test_fail(scenario,
"could not import test image", failure_reason);
359 if(
load_start_history(scenario, actual_imgid, start_xmp_path, start_xmp_name, failure_reason))
goto end;
361 if(
load_xmp_on_image(scenario, expected_imgid, end_xmp_path, failure_reason))
goto end;
362 if(
compare_pipe_order(scenario, actual_imgid, expected_imgid, failure_reason))
goto end;
365 printf(
"[OK] %s\n", scenario);
381 GError *
error = NULL;
382 GDir *dir = g_dir_open(scenario_dir, 0, &
error);
385 fprintf(stderr,
"[FAIL] cannot open style scenario folder `%s`: %s\n", scenario_dir,
387 g_clear_error(&
error);
391 GList *style_files = NULL;
392 const char *entry = NULL;
393 while((entry = g_dir_read_name(dir)) != NULL)
395 if(
is_style_file(entry)) style_files = g_list_prepend(style_files, g_strdup(entry));
399 style_files = g_list_sort(style_files, (GCompareFunc)g_strcmp0);
402 printf(
"[SKIP] no .dtstyle file found in %s\n", scenario_dir);
407 GList *summaries = NULL;
408 for(GList *l = style_files; l; l = g_list_next(l))
410 const char *style_file = (
const char *)l->data;
415 summary->
reason = g_strdup(
"unknown failure");
417 summaries = g_list_prepend(summaries, summary);
418 result |= summary->
result;
421 summaries = g_list_reverse(summaries);
422 printf(
"\n[SUMMARY]\n");
423 for(GList *l = summaries; l; l = g_list_next(l))
426 printf(
"%s: %s", summary->
style_file, summary->
result ?
"FAILED" :
"PASSED");
428 printf(
" - %s", summary->
reason);
432 for(GList *l = summaries; l; l = g_list_next(l))
439 g_list_free(summaries);
446 char *datadir = g_build_filename(tmp_dir,
"data", NULL);
447 char *rawspeed_dir = g_build_filename(datadir,
"rawspeed", NULL);
448 char *rawspeed_xml = g_build_filename(rawspeed_dir,
"cameras.xml", NULL);
449 char *rawspeed_source_xml = g_build_filename(
ANSEL_TEST_SOURCE_DIR,
"src",
"external",
"rawspeed",
"data",
450 "cameras.xml", NULL);
452 g_mkdir(datadir, 0700);
453 g_mkdir(rawspeed_dir, 0700);
455 GError *
error = NULL;
456 GFile *source_file = g_file_new_for_path(rawspeed_source_xml);
457 GFile *dest_file = g_file_new_for_path(rawspeed_xml);
458 const gboolean copied = g_file_copy(source_file, dest_file, G_FILE_COPY_OVERWRITE, NULL, NULL, NULL, &
error);
459 g_object_unref(source_file);
460 g_object_unref(dest_file);
464 fprintf(stderr,
"[FAIL] copy rawspeed cameras.xml: %s\n",
error ?
error->message :
"unknown error");
465 g_clear_error(&
error);
476int main(
int argc,
char *argv[])
478 const gboolean explicit_scenario_dir = argc > 1;
480 char *default_source_image = g_build_filename(
ANSEL_TEST_SOURCE_DIR,
"tests",
"integration",
"images",
482 const char *scenario_dir = explicit_scenario_dir ? argv[1] : default_scenario_dir;
483 const char *source_image_path = (argc > 2) ? argv[2] : default_source_image;
485 if(!g_file_test(scenario_dir, G_FILE_TEST_IS_DIR))
487 fprintf(stderr, explicit_scenario_dir ?
"[FAIL] style scenario folder does not exist: %s\n"
488 :
"[SKIP] style scenario folder does not exist: %s\n",
492 return explicit_scenario_dir ? 1 : 0;
495 if(!g_file_test(source_image_path, G_FILE_TEST_IS_REGULAR))
497 fprintf(stderr,
"[FAIL] test image does not exist: %s\n", source_image_path);
503 char *config_dir = g_strdup_printf(
"%s/ansel-test-styles-config-XXXXXX", g_get_tmp_dir());
504 char *cache_dir = g_strdup_printf(
"%s/ansel-test-styles-cache-XXXXXX", g_get_tmp_dir());
505 char *tmp_dir = g_strdup_printf(
"%s/ansel-test-styles-tmp-XXXXXX", g_get_tmp_dir());
524 char *argv_override[] = {
526 "--library",
":memory:",
527 "--datadir", test_datadir,
528 "--noiseprofiles", noiseprofiles,
530 "--configdir", config_dir,
531 "--cachedir", cache_dir,
534 "--conf",
"write_sidecar_files=FALSE",
535 "--conf",
"plugins/lighttable/export/force_lcms2=FALSE",
539 int argc_override =
sizeof(argv_override) /
sizeof(*argv_override) - 1;
static void error(char *msg)
const char * extension(dt_imageio_module_data_t *data)
int32_t dt_image_import(const int32_t film_id, const char *filename, gboolean raise_signals)
void dt_conf_set_bool(const char *name, int val)
int dt_init(int argc, char *argv[], const gboolean init_gui, const gboolean load_data)
static void dt_free_gpointer(gpointer ptr)
static const dt_aligned_pixel_simd_t value
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
sqlite3 * dt_database_get(const dt_database_t *db)
void dt_film_init(dt_film_t *film)
int dt_film_new(dt_film_t *film, const char *directory)
void dt_film_cleanup(dt_film_t *film)
int dt_history_load_and_apply(const int32_t imgid, gchar *filename, int history_only)
@ DT_HISTORY_MERGE_APPEND
int dt_styles_apply_to_image_merge(const char *name, const int style_id, const int32_t newimgid, const dt_history_merge_strategy_t mode, dt_hm_batch_state_t *batch)
int32_t dt_styles_get_id_by_name(const char *name)
void dt_styles_import_from_file(const char *style_path)
const struct dt_database_t * db
One-line scenario result printed after every style has run.
static int test_fail(const char *scenario, const char *message, char **failure_reason)
static int sql_int_for_bound_images(const char *query, const int32_t imgid_a, const int32_t imgid_b)
static char * prepare_test_datadir(const char *tmp_dir)
static int load_start_history(const char *scenario, const int32_t imgid, const char *start_xmp_path, const char *start_xmp_name, char **failure_reason)
static char * imported_style_name(const int before_import_style_id)
static char * test_image_dir
Run style-application scenarios from tests/styles.
static int compare_enabled_state(const char *scenario, const int32_t actual_imgid, const int32_t expected_imgid, char **failure_reason)
static int run_style_scenarios(const char *scenario_dir, const char *source_image_path)
#define ANSEL_TEST_SOURCE_DIR
static int32_t create_test_image(const char *source_image_path)
static int max_style_id(void)
static char * scenario_name_from_style_file(const char *filename)
static int compare_pipe_order(const char *scenario, const int32_t actual_imgid, const int32_t expected_imgid, char **failure_reason)
static int apply_style_to_image(const char *scenario, const char *style_name, const int32_t imgid, char **failure_reason)
static gboolean is_style_file(const char *filename)
static int run_style_scenario(const char *scenario_dir, const char *source_image_path, const char *style_file, char **failure_reason)
static int load_xmp_on_image(const char *scenario, const int32_t imgid, const char *xmp_path, char **failure_reason)
static void print_module_order_summary(const char *label, const int32_t imgid)
static void print_enabled_state_summary(const char *label, const int32_t imgid)
#define ANSEL_TEST_BINARY_DIR