/*
 *  $Id: module-utils.c 29477 2026-02-14 13:29:30Z yeti-dn $
 *  Copyright (C) 2026 David Nečas (Yeti).
 *  E-mail: yeti@gwyddion.net.
 *
 *  This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public
 *  License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any
 *  later version.
 *
 *  This program 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 General Public License for more
 *  details.
 *
 *  You should have received a copy of the GNU General Public License along with this program; if not, write to the
 *  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include "tests/testlibgwy.h"

// Most of the testing data were adopted from raw-data.c. See comments there how the weirder numeric formats were
// verified.

// Test the extern versions. Do not let the compiler to inline the code.
#undef gwy_get_gboolean8
#undef gwy_get_gint16_le
#undef gwy_get_gint16_be
#undef gwy_get_guint16_le
#undef gwy_get_guint16_be
#undef gwy_get_gint32_le
#undef gwy_get_gint32_be
#undef gwy_get_guint32_le
#undef gwy_get_guint32_be
#undef gwy_get_gint64_le
#undef gwy_get_gint64_be
#undef gwy_get_guint64_le
#undef gwy_get_guint64_be
#undef gwy_get_gfloat_le
#undef gwy_get_gfloat_be
#undef gwy_get_gdouble_le
#undef gwy_get_gdouble_be
#undef gwy_get_pascal_real_le
#undef gwy_get_pascal_real_be

// There is no way to write INT64_MIN as an integer literal. Negative literals do not really exist. They are constant
// expressions formed by positive literals and unary operator minus – leading to a compiler warning about a too large
// value for a signed integer (or maybe even incorrect code) because the largest negative value is larger than the
// largest positive one. Chicken out and use an predefined macros for all the limit values.

void
test_module_utils_get_gboolean8(void)
{
    enum { ndata = 4 };
    static const guchar data[ndata] = {
        0x01, 0x00, 0x80, 0xff
    };
    static const gboolean expected[ndata] = {
        TRUE, FALSE, TRUE, TRUE
    };

    const guchar *p = data;
    for (guint i = 0; i < ndata; i++) {
        gboolean value = gwy_get_gboolean8(&p);
        if (expected[i])
            g_assert_true(value);
        else
            g_assert_false(value);
    }
}

void
test_module_utils_get_guint16_be(void)
{
    enum { ndata = 5 };
    static const guchar data[ndata*sizeof(guint16)] = {
        0x00, 0x01, 0xff, 0xff, 0x80, 0x00, 0x7f, 0xff, 0x12, 0x34
    };
    static const guint16 expected[ndata] = {
        1, G_MAXUINT16, 32768, 32767, 4660
    };

    const guchar *p = data;
    for (guint i = 0; i < ndata; i++) {
        guint16 value = gwy_get_guint16_be(&p);
        g_assert_cmpuint(value, ==, expected[i]);
    }
}

void
test_module_utils_get_guint16_le(void)
{
    enum { ndata = 5 };
    static const guchar data[ndata*sizeof(guint16)] = {
        0x01, 0x00, 0xff, 0xff, 0x00, 0x80, 0xff, 0x7f, 0x34, 0x12
    };
    static const guint16 expected[ndata] = {
        1, G_MAXUINT16, 32768, 32767, 4660
    };

    const guchar *p = data;
    for (guint i = 0; i < ndata; i++) {
        guint16 value = gwy_get_guint16_le(&p);
        g_assert_cmpuint(value, ==, expected[i]);
    }
}

void
test_module_utils_get_gint16_be(void)
{
    enum { ndata = 5 };
    static const guchar data[ndata*sizeof(gint16)] = {
        0x00, 0x01, 0xff, 0xff, 0x80, 0x00, 0x7f, 0xff, 0x12, 0x34
    };
    static const gint16 expected[ndata] = {
        1, -1, G_MININT16, G_MAXINT16, 4660
    };

    const guchar *p = data;
    for (gint i = 0; i < ndata; i++) {
        gint16 value = gwy_get_gint16_be(&p);
        g_assert_cmpint(value, ==, expected[i]);
    }
}

void
test_module_utils_get_gint16_le(void)
{
    enum { ndata = 5 };
    static const guchar data[ndata*sizeof(gint16)] = {
        0x01, 0x00, 0xff, 0xff, 0x00, 0x80, 0xff, 0x7f, 0x34, 0x12
    };
    static const gint16 expected[ndata] = {
        1, -1, G_MININT16, G_MAXINT16, 4660
    };

    const guchar *p = data;
    for (gint i = 0; i < ndata; i++) {
        gint16 value = gwy_get_gint16_le(&p);
        g_assert_cmpint(value, ==, expected[i]);
    }
}

void
test_module_utils_get_guint32_be(void)
{
    enum { ndata = 5 };
    static const guchar data[ndata*sizeof(guint32)] = {
        0x00, 0x00, 0x00, 0x01,
        0xff, 0xff, 0xff, 0xff,
        0x80, 0x00, 0x00, 0x00,
        0x7f, 0xff, 0xff, 0xff,
        0x12, 0x34, 0x56, 0x78
    };
    static const guint32 expected[ndata] = {
        1, G_MAXUINT32, 2147483648, 2147483647, 305419896
    };

    const guchar *p = data;
    for (guint i = 0; i < ndata; i++) {
        guint32 value = gwy_get_guint32_be(&p);
        g_assert_cmpuint(value, ==, expected[i]);
    }
}

void
test_module_utils_get_guint32_le(void)
{
    enum { ndata = 5 };
    static const guchar data[ndata*sizeof(guint32)] = {
        0x01, 0x00, 0x00, 0x00,
        0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x80,
        0xff, 0xff, 0xff, 0x7f,
        0x78, 0x56, 0x34, 0x12
    };
    static const guint32 expected[ndata] = {
        1, G_MAXUINT32, 2147483648, 2147483647, 305419896
    };

    const guchar *p = data;
    for (guint i = 0; i < ndata; i++) {
        guint32 value = gwy_get_guint32_le(&p);
        g_assert_cmpuint(value, ==, expected[i]);
    }
}

void
test_module_utils_get_gint32_be(void)
{
    enum { ndata = 5 };
    static const guchar data[ndata*sizeof(gint32)] = {
        0x00, 0x00, 0x00, 0x01,
        0xff, 0xff, 0xff, 0xff,
        0x80, 0x00, 0x00, 0x00,
        0x7f, 0xff, 0xff, 0xff,
        0x12, 0x34, 0x56, 0x78
    };
    static const gint32 expected[ndata] = {
        1, -1, G_MININT32, G_MAXINT32, 305419896
    };

    const guchar *p = data;
    for (gint i = 0; i < ndata; i++) {
        gint32 value = gwy_get_gint32_be(&p);
        g_assert_cmpint(value, ==, expected[i]);
    }
}

void
test_module_utils_get_gint32_le(void)
{
    enum { ndata = 5 };
    static const guchar data[ndata*sizeof(gint32)] = {
        0x01, 0x00, 0x00, 0x00,
        0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x80,
        0xff, 0xff, 0xff, 0x7f,
        0x78, 0x56, 0x34, 0x12
    };
    static const gint32 expected[ndata] = {
        1, -1, G_MININT32, G_MAXINT32, 305419896
    };

    const guchar *p = data;
    for (gint i = 0; i < ndata; i++) {
        gint32 value = gwy_get_gint32_le(&p);
        g_assert_cmpint(value, ==, expected[i]);
    }
}

void
test_module_utils_get_guint64_be(void)
{
    enum { ndata = 5 };
    static const guchar data[ndata*sizeof(guint64)] = {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0
    };
    static const guint64 expected[ndata] = {
        G_GUINT64_CONSTANT(1),
        G_MAXUINT64,
        G_GUINT64_CONSTANT(9223372036854775808),
        G_GUINT64_CONSTANT(9223372036854775807),
        G_GUINT64_CONSTANT(1311768467463790320)
    };

    const guchar *p = data;
    for (guint i = 0; i < ndata; i++) {
        guint64 value = gwy_get_guint64_be(&p);
        g_assert_cmpuint(value, ==, expected[i]);
    }
}

void
test_module_utils_get_guint64_le(void)
{
    enum { ndata = 5 };
    static const guchar data[ndata*sizeof(guint64)] = {
        0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
        0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12
    };
    static const guint64 expected[ndata] = {
        G_GUINT64_CONSTANT(1),
        G_MAXUINT64,
        G_GUINT64_CONSTANT(9223372036854775808),
        G_GUINT64_CONSTANT(9223372036854775807),
        G_GUINT64_CONSTANT(1311768467463790320)
    };

    const guchar *p = data;
    for (guint i = 0; i < ndata; i++) {
        guint64 value = gwy_get_guint64_le(&p);
        g_assert_cmpuint(value, ==, expected[i]);
    }
}

void
test_module_utils_get_gint64_be(void)
{
    enum { ndata = 5 };
    static const guchar data[ndata*sizeof(gint64)] = {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0
    };
    static const gint64 expected[ndata] = {
        G_GINT64_CONSTANT(1),
        G_GINT64_CONSTANT(-1),
        G_MININT64,
        G_MAXINT64,
        G_GINT64_CONSTANT(1311768467463790320)
    };

    const guchar *p = data;
    for (gint i = 0; i < ndata; i++) {
        gint64 value = gwy_get_gint64_be(&p);
        g_assert_cmpint(value, ==, expected[i]);
    }
}

void
test_module_utils_get_gint64_le(void)
{
    enum { ndata = 5 };
    static const guchar data[ndata*sizeof(gint64)] = {
        0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
        0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12
    };
    static const gint64 expected[ndata] = {
        G_GINT64_CONSTANT(1),
        G_GINT64_CONSTANT(-1),
        G_MININT64,
        G_MAXINT64,
        G_GINT64_CONSTANT(1311768467463790320)
    };

    const guchar *p = data;
    for (gint i = 0; i < ndata; i++) {
        gint64 value = gwy_get_gint64_le(&p);
        g_assert_cmpint(value, ==, expected[i]);
    }
}

void
test_module_utils_get_gfloat_be(void)
{
    enum { ndata = 8 };
    static const guchar data[ndata*sizeof(gfloat)] = {
        0x00, 0x00, 0x00, 0x00,
        0x3f, 0x80, 0x00, 0x00,
        0xbf, 0x80, 0x00, 0x00,
        0x00, 0x80, 0x00, 0x00,
        0x7f, 0x7f, 0xff, 0xff,
        0x80, 0x80, 0x00, 0x00,
        0xff, 0x7f, 0xff, 0xff,
        0x3d, 0xfc, 0xd6, 0xde,
    };
    static const gfloat expected[ndata] = {
        0.0f, 1.0f, -1.0f, G_MINFLOAT, G_MAXFLOAT, -G_MINFLOAT, -G_MAXFLOAT, 0.1234567f,
    };

    const guchar *p = data;
    for (gint i = 0; i < ndata; i++) {
        gfloat value = gwy_get_gfloat_be(&p);
        g_assert_cmpfloat(value, ==, expected[i]);
    }
}

void
test_module_utils_get_gfloat_le(void)
{
    enum { ndata = 8 };
    static const guchar data[ndata*sizeof(gfloat)] = {
        0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x80, 0x3f,
        0x00, 0x00, 0x80, 0xbf,
        0x00, 0x00, 0x80, 0x00,
        0xff, 0xff, 0x7f, 0x7f,
        0x00, 0x00, 0x80, 0x80,
        0xff, 0xff, 0x7f, 0xff,
        0xde, 0xd6, 0xfc, 0x3d,
    };
    static const gfloat expected[ndata] = {
        0.0f, 1.0f, -1.0f, G_MINFLOAT, G_MAXFLOAT, -G_MINFLOAT, -G_MAXFLOAT, 0.1234567f,
    };

    const guchar *p = data;
    for (gint i = 0; i < ndata; i++) {
        gfloat value = gwy_get_gfloat_le(&p);
        g_assert_cmpfloat(value, ==, expected[i]);
    }
}

void
test_module_utils_get_gdouble_be(void)
{
    enum { ndata = 9 };
    static const guchar data[ndata*sizeof(gdouble)] = {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0xbf, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18,
        0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x7f, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0x80, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    };
    static const gdouble expected[ndata] = {
        0.0, 1.0, -1.0, G_PI, G_MINDOUBLE, G_MAXDOUBLE, -G_MINDOUBLE, -G_MAXDOUBLE,
    };

    const guchar *p = data;
    for (gint i = 0; i < ndata; i++) {
        gdouble value = gwy_get_gdouble_be(&p);
        g_assert_cmpfloat(value, ==, expected[i]);
    }
}

void
test_module_utils_get_gdouble_le(void)
{
    enum { ndata = 9 };
    static const guchar data[ndata*sizeof(gdouble)] = {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xbf,
        0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0x7f,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x80,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff,
    };
    static const gdouble expected[ndata] = {
        0.0, 1.0, -1.0, G_PI, G_MINDOUBLE, G_MAXDOUBLE, -G_MINDOUBLE, -G_MAXDOUBLE,
    };

    const guchar *p = data;
    for (gint i = 0; i < ndata; i++) {
        gdouble value = gwy_get_gdouble_le(&p);
        g_assert_cmpfloat(value, ==, expected[i]);
    }
}


void
test_module_utils_get_pascal_real_be(void)
{
    enum { ndata = 9 };
    static const guchar data[ndata*6] = {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x81,
        0x80, 0x00, 0x00, 0x00, 0x00, 0x81,
        0x7f, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
        0x80, 0x00, 0x00, 0x00, 0x00, 0x01,
        0x49, 0x0f, 0xda, 0xa2, 0x21, 0x82
    };
    static const gdouble expected[ndata] = {
        0.0,
        0.0,
        1.0,
        -1.0,
        1.7014118346031449e+038,
        -1.7014118346031449e+038,
        2.9387358770557188e-039,
        -2.9387358770557188e-039,
        3.1415926535883045e+000
    };

    const guchar *p = data;
    for (gint i = 0; i < ndata; i++) {
        gdouble value = gwy_get_pascal_real_be(&p);
        g_assert_cmpfloat(value, ==, expected[i]);
    }
}

void
test_module_utils_get_pascal_real_le(void)
{
    enum { ndata = 9 };
    static const guchar data[ndata*6] = {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
        0x81, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x81, 0x00, 0x00, 0x00, 0x00, 0x80,
        0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x01, 0x00, 0x00, 0x00, 0x00, 0x80,
        0x82, 0x21, 0xa2, 0xda, 0x0f, 0x49
    };
    static const gdouble expected[ndata] = {
        0.0,
        0.0,
        1.0,
        -1.0,
        1.7014118346031449e+038,
        -1.7014118346031449e+038,
        2.9387358770557188e-039,
        -2.9387358770557188e-039,
        3.1415926535883045e+000
    };

    const guchar *p = data;
    for (gint i = 0; i < ndata; i++) {
        gdouble value = gwy_get_pascal_real_le(&p);
        g_assert_cmpfloat(value, ==, expected[i]);
    }
}

void
test_module_utils_nonsquare_image(void)
{
    GwyFile *file = gwy_file_new_in_construction();
    gwy_file_pass_image(file, 0, gwy_field_new(1, 100, 1.0, 100.0, FALSE));
    gwy_file_pass_image(file, 1, gwy_field_new(100, 1, 100.0, 1.0, FALSE));
    gwy_file_pass_image(file, 2, gwy_field_new(10, 10, 1.0, 1.0 + 1e-14, FALSE));
    gwy_file_pass_image(file, 3, gwy_field_new(10, 10, 1.0, 1.0 + 1e-14, FALSE));
    gwy_file_pass_image(file, 4, gwy_field_new(10, 10, 2.0, 2.1, FALSE));
    gwy_file_pass_image(file, 5, gwy_field_new(10, 10, 2.1, 2.0, FALSE));
    gwy_file_pass_image(file, 6, gwy_field_new(10, 10, 1.0, 2.0, FALSE));
    gwy_file_pass_image(file, 7, gwy_field_new(10, 10, 2.0, 1.0, FALSE));
    gwy_dict_finish_construction(GWY_DICT(file));

    g_assert_false(gwy_check_nonsquare_image(file, 0));
    g_assert_false(gwy_check_nonsquare_image(file, 1));
    g_assert_false(gwy_check_nonsquare_image(file, 2));
    g_assert_false(gwy_check_nonsquare_image(file, 3));
    g_assert_false(gwy_check_nonsquare_image(file, 4));
    g_assert_false(gwy_check_nonsquare_image(file, 5));
    g_assert_true(gwy_check_nonsquare_image(file, 6));
    g_assert_true(gwy_check_nonsquare_image(file, 7));
    g_assert_finalize_object(file);
}

void
test_module_utils_image_remove_bad_bad(void)
{
    static const gdouble src[] = {
        1e6, 1.0, 2e6,
        2.0, 8e6, 3.0,
        3e6, 4.0, 4e6,
    };
    static const gchar masksrc[] =
        "   \n"
        " 1 \n"
        "   ";
    GwyField *field = gwy_field_new(3, 3, 3.0, 3.0, FALSE);
    gwy_assign(gwy_field_get_data(field), src, 3*3);
    GwyNield *mask = parse_nield(masksrc);

    GwyNield *newmask = gwy_remove_bad_image_data(field, mask);
    g_assert_true(GWY_IS_NIELD(newmask));
    GwyNield *refmask = parse_nield(masksrc);
    nield_assert_equal(G_OBJECT(newmask), G_OBJECT(refmask));

    GwyField *reffield = gwy_field_new(3, 3, 3.0, 3.0, FALSE);
    gwy_assign(gwy_field_get_data(reffield), src, 3*3);
    gwy_field_set_val(reffield, 1, 1, 2.5);
    field_assert_equal(G_OBJECT(field), G_OBJECT(reffield));

    g_assert_finalize_object(refmask);
    g_assert_finalize_object(newmask);
    g_assert_finalize_object(reffield);
    g_assert_finalize_object(field);
}

void
test_module_utils_image_remove_bad_nobad(void)
{
    static const gdouble src[] = {
        1.5, 1.0, 3.5,
        2.0, 2.5, 3.0,
        0.0, 4.0, 1.0,
    };
    GwyField *field = gwy_field_new(3, 3, 3.0, 3.0, FALSE);
    gwy_assign(gwy_field_get_data(field), src, 3*3);
    GwyNield *mask = gwy_nield_new(3, 3);

    // Take an extra reference to be able to assert finalisation.
    g_object_ref(mask);
    GwyNield *newmask = gwy_remove_bad_image_data(field, mask);
    g_assert_true(newmask == NULL);

    GwyField *reffield = gwy_field_new(3, 3, 3.0, 3.0, FALSE);
    gwy_assign(gwy_field_get_data(reffield), src, 3*3);
    field_assert_equal(G_OBJECT(field), G_OBJECT(reffield));

    GwyNield *nullmask = gwy_remove_bad_image_data(field, NULL);
    g_assert_true(nullmask == NULL);

    g_assert_finalize_object(mask);
    g_assert_finalize_object(reffield);
    g_assert_finalize_object(field);
}

void
test_module_utils_mask_nans(void)
{
    // FIXME: What is the correct way to create NaN and Inf with -ffinite-math-only? We do not want do any arithmetic
    // with them; we want just a sequence of bytes representing NaN or Inf.
    static const gdouble src[] = {
        1.5, 1.0, 3.5,
        2.0, NAN, 3.0,
        0.0, 4.0, 1.0,
        5.0, INFINITY, 6.0,
        0.0, 7.0, 1.0,
    };
    static const gchar masksrc[] =
        "   \n"
        " 1 \n"
        "   \n"
        " 1 \n"
        "   ";
    GwyField *field = gwy_field_new(3, 5, 3.0, 5.0, FALSE);
    gwy_assign(gwy_field_get_data(field), src, 3*5);
    GwyNield *refmask = parse_nield(masksrc);

    GwyNield *mask1 = gwy_mask_nans_in_field(field, FALSE);
    g_assert_true(GWY_IS_NIELD(mask1));
    nield_assert_equal(G_OBJECT(mask1), G_OBJECT(refmask));
    // Do not try to compare doubles which may be NaN by value! Simply check the data have not been modified.
    const gdouble *data = gwy_field_get_data_const(field);
    g_assert_false(memcmp(data, src, 5*3*sizeof(gdouble)));

    GwyNield *mask2 = gwy_mask_nans_in_field(field, TRUE);
    g_assert_true(GWY_IS_NIELD(mask2));
    nield_assert_equal(G_OBJECT(mask2), G_OBJECT(refmask));

    GwyField *reffield = gwy_field_new(3, 5, 3.0, 5.0, FALSE);
    gwy_assign(gwy_field_get_data(reffield), src, 3*5);
    gwy_field_set_val(reffield, 1, 1, 2.5);
    gwy_field_set_val(reffield, 1, 3, 5.5);
    field_assert_equal(G_OBJECT(field), G_OBJECT(reffield));

    g_assert_finalize_object(reffield);
    g_assert_finalize_object(refmask);
    g_assert_finalize_object(mask1);
    g_assert_finalize_object(mask2);
    g_assert_finalize_object(field);
}

/* vim: set cin columns=120 tw=118 et ts=4 sw=4 cino=>1s,e0,n0,f0,{0,}0,^0,\:1s,=0,g1s,h0,t0,+1s,c3,(0,u0 : */
