/*
 *  $Id: brick.c 27897 2025-04-22 17:16:19Z yeti-dn $
 *  Copyright (C) 2025 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"

static void
assert_brick_content(GwyBrick *brick, const gdouble *ref_data, guint ref_n, gdouble eps)
{
    g_assert_true(GWY_IS_BRICK(brick));
    guint xres = gwy_brick_get_xres(brick);
    guint yres = gwy_brick_get_yres(brick);
    guint zres = gwy_brick_get_zres(brick);
    g_assert_cmpuint(xres*yres*zres, ==, ref_n);
    const gdouble *data = gwy_brick_get_data_const(brick);
    g_assert_nonnull(data);

    if (eps > 0.0) {
        for (guint i = 0; i < ref_n; i++)
            g_assert_cmpfloat_with_epsilon(data[i], ref_data[i], eps);
    }
    else {
        for (guint i = 0; i < ref_n; i++)
            g_assert_cmpfloat(data[i], ==, ref_data[i]);
    }
}

static void
brick_assert_equal(GObject *object, GObject *reference)
{
    g_assert_true(GWY_IS_BRICK(object));
    g_assert_true(GWY_IS_BRICK(reference));

    GwyBrick *brick = GWY_BRICK(object), *brick_ref = GWY_BRICK(reference);
    g_assert_cmpint(gwy_brick_get_xres(brick), ==, gwy_brick_get_xres(brick_ref));
    g_assert_cmpint(gwy_brick_get_yres(brick), ==, gwy_brick_get_yres(brick_ref));
    g_assert_cmpint(gwy_brick_get_zres(brick), ==, gwy_brick_get_zres(brick_ref));
    g_assert_cmpfloat(gwy_brick_get_xreal(brick), ==, gwy_brick_get_xreal(brick_ref));
    g_assert_cmpfloat(gwy_brick_get_yreal(brick), ==, gwy_brick_get_yreal(brick_ref));
    g_assert_cmpfloat(gwy_brick_get_zreal(brick), ==, gwy_brick_get_zreal(brick_ref));
    g_assert_cmpfloat(gwy_brick_get_xoffset(brick), ==, gwy_brick_get_xoffset(brick_ref));
    g_assert_cmpfloat(gwy_brick_get_yoffset(brick), ==, gwy_brick_get_yoffset(brick_ref));
    g_assert_cmpfloat(gwy_brick_get_zoffset(brick), ==, gwy_brick_get_zoffset(brick_ref));
    g_assert_true(gwy_unit_equal(gwy_brick_get_unit_x(brick), gwy_brick_get_unit_x(brick_ref)));
    g_assert_true(gwy_unit_equal(gwy_brick_get_unit_y(brick), gwy_brick_get_unit_y(brick_ref)));
    g_assert_true(gwy_unit_equal(gwy_brick_get_unit_z(brick), gwy_brick_get_unit_z(brick_ref)));
    g_assert_true(gwy_unit_equal(gwy_brick_get_unit_w(brick), gwy_brick_get_unit_w(brick_ref)));
    assert_brick_content(brick, gwy_brick_get_data(brick_ref),
                         gwy_brick_get_xres(brick_ref)*gwy_brick_get_yres(brick_ref)*gwy_brick_get_zres(brick_ref),
                         0.0);

    GwyLine *zcal = gwy_brick_get_zcalibration(brick), *zcal_ref = gwy_brick_get_zcalibration(brick_ref);
    if (zcal_ref) {
        g_assert_true(GWY_IS_LINE(zcal_ref));
        g_assert_true(GWY_IS_LINE(zcal));
        line_assert_equal(G_OBJECT(zcal), G_OBJECT(zcal_ref));
    }
    else
        g_assert_null(zcal);
}

void
test_brick_basic(void)
{
    const gdouble zeros[24] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
    const gdouble twos[24] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 };

    GwyBrick *brick = gwy_brick_new(2, 3, 4, 1.6, 7.5, 3.2, TRUE);
    assert_brick_content(brick, zeros, 24, 0.0);
    g_assert_cmpfloat(gwy_brick_get_xreal(brick), ==, 1.6);
    g_assert_cmpfloat(gwy_brick_get_yreal(brick), ==, 7.5);
    g_assert_cmpfloat(gwy_brick_get_zreal(brick), ==, 3.2);
    g_assert_cmpfloat(gwy_brick_get_dx(brick), ==, 1.6/2);
    g_assert_cmpfloat(gwy_brick_get_dy(brick), ==, 7.5/3);
    g_assert_cmpfloat(gwy_brick_get_dz(brick), ==, 3.2/4);
    g_assert_cmpfloat(gwy_brick_get_xoffset(brick), ==, 0);
    g_assert_cmpfloat(gwy_brick_get_yoffset(brick), ==, 0);
    g_assert_cmpfloat(gwy_brick_get_zoffset(brick), ==, 0);

    gwy_brick_set_xreal(brick, 31);
    gwy_brick_set_yreal(brick, 39);
    gwy_brick_set_zreal(brick, 44);
    gwy_brick_set_xoffset(brick, -11);
    gwy_brick_set_yoffset(brick, 77);
    gwy_brick_set_zoffset(brick, 3.5);
    g_assert_cmpfloat(gwy_brick_get_xreal(brick), ==, 31.0);
    g_assert_cmpfloat(gwy_brick_get_yreal(brick), ==, 39.0);
    g_assert_cmpfloat(gwy_brick_get_zreal(brick), ==, 44.0);
    g_assert_cmpfloat(gwy_brick_get_dx(brick), ==, 31.0/2);
    g_assert_cmpfloat(gwy_brick_get_dy(brick), ==, 39.0/3);
    g_assert_cmpfloat(gwy_brick_get_dz(brick), ==, 44.0/4);
    g_assert_cmpfloat(gwy_brick_get_xoffset(brick), ==, -11);
    g_assert_cmpfloat(gwy_brick_get_yoffset(brick), ==, 77);
    g_assert_cmpfloat(gwy_brick_get_zoffset(brick), ==, 3.5);

    gwy_brick_fill(brick, 2.0);
    assert_brick_content(brick, twos, 24, 0.0);

    gwy_brick_clear(brick);
    assert_brick_content(brick, zeros, 24, 0.0);

    g_assert_cmpfloat(gwy_brick_get_xreal(brick), ==, 31.0);
    g_assert_cmpfloat(gwy_brick_get_yreal(brick), ==, 39.0);
    g_assert_cmpfloat(gwy_brick_get_zreal(brick), ==, 44.0);
    g_assert_cmpfloat(gwy_brick_get_dx(brick), ==, 31.0/2);
    g_assert_cmpfloat(gwy_brick_get_dy(brick), ==, 39.0/3);
    g_assert_cmpfloat(gwy_brick_get_dz(brick), ==, 44.0/4);
    g_assert_cmpfloat(gwy_brick_get_xoffset(brick), ==, -11);
    g_assert_cmpfloat(gwy_brick_get_yoffset(brick), ==, 77);
    g_assert_cmpfloat(gwy_brick_get_zoffset(brick), ==, 3.5);

    g_assert_finalize_object(brick);
}

void
test_brick_data_changed(void)
{
    GwyBrick *brick = gwy_brick_new(1, 1, 1, 1.0, 1.0, 1.0, TRUE);
    guint item_changed = 0;
    g_signal_connect_swapped(brick, "data-changed", G_CALLBACK(record_signal), &item_changed);
    gwy_brick_data_changed(brick);
    g_assert_cmpuint(item_changed, ==, 1);
    gwy_brick_data_changed(brick);
    g_assert_cmpuint(item_changed, ==, 2);
    g_assert_finalize_object(brick);
}

static GwyBrick*
create_brick_for_serialisation(void)
{
    GwyBrick *brick = gwy_brick_new(13, 7, 11, 26.0, 1.6, 6.5, FALSE);
    gwy_brick_set_xoffset(brick, G_LN2);
    gwy_brick_set_yoffset(brick, GWY_SQRT3);
    gwy_brick_set_zoffset(brick, G_PI);
    gdouble *data = gwy_brick_get_data(brick);
    for (guint i = 0; i < 13*7*11; i++)
        data[i] = sqrt(i) - 2*G_PI;

    return brick;
}

static void
set_brick_units_for_serialisation(GwyBrick *brick)
{
    gwy_unit_set_from_string(gwy_brick_get_unit_x(brick), "m");
    gwy_unit_set_from_string(gwy_brick_get_unit_y(brick), "A");
    gwy_unit_set_from_string(gwy_brick_get_unit_z(brick), "V");
    gwy_unit_set_from_string(gwy_brick_get_unit_w(brick), "s");
}

static void
add_brick_zcalibration_for_serialisation(GwyBrick *brick)
{
    GwyLine *line = gwy_line_new(11, 5.5, FALSE);
    gwy_line_line_level(line, 1.0, 2.3);
    gwy_unit_set_from_string(gwy_line_get_unit_y(line), "kg");
    gwy_brick_set_zcalibration(brick, line);
    g_object_unref(line);
}

void
test_brick_serialization(void)
{
    GwyBrick *brick = create_brick_for_serialisation();
    serialize_object_and_back(G_OBJECT(brick), brick_assert_equal, FALSE, NULL);

    set_brick_units_for_serialisation(brick);
    serialize_object_and_back(G_OBJECT(brick), brick_assert_equal, FALSE, NULL);

    add_brick_zcalibration_for_serialisation(brick);
    serialize_object_and_back(G_OBJECT(brick), brick_assert_equal, FALSE, NULL);

    g_assert_finalize_object(brick);
}

void
test_brick_copy(void)
{
    GwyBrick *brick = create_brick_for_serialisation();
    serializable_test_copy(GWY_SERIALIZABLE(brick), brick_assert_equal);

    set_brick_units_for_serialisation(brick);
    serializable_test_copy(GWY_SERIALIZABLE(brick), brick_assert_equal);

    add_brick_zcalibration_for_serialisation(brick);
    serializable_test_copy(GWY_SERIALIZABLE(brick), brick_assert_equal);

    g_assert_finalize_object(brick);
}

void
test_brick_assign(void)
{
    GwyBrick *brick = create_brick_for_serialisation();
    serializable_test_assign(GWY_SERIALIZABLE(brick), NULL, brick_assert_equal);

    set_brick_units_for_serialisation(brick);
    serializable_test_assign(GWY_SERIALIZABLE(brick), NULL, brick_assert_equal);

    add_brick_zcalibration_for_serialisation(brick);
    serializable_test_assign(GWY_SERIALIZABLE(brick), NULL, brick_assert_equal);

    GwyBrick *another = gwy_brick_new(6, 1, 5, 4.3, 6.6, 0.2, FALSE);
    gwy_brick_set_xoffset(another, -11.0);
    gwy_brick_set_yoffset(another, 2.0);
    gwy_brick_set_zoffset(another, 7.7);
    gwy_unit_set_from_string(gwy_brick_get_unit_x(another), "V");
    gwy_unit_set_from_string(gwy_brick_get_unit_w(another), "m/s");
    serializable_test_assign(GWY_SERIALIZABLE(brick), GWY_SERIALIZABLE(another), brick_assert_equal);
    g_assert_finalize_object(another);

    g_assert_finalize_object(brick);
}

static void
assert_brick_compatibility(gint xres1, gint yres1, gint zres1,
                           gdouble xreal1, gdouble yreal1, gdouble zreal1,
                           const gchar *xunit1, const gchar *yunit1, const gchar *zunit1, const gchar *wunit1,
                           GwyLine *zcal1,
                           gint xres2, gint yres2, gint zres2,
                           gdouble xreal2, gdouble yreal2, gdouble zreal2,
                           const gchar *xunit2, const gchar *yunit2, const gchar *zunit2, const gchar *wunit2,
                           GwyLine *zcal2,
                           GwyDataMismatchFlags flags_to_test,
                           GwyDataMismatchFlags expected_result)
{
    GwyBrick *brick1 = gwy_brick_new(xres1, yres1, zres1, xreal1, yreal1, zreal1, TRUE);
    if (xunit1)
        gwy_unit_set_from_string(gwy_brick_get_unit_x(brick1), xunit1);
    if (yunit1)
        gwy_unit_set_from_string(gwy_brick_get_unit_y(brick1), yunit1);
    if (zunit1)
        gwy_unit_set_from_string(gwy_brick_get_unit_z(brick1), zunit1);
    if (wunit1)
        gwy_unit_set_from_string(gwy_brick_get_unit_w(brick1), wunit1);
    if (zcal1) {
        gwy_brick_set_zcalibration(brick1, zcal1);
        g_object_unref(zcal1);
    }

    GwyBrick *brick2 = gwy_brick_new(xres2, yres2, zres2, xreal2, yreal2, zreal2, TRUE);
    if (xunit2)
        gwy_unit_set_from_string(gwy_brick_get_unit_x(brick2), xunit2);
    if (yunit2)
        gwy_unit_set_from_string(gwy_brick_get_unit_y(brick2), yunit2);
    if (zunit2)
        gwy_unit_set_from_string(gwy_brick_get_unit_z(brick2), zunit2);
    if (wunit2)
        gwy_unit_set_from_string(gwy_brick_get_unit_w(brick2), wunit2);
    if (zcal2) {
        gwy_brick_set_zcalibration(brick2, zcal2);
        g_object_unref(zcal2);
    }

    g_assert_cmphex(gwy_brick_is_incompatible(brick1, brick2, flags_to_test), ==, expected_result);
    g_assert_finalize_object(brick1);
    g_assert_finalize_object(brick2);
}

void
test_brick_compatibility_res(void)
{
    assert_brick_compatibility(1, 2, 5, G_PI, 7.0, 1e-3, "m", "V", NULL, "N", NULL,
                               1, 2, 5, 0.3, 1e40, 0.5, NULL, "", "A", "s", NULL,
                               GWY_DATA_MISMATCH_RES, 0);
    assert_brick_compatibility(1, 2, 5, G_PI, 7.0, 1e-3, "m", "V", NULL, "N", NULL,
                               2, 2, 5, 0.3, 1e40, 0.5, NULL, "", "A", "s", NULL,
                               GWY_DATA_MISMATCH_RES, GWY_DATA_MISMATCH_RES);
    assert_brick_compatibility(1, 2, 5, G_PI, 7.0, 1e-3, "m", "V", NULL, "N", NULL,
                               1, 1, 5, 0.3, 1e40, 0.5, NULL, "", "A", "s", NULL,
                               GWY_DATA_MISMATCH_RES, GWY_DATA_MISMATCH_RES);
    assert_brick_compatibility(1, 2, 5, G_PI, 7.0, 1e-3, "m", "V", NULL, "N", NULL,
                               1, 5, 5, 0.3, 1e40, 0.5, NULL, "", "A", "s", NULL,
                               GWY_DATA_MISMATCH_RES, GWY_DATA_MISMATCH_RES);
    assert_brick_compatibility(1, 2, 5, G_PI, 7.0, 1e-3, "m", "V", NULL, "N", NULL,
                               1, 2, 2, 0.3, 1e40, 0.5, NULL, "", "A", "s", NULL,
                               GWY_DATA_MISMATCH_RES, GWY_DATA_MISMATCH_RES);
    assert_brick_compatibility(1, 2, 5, G_PI, 7.0, 1e-3, "m", "V", NULL, "N", NULL,
                               2, 5, 1, 0.3, 1e40, 0.5, NULL, "", "A", "s", NULL,
                               GWY_DATA_MISMATCH_RES, GWY_DATA_MISMATCH_RES);
    assert_brick_compatibility(1, 2, 5, G_PI, 7.0, 1e-3, "m", "V", NULL, "N", NULL,
                               5, 1, 2, 0.3, 1e40, 0.5, NULL, "", "A", "s", NULL,
                               GWY_DATA_MISMATCH_RES, GWY_DATA_MISMATCH_RES);
}

void
test_brick_compatibility_real(void)
{
    assert_brick_compatibility(1, 2, 5, G_PI, 7.0, 1e-3, "m", "V", NULL, "N", NULL,
                               2, 4, 3, G_PI, 7.0, 1e-3, NULL, "", "A", "s", NULL,
                               GWY_DATA_MISMATCH_REAL, 0);
    assert_brick_compatibility(1, 2, 5, G_PI, 7.0, 1e-3, "m", "V", NULL, "N", NULL,
                               2, 4, 3, G_PI, G_PI, 1e-3, NULL, "", "A", "s", NULL,
                               GWY_DATA_MISMATCH_REAL, GWY_DATA_MISMATCH_REAL);
    assert_brick_compatibility(1, 2, 5, G_PI, 7.0, 1e-3, "m", "V", NULL, "N", NULL,
                               2, 4, 3, G_PI, 1e-3, 1e-3, NULL, "", "A", "s", NULL,
                               GWY_DATA_MISMATCH_REAL, GWY_DATA_MISMATCH_REAL);
    assert_brick_compatibility(1, 2, 5, G_PI, 7.0, 1e-3, "m", "V", NULL, "N", NULL,
                               2, 4, 3, 7.0, 7.0, 1e-3, NULL, "", "A", "s", NULL,
                               GWY_DATA_MISMATCH_REAL, GWY_DATA_MISMATCH_REAL);
    assert_brick_compatibility(1, 2, 5, G_PI, 7.0, 1e-3, "m", "V", NULL, "N", NULL,
                               2, 4, 3, G_PI, 7.0, 7.0, NULL, "", "A", "s", NULL,
                               GWY_DATA_MISMATCH_REAL, GWY_DATA_MISMATCH_REAL);
    /* Tiny differences do not break compatibility. */
    assert_brick_compatibility(1, 2, 5, G_PI, 7.0*(1.0 + 1e-14), 1e-3, "m", "V", NULL, "N", NULL,
                               2, 4, 3, G_PI*(1.0 - 1e-14), 7.0, 1e-3*(1.0 - 1e-14), NULL, "", "A", "s", NULL,
                               GWY_DATA_MISMATCH_REAL, 0);
}

