From 9db818279aa63d071f2bca369235285314444dcd Mon Sep 17 00:00:00 2001 From: Dudemanguy Date: Sat, 25 Feb 2023 21:50:08 -0600 Subject: [PATCH] test: integrate unittests with meson This reworks all of mpv's unit tests so they are compiled as separate executables (optional) and run via meson test. Because most of the tests are dependant on mpv's internals, existing compiled objects are leveraged to create static libs and used when necessary. As an aside, a function was moved into video/out/gpu/utils for sanity's sake (otherwise most of vo would have been needed). As a plus, meson multithreads running tests automatically and also the output no longer pollutes the source directory. There are tests that can break due to ffmpeg changes, so they require a specific minimum libavutil version to be built. --- DOCS/build-system-differences.md | 1 + meson.build | 30 +++--- meson_options.txt | 2 +- sub/draw_bmp.c | 8 ++ sub/draw_bmp.h | 3 + test/chmap.c | 46 ++++---- test/gl_video.c | 12 +-- test/img_format.c | 59 ++--------- test/img_utils.c | 63 +++++++++++ test/img_utils.h | 24 +++++ test/input-gamepad.conf | 4 - test/json.c | 11 +- libmpv/test.c => test/libmpv_test.c | 0 test/linked_list.c | 10 +- test/meson.build | 135 +++++++++++++++++++++++ test/paths.c | 11 +- test/repack.c | 70 ++++++------ test/scale_sws.c | 11 +- test/scale_test.c | 10 +- test/scale_test.h | 6 +- test/scale_zimg.c | 16 ++- test/subtimes.js | 15 --- test/test_utils.c | 114 ++++++++++++++++++++ test/test_utils.h | 64 +++++++++++ test/tests.c | 159 ---------------------------- test/tests.h | 87 --------------- video/out/gpu/utils.c | 15 +++ video/out/gpu/utils.h | 3 + video/out/gpu/video.c | 15 --- video/sws_utils.c | 3 + 30 files changed, 547 insertions(+), 460 deletions(-) create mode 100644 test/img_utils.c create mode 100644 test/img_utils.h delete mode 100644 test/input-gamepad.conf rename libmpv/test.c => test/libmpv_test.c (100%) create mode 100644 test/meson.build delete mode 100644 test/subtimes.js create mode 100644 test/test_utils.c create mode 100644 test/test_utils.h delete mode 100644 test/tests.c delete mode 100644 test/tests.h diff --git a/DOCS/build-system-differences.md b/DOCS/build-system-differences.md index 7b1a5e5bfd..ba430a219d 100644 --- a/DOCS/build-system-differences.md +++ b/DOCS/build-system-differences.md @@ -27,6 +27,7 @@ that you get for free. In some cases, these overlapped with custom waf options. supported in the meson build. Instead, pass the generic pkg-config values such as ``lua52``, ``lua5.2``, etc. * ``--lgpl`` was changed to ``gpl``. If ``gpl`` is false, the build is LGPL2.1+. +* ``--tests`` was removed since unit tests now explictly require meson to run ### Boolean Options diff --git a/meson.build b/meson.build index b57ce9d3c0..36bcf19f60 100644 --- a/meson.build +++ b/meson.build @@ -393,10 +393,11 @@ if features['cocoa'] endif if posix - sources += files('input/ipc-unix.c', - 'osdep/path-unix.c', + path_source = files('osdep/path-unix.c') + subprocess_source = files('osdep/subprocess-posix.c') + sources += path_source + subprocess_source + \ + files('input/ipc-unix.c', 'osdep/polldev.c', - 'osdep/subprocess-posix.c', 'osdep/terminal-unix.c', 'sub/filter_regex.c') endif @@ -479,10 +480,11 @@ if features['win32-desktop'] cc.find_library('version'), cc.find_library('winmm')] dependencies += win32_desktop_libs - sources += files('input/ipc-win.c', + path_source = files('osdep/path-win.c') + subprocess_source = files('osdep/subprocess-win.c') + sources += path_source + subprocess_source + \ + files('input/ipc-win.c', 'osdep/main-fn-win.c', - 'osdep/path-win.c', - 'osdep/subprocess-win.c', 'osdep/terminal-win.c', 'video/out/w32_common.c', 'video/out/win32/displayconfig.c', @@ -490,9 +492,8 @@ if features['win32-desktop'] endif if not posix and not features['win32-desktop'] - sources += files('input/ipc-dummy.c', - 'osdep/subprocess-dummy.c', - 'osdep/terminal-dummy.c') + subprocess_source = files('osdep/subprocess-dummy.c') + sources += subprocess_source + files('input/ipc-dummy.c') endif features += {'glob-posix': cc.has_function('glob', prefix: '#include ')} @@ -1685,9 +1686,6 @@ if get_option('libmpv') headers = ['libmpv/client.h', 'libmpv/render.h', 'libmpv/render_gl.h', 'libmpv/stream_cb.h'] install_headers(headers, subdir: 'mpv') - - libmpv_test = executable('libmpv-test', 'libmpv/test.c', link_with: [libmpv]) - test('libmpv', libmpv_test) endif if get_option('cplayer') @@ -1718,8 +1716,12 @@ if get_option('cplayer') rename: 'mpv.svg') install_data('etc/mpv-symbolic.svg', install_dir: join_paths(hicolor_dir, 'symbolic', 'apps')) - executable('mpv', objects: libmpv.extract_all_objects(recursive: true), dependencies: dependencies, - win_subsystem: 'windows,6.0', include_directories: includedir, install: true) + mpv = executable('mpv', objects: libmpv.extract_all_objects(recursive: true), dependencies: dependencies, + win_subsystem: 'windows,6.0', include_directories: includedir, install: true) +endif + +if get_option('tests') + subdir('test') endif summary({'d3d11': features['d3d11'], diff --git a/meson_options.txt b/meson_options.txt index 27af048c37..6e9269ffb4 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -3,7 +3,7 @@ option('gpl', type: 'boolean', value: true, description: 'GPL (version 2 or late option('cplayer', type: 'boolean', value: true, description: 'mpv CLI player') option('libmpv', type: 'boolean', value: false, description: 'libmpv library') option('build-date', type: 'boolean', value: true, description: 'whether to include binary compile time') -option('tests', type: 'boolean', value: false, description: 'unit tests (development only)') +option('tests', type: 'boolean', value: false, description: 'meson unit tests') # Reminder: normally always built, but enabled by MPV_LEAK_REPORT. # Building it can be disabled only by defining NDEBUG through CFLAGS. option('ta-leak-report', type: 'boolean', value: false, description: 'enable ta leak report by default (development only)') diff --git a/sub/draw_bmp.c b/sub/draw_bmp.c index 78ce773822..8ed104fdf8 100644 --- a/sub/draw_bmp.c +++ b/sub/draw_bmp.c @@ -840,6 +840,14 @@ struct mp_draw_sub_cache *mp_draw_sub_alloc(void *ta_parent, struct mpv_global * return c; } +// For tests. +struct mp_draw_sub_cache *mp_draw_sub_alloc_test(struct mp_image *dst) +{ + struct mp_draw_sub_cache *c = talloc_zero(NULL, struct mp_draw_sub_cache); + reinit_to_video(c); + return c; +} + bool mp_draw_sub_bitmaps(struct mp_draw_sub_cache *p, struct mp_image *dst, struct sub_bitmap_list *sbs_list) { diff --git a/sub/draw_bmp.h b/sub/draw_bmp.h index e9560e1ca5..fda7797c9e 100644 --- a/sub/draw_bmp.h +++ b/sub/draw_bmp.h @@ -10,6 +10,9 @@ struct mp_draw_sub_cache; struct mp_draw_sub_cache *mp_draw_sub_alloc(void *ta_parent, struct mpv_global *g); +// Only for use in tests. +struct mp_draw_sub_cache *mp_draw_sub_alloc_test(struct mp_image *dst); + // Render the sub-bitmaps in sbs_list to dst. sbs_list must have been rendered // for an OSD resolution equivalent to dst's size (UB if not). // Warning: if dst is a format with alpha, and dst is not set to MP_ALPHA_PREMUL diff --git a/test/chmap.c b/test/chmap.c index 4515a329ee..48af822e72 100644 --- a/test/chmap.c +++ b/test/chmap.c @@ -1,8 +1,11 @@ #include "audio/chmap.h" -#include "audio/chmap_avchannel.h" #include "audio/chmap_sel.h" -#include "common/msg.h" -#include "tests.h" +#include "config.h" +#include "test_utils.h" + +#if HAVE_AV_CHANNEL_LAYOUT +#include "audio/chmap_avchannel.h" +#endif #define LAYOUTS(...) (char*[]){__VA_ARGS__, NULL} @@ -65,13 +68,13 @@ static bool layout_matches(const AVChannelLayout *av_layout, return true; } -static void test_mp_chmap_to_av_channel_layout(const struct test_ctx *ctx) +static void test_mp_chmap_to_av_channel_layout(void) { mp_ch_layout_tuple *mapping_array = NULL; void *iter = NULL; bool anything_failed = false; - MP_VERBOSE(ctx, "Testing mp_chmap -> AVChannelLayout conversions\n"); + printf("Testing mp_chmap -> AVChannelLayout conversions\n"); while ((mapping_array = mp_iterate_builtin_layouts(&iter))) { const char *mapping_name = (*mapping_array)[0]; @@ -93,8 +96,7 @@ static void test_mp_chmap_to_av_channel_layout(const struct test_ctx *ctx) if (!success) anything_failed = true; - MP_MSG(ctx, success ? MSGL_V : MSGL_FATAL, - "%s: %s (%s) -> %s\n", + printf("%s: %s (%s) -> %s\n", success ? "Success" : "Failure", mapping_str, mapping_name, layout_desc); @@ -104,13 +106,13 @@ static void test_mp_chmap_to_av_channel_layout(const struct test_ctx *ctx) assert_false(anything_failed); } -static void test_av_channel_layout_to_mp_chmap(const struct test_ctx *ctx) +static void test_av_channel_layout_to_mp_chmap(void) { const AVChannelLayout *av_layout = NULL; void *iter = NULL; bool anything_failed = false; - MP_VERBOSE(ctx, "Testing AVChannelLayout -> mp_chmap conversions\n"); + printf("Testing AVChannelLayout -> mp_chmap conversions\n"); while ((av_layout = av_channel_layout_standard(&iter))) { struct mp_chmap mp_layout = { 0 }; @@ -123,12 +125,11 @@ static void test_av_channel_layout_to_mp_chmap(const struct test_ctx *ctx) if (!ret) { bool too_many_channels = av_layout->nb_channels > MP_NUM_CHANNELS; - MP_MSG(ctx, too_many_channels ? MSGL_V : MSGL_FATAL, - "Conversion from '%s' to mp_chmap failed (%s)!\n", - layout_desc, - too_many_channels ? - "channel count was over max, ignoring" : - "unexpected, failing"); + printf("Conversion from '%s' to mp_chmap failed (%s)!\n", + layout_desc, + too_many_channels ? + "channel count was over max, ignoring" : + "unexpected, failing"); // we should for now only fail with things such as 22.2 // due to mp_chmap being currently limited to 16 channels @@ -143,8 +144,7 @@ static void test_av_channel_layout_to_mp_chmap(const struct test_ctx *ctx) if (!success) anything_failed = true; - MP_MSG(ctx, success ? MSGL_V : MSGL_FATAL, - "%s: %s -> %s\n", + printf("%s: %s -> %s\n", success ? "Success" : "Failure", layout_desc, mp_chmap_to_str(&mp_layout)); } @@ -154,7 +154,7 @@ static void test_av_channel_layout_to_mp_chmap(const struct test_ctx *ctx) #endif -static void run(struct test_ctx *ctx) +int main(void) { struct mp_chmap a; struct mp_chmap b; @@ -211,12 +211,8 @@ static void run(struct test_ctx *ctx) assert_int_equal(mp_chmap_diffn(&b, &a), 3); #if HAVE_AV_CHANNEL_LAYOUT - test_av_channel_layout_to_mp_chmap(ctx); - test_mp_chmap_to_av_channel_layout(ctx); + test_av_channel_layout_to_mp_chmap(); + test_mp_chmap_to_av_channel_layout(); #endif + return 0; } - -const struct unittest test_chmap = { - .name = "chmap", - .run = run, -}; diff --git a/test/gl_video.c b/test/gl_video.c index af1f082a40..a2bdda43a3 100644 --- a/test/gl_video.c +++ b/test/gl_video.c @@ -1,7 +1,7 @@ -#include "tests.h" -#include "video/out/gpu/video.h" +#include "test_utils.h" +#include "video/out/gpu/utils.h" -static void run(struct test_ctx *ctx) +int main(void) { float x; @@ -21,9 +21,5 @@ static void run(struct test_ctx *ctx) x = gl_video_scale_ambient_lux(16.0, 64.0, 2.40, 1.961, 32.0); float mid_gamma = (2.40 - 1.961) / 2 + 1.961; assert_float_equal(x, mid_gamma, FLT_EPSILON); + return 0; } - -const struct unittest test_gl_video = { - .name = "gl_video", - .run = run, -}; diff --git a/test/img_format.c b/test/img_format.c index 8c4a7d45e5..3cc8ff5fe0 100644 --- a/test/img_format.c +++ b/test/img_format.c @@ -1,55 +1,16 @@ #include #include -#include "tests.h" +#include "img_utils.h" +#include "options/path.h" +#include "test_utils.h" #include "video/fmt-conversion.h" #include "video/img_format.h" #include "video/mp_image.h" #include "video/sws_utils.h" -int imgfmts[IMGFMT_AVPIXFMT_END - IMGFMT_AVPIXFMT_START + 100]; -int num_imgfmts; - static enum AVPixelFormat pixfmt_unsup[100]; static int num_pixfmt_unsup; -static bool imgfmts_initialized; - -static int cmp_imgfmt_name(const void *a, const void *b) -{ - char *name_a = mp_imgfmt_to_name(*(int *)a); - char *name_b = mp_imgfmt_to_name(*(int *)b); - - return strcmp(name_a, name_b); -} - -void init_imgfmts_list(void) -{ - if (imgfmts_initialized) - return; - - const AVPixFmtDescriptor *avd = av_pix_fmt_desc_next(NULL); - for (; avd; avd = av_pix_fmt_desc_next(avd)) { - enum AVPixelFormat fmt = av_pix_fmt_desc_get_id(avd); - int mpfmt = pixfmt2imgfmt(fmt); - if (!mpfmt) { - assert(num_pixfmt_unsup < MP_ARRAY_SIZE(pixfmt_unsup)); - pixfmt_unsup[num_pixfmt_unsup++] = fmt; - } - } - - for (int fmt = IMGFMT_START; fmt <= IMGFMT_END; fmt++) { - struct mp_imgfmt_desc d = mp_imgfmt_get_desc(fmt); - enum AVPixelFormat pixfmt = imgfmt2pixfmt(fmt); - if (d.id || pixfmt != AV_PIX_FMT_NONE) { - assert(num_imgfmts < MP_ARRAY_SIZE(imgfmts)); // enlarge that array - imgfmts[num_imgfmts++] = fmt; - } - } - - qsort(imgfmts, num_imgfmts, sizeof(imgfmts[0]), cmp_imgfmt_name); - - imgfmts_initialized = true; -} static const char *comp_type(enum mp_component_type type) { @@ -60,11 +21,13 @@ static const char *comp_type(enum mp_component_type type) } } -static void run(struct test_ctx *ctx) +int main(int argc, char *argv[]) { init_imgfmts_list(); + const char *refdir = argv[1]; + const char *outdir = argv[2]; - FILE *f = test_open_out(ctx, "img_formats.txt"); + FILE *f = test_open_out(outdir, "img_formats.txt"); for (int z = 0; z < num_imgfmts; z++) { int mpfmt = imgfmts[z]; @@ -248,11 +211,7 @@ static void run(struct test_ctx *ctx) fclose(f); - assert_text_files_equal(ctx, "img_formats.txt", "img_formats.txt", + assert_text_files_equal(refdir, outdir, "img_formats.txt", "This can fail if FFmpeg adds new formats or flags."); + return 0; } - -const struct unittest test_img_format = { - .name = "img_format", - .run = run, -}; diff --git a/test/img_utils.c b/test/img_utils.c new file mode 100644 index 0000000000..71764f304f --- /dev/null +++ b/test/img_utils.c @@ -0,0 +1,63 @@ +/* + * This file is part of mpv. + * + * mpv is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * mpv is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with mpv. If not, see . + */ + +#include +#include +#include + +#include "common/common.h" +#include "img_utils.h" +#include "video/img_format.h" +#include "video/fmt-conversion.h" + +int imgfmts[IMGFMT_AVPIXFMT_END - IMGFMT_AVPIXFMT_START + 100]; +int num_imgfmts; + +static enum AVPixelFormat pixfmt_unsup[100]; +static int num_pixfmt_unsup; + +static int cmp_imgfmt_name(const void *a, const void *b) +{ + char *name_a = mp_imgfmt_to_name(*(int *)a); + char *name_b = mp_imgfmt_to_name(*(int *)b); + + return strcmp(name_a, name_b); +} + +void init_imgfmts_list(void) +{ + const AVPixFmtDescriptor *avd = av_pix_fmt_desc_next(NULL); + for (; avd; avd = av_pix_fmt_desc_next(avd)) { + enum AVPixelFormat fmt = av_pix_fmt_desc_get_id(avd); + int mpfmt = pixfmt2imgfmt(fmt); + if (!mpfmt) { + assert(num_pixfmt_unsup < MP_ARRAY_SIZE(pixfmt_unsup)); + pixfmt_unsup[num_pixfmt_unsup++] = fmt; + } + } + + for (int fmt = IMGFMT_START; fmt <= IMGFMT_END; fmt++) { + struct mp_imgfmt_desc d = mp_imgfmt_get_desc(fmt); + enum AVPixelFormat pixfmt = imgfmt2pixfmt(fmt); + if (d.id || pixfmt != AV_PIX_FMT_NONE) { + assert(num_imgfmts < MP_ARRAY_SIZE(imgfmts)); // enlarge that array + imgfmts[num_imgfmts++] = fmt; + } + } + + qsort(imgfmts, num_imgfmts, sizeof(imgfmts[0]), cmp_imgfmt_name); +} diff --git a/test/img_utils.h b/test/img_utils.h new file mode 100644 index 0000000000..2c21bcd954 --- /dev/null +++ b/test/img_utils.h @@ -0,0 +1,24 @@ +/* + * This file is part of mpv. + * + * mpv is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * mpv is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with mpv. If not, see . + */ + +#pragma once + +// Sorted list of valid imgfmts. Call init_imgfmts_list() before use. +extern int imgfmts[]; +extern int num_imgfmts; + +void init_imgfmts_list(void); diff --git a/test/input-gamepad.conf b/test/input-gamepad.conf deleted file mode 100644 index ad79fb9973..0000000000 --- a/test/input-gamepad.conf +++ /dev/null @@ -1,4 +0,0 @@ -GAMEPAD_RIGHT_STICK_LEFT seek -10 -GAMEPAD_RIGHT_STICK_RIGHT seek 10 -GAMEPAD_LEFT_TRIGGER seek -1 -GAMEPAD_RIGHT_TRIGGER seek 1 diff --git a/test/json.c b/test/json.c index e95f88c972..fb6633accf 100644 --- a/test/json.c +++ b/test/json.c @@ -1,7 +1,6 @@ -#include "common/common.h" #include "misc/json.h" #include "misc/node.h" -#include "tests.h" +#include "test_utils.h" struct entry { const char *src; @@ -66,7 +65,7 @@ static const struct entry entries[] = { #define MAX_DEPTH 10 -static void run(struct test_ctx *ctx) +int main(void) { for (int n = 0; n < MP_ARRAY_SIZE(entries); n++) { const struct entry *e = &entries[n]; @@ -86,9 +85,5 @@ static void run(struct test_ctx *ctx) assert_true(equal_mpv_node(&e->out_data, &res)); talloc_free(tmp); } + return 0; } - -const struct unittest test_json = { - .name = "json", - .run = run, -}; diff --git a/libmpv/test.c b/test/libmpv_test.c similarity index 100% rename from libmpv/test.c rename to test/libmpv_test.c diff --git a/test/linked_list.c b/test/linked_list.c index c9fbf9639e..691de3534b 100644 --- a/test/linked_list.c +++ b/test/linked_list.c @@ -1,6 +1,6 @@ #include "common/common.h" #include "misc/linked_list.h" -#include "tests.h" +#include "test_utils.h" struct list_item { int v; @@ -55,7 +55,7 @@ static bool do_check_list(struct the_list *lst, int *c, int num_c) return true; } -static void run(struct test_ctx *ctx) +int main(void) { struct the_list lst = {0}; struct list_item e1 = {1}; @@ -156,9 +156,5 @@ static void run(struct test_ctx *ctx) LL_INSERT_AFTER(list_node, &lst, STUPID_SHIT(&e1), &e6); check_list(3, 4, 5, 2, 1, 6); + return 0; } - -const struct unittest test_linked_list = { - .name = "linked_list", - .run = run, -}; diff --git a/test/meson.build b/test/meson.build new file mode 100644 index 0000000000..61cd514c89 --- /dev/null +++ b/test/meson.build @@ -0,0 +1,135 @@ +# So we don't have to reorganize the entire directory tree. +incdir = include_directories('../') +outdir = join_paths(build_root, 'test', 'out') +refdir = join_paths(source_root, 'test', 'ref') + +# Convenient testing libraries. An adhoc collection of +# mpv objects that test_utils.c needs. Paths and subprocesses +# are required in order to run a diff command when comparing +# different files. Stuff will probably break if core things are +# carelessly moved around. +test_utils_args = [] +test_utils_files = [ + 'audio/chmap.c', + 'audio/format.c', + 'common/common.c', + 'misc/bstr.c', + 'misc/dispatch.c', + 'misc/json.c', + 'misc/node.c', + 'misc/random.c', + 'misc/thread_tools.c', + 'options/m_config_core.c', + 'options/m_config_frontend.c', + 'options/m_option.c', + 'options/path.c', + 'osdep/io.c', + 'osdep/subprocess.c', + path_source, + subprocess_source, + 'ta/ta.c', + 'ta/ta_talloc.c', + 'ta/ta_utils.c' +] +# The zimg code requires using threads. On windows, threads +# also requires timer code so this is added. +if features['win32-internal-pthreads'] + test_utils_args += '-DWIN32_TESTS' + test_utils_files += ['osdep/timer.c', + 'osdep/timer-win2.c', + 'osdep/win32/pthread.c', + 'osdep/windows_utils.c'] +endif + +test_utils_deps = [libavutil, libm, pthreads] +if features['win32-desktop'] + test_utils_deps += cc.find_library('winmm') +endif +test_utils_objects = libmpv.extract_objects(test_utils_files) +test_utils = static_library('test-utils', 'test_utils.c', include_directories: incdir, + c_args: test_utils_args, objects: test_utils_objects, + dependencies: test_utils_deps) + +# For getting imgfmts and stuff. +img_utils_files = [ + 'misc/thread_pool.c', + 'osdep/threads.c', + 'video/csputils.c', + 'video/fmt-conversion.c', + 'video/img_format.c', + 'video/mp_image.c', + 'video/sws_utils.c' +] +if features['zimg'] + img_utils_files += ['video/repack.c', 'video/zimg.c'] +endif + +img_utils_objects = libmpv.extract_objects(img_utils_files) +img_utils = static_library('img-utils', 'img_utils.c', include_directories: incdir, + dependencies: [libavcodec], objects: img_utils_objects) + +# The actual tests. +chmap_files = [ + 'audio/chmap_sel.c' +] +if features['av-channel-layout'] + chmap_files += 'audio/chmap_avchannel.c' +endif +chmap_objects = libmpv.extract_objects(chmap_files) +chmap = executable('chmap', 'chmap.c', include_directories: incdir, + objects: chmap_objects, link_with: test_utils) +test('chmap', chmap) + +gl_video_objects = libmpv.extract_objects('video/out/gpu/ra.c', + 'video/out/gpu/utils.c') +gl_video = executable('gl-video', 'gl_video.c', objects: gl_video_objects, + include_directories: incdir, link_with: [img_utils, test_utils]) +test('gl-video', gl_video) + +json = executable('json', 'json.c', include_directories: incdir, link_with: test_utils) +test('json', json) + +linked_list = executable('linked-list', files('linked_list.c'), include_directories: incdir) +test('linked-list', linked_list) + +paths_objects = libmpv.extract_objects('options/path.c', path_source) +paths = executable('paths', 'paths.c', include_directories: incdir, + objects: paths_objects, link_with: test_utils) +test('paths', paths) + +if get_option('libmpv') + libmpv_test = executable('libmpv-test', 'libmpv_test.c', + include_directories: incdir, link_with: libmpv) + test('libmpv', libmpv_test) +endif + +# Minimum required libavutil version that works with these tests. +# Will need to be manually updated when ffmpeg adds/removes more formats in the future. +if libavutil.version().version_compare('>= 57.10.101') + +# The CI can randomly fail if libavutil isn't explictly linked again here. + img_format = executable('img-format', 'img_format.c', include_directories: incdir, + dependencies: libavutil, link_with: [img_utils, test_utils]) + test('img-format', img_format, args: [refdir, outdir], suite: 'ffmpeg') + + + scale_sws_objects = libmpv.extract_objects('video/image_writer.c', + 'video/repack.c') + scale_sws = executable('scale-sws', ['scale_sws.c', 'scale_test.c'], include_directories: incdir, + objects: scale_sws_objects, dependencies: [libswscale, jpeg, zimg], + link_with: [img_utils, test_utils]) + test('scale-sws', scale_sws, args: [refdir, outdir], suite: 'ffmpeg') + + if features['zimg'] + repack_objects = libmpv.extract_objects('sub/draw_bmp.c') + repack = executable('repack', 'repack.c', include_directories: incdir, objects: repack_objects, + dependencies: [libswscale, zimg], link_with: [img_utils, test_utils]) + test('repack', repack, args: [refdir, outdir], suite: 'ffmpeg') + + scale_zimg_objects = libmpv.extract_objects('video/image_writer.c') + scale_zimg = executable('scale-zimg', ['scale_test.c', 'scale_zimg.c'], include_directories: incdir, + objects: scale_zimg_objects, dependencies:[libswscale, jpeg, zimg], + link_with: [img_utils, test_utils]) + test('scale-zimg', scale_zimg, args: [refdir, outdir], suite: 'ffmpeg') + endif +endif diff --git a/test/paths.c b/test/paths.c index 66d4ee2e2d..aa610db437 100644 --- a/test/paths.c +++ b/test/paths.c @@ -1,7 +1,8 @@ #include "common/common.h" +#include "common/msg.h" #include "config.h" #include "options/path.h" -#include "tests.h" +#include "test_utils.h" static void test_join(char *file, int line, char *a, char *b, char *c) { @@ -29,7 +30,7 @@ static void test_abs(char *file, int line, bool abs, char *a) #define TEST_ABS(abs, a) \ test_abs(__FILE__, __LINE__, abs, a) -static void run(struct test_ctx *ctx) +int main(void) { TEST_ABS(true, "/ab"); TEST_ABS(false, "ab"); @@ -60,9 +61,5 @@ static void run(struct test_ctx *ctx) TEST_JOIN("c:a", "b", "c:a/b"); TEST_JOIN("c:", "b", "c:b"); #endif + return 0; } - -const struct unittest test_paths = { - .name = "paths", - .run = run, -}; diff --git a/test/repack.c b/test/repack.c index 29eadd3a50..a37559b705 100644 --- a/test/repack.c +++ b/test/repack.c @@ -3,10 +3,13 @@ #include #include "common/common.h" +#include "common/global.h" +#include "img_utils.h" #include "sub/draw_bmp.h" #include "sub/osd.h" -#include "tests.h" +#include "test_utils.h" #include "video/fmt-conversion.h" +#include "video/mp_image.h" #include "video/img_format.h" #include "video/repack.h" #include "video/sws_utils.h" @@ -185,8 +188,7 @@ static bool is_true_planar(int imgfmt) return true; } -static int try_repack(struct test_ctx *ctx, FILE *f, int imgfmt, int flags, - int not_if_fmt) +static int try_repack(FILE *f, int imgfmt, int flags, int not_if_fmt) { char *head = mp_tprintf(80, "%-15s =>", mp_imgfmt_to_name(imgfmt)); struct mp_repack *un = mp_repack_create_planar(imgfmt, false, flags); @@ -324,7 +326,7 @@ static int try_repack(struct test_ctx *ctx, FILE *f, int imgfmt, int flags, return b; } -static void check_float_repack(struct test_ctx *ctx, int imgfmt, enum mp_csp csp, +static void check_float_repack(int imgfmt, enum mp_csp csp, enum mp_csp_levels levels) { imgfmt = UNFUCK(imgfmt); @@ -339,10 +341,8 @@ static void check_float_repack(struct test_ctx *ctx, int imgfmt, enum mp_csp csp int w = 1 << (bpp * 8); if (w > ZIMG_IMAGE_DIMENSION_MAX) { - MP_WARN(ctx, - "Image dimension (%d) exceeded maximum allowed by zimg (%zu)." - " Skipping test...\n", - w, ZIMG_IMAGE_DIMENSION_MAX); + printf("Image dimension (%d) exceeded maximum allowed by zimg (%zu)." + " Skipping test...\n", w, ZIMG_IMAGE_DIMENSION_MAX); return; } @@ -433,7 +433,7 @@ static void check_float_repack(struct test_ctx *ctx, int imgfmt, enum mp_csp csp talloc_free(from_f); } -static bool try_draw_bmp(struct mpv_global *g, FILE *f, int imgfmt) +static bool try_draw_bmp(FILE *f, int imgfmt) { bool ok = false; @@ -465,7 +465,7 @@ static bool try_draw_bmp(struct mpv_global *g, FILE *f, int imgfmt) .num_items = 1, }; - struct mp_draw_sub_cache *c = mp_draw_sub_alloc(NULL, g); + struct mp_draw_sub_cache *c = mp_draw_sub_alloc_test(dst); if (mp_draw_sub_bitmaps(c, dst, &sbs_list)) { char *info = mp_draw_sub_get_dbg_info(c); fprintf(f, "%s\n", info); @@ -482,53 +482,51 @@ done: return ok; } -static void run(struct test_ctx *ctx) +int main(int argc, char *argv[]) { - FILE *f = test_open_out(ctx, "repack.txt"); + const char *refdir = argv[1]; + const char *outdir = argv[2]; + FILE *f = test_open_out(outdir, "repack.txt"); init_imgfmts_list(); for (int n = 0; n < num_imgfmts; n++) { int imgfmt = imgfmts[n]; - int other = try_repack(ctx, f, imgfmt, 0, 0); - try_repack(ctx, f, imgfmt, REPACK_CREATE_ROUND_DOWN, other); - try_repack(ctx, f, imgfmt, REPACK_CREATE_EXPAND_8BIT, other); - try_repack(ctx, f, imgfmt, REPACK_CREATE_PLANAR_F32, other); + int other = try_repack(f, imgfmt, 0, 0); + try_repack(f, imgfmt, REPACK_CREATE_ROUND_DOWN, other); + try_repack(f, imgfmt, REPACK_CREATE_EXPAND_8BIT, other); + try_repack(f, imgfmt, REPACK_CREATE_PLANAR_F32, other); } fclose(f); - assert_text_files_equal(ctx, "repack.txt", "repack.txt", - "This can fail if FFmpeg/libswscale adds or removes pixfmts."); + assert_text_files_equal(refdir, outdir, "repack.txt", + "This can fail if FFmpeg/libswscale adds or removes pixfmts."); - check_float_repack(ctx, -AV_PIX_FMT_GBRAP, MP_CSP_RGB, MP_CSP_LEVELS_PC); - check_float_repack(ctx, -AV_PIX_FMT_GBRAP10, MP_CSP_RGB, MP_CSP_LEVELS_PC); - check_float_repack(ctx, -AV_PIX_FMT_GBRAP16, MP_CSP_RGB, MP_CSP_LEVELS_PC); - check_float_repack(ctx, -AV_PIX_FMT_YUVA444P, MP_CSP_BT_709, MP_CSP_LEVELS_PC); - check_float_repack(ctx, -AV_PIX_FMT_YUVA444P, MP_CSP_BT_709, MP_CSP_LEVELS_TV); - check_float_repack(ctx, -AV_PIX_FMT_YUVA444P10, MP_CSP_BT_709, MP_CSP_LEVELS_PC); - check_float_repack(ctx, -AV_PIX_FMT_YUVA444P10, MP_CSP_BT_709, MP_CSP_LEVELS_TV); - check_float_repack(ctx, -AV_PIX_FMT_YUVA444P16, MP_CSP_BT_709, MP_CSP_LEVELS_PC); - check_float_repack(ctx, -AV_PIX_FMT_YUVA444P16, MP_CSP_BT_709, MP_CSP_LEVELS_TV); + check_float_repack(-AV_PIX_FMT_GBRAP, MP_CSP_RGB, MP_CSP_LEVELS_PC); + check_float_repack(-AV_PIX_FMT_GBRAP10, MP_CSP_RGB, MP_CSP_LEVELS_PC); + check_float_repack(-AV_PIX_FMT_GBRAP16, MP_CSP_RGB, MP_CSP_LEVELS_PC); + check_float_repack(-AV_PIX_FMT_YUVA444P, MP_CSP_BT_709, MP_CSP_LEVELS_PC); + check_float_repack(-AV_PIX_FMT_YUVA444P, MP_CSP_BT_709, MP_CSP_LEVELS_TV); + check_float_repack(-AV_PIX_FMT_YUVA444P10, MP_CSP_BT_709, MP_CSP_LEVELS_PC); + check_float_repack(-AV_PIX_FMT_YUVA444P10, MP_CSP_BT_709, MP_CSP_LEVELS_TV); + check_float_repack(-AV_PIX_FMT_YUVA444P16, MP_CSP_BT_709, MP_CSP_LEVELS_PC); + check_float_repack(-AV_PIX_FMT_YUVA444P16, MP_CSP_BT_709, MP_CSP_LEVELS_TV); // Determine the list of possible draw_bmp input formats. Do this here // because it mostly depends on repack and imgformat stuff. - f = test_open_out(ctx, "draw_bmp.txt"); + f = test_open_out(outdir, "draw_bmp.txt"); for (int n = 0; n < num_imgfmts; n++) { int imgfmt = imgfmts[n]; fprintf(f, "%-12s= ", mp_imgfmt_to_name(imgfmt)); - try_draw_bmp(ctx->global, f, imgfmt); + try_draw_bmp(f, imgfmt); } fclose(f); - assert_text_files_equal(ctx, "draw_bmp.txt", "draw_bmp.txt", - "This can fail if FFmpeg/libswscale adds or removes pixfmts."); + assert_text_files_equal(refdir, outdir, "draw_bmp.txt", + "This can fail if FFmpeg/libswscale adds or removes pixfmts."); + return 0; } - -const struct unittest test_repack = { - .name = "repack", - .run = run, -}; diff --git a/test/scale_sws.c b/test/scale_sws.c index bfc3bb93ae..c9f5e3176b 100644 --- a/test/scale_sws.c +++ b/test/scale_sws.c @@ -23,7 +23,7 @@ static const struct scale_test_fns fns = { .supports_fmts = supports_fmts, }; -static void run(struct test_ctx *ctx) +int main(int argc, char *argv[]) { struct mp_sws_context *sws = mp_sws_alloc(NULL); @@ -31,15 +31,12 @@ static void run(struct test_ctx *ctx) stest->fns = &fns; stest->fns_priv = sws; stest->test_name = "repack_sws"; - stest->ctx = ctx; + stest->refdir = talloc_strdup(stest, argv[1]); + stest->outdir = talloc_strdup(stest, argv[2]); repack_test_run(stest); talloc_free(stest); talloc_free(sws); + return 0; } - -const struct unittest test_repack_sws = { - .name = "repack_sws", - .run = run, -}; diff --git a/test/scale_test.c b/test/scale_test.c index ccd83c7658..f919dca1e2 100644 --- a/test/scale_test.c +++ b/test/scale_test.c @@ -55,13 +55,13 @@ static struct mp_image *gen_repack_test_img(int w, int h, int bytes, bool rgb, static void dump_image(struct scale_test *stest, const char *name, struct mp_image *img) { - char *path = mp_tprintf(4096, "%s/%s.png", stest->ctx->out_path, name); + char *path = mp_tprintf(4096, "%s/%s.png", stest->outdir, name); struct image_writer_opts opts = image_writer_opts_defaults; opts.format = AV_CODEC_ID_PNG; - if (!write_image(img, &opts, path, stest->ctx->global, stest->ctx->log)) { - MP_FATAL(stest->ctx, "Failed to write '%s'.\n", path); + if (!write_image(img, &opts, path, NULL, NULL)) { + printf("Failed to write '%s'.\n", path); abort(); } } @@ -102,7 +102,7 @@ static void assert_imgs_equal(struct scale_test *stest, FILE *f, void repack_test_run(struct scale_test *stest) { char *logname = mp_tprintf(80, "%s.log", stest->test_name); - FILE *f = test_open_out(stest->ctx, logname); + FILE *f = test_open_out(stest->outdir, logname); if (!stest->sws) { init_imgfmts_list(); @@ -187,6 +187,6 @@ void repack_test_run(struct scale_test *stest) fclose(f); - assert_text_files_equal(stest->ctx, logname, logname, + assert_text_files_equal(stest->refdir, stest->outdir, logname, "This can fail if FFmpeg adds or removes pixfmts."); } diff --git a/test/scale_test.h b/test/scale_test.h index f49b456ecb..5c83786ac2 100644 --- a/test/scale_test.h +++ b/test/scale_test.h @@ -1,6 +1,7 @@ #pragma once -#include "tests.h" +#include "img_utils.h" +#include "test_utils.h" #include "video/mp_image.h" struct scale_test_fns { @@ -13,7 +14,8 @@ struct scale_test { const struct scale_test_fns *fns; void *fns_priv; const char *test_name; - struct test_ctx *ctx; + const char *refdir; + const char *outdir; // Private. struct mp_image *img_repack_rgb8; diff --git a/test/scale_zimg.c b/test/scale_zimg.c index f5957067c2..57894bea67 100644 --- a/test/scale_zimg.c +++ b/test/scale_zimg.c @@ -21,7 +21,7 @@ static const struct scale_test_fns fns = { .supports_fmts = supports_fmts, }; -static void run(struct test_ctx *ctx) +int main(int argc, char *argv[]) { struct mp_zimg_context *zimg = mp_zimg_alloc(); zimg->opts.threads = 1; @@ -30,12 +30,12 @@ static void run(struct test_ctx *ctx) stest->fns = &fns; stest->fns_priv = zimg; stest->test_name = "repack_zimg"; - stest->ctx = ctx; + stest->refdir = talloc_strdup(stest, argv[1]); + stest->outdir = talloc_strdup(stest, argv[2]); repack_test_run(stest); - FILE *f = test_open_out(ctx, "zimg_formats.txt"); - init_imgfmts_list(); + FILE *f = test_open_out(stest->outdir, "zimg_formats.txt"); for (int n = 0; n < num_imgfmts; n++) { int imgfmt = imgfmts[n]; fprintf(f, "%15s%7s%7s%7s%8s |\n", mp_imgfmt_to_name(imgfmt), @@ -47,14 +47,10 @@ static void run(struct test_ctx *ctx) } fclose(f); - assert_text_files_equal(stest->ctx, "zimg_formats.txt", "zimg_formats.txt", + assert_text_files_equal(stest->refdir, stest->outdir, "zimg_formats.txt", "This can fail if FFmpeg/libswscale adds or removes pixfmts."); talloc_free(stest); talloc_free(zimg); + return 0; } - -const struct unittest test_repack_zimg = { - .name = "repack_zimg", - .run = run, -}; diff --git a/test/subtimes.js b/test/subtimes.js deleted file mode 100644 index be6940ad3b..0000000000 --- a/test/subtimes.js +++ /dev/null @@ -1,15 +0,0 @@ -function subtimes() { - mp.msg.info("sub-start: " + mp.get_property_number("sub-start")); - mp.msg.info("sub-end: " + mp.get_property_number("sub-end")); - mp.msg.info("sub-text: " + mp.get_property_native("sub-text")); -} - -mp.add_key_binding("t", "subtimes", subtimes); - -function secondary_subtimes() { - mp.msg.info("secondary-sub-start: " + mp.get_property_number("secondary-sub-start")); - mp.msg.info("secondary-sub-end: " + mp.get_property_number("secondary-sub-end")); - mp.msg.info("secondary-sub-text: " + mp.get_property_native("secondary-sub-text")); -} - -mp.add_key_binding("T", "secondary_subtimes", secondary_subtimes); \ No newline at end of file diff --git a/test/test_utils.c b/test/test_utils.c new file mode 100644 index 0000000000..a1ecfacfd7 --- /dev/null +++ b/test/test_utils.c @@ -0,0 +1,114 @@ +#include + +#include "options/m_option.h" +#include "options/path.h" +#include "osdep/subprocess.h" +#include "test_utils.h" + +#ifdef NDEBUG +static_assert(false, "don't define NDEBUG for tests"); +#endif + +void assert_int_equal_impl(const char *file, int line, int64_t a, int64_t b) +{ + if (a != b) { + printf("%s:%d: %"PRId64" != %"PRId64"\n", file, line, a, b); + abort(); + } +} + +void assert_string_equal_impl(const char *file, int line, + const char *a, const char *b) +{ + if (strcmp(a, b) != 0) { + printf("%s:%d: '%s' != '%s'\n", file, line, a, b); + abort(); + } +} + +void assert_float_equal_impl(const char *file, int line, + double a, double b, double tolerance) +{ + if (fabs(a - b) > tolerance) { + printf("%s:%d: %f != %f\n", file, line, a, b); + abort(); + } +} + +FILE *test_open_out(const char *outdir, const char *name) +{ + mp_mkdirp(outdir); + assert(mp_path_isdir(outdir)); + char *path = mp_tprintf(4096, "%s/%s", outdir, name); + FILE *f = fopen(path, "wb"); + if (!f) { + printf("Could not open '%s' for writing: %s\n", path, + mp_strerror(errno)); + abort(); + } + return f; +} + +void assert_text_files_equal_impl(const char *file, int line, + const char *refdir, const char *outdir, + const char *ref, const char *new, + const char *err) +{ + char *path_ref = mp_tprintf(4096, "%s/%s", refdir, ref); + char *path_new = mp_tprintf(4096, "%s/%s", outdir, new); + + struct mp_subprocess_opts opts = { + .exe = "diff", + .args = (char*[]){"diff", "-u", "--", path_ref, path_new, 0}, + .fds = { {0, .src_fd = 0}, {1, .src_fd = 1}, {2, .src_fd = 2} }, + .num_fds = 3, + }; + + struct mp_subprocess_result res; + mp_subprocess2(&opts, &res); + + if (res.error || res.exit_status) { + if (res.error) + printf("Note: %s\n", mp_subprocess_err_str(res.error)); + printf("Giving up.\n"); + abort(); + } +} + +static void hexdump(const uint8_t *d, size_t size) +{ + printf("|"); + while (size--) { + printf(" %02x", d[0]); + d++; + } + printf(" |\n"); +} + +void assert_memcmp_impl(const char *file, int line, + const void *a, const void *b, size_t size) +{ + if (memcmp(a, b, size) == 0) + return; + + printf("%s:%d: mismatching data:\n", file, line); + hexdump(a, size); + hexdump(b, size); + abort(); +} + +/* Stubs: see test_utils.h */ +struct mp_log *mp_null_log; +const char *mp_help_text; + +void mp_msg(struct mp_log *log, int lev, const char *format, ...) {}; +int mp_msg_find_level(const char *s) {return 0;}; +int mp_msg_level(struct mp_log *log) {return 0;}; +void mp_write_console_ansi(void) {}; + +#ifndef WIN32_TESTS +void mp_add_timeout(void) {}; +void mp_rel_time_to_timespec(void) {}; +void mp_time_us(void) {}; +void mp_time_us_to_timespec(void) {}; +#endif diff --git a/test/test_utils.h b/test/test_utils.h new file mode 100644 index 0000000000..7dcb32cc3b --- /dev/null +++ b/test/test_utils.h @@ -0,0 +1,64 @@ +#pragma once + +#include +#include +#include + +#include "common/common.h" + +#define assert_true(x) assert(x) +#define assert_false(x) assert(!(x)) +#define assert_int_equal(a, b) \ + assert_int_equal_impl(__FILE__, __LINE__, (a), (b)) +#define assert_string_equal(a, b) \ + assert_string_equal_impl(__FILE__, __LINE__, (a), (b)) +#define assert_float_equal(a, b, tolerance) \ + assert_float_equal_impl(__FILE__, __LINE__, (a), (b), (tolerance)) + +// Assert that memcmp(a,b,s)==0, or hexdump output on failure. +#define assert_memcmp(a, b, s) \ + assert_memcmp_impl(__FILE__, __LINE__, (a), (b), (s)) + +// Require that the files "ref" and "new" are the same. The paths can be +// relative to ref_path and out_path respectively. If they're not the same, +// the output of "diff" is shown, the err message (if not NULL), and the test +// fails. +#define assert_text_files_equal(refdir, outdir, name, err) \ + assert_text_files_equal_impl(__FILE__, __LINE__, (refdir), (outdir), (name), (name), (err)) + +void assert_int_equal_impl(const char *file, int line, int64_t a, int64_t b); +void assert_string_equal_impl(const char *file, int line, + const char *a, const char *b); +void assert_float_equal_impl(const char *file, int line, + double a, double b, double tolerance); +void assert_text_files_equal_impl(const char *file, int line, + const char *refdir, const char *outdir, + const char *ref, const char *new, + const char *err); +void assert_memcmp_impl(const char *file, int line, + const void *a, const void *b, size_t size); + +// Open a new file in the build dir path. Always succeeds. +FILE *test_open_out(const char *outdir, const char *name); + +/* Stubs */ + +// Files commonly import common/msg.h which requires these to be +// defined. We don't actually need mpv's logging system here so +// just define these as stubs that do nothing. +struct mp_log; +void mp_msg(struct mp_log *log, int lev, const char *format, ...) + PRINTF_ATTRIBUTE(3, 4); +int mp_msg_find_level(const char *s); +int mp_msg_level(struct mp_log *log); +void mp_write_console_ansi(void); + +// Windows additionally requires timer related code so it will actually +// import the real versions of these functions and use them. On other +// platforms, these can just be stubs for simplicity. +#ifndef WIN32_TESTS +void mp_add_timeout(void); +void mp_rel_time_to_timespec(void); +void mp_time_us(void); +void mp_time_us_to_timespec(void); +#endif diff --git a/test/tests.c b/test/tests.c deleted file mode 100644 index eb55bb302b..0000000000 --- a/test/tests.c +++ /dev/null @@ -1,159 +0,0 @@ -#include "options/path.h" -#include "osdep/subprocess.h" -#include "player/core.h" -#include "tests.h" - -static const struct unittest *unittests[] = { - &test_chmap, - &test_gl_video, - &test_img_format, - &test_json, - &test_linked_list, - &test_paths, - &test_repack_sws, -#if HAVE_ZIMG - &test_repack, // zimg only due to cross-checking with zimg.c - &test_repack_zimg, -#endif - NULL -}; - -bool run_tests(struct MPContext *mpctx) -{ - char *sel = mpctx->opts->test_mode; - assert(sel && sel[0]); - - if (strcmp(sel, "help") == 0) { - MP_INFO(mpctx, "Available tests:\n"); - for (int n = 0; unittests[n]; n++) - MP_INFO(mpctx, " %s\n", unittests[n]->name); - MP_INFO(mpctx, " all-simple\n"); - return true; - } - - struct test_ctx ctx = { - .global = mpctx->global, - .log = mpctx->log, - .ref_path = "test/ref", - .out_path = "test/out", - }; - - if (!mp_path_isdir(ctx.ref_path)) { - MP_FATAL(mpctx, "Must be run from git repo root dir.\n"); - abort(); - } - mp_mkdirp(ctx.out_path); - assert(mp_path_isdir(ctx.out_path)); - - int num_run = 0; - - for (int n = 0; unittests[n]; n++) { - const struct unittest *t = unittests[n]; - - // Exactly 1 entrypoint please. - assert(MP_IS_POWER_OF_2( - (t->run ? (1 << 1) : 0))); - - bool run = false; - run |= strcmp(sel, "all-simple") == 0 && !t->is_complex; - run |= strcmp(sel, t->name) == 0; - - if (run) { - if (t->run) - t->run(&ctx); - num_run++; - } - } - - MP_INFO(mpctx, "%d unittests successfully run.\n", num_run); - - return num_run > 0; // still error if none -} - -#ifdef NDEBUG -static_assert(false, "don't define NDEBUG for tests"); -#endif - -void assert_int_equal_impl(const char *file, int line, int64_t a, int64_t b) -{ - if (a != b) { - printf("%s:%d: %"PRId64" != %"PRId64"\n", file, line, a, b); - abort(); - } -} - -void assert_string_equal_impl(const char *file, int line, - const char *a, const char *b) -{ - if (strcmp(a, b) != 0) { - printf("%s:%d: '%s' != '%s'\n", file, line, a, b); - abort(); - } -} - -void assert_float_equal_impl(const char *file, int line, - double a, double b, double tolerance) -{ - if (fabs(a - b) > tolerance) { - printf("%s:%d: %f != %f\n", file, line, a, b); - abort(); - } -} - -FILE *test_open_out(struct test_ctx *ctx, const char *name) -{ - char *path = mp_tprintf(4096, "%s/%s", ctx->out_path, name); - FILE *f = fopen(path, "wb"); - if (!f) { - MP_FATAL(ctx, "Could not open '%s' for writing.\n", path); - abort(); - } - return f; -} - -void assert_text_files_equal_impl(const char *file, int line, - struct test_ctx *ctx, const char *ref, - const char *new, const char *err) -{ - char *path_ref = mp_tprintf(4096, "%s/%s", ctx->ref_path, ref); - char *path_new = mp_tprintf(4096, "%s/%s", ctx->out_path, new); - - struct mp_subprocess_opts opts = { - .exe = "diff", - .args = (char*[]){"diff", "-u", "--", path_ref, path_new, 0}, - .fds = { {0, .src_fd = 0}, {1, .src_fd = 1}, {2, .src_fd = 2} }, - .num_fds = 3, - }; - - struct mp_subprocess_result res; - mp_subprocess2(&opts, &res); - - if (res.error || res.exit_status) { - if (res.error) - MP_WARN(ctx, "Note: %s\n", mp_subprocess_err_str(res.error)); - MP_FATAL(ctx, "Giving up.\n"); - abort(); - } -} - -static void hexdump(const uint8_t *d, size_t size) -{ - printf("|"); - while (size--) { - printf(" %02x", d[0]); - d++; - } - printf(" |\n"); -} - -void assert_memcmp_impl(const char *file, int line, - const void *a, const void *b, size_t size) -{ - if (memcmp(a, b, size) == 0) - return; - - printf("%s:%d: mismatching data:\n", file, line); - hexdump(a, size); - hexdump(b, size); - abort(); -} diff --git a/test/tests.h b/test/tests.h deleted file mode 100644 index 8b2eb98174..0000000000 --- a/test/tests.h +++ /dev/null @@ -1,87 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "common/common.h" - -struct MPContext; - -bool run_tests(struct MPContext *mpctx); - -struct test_ctx { - struct mpv_global *global; - struct mp_log *log; - - // Path for ref files, without trailing "/". - const char *ref_path; - - // Path for result files, without trailing "/". - const char *out_path; -}; - -struct unittest { - // This is used to select the test on command line with --unittest=. - const char *name; - - // Cannot run without additional arguments supplied. - bool is_complex; - - // Entrypoints. There are various for various purposes. Only 1 of them must - // be set. - - // Entrypoint for tests which have a simple dependency on the mpv core. The - // core is sufficiently initialized at this point. - void (*run)(struct test_ctx *ctx); -}; - -extern const struct unittest test_chmap; -extern const struct unittest test_gl_video; -extern const struct unittest test_img_format; -extern const struct unittest test_json; -extern const struct unittest test_linked_list; -extern const struct unittest test_repack_sws; -extern const struct unittest test_repack_zimg; -extern const struct unittest test_repack; -extern const struct unittest test_paths; - -#define assert_true(x) assert(x) -#define assert_false(x) assert(!(x)) -#define assert_int_equal(a, b) \ - assert_int_equal_impl(__FILE__, __LINE__, (a), (b)) -#define assert_string_equal(a, b) \ - assert_string_equal_impl(__FILE__, __LINE__, (a), (b)) -#define assert_float_equal(a, b, tolerance) \ - assert_float_equal_impl(__FILE__, __LINE__, (a), (b), (tolerance)) - -// Assert that memcmp(a,b,s)==0, or hexdump output on failure. -#define assert_memcmp(a, b, s) \ - assert_memcmp_impl(__FILE__, __LINE__, (a), (b), (s)) - -// Require that the files "ref" and "new" are the same. The paths can be -// relative to ref_path and out_path respectively. If they're not the same, -// the output of "diff" is shown, the err message (if not NULL), and the test -// fails. -#define assert_text_files_equal(ctx, ref, new, err) \ - assert_text_files_equal_impl(__FILE__, __LINE__, (ctx), (ref), (new), (err)) - -void assert_int_equal_impl(const char *file, int line, int64_t a, int64_t b); -void assert_string_equal_impl(const char *file, int line, - const char *a, const char *b); -void assert_float_equal_impl(const char *file, int line, - double a, double b, double tolerance); -void assert_text_files_equal_impl(const char *file, int line, - struct test_ctx *ctx, const char *ref, - const char *new, const char *err); -void assert_memcmp_impl(const char *file, int line, - const void *a, const void *b, size_t size); - -// Open a new file in the out_path. Always succeeds. -FILE *test_open_out(struct test_ctx *ctx, const char *name); - -// Sorted list of valid imgfmts. Call init_imgfmts_list() before use. -extern int imgfmts[]; -extern int num_imgfmts; - -void init_imgfmts_list(void); diff --git a/video/out/gpu/utils.c b/video/out/gpu/utils.c index 2c625dc26a..8a1aacfff5 100644 --- a/video/out/gpu/utils.c +++ b/video/out/gpu/utils.c @@ -39,6 +39,21 @@ void gl_transform_ortho_fbo(struct gl_transform *t, struct ra_fbo fbo) gl_transform_ortho(t, 0, fbo.tex->params.w, 0, fbo.tex->params.h * y_dir); } +float gl_video_scale_ambient_lux(float lmin, float lmax, + float rmin, float rmax, float lux) +{ + assert(lmax > lmin); + + float num = (rmax - rmin) * (log10(lux) - log10(lmin)); + float den = log10(lmax) - log10(lmin); + float result = num / den + rmin; + + // clamp the result + float max = MPMAX(rmax, rmin); + float min = MPMIN(rmax, rmin); + return MPMAX(MPMIN(result, max), min); +} + void ra_buf_pool_uninit(struct ra *ra, struct ra_buf_pool *pool) { for (int i = 0; i < pool->num_buffers; i++) diff --git a/video/out/gpu/utils.h b/video/out/gpu/utils.h index ac0cbf28d7..215873eec8 100644 --- a/video/out/gpu/utils.h +++ b/video/out/gpu/utils.h @@ -65,6 +65,9 @@ void gl_transform_trans(struct gl_transform t, struct gl_transform *x); void gl_transform_ortho_fbo(struct gl_transform *t, struct ra_fbo fbo); +float gl_video_scale_ambient_lux(float lmin, float lmax, + float rmin, float rmax, float lux); + // A pool of buffers, which can grow as needed struct ra_buf_pool { struct ra_buf_params current_params; diff --git a/video/out/gpu/video.c b/video/out/gpu/video.c index df689b53c3..21e004cd43 100644 --- a/video/out/gpu/video.c +++ b/video/out/gpu/video.c @@ -4239,21 +4239,6 @@ static int validate_error_diffusion_opt(struct mp_log *log, const m_option_t *op return r; } -float gl_video_scale_ambient_lux(float lmin, float lmax, - float rmin, float rmax, float lux) -{ - assert(lmax > lmin); - - float num = (rmax - rmin) * (log10(lux) - log10(lmin)); - float den = log10(lmax) - log10(lmin); - float result = num / den + rmin; - - // clamp the result - float max = MPMAX(rmax, rmin); - float min = MPMIN(rmax, rmin); - return MPMAX(MPMIN(result, max), min); -} - void gl_video_set_ambient_lux(struct gl_video *p, int lux) { if (p->opts.gamma_auto) { diff --git a/video/sws_utils.c b/video/sws_utils.c index 0f1708af3f..5e9c35876a 100644 --- a/video/sws_utils.c +++ b/video/sws_utils.c @@ -213,6 +213,9 @@ struct mp_sws_context *mp_sws_alloc(void *talloc_ctx) // if the user changes any options. void mp_sws_enable_cmdline_opts(struct mp_sws_context *ctx, struct mpv_global *g) { + // Should only ever be NULL for tests. + if (!g) + return; if (ctx->opts_cache) return;