void
test_brick_compatibility_lateral(void)
{
    assert_brick_compatibility(1, 2, 5, G_PI, 7.0, 1e-3, NULL, NULL, NULL, "N", NULL,
                               2, 4, 3, 1.0, 0.1, 5.3, NULL, NULL, NULL, "s", NULL,
                               GWY_DATA_MISMATCH_LATERAL, 0);
    assert_brick_compatibility(1, 2, 5, G_PI, 7.0, 1e-3, "", "V", "", "N", NULL,
                               2, 4, 3, 1.0, 0.1, 5.3, NULL, "V", "", "s", NULL,
                               GWY_DATA_MISMATCH_LATERAL, 0);
    assert_brick_compatibility(1, 2, 5, G_PI, 7.0, 1e-3, "V", "V", "", "N", NULL,
                               2, 4, 3, 1.0, 0.1, 5.3, NULL, "V", "", "s", NULL,
                               GWY_DATA_MISMATCH_LATERAL, GWY_DATA_MISMATCH_LATERAL);
    assert_brick_compatibility(1, 2, 5, G_PI, 7.0, 1e-3, "", "V", "", "N", NULL,
                               2, 4, 3, 1.0, 0.1, 5.3, NULL, NULL, "", "s", NULL,
                               GWY_DATA_MISMATCH_LATERAL, GWY_DATA_MISMATCH_LATERAL);
    assert_brick_compatibility(1, 2, 5, G_PI, 7.0, 1e-3, "", "V", "V", "N", NULL,
                               2, 4, 3, 1.0, 0.1, 5.3, NULL, "V", "", "s", NULL,
                               GWY_DATA_MISMATCH_LATERAL, GWY_DATA_MISMATCH_LATERAL);
}

void
test_brick_compatibility_value(void)
{
    assert_brick_compatibility(1, 2, 5, G_PI, 7.0, 1e-3, "m", "", "s", NULL, NULL,
                               2, 4, 3, 1.0, 0.1, 5.3, NULL, "A", "N", "", NULL,
                               GWY_DATA_MISMATCH_VALUE, 0);
    assert_brick_compatibility(1, 2, 5, G_PI, 7.0, 1e-3, "m", "", "s", "nanometre", NULL,
                               2, 4, 3, 1.0, 0.1, 5.3, NULL, "A", "N", "km", NULL,
                               GWY_DATA_MISMATCH_VALUE, 0);
    assert_brick_compatibility(1, 2, 5, G_PI, 7.0, 1e-3, "m", "m", "m", "m", NULL,
                               2, 4, 3, 1.0, 0.1, 5.3, "m", "m", "m", "V", NULL,
                               GWY_DATA_MISMATCH_VALUE, GWY_DATA_MISMATCH_VALUE);
    assert_brick_compatibility(1, 2, 5, G_PI, 7.0, 1e-3, "m", "m", "m", "V", NULL,
                               2, 4, 3, 1.0, 0.1, 5.3, "m", "m", "m", "m", NULL,
                               GWY_DATA_MISMATCH_VALUE, GWY_DATA_MISMATCH_VALUE);
}

void
test_brick_compatibility_measure(void)
{
    assert_brick_compatibility(1, 2, 5, 2e-9, 1e-9, 5e-3, "m", "V", NULL, "N", NULL,
                               2, 4, 3, 4e-9, 2e-9, 3e-3, NULL, "", "A", "s", NULL,
                               GWY_DATA_MISMATCH_MEASURE, 0);
    assert_brick_compatibility(1, 2, 5, 2e-9, 1e-9, 5e-3, "m", "V", NULL, "N", NULL,
                               1, 2, 5, 4e-9, 2e-9, 3e-3, NULL, "", "A", "s", NULL,
                               GWY_DATA_MISMATCH_MEASURE, GWY_DATA_MISMATCH_MEASURE);
    assert_brick_compatibility(1, 2, 5, 2e-9, 1e-9, 5e-3, "m", "V", NULL, "N", NULL,
                               2, 4, 3, 2e-9, 1e-9, 5e-3, NULL, "", "A", "s", NULL,
                               GWY_DATA_MISMATCH_MEASURE, GWY_DATA_MISMATCH_MEASURE);
    assert_brick_compatibility(1, 2, 5, 2e-9, 1e-9, 5e-3, "m", "V", NULL, "N", NULL,
                               2, 4, 3, 4.5e-9, 2e-9, 3e-3, NULL, "", "A", "s", NULL,
                               GWY_DATA_MISMATCH_MEASURE, GWY_DATA_MISMATCH_MEASURE);
    assert_brick_compatibility(1, 2, 5, 2e-9, 1e-9, 5e-3, "m", "V", NULL, "N", NULL,
                               2, 4, 3, 4e-9, 1.9e-9, 3e-3, NULL, "", "A", "s", NULL,
                               GWY_DATA_MISMATCH_MEASURE, GWY_DATA_MISMATCH_MEASURE);
    assert_brick_compatibility(1, 2, 5, 2e-9, 1e-9, 5e-3, "m", "V", NULL, "N", NULL,
                               2, 4, 3, 4e-9, 2e-9, 3.06e-3, NULL, "", "A", "s", NULL,
                               GWY_DATA_MISMATCH_MEASURE, GWY_DATA_MISMATCH_MEASURE);
    /* Tiny differences do not break compatibility. */
    assert_brick_compatibility(1, 2, 5, 2e-9*(1.0 - 1e-14), 1e-9, 5e-3*(1.0 - 1e-14), "m", "V", NULL, "N", NULL,
                               2, 4, 3, 4e-9, 2e-9*(1.0 + 1e-14), 3e-3, NULL, "", "A", "s", NULL,
                               GWY_DATA_MISMATCH_MEASURE, 0);
}

void
test_brick_compatibility_axiscal(void)
{
    GwyLine *zcal1, *zcal2;

    assert_brick_compatibility(1, 2, 3, G_PI, 7.0, 1e-3, "m", "", "s", "V", NULL,
                               2, 4, 3, 1.0, 0.1, 5.3, NULL, "A", "N", "kg", NULL,
                               GWY_DATA_MISMATCH_AXISCAL, 0);
    assert_brick_compatibility(1, 2, 5, G_PI, 7.0, 1e-3, "m", "", "s", "V", NULL,
                               2, 4, 3, 1.0, 0.1, 5.3, NULL, "A", "N", "kg", NULL,
                               GWY_DATA_MISMATCH_AXISCAL, GWY_DATA_MISMATCH_AXISCAL);

    zcal1 = gwy_line_new(5, 1.0, FALSE);
    gwy_math_linspace(gwy_line_get_data(zcal1), gwy_line_get_res(zcal1), 0.0, 1.0);
    assert_brick_compatibility(1, 2, 5, G_PI, 7.0, 1e-3, "m", "", "s", "V", zcal1,
                               2, 4, 3, 1.0, 0.1, 5.3, NULL, "A", "N", "kg", NULL,
                               GWY_DATA_MISMATCH_AXISCAL, GWY_DATA_MISMATCH_AXISCAL);

    zcal2 = gwy_line_new(3, 1.0, FALSE);
    gwy_math_linspace(gwy_line_get_data(zcal2),  gwy_line_get_res(zcal2), 0.0, 1.0);
    assert_brick_compatibility(1, 2, 5, G_PI, 7.0, 1e-3, "m", "", "s", "V", NULL,
                               2, 4, 3, 1.0, 0.1, 5.3, NULL, "A", "N", "kg", zcal2,
                               GWY_DATA_MISMATCH_AXISCAL, GWY_DATA_MISMATCH_AXISCAL);

    zcal1 = gwy_line_new(3, 1.0, FALSE);
    gwy_math_linspace(gwy_line_get_data(zcal1), gwy_line_get_res(zcal1), 0.0, 1.0);
    zcal2 = gwy_line_new(3, 1.0, FALSE);
    gwy_math_linspace(gwy_line_get_data(zcal2), gwy_line_get_res(zcal2), 0.0, 1.5);
    assert_brick_compatibility(1, 2, 3, G_PI, 7.0, 1e-3, "m", "", "s", "V", zcal1,
                               2, 4, 3, 1.0, 0.1, 5.3, NULL, "A", "N", "kg", zcal2,
                               GWY_DATA_MISMATCH_AXISCAL, GWY_DATA_MISMATCH_AXISCAL);

    zcal1 = gwy_line_new(3, 1.0, FALSE);
    gwy_math_linspace(gwy_line_get_data(zcal1), gwy_line_get_res(zcal1), 0.0, 2.0);
    zcal2 = gwy_line_copy(zcal1);
    assert_brick_compatibility(1, 2, 3, G_PI, 7.0, 1e-3, "m", "", "s", "V", zcal1,
                               2, 4, 3, 1.0, 0.1, 5.3, NULL, "A", "N", "kg", zcal2,
                               GWY_DATA_MISMATCH_AXISCAL, 0);

    zcal1 = gwy_line_new(3, 1.0, FALSE);
    gwy_math_linspace(gwy_line_get_data(zcal1), gwy_line_get_res(zcal1), 0.0, 2.0);
    zcal2 = gwy_line_copy(zcal1);
    gwy_unit_set_from_string(gwy_line_get_unit_y(zcal1), "s");
    assert_brick_compatibility(1, 2, 3, G_PI, 7.0, 1e-3, "m", "", "s", "V", zcal1,
                               2, 4, 3, 1.0, 0.1, 5.3, NULL, "A", "N", "kg", zcal2,
                               GWY_DATA_MISMATCH_AXISCAL, GWY_DATA_MISMATCH_AXISCAL);

    zcal1 = gwy_line_new(3, 1.0, FALSE);
    gwy_math_linspace(gwy_line_get_data(zcal1), gwy_line_get_res(zcal1), 0.0, 2.0);
    gwy_unit_set_from_string(gwy_line_get_unit_y(zcal1), "s");
    zcal2 = gwy_line_copy(zcal1);
    assert_brick_compatibility(1, 2, 3, G_PI, 7.0, 1e-3, "m", "", "s", "V", zcal1,
                               2, 4, 3, 1.0, 0.1, 5.3, NULL, "A", "N", "kg", zcal2,
                               GWY_DATA_MISMATCH_AXISCAL, 0);
}

void
test_brick_compatibility_mixed(void)
{
    GwyDataMismatchFlags all_flags = (GWY_DATA_MISMATCH_RES
                                      | GWY_DATA_MISMATCH_REAL
                                      | GWY_DATA_MISMATCH_MEASURE
                                      | GWY_DATA_MISMATCH_LATERAL
                                      | GWY_DATA_MISMATCH_VALUE
                                      | GWY_DATA_MISMATCH_AXISCAL);
    assert_brick_compatibility(1, 2, 5, 2e-9, 1e-9, 6.0, NULL, NULL, "m", "V", NULL,
                               3, 4, 5, 2e-9, 1e-9, 6.0, NULL, NULL, "A", "V", NULL,
                               all_flags,
                               GWY_DATA_MISMATCH_RES | GWY_DATA_MISMATCH_MEASURE | GWY_DATA_MISMATCH_LATERAL);
    assert_brick_compatibility(3, 4, 5, 3e-9, 40e-9, 2.5, NULL, NULL, NULL, NULL, NULL,
                               6, 8, 10, 6e-9, 80e-9, 5.0, NULL, NULL, NULL, NULL, NULL,
                               all_flags,
                               GWY_DATA_MISMATCH_RES | GWY_DATA_MISMATCH_REAL | GWY_DATA_MISMATCH_AXISCAL);

    GwyLine *zcal1 = gwy_line_new(5, 1.0, FALSE);
    gwy_math_linspace(gwy_line_get_data(zcal1), gwy_line_get_res(zcal1), 0.0, 1.0);
    GwyLine *zcal2 = gwy_line_new(10, 1.0, FALSE);
    gwy_math_linspace(gwy_line_get_data(zcal2), gwy_line_get_res(zcal2), 0.0, 1.0);
    assert_brick_compatibility(3, 4, 5, 3e-9, 40e-9, 2.5, NULL, NULL, NULL, "V", zcal1,
                               6, 8, 10, 3e-9, 40e-9, 2.5, NULL, NULL, NULL, "g", zcal2,
                               all_flags,
                               GWY_DATA_MISMATCH_RES | GWY_DATA_MISMATCH_MEASURE
                               | GWY_DATA_MISMATCH_VALUE | GWY_DATA_MISMATCH_AXISCAL);
}

/* 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 : */
