/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Copyright (C) 2008 - 2011 Red Hat, Inc.
 */

#include "src/core/nm-default-daemon.h"

#include <stdio.h>
#include <stdarg.h>
#include <unistd.h>
#include <linux/pkt_sched.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/if_ether.h>
#include <linux/if_infiniband.h>

#include "libnm-glib-aux/nm-uuid.h"
#include "libnm-glib-aux/nm-json-aux.h"
#include "nm-utils.h"
#include "nm-setting-connection.h"
#include "nm-setting-wired.h"
#include "nm-setting-user.h"
#include "nm-setting-wireless.h"
#include "nm-setting-wireless-security.h"
#include "nm-setting-ip4-config.h"
#include "nm-setting-ip6-config.h"
#include "nm-setting-8021x.h"
#include "nm-setting-pppoe.h"
#include "nm-setting-ppp.h"
#include "nm-setting-vpn.h"
#include "nm-setting-ethtool.h"
#include "nm-setting-gsm.h"
#include "nm-setting-cdma.h"
#include "nm-setting-serial.h"
#include "nm-setting-vlan.h"
#include "nm-setting-dcb.h"
#include "libnm-core-intern/nm-core-internal.h"
#include "libnm-base/nm-ethtool-base.h"
#include "libnm-base/nm-ethtool-utils-base.h"

#include "NetworkManagerUtils.h"

#include "settings/plugins/ifcfg-rh/nms-ifcfg-rh-common.h"
#include "settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.h"
#include "settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.h"
#include "settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h"

#include "nm-test-utils-core.h"

#define TEST_IFCFG_DIR NM_BUILD_SRCDIR "/src/core/settings/plugins/ifcfg-rh/tests/network-scripts"
#define TEST_SCRATCH_DIR \
    NM_BUILD_BUILDDIR "/src/core/settings/plugins/ifcfg-rh/tests/network-scripts"
#define TEST_SCRATCH_DIR_TMP TEST_SCRATCH_DIR "/tmp"

#define TEST_SCRATCH_ALIAS_BASE TEST_SCRATCH_DIR "/ifcfg-alias0"

/*****************************************************************************/

#define _svOpenFile(testfile)                \
    ({                                       \
        shvarFile  *_f;                      \
        GError     *_error    = NULL;        \
        const char *_testfile = (testfile);  \
                                             \
        g_assert(_testfile);                 \
        _f = svOpenFile(_testfile, &_error); \
        nmtst_assert_success(_f, _error);    \
        _f;                                  \
    })

#define _svGetValue_check(f, key, expected_value)                   \
    G_STMT_START                                                    \
    {                                                               \
        const char       *_val;                                     \
        gs_free char     *_to_free    = NULL;                       \
        gs_free char     *_val_string = NULL;                       \
        shvarFile *const  _f          = (f);                        \
        const char *const _key        = (key);                      \
                                                                    \
        _val_string = svGetValueStr_cp(_f, _key);                   \
        _val        = svGetValue(_f, _key, &_to_free);              \
        g_assert_cmpstr(_val, ==, (expected_value));                \
        g_assert((!_val_string && (!_val || !_val[0]))              \
                 || (_val_string && nm_streq0(_val, _val_string))); \
    }                                                               \
    G_STMT_END

static void
_assert_reread_same(NMConnection *connection, NMConnection *reread)
{
    nmtst_assert_connection_verifies_without_normalization(reread);
    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
_assert_reread_same_FIXME(NMConnection *connection, NMConnection *reread)
{
    gs_unref_object NMConnection  *connection_normalized = NULL;
    gs_unref_hashtable GHashTable *settings              = NULL;

    /* FIXME: these assertion failures should not happen as we expect
     * that re-reading a connection after write yields the same result.
     *
     * Needs investigation and fixing. */
    nmtst_assert_connection_verifies_without_normalization(reread);

    connection_normalized = nmtst_connection_duplicate_and_normalize(connection);

    g_assert(!nm_connection_compare(connection_normalized, reread, NM_SETTING_COMPARE_FLAG_EXACT));
    g_assert(!nm_connection_diff(connection_normalized,
                                 reread,
                                 NM_SETTING_COMPARE_FLAG_EXACT,
                                 &settings));
}

/* dummy path for an "expected" file, meaning: don't check for expected
 * written ifcfg file. */
static const char NO_EXPECTED[1];

static void
_assert_expected_content(NMConnection *connection, const char *filename, const char *expected)
{
    gs_free char *content_expectd = NULL;
    gs_free char *content_written = NULL;
    GError       *error           = NULL;
    gsize         len_expectd     = 0;
    gsize         len_written     = 0;
    gboolean      success;
    const char   *uuid = NULL;

    g_assert(NM_IS_CONNECTION(connection));
    g_assert(filename);
    g_assert(g_file_test(filename, G_FILE_TEST_EXISTS));

    g_assert(expected);
    if (expected == NO_EXPECTED)
        return;

    success = g_file_get_contents(filename, &content_written, &len_written, &error);
    nmtst_assert_success(success, error);

    success = g_file_get_contents(expected, &content_expectd, &len_expectd, &error);
    nmtst_assert_success(success, error);

    {
        gsize i, j;

        for (i = 0; i < len_expectd;) {
            if (content_expectd[i] != '$') {
                i++;
                continue;
            }
            if (g_str_has_prefix(&content_expectd[i], "${UUID}")) {
                GString *str;

                if (!uuid) {
                    uuid = nm_connection_get_uuid(connection);
                    g_assert(uuid);
                }

                j = strlen(uuid);

                str = g_string_new_len(content_expectd, len_expectd);
                g_string_erase(str, i, NM_STRLEN("${UUID}"));
                g_string_insert_len(str, i, uuid, j);

                len_expectd = str->len;
                nm_strdup_reset_take(&content_expectd, g_string_free(str, FALSE));
                i += j;
                continue;
            }

            /* other '$' is not supported. If need be, support escaping of
             * '$' via '$$'. */
            g_assert_not_reached();
        }
    }

    if (len_expectd != len_written || memcmp(content_expectd, content_written, len_expectd) != 0) {
        static int rewrite_static = 0;
        int        rewrite;

        rewrite = g_atomic_int_get(&rewrite_static);
        if (G_UNLIKELY(rewrite == 0)) {
            rewrite = (g_getenv("NMTST_IFCFG_RH_UPDATE_EXPECTED")
                       || nm_streq0(g_getenv("NM_TEST_REGENERATE"), "1"))
                          ? 1
                          : -1;
            if (!g_atomic_int_compare_and_exchange(&rewrite_static, 0, rewrite))
                g_assert_not_reached();
        }

        if (rewrite > 0) {
            if (uuid) {
                gs_free char *search = g_strdup_printf("UUID=%s\n", uuid);
                const char   *s;
                gsize         i;
                GString      *str;

                s = content_written;
                while (TRUE) {
                    s = strstr(s, search);
                    g_assert(s);
                    if (s == content_written || s[-1] == '\n')
                        break;
                    s += strlen(search);
                }

                i = s - content_written;

                str = g_string_new_len(content_written, len_written);
                g_string_erase(str, i, strlen(search));
                g_string_insert(str, i, "UUID=${UUID}\n");

                len_written     = str->len;
                content_written = g_string_free(str, FALSE);
            }
            success = g_file_set_contents(expected, content_written, len_written, &error);
            nmtst_assert_success(success, error);
        } else {
            NM_PRAGMA_WARNING_DISABLE_DANGLING_POINTER
            g_error(
                "The content of \"%s\" (%zu) differs from \"%s\" (%zu). Set "
                "NMTST_IFCFG_RH_UPDATE_EXPECTED=yes (or NM_TEST_REGENERATE=1) to update the files "
                "inplace\n\n>>>%s<<<\n\n>>>%s<<<\n",
                filename,
                len_written,
                expected,
                len_expectd,
                content_written,
                content_expectd);
            NM_PRAGMA_WARNING_REENABLE
        }
    }
}

#define _writer_update_connection_reread(connection,                      \
                                         ifcfg_dir,                       \
                                         filename,                        \
                                         expected,                        \
                                         out_reread,                      \
                                         out_reread_same)                 \
    G_STMT_START                                                          \
    {                                                                     \
        gs_unref_object NMConnection *_connection =                       \
            nmtst_connection_duplicate_and_normalize(connection);         \
        NMConnection **_out_reread      = (out_reread);                   \
        gboolean      *_out_reread_same = (out_reread_same);              \
        const char    *_ifcfg_dir       = (ifcfg_dir);                    \
        const char    *_filename        = (filename);                     \
        const char    *_expected        = (expected);                     \
        GError        *_error           = NULL;                           \
        gboolean       _success;                                          \
                                                                          \
        g_assert(_ifcfg_dir && _ifcfg_dir[0]);                            \
        g_assert(_filename && _filename[0]);                              \
                                                                          \
        _success = nms_ifcfg_rh_writer_write_connection(_connection,      \
                                                        _ifcfg_dir,       \
                                                        _filename,        \
                                                        NULL,             \
                                                        NULL,             \
                                                        NULL,             \
                                                        _out_reread,      \
                                                        _out_reread_same, \
                                                        &_error);         \
        nmtst_assert_success(_success, _error);                           \
        _assert_expected_content(_connection, _filename, _expected);      \
    }                                                                     \
    G_STMT_END

#define _writer_update_connection(connection, ifcfg_dir, filename, expected) \
    G_STMT_START                                                             \
    {                                                                        \
        gs_unref_object NMConnection *_reread      = NULL;                   \
        NMConnection                 *_c           = (connection);           \
        gboolean                      _reread_same = FALSE;                  \
                                                                             \
        _writer_update_connection_reread(_c,                                 \
                                         ifcfg_dir,                          \
                                         filename,                           \
                                         expected,                           \
                                         &_reread,                           \
                                         &_reread_same);                     \
        _assert_reread_same(_c, _reread);                                    \
        g_assert(_reread_same);                                              \
    }                                                                        \
    G_STMT_END

static NMConnection *
_connection_from_file(const char *filename,
                      const char *network_file,
                      const char *test_type,
                      char      **out_unhandled)
{
    NMConnection *connection;
    GError       *error              = NULL;
    char         *unhandled_fallback = NULL;

    g_assert(!out_unhandled || !*out_unhandled);

    connection = nmtst_connection_from_file(filename,
                                            network_file,
                                            test_type,
                                            out_unhandled ?: &unhandled_fallback,
                                            &error);
    g_assert_no_error(error);
    g_assert(!unhandled_fallback);

    if (out_unhandled && *out_unhandled)
        nmtst_assert_connection_verifies(connection);
    else
        nmtst_assert_connection_verifies_without_normalization(connection);
    return connection;
}

static void
_connection_from_file_fail(const char *filename,
                           const char *network_file,
                           const char *test_type,
                           GError    **error)
{
    NMConnection *connection;
    GError       *local     = NULL;
    char         *unhandled = NULL;

    connection = nmtst_connection_from_file(filename, network_file, test_type, &unhandled, &local);

    g_assert(!connection);
    g_assert(local);
    g_assert(!unhandled);
    g_propagate_error(error, local);
}

static void
_writer_new_connection_reread(NMConnection  *connection,
                              const char    *ifcfg_dir,
                              char         **out_filename,
                              const char    *expected,
                              NMConnection **out_reread,
                              gboolean      *out_reread_same)
{
    gboolean                      success;
    GError                       *error        = NULL;
    gs_free char                 *filename     = NULL;
    gs_unref_object NMConnection *con_verified = NULL;
    gs_unref_object NMConnection *reread_copy  = NULL;
    NMConnection **reread = out_reread ?: ((nmtst_get_rand_uint32() % 2) ? &reread_copy : NULL);

    g_assert(NM_IS_CONNECTION(connection));
    g_assert(ifcfg_dir);

    con_verified = nmtst_connection_duplicate_and_normalize(connection);

    success = nms_ifcfg_rh_writer_write_connection(con_verified,
                                                   ifcfg_dir,
                                                   NULL,
                                                   NULL,
                                                   NULL,
                                                   &filename,
                                                   reread,
                                                   out_reread_same,
                                                   &error);
    nmtst_assert_success(success, error);
    g_assert(filename && filename[0]);

    if (reread)
        nmtst_assert_connection_verifies_without_normalization(*reread);

    _assert_expected_content(con_verified, filename, expected);

    if (out_filename)
        *out_filename = g_steal_pointer(&filename);
    else
        nmtst_file_unlink(filename);
}

static void
_writer_new_connec_exp(NMConnection *connection,
                       const char   *ifcfg_dir,
                       const char   *expected,
                       char        **out_filename)
{
    gs_unref_object NMConnection *reread      = NULL;
    gboolean                      reread_same = FALSE;

    _writer_new_connection_reread(connection,
                                  ifcfg_dir,
                                  out_filename,
                                  expected,
                                  &reread,
                                  &reread_same);
    _assert_reread_same(connection, reread);
    g_assert(reread_same);
}

static void
_writer_new_connection(NMConnection *connection, const char *ifcfg_dir, char **out_filename)
{
    _writer_new_connec_exp(connection, ifcfg_dir, NO_EXPECTED, out_filename);
}

static void
_writer_new_connection_FIXME(NMConnection *connection, const char *ifcfg_dir, char **out_filename)
{
    gs_unref_object NMConnection *reread      = NULL;
    gboolean                      reread_same = FALSE;

    /* FIXME: this should not happen. Fix it to use _writer_new_connection() instead. */

    _writer_new_connection_reread(connection,
                                  ifcfg_dir,
                                  out_filename,
                                  NO_EXPECTED,
                                  &reread,
                                  &reread_same);
    _assert_reread_same_FIXME(connection, reread);
    g_assert(!reread_same);
}

static void
_writer_new_connection_fail(NMConnection *connection, const char *ifcfg_dir, GError **error)
{
    gs_unref_object NMConnection *connection_normalized = NULL;
    gs_unref_object NMConnection *reread                = NULL;
    gboolean                      success;
    GError                       *local    = NULL;
    char                         *filename = NULL;

    g_assert(NM_IS_CONNECTION(connection));
    g_assert(ifcfg_dir);

    connection_normalized = nmtst_connection_duplicate_and_normalize(connection);

    success = nms_ifcfg_rh_writer_write_connection(connection_normalized,
                                                   ifcfg_dir,
                                                   NULL,
                                                   NULL,
                                                   NULL,
                                                   &filename,
                                                   &reread,
                                                   NULL,
                                                   &local);
    nmtst_assert_no_success(success, local);
    g_assert(!filename);
    g_assert(!reread);

    g_propagate_error(error, local);
}

/*****************************************************************************/

static void
test_read_netmask_1(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_free char                 *content    = NULL;
    NMSettingConnection          *s_con;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    NMIPAddress                  *ip4_addr;
    const char                   *FILENAME = TEST_IFCFG_DIR "/ifcfg-netmask-1";

    connection = _connection_from_file(FILENAME, NULL, TYPE_ETHERNET, NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "System netmask-1");

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert_cmpuint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 2);
    g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip4, 0), ==, "192.0.2.1");
    g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip4, 1), ==, "192.0.2.2#adfs.afddsaf");

    ip4_addr = nm_setting_ip_config_get_address(s_ip4, 0);
    g_assert(ip4_addr);
    g_assert_cmpstr(nm_ip_address_get_address(ip4_addr), ==, "102.0.2.2");
    g_assert_cmpint(nm_ip_address_get_prefix(ip4_addr), ==, 15);

    s_ip6 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_assert_cmpuint(nm_setting_ip_config_get_num_dns(s_ip6), ==, 2);
    g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip6, 0), ==, "1::2");
    g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip6, 1), ==, "1::3#dfdf.er");

    nmtst_assert_connection_verifies_without_normalization(connection);

    content = nmtst_file_get_contents(FILENAME);

    testfile = g_strdup(TEST_SCRATCH_DIR "/ifcfg-netmask-1.copy");

    nmtst_file_set_contents(testfile, content);

    _writer_update_connection(connection,
                              TEST_SCRATCH_DIR,
                              testfile,
                              TEST_IFCFG_DIR "/ifcfg-netmask-1.cexpected");
}

/*****************************************************************************/

static gboolean
verify_cert_or_key(NMSetting8021x *s_compare,
                   const char     *file,
                   const char     *privkey_password,
                   const char     *property)
{
    gs_unref_object NMSetting8021x *s_8021x  = NULL;
    GError                         *error    = NULL;
    gboolean                        success  = FALSE;
    const char                     *expected = NULL, *setting = NULL;
    gboolean                        phase2 = FALSE;
    NMSetting8021xCKScheme          scheme = NM_SETTING_802_1X_CK_SCHEME_UNKNOWN;

    if (strstr(property, "phase2"))
        phase2 = TRUE;

    s_8021x = (NMSetting8021x *) nm_setting_802_1x_new();

    /* Load the certificate into an empty setting */
    if (strstr(property, "ca-cert")) {
        if (phase2)
            success = nm_setting_802_1x_set_phase2_ca_cert(s_8021x,
                                                           file,
                                                           NM_SETTING_802_1X_CK_SCHEME_PATH,
                                                           NULL,
                                                           &error);
        else
            success = nm_setting_802_1x_set_ca_cert(s_8021x,
                                                    file,
                                                    NM_SETTING_802_1X_CK_SCHEME_PATH,
                                                    NULL,
                                                    &error);
    } else if (strstr(property, "client-cert")) {
        if (phase2)
            success = nm_setting_802_1x_set_phase2_client_cert(s_8021x,
                                                               file,
                                                               NM_SETTING_802_1X_CK_SCHEME_PATH,
                                                               NULL,
                                                               &error);
        else
            success = nm_setting_802_1x_set_client_cert(s_8021x,
                                                        file,
                                                        NM_SETTING_802_1X_CK_SCHEME_PATH,
                                                        NULL,
                                                        &error);
    } else if (strstr(property, "private-key")) {
        if (phase2)
            success = nm_setting_802_1x_set_phase2_private_key(s_8021x,
                                                               file,
                                                               privkey_password,
                                                               NM_SETTING_802_1X_CK_SCHEME_PATH,
                                                               NULL,
                                                               &error);
        else
            success = nm_setting_802_1x_set_private_key(s_8021x,
                                                        file,
                                                        privkey_password,
                                                        NM_SETTING_802_1X_CK_SCHEME_PATH,
                                                        NULL,
                                                        &error);
    }
    g_assert_no_error(error);
    g_assert_cmpint(success, ==, TRUE);

    /* Ensure it was loaded using the PATH scheme */
    if (strstr(property, "ca-cert")) {
        if (phase2)
            scheme = nm_setting_802_1x_get_phase2_ca_cert_scheme(s_8021x);
        else
            scheme = nm_setting_802_1x_get_ca_cert_scheme(s_8021x);
    } else if (strstr(property, "client-cert")) {
        if (phase2)
            scheme = nm_setting_802_1x_get_phase2_client_cert_scheme(s_8021x);
        else
            scheme = nm_setting_802_1x_get_client_cert_scheme(s_8021x);
    } else if (strstr(property, "private-key")) {
        if (phase2)
            scheme = nm_setting_802_1x_get_phase2_private_key_scheme(s_8021x);
        else
            scheme = nm_setting_802_1x_get_private_key_scheme(s_8021x);
    }
    g_assert_cmpint(scheme, ==, NM_SETTING_802_1X_CK_SCHEME_PATH);

    /* Grab the path back out */
    if (strstr(property, "ca-cert")) {
        if (phase2)
            expected = nm_setting_802_1x_get_phase2_ca_cert_path(s_8021x);
        else
            expected = nm_setting_802_1x_get_ca_cert_path(s_8021x);
    } else if (strstr(property, "client-cert")) {
        if (phase2)
            expected = nm_setting_802_1x_get_phase2_client_cert_path(s_8021x);
        else
            expected = nm_setting_802_1x_get_client_cert_path(s_8021x);
    } else if (strstr(property, "private-key")) {
        if (phase2)
            expected = nm_setting_802_1x_get_phase2_private_key_path(s_8021x);
        else
            expected = nm_setting_802_1x_get_private_key_path(s_8021x);
    }
    g_assert_cmpstr(expected, ==, file);

    /* Compare the path with the expected path from the real setting */
    if (strstr(property, "ca-cert")) {
        if (phase2)
            setting = nm_setting_802_1x_get_phase2_ca_cert_path(s_compare);
        else
            setting = nm_setting_802_1x_get_ca_cert_path(s_compare);
    } else if (strstr(property, "client-cert")) {
        if (phase2)
            setting = nm_setting_802_1x_get_phase2_client_cert_path(s_compare);
        else
            setting = nm_setting_802_1x_get_client_cert_path(s_compare);
    } else if (strstr(property, "private-key")) {
        if (phase2)
            setting = nm_setting_802_1x_get_phase2_private_key_path(s_compare);
        else
            setting = nm_setting_802_1x_get_private_key_path(s_compare);
    }
    g_assert_cmpstr(setting, ==, expected);
    return TRUE;
}

static void
test_read_basic(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingWired               *s_wired;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    const char                   *mac;
    char expected_mac_address[ETH_ALEN] = {0x00, 0x16, 0x41, 0x11, 0x22, 0x33};

    connection =
        _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-minimal", NULL, TYPE_ETHERNET, NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "System test-minimal");
    g_assert_cmpint(nm_setting_connection_get_timestamp(s_con), ==, 0);
    g_assert(nm_setting_connection_get_autoconnect(s_con));
    g_assert_cmpint(nm_setting_connection_get_autoconnect_retries(s_con), ==, -1);

    /* UUID can't be tested if the ifcfg does not contain the UUID key, because
     * the UUID is generated on the full path of the ifcfg file, which can change
     * depending on where the tests are run.
     */

    s_wired = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);
    g_assert_cmpint(nm_setting_wired_get_mtu(s_wired), ==, 0);

    mac = nm_setting_wired_get_mac_address(s_wired);
    g_assert(mac);
    g_assert(nm_utils_hwaddr_matches(mac, -1, expected_mac_address, ETH_ALEN));

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
                    ==,
                    NM_SETTING_IP4_CONFIG_METHOD_DISABLED);
    g_assert(nm_setting_ip_config_get_never_default(s_ip4) == FALSE);

    s_ip6 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6),
                    ==,
                    NM_SETTING_IP6_CONFIG_METHOD_IGNORE);
    g_assert(nm_setting_ip_config_get_never_default(s_ip6) == FALSE);
}

static void
test_read_miscellaneous_variables(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingWired               *s_wired;
    NMSettingIPConfig            *s_ip4;
    char                         *expected_mac_blacklist[3] = {"00:16:41:11:22:88",
                                                               "00:16:41:11:22:99",
                                                               "6a:5d:5a:fa:dd:f0"};
    int                           mac_blacklist_num, i;
    guint64                       expected_timestamp = 0;

    NMTST_EXPECT_NM_WARN("*invalid MAC in HWADDR_BLACKLIST 'XX:aa:invalid'*");
    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-misc-variables",
                                       NULL,
                                       TYPE_ETHERNET,
                                       NULL);
    g_test_assert_expected_messages();

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpint(nm_setting_connection_get_timestamp(s_con), ==, expected_timestamp);
    g_assert(nm_setting_connection_get_autoconnect(s_con));
    g_assert_cmpint(nm_setting_connection_get_autoconnect_retries(s_con), ==, 100);

    s_wired = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);
    g_assert_cmpint(nm_setting_wired_get_mtu(s_wired), ==, 0);

    mac_blacklist_num = nm_setting_wired_get_num_mac_blacklist_items(s_wired);
    g_assert_cmpint(mac_blacklist_num, ==, 3);
    for (i = 0; i < mac_blacklist_num; i++)
        g_assert(nm_utils_hwaddr_matches(nm_setting_wired_get_mac_blacklist_item(s_wired, i),
                                         -1,
                                         expected_mac_blacklist[i],
                                         -1));

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
                    ==,
                    NM_SETTING_IP4_CONFIG_METHOD_DISABLED);
    g_assert(nm_setting_ip_config_get_never_default(s_ip4) == FALSE);
}

static void
test_read_variables_corner_cases(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingWired               *s_wired;
    NMSettingIPConfig            *s_ip4;
    const char                   *mac;
    char expected_mac_address[ETH_ALEN] = {0x00, 0x16, 0x41, 0x11, 0x22, 0x33};

    NMTST_EXPECT_NM_WARN("*key NAME is badly quoted and is treated as \"\"*");
    NMTST_EXPECT_NM_WARN("*key ZONE is badly quoted and is treated as \"\"*");
    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-variables-corner-cases-1",
                                       NULL,
                                       TYPE_ETHERNET,
                                       NULL);
    g_test_assert_expected_messages();

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con),
                    ==,
                    "System test-variables-corner-cases-1");
    g_assert_cmpstr(nm_setting_connection_get_zone(s_con), ==, NULL);
    g_assert_cmpint(nm_setting_connection_get_timestamp(s_con), ==, 0);
    g_assert(nm_setting_connection_get_autoconnect(s_con));

    s_wired = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);
    g_assert_cmpint(nm_setting_wired_get_mtu(s_wired), ==, 0);

    mac = nm_setting_wired_get_mac_address(s_wired);
    g_assert(mac);
    g_assert(nm_utils_hwaddr_matches(mac, -1, expected_mac_address, ETH_ALEN));

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
                    ==,
                    NM_SETTING_IP4_CONFIG_METHOD_DISABLED);
    g_assert(nm_setting_ip_config_get_never_default(s_ip4) == FALSE);
}

static void
test_read_unmanaged(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    gs_free char                 *unhandled_spec     = NULL;
    guint64                       expected_timestamp = 0;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-nm-controlled",
                                       NULL,
                                       TYPE_ETHERNET,
                                       &unhandled_spec);
    g_assert_cmpstr(unhandled_spec, ==, "unmanaged:mac:00:11:22:33:f8:9f");

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "System test-nm-controlled");
    g_assert_cmpint(nm_setting_connection_get_timestamp(s_con), ==, expected_timestamp);
    g_assert(nm_setting_connection_get_autoconnect(s_con));
}

static void
test_read_unmanaged_unrecognized(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    gs_free char                 *unhandled_spec     = NULL;
    guint64                       expected_timestamp = 0;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-nm-controlled-unrecognized",
                                       NULL,
                                       NULL,
                                       &unhandled_spec);
    g_assert_cmpstr(unhandled_spec, ==, "unmanaged:interface-name:=ipoac0");

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "PigeonNet");
    g_assert_cmpint(nm_setting_connection_get_timestamp(s_con), ==, expected_timestamp);
}

static void
test_read_unrecognized(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    gs_free char                 *unhandled_spec     = NULL;
    guint64                       expected_timestamp = 0;

    NMTST_EXPECT_NM_WARN("*key NAME is badly quoted and is treated as \"\"*");
    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-unrecognized",
                                       NULL,
                                       NULL,
                                       &unhandled_spec);
    g_test_assert_expected_messages();
    g_assert_cmpstr(unhandled_spec, ==, "unrecognized:mac:00:11:22:33");

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "System test-unrecognized");
    g_assert_cmpint(nm_setting_connection_get_timestamp(s_con), ==, expected_timestamp);
}

static void
test_read_wired_static(gconstpointer test_data)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingWired               *s_wired;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    char                         *unmanaged = NULL;
    const char                   *mac;
    char         expected_mac_address[ETH_ALEN] = {0x00, 0x11, 0x22, 0x33, 0x44, 0xee};
    NMIPAddress *ip4_addr;
    NMIPAddress *ip6_addr;
    const char  *file, *expected_id;
    gpointer     expect_ip6_p;

    nmtst_test_data_unpack(test_data, &file, &expected_id, &expect_ip6_p);

    g_assert(expected_id);

    connection = _connection_from_file(file, NULL, TYPE_ETHERNET, &unmanaged);
    g_assert_cmpstr(unmanaged, ==, NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, expected_id);
    g_assert_cmpint(nm_setting_connection_get_timestamp(s_con), ==, 0);
    g_assert(nm_setting_connection_get_autoconnect(s_con));

    s_wired = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);
    g_assert_cmpint(nm_setting_wired_get_mtu(s_wired), ==, 1492);

    mac = nm_setting_wired_get_mac_address(s_wired);
    g_assert(mac);
    g_assert(nm_utils_hwaddr_matches(mac, -1, expected_mac_address, ETH_ALEN));

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
                    ==,
                    NM_SETTING_IP4_CONFIG_METHOD_MANUAL);
    g_assert(nm_setting_ip_config_get_may_fail(s_ip4));

    g_assert(nm_setting_ip_config_has_dns_options(s_ip4));
    g_assert_cmpint(nm_setting_ip_config_get_num_dns_options(s_ip4), ==, 0);

    g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 2);
    g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip4, 0), ==, "4.2.2.1");
    g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip4, 1), ==, "4.2.2.2");

    g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip4), ==, 1);
    ip4_addr = nm_setting_ip_config_get_address(s_ip4, 0);
    g_assert(ip4_addr);
    g_assert_cmpint(nm_ip_address_get_prefix(ip4_addr), ==, 24);
    g_assert_cmpstr(nm_ip_address_get_address(ip4_addr), ==, "192.168.1.5");

    g_assert_cmpstr(nm_setting_ip_config_get_gateway(s_ip4), ==, "192.168.1.1");

    s_ip6 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    if (GPOINTER_TO_INT(expect_ip6_p)) {
        g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6),
                        ==,
                        NM_SETTING_IP6_CONFIG_METHOD_MANUAL);
        g_assert(nm_setting_ip_config_get_may_fail(s_ip6));

        g_assert(nm_setting_ip_config_has_dns_options(s_ip6));
        g_assert_cmpint(nm_setting_ip_config_get_num_dns_options(s_ip6), ==, 0);

        /* DNS Addresses */
        g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip6), ==, 2);
        g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip6, 0), ==, "1:2:3:4::a");
        g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip6, 1), ==, "1:2:3:4::b");

        /* IP addresses */
        g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip6), ==, 2);

        ip6_addr = nm_setting_ip_config_get_address(s_ip6, 0);
        g_assert(ip6_addr);
        g_assert_cmpint(nm_ip_address_get_prefix(ip6_addr), ==, 64);
        g_assert_cmpstr(nm_ip_address_get_address(ip6_addr), ==, "dead:beaf::1");

        ip6_addr = nm_setting_ip_config_get_address(s_ip6, 1);
        g_assert(ip6_addr);
        g_assert_cmpint(nm_ip_address_get_prefix(ip6_addr), ==, 56);
        g_assert_cmpstr(nm_ip_address_get_address(ip6_addr), ==, "dead:beaf::2");
    } else {
        g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6),
                        ==,
                        NM_SETTING_IP6_CONFIG_METHOD_IGNORE);
        g_assert(!nm_setting_ip_config_has_dns_options(s_ip6));
    }
}

static void
test_read_wired_static_no_prefix(gconstpointer user_data)
{
    guint32                       expected_prefix = GPOINTER_TO_UINT(user_data);
    gs_unref_object NMConnection *connection      = NULL;
    NMSettingConnection          *s_con;
    NMSettingIPConfig            *s_ip4;
    NMIPAddress                  *ip4_addr;
    gs_free char                 *file        = NULL;
    gs_free char                 *expected_id = NULL;

    file = g_strdup_printf(TEST_IFCFG_DIR "/ifcfg-test-wired-static-no-prefix-%u", expected_prefix);
    expected_id = g_strdup_printf("System test-wired-static-no-prefix-%u", expected_prefix);

    NMTST_EXPECT_NM_WARN("*missing PREFIX, assuming*");
    connection = _connection_from_file(file, NULL, TYPE_ETHERNET, NULL);
    g_test_assert_expected_messages();

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, expected_id);

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
                    ==,
                    NM_SETTING_IP4_CONFIG_METHOD_MANUAL);

    g_assert(!nm_setting_ip_config_has_dns_options(s_ip4));
    g_assert_cmpint(nm_setting_ip_config_get_num_dns_options(s_ip4), ==, 0);

    g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip4), ==, 1);
    ip4_addr = nm_setting_ip_config_get_address(s_ip4, 0);
    g_assert(ip4_addr);
    g_assert_cmpint(nm_ip_address_get_prefix(ip4_addr), ==, expected_prefix);
}

static void
test_read_wired_dhcp(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingWired               *s_wired;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    char                         *unmanaged    = NULL;
    char        expected_mac_address[ETH_ALEN] = {0x00, 0x11, 0x22, 0x33, 0x44, 0xee};
    const char *mac;

    NMTST_EXPECT_NM_WARN("*key IPV6INIT is duplicated and the early occurrence ignored*");
    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wired-dhcp",
                                       NULL,
                                       TYPE_ETHERNET,
                                       &unmanaged);
    g_test_assert_expected_messages();
    g_assert(unmanaged == NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "System test-wired-dhcp");
    g_assert_cmpuint(nm_setting_connection_get_timestamp(s_con), ==, 0);
    g_assert(nm_setting_connection_get_autoconnect(s_con));

    s_wired = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);

    mac = nm_setting_wired_get_mac_address(s_wired);
    g_assert(mac);
    g_assert(nm_utils_hwaddr_matches(mac, -1, expected_mac_address, sizeof(expected_mac_address)));

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);
    g_assert_cmpstr(nm_setting_ip4_config_get_dhcp_fqdn(NM_SETTING_IP4_CONFIG(s_ip4)),
                    ==,
                    "foo.bar");
    g_assert(nm_setting_ip_config_get_ignore_auto_dns(s_ip4));
    g_assert_cmpuint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 2);
    g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip4, 0), ==, "4.2.2.1");
    g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip4, 1), ==, "4.2.2.2");
    g_assert_cmpuint(nm_setting_ip_config_get_dhcp_hostname_flags(s_ip4),
                     ==,
                     NM_DHCP_HOSTNAME_FLAG_FQDN_ENCODED | NM_DHCP_HOSTNAME_FLAG_FQDN_NO_UPDATE);

    s_ip6 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_DHCP);
    g_assert_cmpstr(nm_setting_ip_config_get_dhcp_hostname(s_ip6), ==, "foo.bar");
    g_assert_cmpuint(nm_setting_ip_config_get_dhcp_hostname_flags(s_ip6),
                     ==,
                     NM_DHCP_HOSTNAME_FLAG_FQDN_CLEAR_FLAGS);
}

static void
test_read_wired_dhcp_plus_ip(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    NMIPAddress                  *ip4_addr;
    NMIPAddress                  *ip6_addr;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wired-dhcp-plus-ip",
                                       NULL,
                                       TYPE_ETHERNET,
                                       NULL);

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);
    g_assert(nm_setting_ip_config_get_may_fail(s_ip4));

    /* DNS Addresses */
    g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 2);
    g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip4, 0), ==, "4.2.2.1");
    g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip4, 1), ==, "4.2.2.2");

    /* IP addresses */
    g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip4), ==, 2);
    ip4_addr = nm_setting_ip_config_get_address(s_ip4, 0);
    g_assert(ip4_addr);
    g_assert_cmpint(nm_ip_address_get_prefix(ip4_addr), ==, 24);
    g_assert_cmpstr(nm_ip_address_get_address(ip4_addr), ==, "1.2.3.4");

    /* Gateway */
    g_assert_cmpstr(nm_setting_ip_config_get_gateway(s_ip4), ==, "1.1.1.1");

    ip4_addr = nm_setting_ip_config_get_address(s_ip4, 1);
    g_assert(ip4_addr);
    g_assert_cmpint(nm_ip_address_get_prefix(ip4_addr), ==, 16);
    g_assert_cmpstr(nm_ip_address_get_address(ip4_addr), ==, "9.8.7.6");

    s_ip6 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO);
    g_assert(nm_setting_ip_config_get_may_fail(s_ip6));

    /* DNS Addresses */
    g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip6), ==, 2);
    g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip6, 0), ==, "1:2:3:4::a");
    g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip6, 1), ==, "1:2:3:4::b");

    /* IP addresses */
    g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip6), ==, 3);
    ip6_addr = nm_setting_ip_config_get_address(s_ip6, 0);
    g_assert(ip6_addr);
    g_assert_cmpint(nm_ip_address_get_prefix(ip6_addr), ==, 56);
    g_assert_cmpstr(nm_ip_address_get_address(ip6_addr), ==, "1001:abba::1234");

    ip6_addr = nm_setting_ip_config_get_address(s_ip6, 1);
    g_assert(ip6_addr);
    g_assert_cmpint(nm_ip_address_get_prefix(ip6_addr), ==, 64);
    g_assert_cmpstr(nm_ip_address_get_address(ip6_addr), ==, "2001:abba::2234");

    ip6_addr = nm_setting_ip_config_get_address(s_ip6, 2);
    g_assert(ip6_addr);
    g_assert_cmpint(nm_ip_address_get_prefix(ip6_addr), ==, 96);
    g_assert_cmpstr(nm_ip_address_get_address(ip6_addr), ==, "3001:abba::3234");
}

static void
test_read_wired_shared_plus_ip(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingIPConfig            *s_ip4;
    NMIPAddress                  *ip4_addr;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wired-shared-plus-ip",
                                       NULL,
                                       TYPE_ETHERNET,
                                       NULL);

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
                    ==,
                    NM_SETTING_IP4_CONFIG_METHOD_SHARED);
    g_assert(nm_setting_ip_config_get_may_fail(s_ip4));

    /* IP addresses */
    g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip4), ==, 1);
    ip4_addr = nm_setting_ip_config_get_address(s_ip4, 0);
    g_assert(ip4_addr);
    g_assert_cmpint(nm_ip_address_get_prefix(ip4_addr), ==, 24);
    g_assert_cmpstr(nm_ip_address_get_address(ip4_addr), ==, "10.20.30.5");

    /* Gateway */
    g_assert_cmpstr(nm_setting_ip_config_get_gateway(s_ip4), ==, "1.1.1.1");
}

static void
test_read_wired_global_gateway(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingIPConfig            *s_ip4;
    NMIPAddress                  *ip4_addr;
    char                         *unmanaged = NULL;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wired-global-gateway",
                                       TEST_IFCFG_DIR "/network-test-wired-global-gateway",
                                       TYPE_ETHERNET,
                                       &unmanaged);
    g_assert(unmanaged == NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "System test-wired-global-gateway");

    nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
                    ==,
                    NM_SETTING_IP4_CONFIG_METHOD_MANUAL);

    /* Address #1 */
    ip4_addr = nm_setting_ip_config_get_address(s_ip4, 0);
    g_assert(ip4_addr);
    g_assert_cmpint(nm_ip_address_get_prefix(ip4_addr), ==, 24);
    g_assert_cmpstr(nm_ip_address_get_address(ip4_addr), ==, "192.168.1.5");

    /* Gateway */
    g_assert_cmpstr(nm_setting_ip_config_get_gateway(s_ip4), ==, "192.168.1.2");
}

/* Ignore GATEWAY from /etc/sysconfig/network for automatic connections */
static void
test_read_wired_global_gateway_ignore(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingIPConfig            *s_ip4;
    char                         *unmanaged = NULL;

    NMTST_EXPECT_NM_WARN("*ignoring GATEWAY (/etc/sysconfig/network) for * because the connection "
                         "has no static addresses");
    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wired-global-gateway-ignore",
                                       TEST_IFCFG_DIR "/network-test-wired-global-gateway-ignore",
                                       TYPE_ETHERNET,
                                       &unmanaged);
    g_test_assert_expected_messages();
    g_assert(unmanaged == NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con),
                    ==,
                    "System test-wired-global-gateway-ignore");

    nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);

    /* Addresses */
    g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip4), ==, 0);

    /* Gateway */
    g_assert_cmpstr(nm_setting_ip_config_get_gateway(s_ip4), ==, NULL);
}

static void
test_read_wired_obsolete_gateway_n(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingIPConfig            *s_ip4;
    NMIPAddress                  *ip4_addr;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wired-obsolete-gateway-n",
                                       NULL,
                                       TYPE_ETHERNET,
                                       NULL);

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
                    ==,
                    NM_SETTING_IP4_CONFIG_METHOD_MANUAL);

    /* IP addresses */
    g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip4), ==, 1);
    ip4_addr = nm_setting_ip_config_get_address(s_ip4, 0);
    g_assert(ip4_addr);
    g_assert_cmpint(nm_ip_address_get_prefix(ip4_addr), ==, 24);
    g_assert_cmpstr(nm_ip_address_get_address(ip4_addr), ==, "1.2.3.4");

    /* Gateway */
    g_assert_cmpstr(nm_setting_ip_config_get_gateway(s_ip4), ==, "1.1.1.1");
}

static void
test_user_1(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingUser                *s_user;

    connection =
        nmtst_create_minimal_connection("Test User 1", NULL, NM_SETTING_WIRED_SETTING_NAME, NULL);

    s_user = _nm_connection_new_setting(connection, NM_TYPE_SETTING_USER);

#define _USER_SET_DATA(s_user, key, val)                                      \
    G_STMT_START                                                              \
    {                                                                         \
        GError  *_error = NULL;                                               \
        gboolean _success;                                                    \
                                                                              \
        _success = nm_setting_user_set_data((s_user), (key), (val), &_error); \
        nmtst_assert_success(_success, _error);                               \
    }                                                                         \
    G_STMT_END

#define _USER_SET_DATA_X(s_user, key) _USER_SET_DATA(s_user, key, "val=" key "")

    _USER_SET_DATA(s_user, "my.val1", "");
    _USER_SET_DATA_X(s_user, "my.val2");
    _USER_SET_DATA_X(s_user, "my.v__al3");
    _USER_SET_DATA_X(s_user, "my._v");
    _USER_SET_DATA_X(s_user, "my.v+");
    _USER_SET_DATA_X(s_user, "my.Av");
    _USER_SET_DATA_X(s_user, "MY.AV");
    _USER_SET_DATA_X(s_user, "MY.8V");
    _USER_SET_DATA_X(s_user, "MY.8-V");
    _USER_SET_DATA_X(s_user, "MY.8_V");
    _USER_SET_DATA_X(s_user, "MY.8+V");
    _USER_SET_DATA_X(s_user, "MY.8/V");
    _USER_SET_DATA_X(s_user, "MY.8=V");
    _USER_SET_DATA_X(s_user, "MY.-");
    _USER_SET_DATA_X(s_user, "MY._");
    _USER_SET_DATA_X(s_user, "MY.+");
    _USER_SET_DATA_X(s_user, "MY./");
    _USER_SET_DATA_X(s_user, "MY.=");
    _USER_SET_DATA_X(s_user, "my.keys.1");
    _USER_SET_DATA_X(s_user, "my.other.KEY.42");

    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR,
                           TEST_IFCFG_DIR "/ifcfg-Test_User_1.cexpected",
                           &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_read_wired_never_default(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wired-never-default",
                                       TEST_IFCFG_DIR "/network-test-wired-never-default",
                                       TYPE_ETHERNET,
                                       NULL);

    nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);
    g_assert(nm_setting_ip_config_get_never_default(s_ip4));
    g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 0);

    s_ip6 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO);
    g_assert(nm_setting_ip_config_get_never_default(s_ip6));
}

static void
test_read_wired_defroute_no(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    char                         *unmanaged = NULL;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wired-defroute-no",
                                       NULL,
                                       TYPE_ETHERNET,
                                       &unmanaged);
    g_assert(unmanaged == NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "System test-wired-defroute-no");

    nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);
    g_assert(nm_setting_ip_config_get_never_default(s_ip4));

    s_ip6 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO);
    g_assert(nm_setting_ip_config_get_never_default(s_ip6));
}

static void
test_read_wired_defroute_no_gatewaydev_yes(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    char                         *unmanaged = NULL;

    connection =
        _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wired-defroute-no-gatewaydev-yes",
                              TEST_IFCFG_DIR "/network-test-wired-defroute-no-gatewaydev-yes",
                              TYPE_ETHERNET,
                              &unmanaged);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con),
                    ==,
                    "System test-wired-defroute-no-gatewaydev-yes");

    nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);
    g_assert(nm_setting_ip_config_get_never_default(s_ip4) == FALSE);

    s_ip6 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO);
    g_assert(nm_setting_ip_config_get_never_default(s_ip6) == FALSE);
}

static void
test_read_wired_static_routes(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingIPConfig            *s_ip4;
    NMIPRoute                    *ip4_route;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wired-static-routes",
                                       NULL,
                                       TYPE_ETHERNET,
                                       NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "System test-wired-static-routes");

    nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
                    ==,
                    NM_SETTING_IP4_CONFIG_METHOD_MANUAL);

    g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip4), ==, 4);

    ip4_route = nm_setting_ip_config_get_route(s_ip4, 0);
    g_assert(ip4_route);
    g_assert_cmpstr(nm_ip_route_get_dest(ip4_route), ==, "11.22.33.0");
    g_assert_cmpint(nm_ip_route_get_prefix(ip4_route), ==, 24);
    g_assert_cmpstr(nm_ip_route_get_next_hop(ip4_route), ==, "192.168.1.5");
    g_assert_cmpint(nm_ip_route_get_metric(ip4_route), ==, -1);

    ip4_route = nm_setting_ip_config_get_route(s_ip4, 1);
    g_assert(ip4_route);
    g_assert_cmpstr(nm_ip_route_get_dest(ip4_route), ==, "44.55.66.77");
    g_assert_cmpint(nm_ip_route_get_prefix(ip4_route), ==, 32);
    g_assert_cmpstr(nm_ip_route_get_next_hop(ip4_route), ==, "192.168.1.7");
    g_assert_cmpint(nm_ip_route_get_metric(ip4_route), ==, 3);
    nmtst_assert_route_attribute_uint32(ip4_route, NM_IP_ROUTE_ATTRIBUTE_ADVMSS, 1300);
    nmtst_assert_route_attribute_byte(ip4_route, NM_IP_ROUTE_ATTRIBUTE_TOS, 0x28);
    nmtst_assert_route_attribute_uint32(ip4_route, NM_IP_ROUTE_ATTRIBUTE_WINDOW, 30000);
    nmtst_assert_route_attribute_uint32(ip4_route, NM_IP_ROUTE_ATTRIBUTE_CWND, 12);
    nmtst_assert_route_attribute_uint32(ip4_route, NM_IP_ROUTE_ATTRIBUTE_WEIGHT, 5);
    nmtst_assert_route_attribute_uint32(ip4_route, NM_IP_ROUTE_ATTRIBUTE_INITCWND, 13);
    nmtst_assert_route_attribute_uint32(ip4_route, NM_IP_ROUTE_ATTRIBUTE_INITRWND, 14);
    nmtst_assert_route_attribute_uint32(ip4_route, NM_IP_ROUTE_ATTRIBUTE_MTU, 9000);
    nmtst_assert_route_attribute_boolean(ip4_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, TRUE);
    nmtst_assert_route_attribute_boolean(ip4_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, TRUE);
    nmtst_assert_route_attribute_uint32(ip4_route, NM_IP_ROUTE_ATTRIBUTE_RTO_MIN, 300);
    nmtst_assert_route_attribute_boolean(ip4_route, NM_IP_ROUTE_ATTRIBUTE_QUICKACK, TRUE);
    nmtst_assert_route_attribute_string(ip4_route, NM_IP_ROUTE_ATTRIBUTE_SRC, "1.1.1.1");
    nmtst_assert_route_attribute_byte(ip4_route, NM_IP_ROUTE_ATTRIBUTE_SCOPE, 10);

    ip4_route = nm_setting_ip_config_get_route(s_ip4, 2);
    g_assert(ip4_route);
    g_assert_cmpstr(nm_ip_route_get_dest(ip4_route), ==, "44.55.66.78");
    g_assert_cmpint(nm_ip_route_get_prefix(ip4_route), ==, 32);
    g_assert_cmpstr(nm_ip_route_get_next_hop(ip4_route), ==, "192.168.1.8");
    g_assert_cmpint(nm_ip_route_get_metric(ip4_route), ==, 3);
    nmtst_assert_route_attribute_byte(ip4_route, NM_IP_ROUTE_ATTRIBUTE_TOS, 0x28);
    nmtst_assert_route_attribute_uint32(ip4_route, NM_IP_ROUTE_ATTRIBUTE_WINDOW, 30000);
    nmtst_assert_route_attribute_uint32(ip4_route, NM_IP_ROUTE_ATTRIBUTE_CWND, 12);
    nmtst_assert_route_attribute_uint32(ip4_route, NM_IP_ROUTE_ATTRIBUTE_INITCWND, 13);
    nmtst_assert_route_attribute_uint32(ip4_route, NM_IP_ROUTE_ATTRIBUTE_INITRWND, 14);
    nmtst_assert_route_attribute_uint32(ip4_route, NM_IP_ROUTE_ATTRIBUTE_MTU, 9000);
    nmtst_assert_route_attribute_boolean(ip4_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, TRUE);
    nmtst_assert_route_attribute_boolean(ip4_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, TRUE);
    nmtst_assert_route_attribute_string(ip4_route, NM_IP_ROUTE_ATTRIBUTE_SRC, "1.1.1.1");
    nmtst_assert_route_attribute_boolean(ip4_route, NM_IP_ROUTE_ATTRIBUTE_ONLINK, TRUE);
    nmtst_assert_route_attribute_byte(ip4_route, NM_IP_ROUTE_ATTRIBUTE_SCOPE, 253);

    ip4_route = nm_setting_ip_config_get_route(s_ip4, 3);
    g_assert(ip4_route);
    g_assert_cmpstr(nm_ip_route_get_dest(ip4_route), ==, "1.2.3.4");
    g_assert_cmpint(nm_ip_route_get_prefix(ip4_route), ==, 32);
    nmtst_assert_route_attribute_string(ip4_route, NM_IP_ROUTE_ATTRIBUTE_TYPE, "local");
    nmtst_assert_route_attribute_byte(ip4_route, NM_IP_ROUTE_ATTRIBUTE_SCOPE, 254);

    g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 2);
    g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip4, 0), ==, "4.2.2.1");
    g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip4, 1), ==, "4.2.2.2#dns.name");
}

static void
test_read_wired_static_routes_legacy(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingIPConfig            *s_ip4;
    char                         *unmanaged = NULL;
    NMIPRoute                    *ip4_route;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wired-static-routes-legacy",
                                       NULL,
                                       TYPE_ETHERNET,
                                       &unmanaged);
    g_assert(!unmanaged);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con),
                    ==,
                    "System test-wired-static-routes-legacy");

    nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
                    ==,
                    NM_SETTING_IP4_CONFIG_METHOD_MANUAL);

    g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip4), ==, 5);

    /* Route #1 */
    ip4_route = nm_setting_ip_config_get_route(s_ip4, 0);
    g_assert(ip4_route != NULL);
    g_assert_cmpstr(nm_ip_route_get_dest(ip4_route), ==, "21.31.41.0");
    g_assert_cmpint(nm_ip_route_get_prefix(ip4_route), ==, 24);
    g_assert_cmpstr(nm_ip_route_get_next_hop(ip4_route), ==, "9.9.9.9");
    g_assert_cmpint(nm_ip_route_get_metric(ip4_route), ==, 1);

    /* Route #2 */
    ip4_route = nm_setting_ip_config_get_route(s_ip4, 1);
    g_assert(ip4_route != NULL);
    g_assert_cmpstr(nm_ip_route_get_dest(ip4_route), ==, "32.42.52.62");
    g_assert_cmpint(nm_ip_route_get_prefix(ip4_route), ==, 32);
    g_assert_cmpstr(nm_ip_route_get_next_hop(ip4_route), ==, "8.8.8.8");
    g_assert_cmpint(nm_ip_route_get_metric(ip4_route), ==, -1);

    /* Route #3 */
    ip4_route = nm_setting_ip_config_get_route(s_ip4, 2);
    g_assert(ip4_route != NULL);
    g_assert_cmpstr(nm_ip_route_get_dest(ip4_route), ==, "43.53.0.0");
    g_assert_cmpint(nm_ip_route_get_prefix(ip4_route), ==, 16);
    g_assert_cmpstr(nm_ip_route_get_next_hop(ip4_route), ==, "7.7.7.7");
    g_assert_cmpint(nm_ip_route_get_metric(ip4_route), ==, 3);
    nmtst_assert_route_attribute_uint32(ip4_route, NM_IP_ROUTE_ATTRIBUTE_WINDOW, 10000);
    nmtst_assert_route_attribute_uint32(ip4_route, NM_IP_ROUTE_ATTRIBUTE_CWND, 14);
    nmtst_assert_route_attribute_uint32(ip4_route, NM_IP_ROUTE_ATTRIBUTE_INITCWND, 42);
    nmtst_assert_route_attribute_uint32(ip4_route, NM_IP_ROUTE_ATTRIBUTE_INITRWND, 20);
    nmtst_assert_route_attribute_uint32(ip4_route, NM_IP_ROUTE_ATTRIBUTE_MTU, 9000);
    nmtst_assert_route_attribute_boolean(ip4_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_WINDOW, TRUE);
    nmtst_assert_route_attribute_boolean(ip4_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, TRUE);
    nmtst_assert_route_attribute_string(ip4_route, NM_IP_ROUTE_ATTRIBUTE_SRC, "1.2.3.4");

    ip4_route = nm_setting_ip_config_get_route(s_ip4, 3);
    g_assert(ip4_route != NULL);
    g_assert_cmpstr(nm_ip_route_get_dest(ip4_route), ==, "7.7.7.8");
    g_assert_cmpint(nm_ip_route_get_prefix(ip4_route), ==, 32);
    g_assert_cmpstr(nm_ip_route_get_next_hop(ip4_route), ==, NULL);
    g_assert_cmpint(nm_ip_route_get_metric(ip4_route), ==, 18);

    /* Route #5 */
    ip4_route = nm_setting_ip_config_get_route(s_ip4, 4);
    g_assert(ip4_route != NULL);
    g_assert_cmpstr(nm_ip_route_get_dest(ip4_route), ==, "1.2.3.4");
    nmtst_assert_route_attribute_string(ip4_route, NM_IP_ROUTE_ATTRIBUTE_TYPE, "local");
}

static void
test_read_wired_ipv4_manual(gconstpointer data)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingIPConfig            *s_ip4;
    char                         *unmanaged = NULL;
    NMIPAddress                  *ip4_addr;
    const char                   *file, *expected_id;

    nmtst_test_data_unpack(data, &file, &expected_id);

    g_assert(expected_id);

    connection = _connection_from_file(file, NULL, TYPE_ETHERNET, &unmanaged);
    g_assert(!unmanaged);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, expected_id);

    nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
                    ==,
                    NM_SETTING_IP4_CONFIG_METHOD_MANUAL);
    g_assert_cmpint(nm_setting_ip_config_get_dad_timeout(s_ip4), ==, 2000);

    /* IP addresses */
    g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip4), ==, 3);

    /* Address #1 */
    ip4_addr = nm_setting_ip_config_get_address(s_ip4, 0);
    g_assert(ip4_addr != NULL);
    g_assert_cmpstr(nm_ip_address_get_address(ip4_addr), ==, "1.2.3.4");
    g_assert_cmpint(nm_ip_address_get_prefix(ip4_addr), ==, 24);

    /* Address #2 */
    ip4_addr = nm_setting_ip_config_get_address(s_ip4, 1);
    g_assert(ip4_addr != NULL);
    g_assert_cmpstr(nm_ip_address_get_address(ip4_addr), ==, "9.8.7.6");
    g_assert_cmpint(nm_ip_address_get_prefix(ip4_addr), ==, 16);

    /* Address #3 */
    ip4_addr = nm_setting_ip_config_get_address(s_ip4, 2);
    g_assert(ip4_addr != NULL);
    g_assert_cmpstr(nm_ip_address_get_address(ip4_addr), ==, "3.3.3.3");
    g_assert_cmpint(nm_ip_address_get_prefix(ip4_addr), ==, 8);
}

static void
test_read_wired_ipv6_manual(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    char                         *unmanaged = NULL;
    NMIPAddress                  *ip6_addr;
    NMIPRoute                    *ip6_route;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wired-ipv6-manual",
                                       NULL,
                                       TYPE_ETHERNET,
                                       &unmanaged);
    g_assert(!unmanaged);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "System test-wired-ipv6-manual");

    nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);

    /* DNS Addresses */
    g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 2);

    /* DNS search domains */
    g_assert_cmpint(nm_setting_ip_config_get_num_dns_searches(s_ip4), ==, 3);
    g_assert_cmpstr(nm_setting_ip_config_get_dns_search(s_ip4, 0), ==, "lorem.com");
    g_assert_cmpstr(nm_setting_ip_config_get_dns_search(s_ip4, 1), ==, "ipsum.org");
    g_assert_cmpstr(nm_setting_ip_config_get_dns_search(s_ip4, 2), ==, "dolor.edu");

    s_ip6 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6),
                    ==,
                    NM_SETTING_IP6_CONFIG_METHOD_MANUAL);
    g_assert(!nm_setting_ip_config_get_never_default(s_ip6));
    g_assert(nm_setting_ip_config_get_may_fail(s_ip6));

    /* IP addresses */
    g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip6), ==, 3);

    /* Address #1 */
    ip6_addr = nm_setting_ip_config_get_address(s_ip6, 0);
    g_assert(ip6_addr != NULL);
    g_assert_cmpstr(nm_ip_address_get_address(ip6_addr), ==, "1001:abba::1234");
    g_assert_cmpint(nm_ip_address_get_prefix(ip6_addr), ==, 56);

    /* Address #2 */
    ip6_addr = nm_setting_ip_config_get_address(s_ip6, 1);
    g_assert(ip6_addr != NULL);
    g_assert_cmpstr(nm_ip_address_get_address(ip6_addr), ==, "2001:abba::2234");
    g_assert_cmpint(nm_ip_address_get_prefix(ip6_addr), ==, 64);

    /* Address #3 */
    ip6_addr = nm_setting_ip_config_get_address(s_ip6, 2);
    g_assert(ip6_addr != NULL);
    g_assert_cmpstr(nm_ip_address_get_address(ip6_addr), ==, "3001:abba::3234");
    g_assert_cmpint(nm_ip_address_get_prefix(ip6_addr), ==, 96);

    /* Routes */
    g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip6), ==, 4);
    /* Route #1 */
    ip6_route = nm_setting_ip_config_get_route(s_ip6, 0);
    g_assert(ip6_route);
    g_assert_cmpstr(nm_ip_route_get_dest(ip6_route), ==, "9876::1234");
    g_assert_cmpint(nm_ip_route_get_prefix(ip6_route), ==, 96);
    g_assert_cmpstr(nm_ip_route_get_next_hop(ip6_route), ==, "9876::7777");
    g_assert_cmpint(nm_ip_route_get_metric(ip6_route), ==, 2);
    /* Route #2 */
    ip6_route = nm_setting_ip_config_get_route(s_ip6, 1);
    g_assert(ip6_route);
    g_assert_cmpstr(nm_ip_route_get_dest(ip6_route), ==, "::");
    g_assert_cmpint(nm_ip_route_get_prefix(ip6_route), ==, 0);
    g_assert_cmpstr(nm_ip_route_get_next_hop(ip6_route), ==, "dead::beaf");
    g_assert_cmpint(nm_ip_route_get_metric(ip6_route), ==, -1);
    /* Route #3 */
    ip6_route = nm_setting_ip_config_get_route(s_ip6, 2);
    g_assert(ip6_route);
    g_assert_cmpstr(nm_ip_route_get_dest(ip6_route), ==, "abbe::cafe");
    g_assert_cmpint(nm_ip_route_get_prefix(ip6_route), ==, 64);
    g_assert_cmpstr(nm_ip_route_get_next_hop(ip6_route), ==, NULL);
    g_assert_cmpint(nm_ip_route_get_metric(ip6_route), ==, 777);
    /* Route #4 */
    ip6_route = nm_setting_ip_config_get_route(s_ip6, 3);
    g_assert(ip6_route);
    g_assert_cmpstr(nm_ip_route_get_dest(ip6_route), ==, "aaaa::cccc");
    g_assert_cmpint(nm_ip_route_get_prefix(ip6_route), ==, 64);
    g_assert_cmpstr(nm_ip_route_get_next_hop(ip6_route), ==, "3333::4444");
    nmtst_assert_route_attribute_uint32(ip6_route, NM_IP_ROUTE_ATTRIBUTE_CWND, 13);
    nmtst_assert_route_attribute_uint32(ip6_route, NM_IP_ROUTE_ATTRIBUTE_MTU, 1450);
    nmtst_assert_route_attribute_boolean(ip6_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, TRUE);
    nmtst_assert_route_attribute_string(ip6_route, NM_IP_ROUTE_ATTRIBUTE_FROM, "1111::2222/48");
    nmtst_assert_route_attribute_string(ip6_route, NM_IP_ROUTE_ATTRIBUTE_SRC, "5555::6666");

    /* DNS Addresses */
    g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip6), ==, 2);
    g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip6, 0), ==, "1:2:3:4::a");
    g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip6, 1), ==, "1:2:3:4::b");

    /* DNS domains - none as domains are stuffed to 'ipv4' setting */
    g_assert_cmpint(nm_setting_ip_config_get_num_dns_searches(s_ip6), ==, 0);
}

static void
test_read_wired_ipv6_only(gconstpointer test_data)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    char                         *unmanaged = NULL;
    NMIPAddress                  *ip6_addr;
    const char                   *method;
    const char                   *file, *expected_id;

    nmtst_test_data_unpack(test_data, &file, &expected_id);

    g_assert(expected_id);

    connection = _connection_from_file(file, NULL, TYPE_ETHERNET, &unmanaged);
    g_assert(!unmanaged);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, expected_id);

    nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);

    method = nm_setting_ip_config_get_method(s_ip4);
    g_assert_cmpstr(method, ==, NM_SETTING_IP4_CONFIG_METHOD_DISABLED);

    s_ip6 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6),
                    ==,
                    NM_SETTING_IP6_CONFIG_METHOD_MANUAL);

    /* IP addresses */
    g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip6), ==, 1);

    /* Address #1 */
    ip6_addr = nm_setting_ip_config_get_address(s_ip6, 0);
    g_assert(ip6_addr != NULL);
    g_assert_cmpstr(nm_ip_address_get_address(ip6_addr), ==, "1001:abba::1234");
    g_assert_cmpint(nm_ip_address_get_prefix(ip6_addr), ==, 56);

    /* DNS Addresses */
    g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip6), ==, 1);
    g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip6, 0), ==, "1:2:3:4::a");

    /* DNS domains should be in IPv6, because IPv4 is disabled */
    g_assert_cmpint(nm_setting_ip_config_get_num_dns_searches(s_ip6), ==, 3);
    g_assert_cmpstr(nm_setting_ip_config_get_dns_search(s_ip6, 0), ==, "lorem.com");
    g_assert_cmpstr(nm_setting_ip_config_get_dns_search(s_ip6, 1), ==, "ipsum.org");
    g_assert_cmpstr(nm_setting_ip_config_get_dns_search(s_ip6, 2), ==, "dolor.edu");
}

static void
test_read_wired_dhcp6_only(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    char                         *unmanaged = NULL;
    const char                   *method;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wired-dhcp6-only",
                                       NULL,
                                       TYPE_ETHERNET,
                                       &unmanaged);
    g_assert(!unmanaged);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "System test-wired-dhcp6-only");

    nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);

    method = nm_setting_ip_config_get_method(s_ip4);
    g_assert_cmpstr(method, ==, NM_SETTING_IP4_CONFIG_METHOD_DISABLED);

    s_ip6 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_DHCP);
}

static void
test_read_wired_autoip(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingIPConfig            *s_ip4;
    char                         *unmanaged = NULL;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wired-autoip",
                                       NULL,
                                       TYPE_ETHERNET,
                                       &unmanaged);
    g_assert(unmanaged == NULL);

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
                    ==,
                    NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL);
    g_assert(!nm_setting_ip_config_get_may_fail(s_ip4));
    g_assert(nm_setting_ip_config_get_ignore_auto_dns(s_ip4));

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con), ==, 2600);
}

static void
test_read_onboot_no(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    char                         *unmanaged = NULL;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-onboot-no",
                                       NULL,
                                       TYPE_ETHERNET,
                                       &unmanaged);
    g_assert(!unmanaged);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);

    g_assert(!nm_setting_connection_get_autoconnect(s_con));
}

static void
test_read_noip(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;

    connection =
        _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-noip", NULL, TYPE_ETHERNET, NULL);

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
                    ==,
                    NM_SETTING_IP4_CONFIG_METHOD_DISABLED);
    g_assert(nm_setting_ip_config_get_never_default(s_ip4) == FALSE);

    s_ip6 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6),
                    ==,
                    NM_SETTING_IP6_CONFIG_METHOD_IGNORE);
    g_assert(nm_setting_ip_config_get_never_default(s_ip6) == FALSE);
}

#define TEST_IFCFG_WIRED_8021x_PEAP_MSCHAPV2_CA_CERT TEST_IFCFG_DIR "/test_ca_cert.pem"

static void
test_read_wired_8021x_peap_mschapv2(void)
{
    gs_unref_object NMConnection   *connection = NULL;
    NMSettingIPConfig              *s_ip4;
    NMSetting8021x                 *s_8021x;
    gs_unref_object NMSetting8021x *tmp_8021x = NULL;
    char                           *unmanaged = NULL;
    GError                         *error     = NULL;
    gboolean                        success   = FALSE;
    const char                     *expected_ca_cert_path;
    const char                     *read_ca_cert_path;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wired-8021x-peap-mschapv2",
                                       NULL,
                                       TYPE_ETHERNET,
                                       &unmanaged);
    g_assert(!unmanaged);

    nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);

    s_8021x = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_802_1X);

    g_assert_cmpint(nm_setting_802_1x_get_num_eap_methods(s_8021x), ==, 1);
    g_assert_cmpstr(nm_setting_802_1x_get_eap_method(s_8021x, 0), ==, "peap");
    g_assert_cmpstr(nm_setting_802_1x_get_identity(s_8021x), ==, "David Smith");
    g_assert_cmpstr(nm_setting_802_1x_get_anonymous_identity(s_8021x), ==, "somebody");
    g_assert_cmpstr(nm_setting_802_1x_get_password(s_8021x), ==, "foobar baz");
    g_assert_cmpstr(nm_setting_802_1x_get_phase1_peapver(s_8021x), ==, "1");
    g_assert_cmpstr(nm_setting_802_1x_get_phase1_peaplabel(s_8021x), ==, "1");

    /* CA Cert */
    tmp_8021x = (NMSetting8021x *) nm_setting_802_1x_new();

    success = nm_setting_802_1x_set_ca_cert(tmp_8021x,
                                            TEST_IFCFG_WIRED_8021x_PEAP_MSCHAPV2_CA_CERT,
                                            NM_SETTING_802_1X_CK_SCHEME_PATH,
                                            NULL,
                                            &error);
    g_assert_no_error(error);
    g_assert(success == TRUE);

    expected_ca_cert_path = nm_setting_802_1x_get_ca_cert_path(tmp_8021x);
    g_assert(expected_ca_cert_path);

    read_ca_cert_path = nm_setting_802_1x_get_ca_cert_path(s_8021x);
    g_assert(read_ca_cert_path);

    g_assert_cmpstr(read_ca_cert_path, ==, expected_ca_cert_path);
}

static void
test_read_wired_8021x_tls_secret_flags(gconstpointer test_data)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSetting8021x               *s_8021x;
    gs_free char                 *dirname = NULL;
    gs_free char                 *tmp1    = NULL;
    gs_free char                 *tmp2    = NULL;
    const char                   *ifcfg;
    gpointer                      expected_flags_p;

    nmtst_test_data_unpack(test_data, &ifcfg, &expected_flags_p);

    connection = _connection_from_file(ifcfg, NULL, TYPE_ETHERNET, NULL);

    nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);

    s_8021x = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_802_1X);
    g_assert_cmpint(nm_setting_802_1x_get_num_eap_methods(s_8021x), ==, 1);
    g_assert_cmpstr(nm_setting_802_1x_get_eap_method(s_8021x, 0), ==, "tls");
    g_assert_cmpstr(nm_setting_802_1x_get_identity(s_8021x), ==, "David Smith");
    g_assert_cmpint(nm_setting_802_1x_get_private_key_password_flags(s_8021x),
                    ==,
                    GPOINTER_TO_INT(expected_flags_p));

    dirname = g_path_get_dirname(ifcfg);

    tmp1 = g_build_path("/", dirname, "test_ca_cert.pem", NULL);
    g_assert_cmpstr(nm_setting_802_1x_get_ca_cert_path(s_8021x), ==, tmp1);

    tmp2 = g_build_path("/", dirname, "test1_key_and_cert.pem", NULL);
    g_assert_cmpstr(nm_setting_802_1x_get_client_cert_path(s_8021x), ==, tmp2);
    g_assert_cmpstr(nm_setting_802_1x_get_private_key_path(s_8021x), ==, tmp2);
}

static void
test_read_write_802_1X_subj_matches(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSetting8021x               *s_8021x;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wired-802-1X-subj-matches",
                                       NULL,
                                       TYPE_ETHERNET,
                                       NULL);

    s_8021x = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_802_1X);
    g_assert_cmpint(nm_setting_802_1x_get_num_eap_methods(s_8021x), ==, 1);
    g_assert_cmpstr(nm_setting_802_1x_get_eap_method(s_8021x, 0), ==, "peap");
    g_assert_cmpstr(nm_setting_802_1x_get_identity(s_8021x), ==, "Jara Cimrman");
    g_assert_cmpstr(nm_setting_802_1x_get_subject_match(s_8021x), ==, "server1.yourdomain.tld");
    g_assert_cmpstr(nm_setting_802_1x_get_phase2_subject_match(s_8021x),
                    ==,
                    "server2.yourdomain.tld");
    g_assert_cmpint(nm_setting_802_1x_get_num_altsubject_matches(s_8021x), ==, 3);
    g_assert_cmpstr(nm_setting_802_1x_get_altsubject_match(s_8021x, 0), ==, "a.yourdomain.tld");
    g_assert_cmpstr(nm_setting_802_1x_get_altsubject_match(s_8021x, 1), ==, "b.yourdomain.tld");
    g_assert_cmpstr(nm_setting_802_1x_get_altsubject_match(s_8021x, 2), ==, "c.yourdomain.tld");
    g_assert_cmpint(nm_setting_802_1x_get_num_phase2_altsubject_matches(s_8021x), ==, 2);
    g_assert_cmpstr(nm_setting_802_1x_get_phase2_altsubject_match(s_8021x, 0),
                    ==,
                    "x.yourdomain.tld");
    g_assert_cmpstr(nm_setting_802_1x_get_phase2_altsubject_match(s_8021x, 1),
                    ==,
                    "y.yourdomain.tld");

    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR,
                           TEST_IFCFG_DIR "/ifcfg-System_test-wired-802-1X-subj-matches.cexpected",
                           &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);

    /* Check 802.1X stuff of the re-read connection. */
    s_8021x = nmtst_connection_assert_setting(reread, NM_TYPE_SETTING_802_1X);
    g_assert_cmpint(nm_setting_802_1x_get_num_eap_methods(s_8021x), ==, 1);
    g_assert_cmpstr(nm_setting_802_1x_get_eap_method(s_8021x, 0), ==, "peap");
    g_assert_cmpstr(nm_setting_802_1x_get_identity(s_8021x), ==, "Jara Cimrman");
    g_assert_cmpstr(nm_setting_802_1x_get_subject_match(s_8021x), ==, "server1.yourdomain.tld");
    g_assert_cmpstr(nm_setting_802_1x_get_phase2_subject_match(s_8021x),
                    ==,
                    "server2.yourdomain.tld");
    g_assert_cmpint(nm_setting_802_1x_get_num_altsubject_matches(s_8021x), ==, 3);
    g_assert_cmpstr(nm_setting_802_1x_get_altsubject_match(s_8021x, 0), ==, "a.yourdomain.tld");
    g_assert_cmpstr(nm_setting_802_1x_get_altsubject_match(s_8021x, 1), ==, "b.yourdomain.tld");
    g_assert_cmpstr(nm_setting_802_1x_get_altsubject_match(s_8021x, 2), ==, "c.yourdomain.tld");
    g_assert_cmpint(nm_setting_802_1x_get_num_phase2_altsubject_matches(s_8021x), ==, 2);
    g_assert_cmpstr(nm_setting_802_1x_get_phase2_altsubject_match(s_8021x, 0),
                    ==,
                    "x.yourdomain.tld");
    g_assert_cmpstr(nm_setting_802_1x_get_phase2_altsubject_match(s_8021x, 1),
                    ==,
                    "y.yourdomain.tld");
}

static void
test_read_802_1x_ttls_eapgtc(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSetting8021x               *s_8021x;

    /* Test that EAP-* inner methods are correctly read into the
     * NMSetting8021x::autheap property.
     */

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wired-802-1x-ttls-eapgtc",
                                       NULL,
                                       TYPE_WIRELESS,
                                       NULL);

    s_8021x = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_802_1X);

    /* EAP methods */
    g_assert_cmpint(nm_setting_802_1x_get_num_eap_methods(s_8021x), ==, 1);
    g_assert_cmpstr(nm_setting_802_1x_get_eap_method(s_8021x, 0), ==, "ttls");

    /* Auth methods */
    g_assert_cmpstr(nm_setting_802_1x_get_phase2_auth(s_8021x), ==, NULL);
    g_assert_cmpstr(nm_setting_802_1x_get_phase2_autheap(s_8021x), ==, "gtc");
}

static void
test_read_802_1x_tls_p12_no_client_cert(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSetting8021x               *s_8021x;
    const char                   *path;

    connection =
        _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wired-8021x-tls-p12-no-client-cert",
                              NULL,
                              TYPE_ETHERNET,
                              NULL);

    s_8021x = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_802_1X);

    g_assert_cmpint(nm_setting_802_1x_get_private_key_scheme(s_8021x),
                    ==,
                    NM_SETTING_802_1X_CK_SCHEME_PATH);
    path = nm_setting_802_1x_get_private_key_path(s_8021x);
    g_assert(path);

    g_assert_cmpint(nm_setting_802_1x_get_client_cert_scheme(s_8021x),
                    ==,
                    NM_SETTING_802_1X_CK_SCHEME_PATH);
    g_assert_cmpstr(path, ==, nm_setting_802_1x_get_client_cert_path(s_8021x));
}

static void
test_read_write_802_1x_password_raw(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    nmtst_auto_unlinkfile char   *keyfile    = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSetting8021x               *s_8021x;
    GBytes                       *bytes;
    gconstpointer                 data;
    gsize                         size;

    /* Test that the 802-1x.password-raw is correctly read and written. */

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wired-802-1x-password-raw",
                                       NULL,
                                       TYPE_ETHERNET,
                                       NULL);

    s_8021x = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_802_1X);

    bytes = nm_setting_802_1x_get_password_raw(s_8021x);
    g_assert(bytes);
    data = g_bytes_get_data(bytes, &size);
    g_assert_cmpmem(data, size, "\x04\x08\x15\x16\x23\x42\x00\x01", 8);

    g_assert_cmpint(nm_setting_802_1x_get_password_raw_flags(s_8021x),
                    ==,
                    NM_SETTING_SECRET_FLAG_NONE);

    g_assert_cmpstr(nm_setting_802_1x_get_pin(s_8021x), ==, "hallo2");
    g_assert_cmpint(nm_setting_802_1x_get_pin_flags(s_8021x), ==, NM_SETTING_SECRET_FLAG_NONE);

    _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile);
    reread  = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);
    keyfile = utils_get_keys_path(testfile);
    g_assert(g_file_test(keyfile, G_FILE_TEST_EXISTS));

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_read_wired_aliases_good(gconstpointer test_data)
{
    const int                     N          = GPOINTER_TO_INT(test_data);
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingIPConfig            *s_ip4;
    int                           expected_num_addresses;
    const char                   *expected_address_0[] = {"192.168.1.5",
                                                          "192.168.1.6",
                                                          "192.168.1.9",
                                                          "192.168.1.99",
                                                          NULL};
    const char                   *expected_address_3[] = {"192.168.1.5", "192.168.1.6", NULL};
    const char                   *expected_label_0[]   = {
        NULL,
        "aliasem0:1",
        "aliasem0:2",
        "aliasem0:99",
        NULL,
    };
    const char *expected_label_3[] = {
        NULL,
        "aliasem3:1",
        NULL,
    };
    const char **expected_address;
    const char **expected_label;
    int          i, j;
    char         path[256];

    expected_address       = N == 0 ? expected_address_0 : expected_address_3;
    expected_label         = N == 0 ? expected_label_0 : expected_label_3;
    expected_num_addresses = g_strv_length((char **) expected_address);

    nm_sprintf_buf(path, TEST_IFCFG_DIR "/ifcfg-aliasem%d", N);

    connection = _connection_from_file(path, NULL, TYPE_ETHERNET, NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    if (N == 0)
        g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "System aliasem0");
    else
        g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "System aliasem3");

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
                    ==,
                    NM_SETTING_IP4_CONFIG_METHOD_MANUAL);
    g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip4), ==, expected_num_addresses);

    /* Addresses */
    for (i = 0; i < expected_num_addresses; i++) {
        NMIPAddress *ip4_addr;
        const char  *addr;
        GVariant    *label;

        ip4_addr = nm_setting_ip_config_get_address(s_ip4, i);
        g_assert(ip4_addr != NULL);

        addr = nm_ip_address_get_address(ip4_addr);
        g_assert(nm_inet_is_valid(AF_INET, addr));

        for (j = 0; j < expected_num_addresses; j++) {
            if (!g_strcmp0(addr, expected_address[j]))
                break;
        }
        g_assert(j < expected_num_addresses);

        g_assert_cmpint(nm_ip_address_get_prefix(ip4_addr), ==, 24);
        label = nm_ip_address_get_attribute(ip4_addr, NM_IP_ADDRESS_ATTRIBUTE_LABEL);
        if (expected_label[j])
            g_assert_cmpstr(g_variant_get_string(label, NULL), ==, expected_label[j]);
        else
            g_assert(label == NULL);

        expected_address[j] = NULL;
        expected_label[j]   = NULL;
    }

    /* Gateway */
    g_assert(!nm_setting_ip_config_get_never_default(s_ip4));
    g_assert_cmpstr(nm_setting_ip_config_get_gateway(s_ip4), ==, "192.168.1.1");

    for (i = 0; i < expected_num_addresses; i++)
        g_assert(!expected_address[i]);
}

static void
test_read_wired_aliases_bad(const char *base, const char *expected_id)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingIPConfig            *s_ip4;
    NMIPAddress                  *ip4_addr;

    g_assert(expected_id);

    connection = _connection_from_file(base, NULL, TYPE_ETHERNET, NULL);
    g_test_assert_expected_messages();

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, expected_id);

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
                    ==,
                    NM_SETTING_IP4_CONFIG_METHOD_MANUAL);

    g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip4), ==, 1);

    /* Addresses */
    ip4_addr = nm_setting_ip_config_get_address(s_ip4, 0);
    g_assert(ip4_addr != NULL);
    g_assert_cmpstr(nm_ip_address_get_address(ip4_addr), ==, "192.168.1.5");
    g_assert_cmpint(nm_ip_address_get_prefix(ip4_addr), ==, 24);
    g_assert(nm_ip_address_get_attribute(ip4_addr, NM_IP_ADDRESS_ATTRIBUTE_LABEL) == NULL);

    /* Gateway */
    g_assert_cmpstr(nm_setting_ip_config_get_gateway(s_ip4), ==, "192.168.1.1");
}

static void
test_read_wired_aliases_bad_1(void)
{
    NMTST_EXPECT_NM_WARN("*aliasem1:1*has no DEVICE*");
    test_read_wired_aliases_bad(TEST_IFCFG_DIR "/ifcfg-aliasem1", "System aliasem1");
}

static void
test_read_wired_aliases_bad_2(void)
{
    NMTST_EXPECT_NM_WARN("*aliasem2:1*has invalid DEVICE*");
    test_read_wired_aliases_bad(TEST_IFCFG_DIR "/ifcfg-aliasem2", "System aliasem2");
}

static void
test_read_dns_options(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    char                         *unmanaged = NULL;
    const char                   *option;
    const char                   *options4[] = {"ndots:3", "single-request-reopen"};
    const char                   *options6[] = {"inet6"};
    guint32                       num;
    guint32                       i;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-dns-options",
                                       NULL,
                                       TYPE_ETHERNET,
                                       &unmanaged);
    g_assert_cmpstr(unmanaged, ==, NULL);

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);

    s_ip6 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);

    num = nm_setting_ip_config_get_num_dns_options(s_ip4);
    g_assert_cmpint(num, ==, G_N_ELEMENTS(options4));

    for (i = 0; i < num; i++) {
        option = nm_setting_ip_config_get_dns_option(s_ip4, i);
        g_assert_cmpstr(options4[i], ==, option);
    }

    num = nm_setting_ip_config_get_num_dns_options(s_ip6);
    g_assert_cmpint(num, ==, G_N_ELEMENTS(options6));

    for (i = 0; i < num; i++) {
        option = nm_setting_ip_config_get_dns_option(s_ip6, i);
        g_assert_cmpstr(options6[i], ==, option);
    }
}

static void
test_clear_controller(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_free char                 *keyfile    = NULL;
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    char                         *unmanaged = NULL;
    shvarFile                    *f;

    /* 1. load the bridge port connection from disk */
    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-bridge-component",
                                       NULL,
                                       TYPE_ETHERNET,
                                       &unmanaged);
    g_assert_cmpstr(unmanaged, ==, NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);

    g_assert_cmpstr(nm_setting_connection_get_controller(s_con), ==, "br0");
    g_assert_cmpstr(nm_setting_connection_get_port_type(s_con), ==, "bridge");

    /* 2. write the connection to a new file */
    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR,
                           TEST_IFCFG_DIR "/ifcfg-System_test-bridge-component-a.cexpected",
                           &testfile);

    /* 3. clear controller and port-type */
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_MASTER,
                 NULL,
                 NM_SETTING_CONNECTION_SLAVE_TYPE,
                 NULL,
                 NULL);

    g_assert_cmpstr(nm_setting_connection_get_controller(s_con), ==, NULL);
    g_assert_cmpstr(nm_setting_connection_get_port_type(s_con), ==, NULL);

    nmtst_assert_connection_verifies_after_normalization(connection, 0, 0);

    /* 4. update the connection on disk */
    _writer_update_connection(connection,
                              TEST_SCRATCH_DIR,
                              testfile,
                              TEST_IFCFG_DIR "/ifcfg-System_test-bridge-component-b.cexpected");
    keyfile = utils_get_keys_path(testfile);
    g_assert(!g_file_test(keyfile, G_FILE_TEST_EXISTS));

    /* 5. check that BRIDGE variable has been removed */
    f = _svOpenFile(testfile);
    _svGetValue_check(f, "BRIDGE", NULL);
    svCloseFile(f);
}

static void
test_write_dns_options(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingWired               *s_wired;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    static const char            *mac = "31:33:33:37:be:cd";
    guint32                       mtu = 1492;
    NMIPAddress                  *addr;
    NMIPAddress                  *addr6;
    GError                       *error = NULL;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test DNS options",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRED_SETTING_NAME,
                 NULL);

    s_wired = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRED);
    g_object_set(s_wired, NM_SETTING_WIRED_MAC_ADDRESS, mac, NM_SETTING_WIRED_MTU, mtu, NULL);

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NM_SETTING_IP_CONFIG_GATEWAY,
                 "1.1.1.1",
                 NM_SETTING_IP_CONFIG_ROUTE_METRIC,
                 (gint64) 204,
                 NULL);

    addr = nm_ip_address_new(AF_INET, "1.1.1.3", 24, &error);
    nm_setting_ip_config_add_address(s_ip4, addr);
    nm_ip_address_unref(addr);

    nm_setting_ip_config_add_dns_option(s_ip4, "debug");

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP6_CONFIG_METHOD_MANUAL,
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NM_SETTING_IP_CONFIG_ROUTE_METRIC,
                 (gint64) 206,
                 NULL);

    /* Add addresses */
    addr6 = nm_ip_address_new(AF_INET6, "1003:1234:abcd::1", 11, &error);
    nm_setting_ip_config_add_address(s_ip6, addr6);
    nm_ip_address_unref(addr6);

    nm_setting_ip_config_add_dns_option(s_ip6, "timeout:3");

    nmtst_assert_connection_verifies(connection);

    _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_read_wifi_open(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingWireless            *s_wifi;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    GBytes                       *ssid;
    const char                   *mac;
    char        expected_mac_address[ETH_ALEN] = {0x00, 0x16, 0x41, 0x11, 0x22, 0x33};
    const char *expected_ssid                  = "blahblah";

    connection =
        _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wifi-open", NULL, TYPE_WIRELESS, NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "System blahblah (test-wifi-open)");

    /* UUID can't be tested if the ifcfg does not contain the UUID key, because
     * the UUID is generated on the full path of the ifcfg file, which can change
     * depending on where the tests are run.
     */

    g_assert_cmpint(nm_setting_connection_get_timestamp(s_con), ==, 0);
    g_assert(nm_setting_connection_get_autoconnect(s_con));
    g_assert_cmpint(nm_setting_connection_get_autoconnect_priority(s_con), ==, -1);

    s_wifi = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS);

    mac = nm_setting_wireless_get_mac_address(s_wifi);
    g_assert(mac);
    g_assert(nm_utils_hwaddr_matches(mac, -1, expected_mac_address, sizeof(expected_mac_address)));

    g_assert_cmpint(nm_setting_wireless_get_mtu(s_wifi), ==, 0);

    ssid = nm_setting_wireless_get_ssid(s_wifi);
    g_assert(ssid);
    g_assert_cmpmem(g_bytes_get_data(ssid, NULL),
                    g_bytes_get_size(ssid),
                    expected_ssid,
                    strlen(expected_ssid));

    g_assert(!nm_setting_wireless_get_bssid(s_wifi));
    g_assert_cmpstr(nm_setting_wireless_get_mode(s_wifi), ==, "infrastructure");
    g_assert_cmpint(nm_setting_wireless_get_channel(s_wifi), ==, 1);

    nmtst_connection_assert_no_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert_cmpint(nm_setting_ip_config_get_route_metric(s_ip4), ==, 104);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);

    s_ip6 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_assert_cmpint(nm_setting_ip_config_get_route_metric(s_ip6), ==, 106);
}

static void
test_read_wifi_open_auto(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingWireless            *s_wifi;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wifi-open-auto",
                                       NULL,
                                       TYPE_WIRELESS,
                                       NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con),
                    ==,
                    "System blahblah (test-wifi-open-auto)");

    s_wifi = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS);
    g_assert_cmpstr(nm_setting_wireless_get_mode(s_wifi), ==, "infrastructure");
}

static void
test_read_wifi_open_ssid_hex(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingWireless            *s_wifi;
    GBytes                       *ssid;
    const char                   *expected_ssid = "blahblah";

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wifi-open-ssid-hex",
                                       NULL,
                                       TYPE_WIRELESS,
                                       NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con),
                    ==,
                    "System blahblah (test-wifi-open-ssid-hex)");

    s_wifi = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS);

    ssid = nm_setting_wireless_get_ssid(s_wifi);
    g_assert(ssid);
    g_assert_cmpmem(g_bytes_get_data(ssid, NULL),
                    g_bytes_get_size(ssid),
                    expected_ssid,
                    strlen(expected_ssid));
}

static void
test_read_wifi_open_ssid_hex_bad(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingWireless            *s_wifi;
    GBytes                       *ssid;
    const char                   *expected_ssid = "0x626cxx";

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wifi-open-ssid-bad-hex",
                                       NULL,
                                       TYPE_WIRELESS,
                                       NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con),
                    ==,
                    "System 0x626cxx (test-wifi-open-ssid-bad-hex)");

    s_wifi = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS);

    ssid = nm_setting_wireless_get_ssid(s_wifi);
    g_assert(ssid);
    g_assert_cmpmem(g_bytes_get_data(ssid, NULL),
                    g_bytes_get_size(ssid),
                    expected_ssid,
                    strlen(expected_ssid));
}

static void
test_read_wifi_open_ssid_bad(gconstpointer data)
{
    _connection_from_file_fail((const char *) data, NULL, TYPE_WIRELESS, NULL);
}

static void
test_read_wifi_open_ssid_quoted(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingWireless            *s_wifi;
    GBytes                       *ssid;
    const char                   *expected_ssid = "foo\"bar\\";

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wifi-open-ssid-quoted",
                                       NULL,
                                       TYPE_WIRELESS,
                                       NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con),
                    ==,
                    "System foo\"bar\\ (test-wifi-open-ssid-quoted)");

    s_wifi = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS);

    ssid = nm_setting_wireless_get_ssid(s_wifi);
    g_assert(ssid);
    g_assert_cmpmem(g_bytes_get_data(ssid, NULL),
                    g_bytes_get_size(ssid),
                    expected_ssid,
                    strlen(expected_ssid));
}

static void
test_read_wifi_wep(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingWireless            *s_wifi;
    NMSettingWirelessSecurity    *s_wsec;
    NMSettingIPConfig            *s_ip4;
    GBytes                       *ssid;
    const char                   *mac;
    char         expected_mac_address[ETH_ALEN] = {0x00, 0x16, 0x41, 0x11, 0x22, 0x33};
    const char  *expected_ssid                  = "blahblah";
    NMWepKeyType key_type;

    connection =
        _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wifi-wep", NULL, TYPE_WIRELESS, NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "System blahblah (test-wifi-wep)");

    /* UUID can't be tested if the ifcfg does not contain the UUID key, because
     * the UUID is generated on the full path of the ifcfg file, which can change
     * depending on where the tests are run.
     */

    g_assert_cmpint(nm_setting_connection_get_timestamp(s_con), ==, 0);
    g_assert(nm_setting_connection_get_autoconnect(s_con));

    s_wifi = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS);

    mac = nm_setting_wireless_get_mac_address(s_wifi);
    g_assert(mac);
    g_assert(nm_utils_hwaddr_matches(mac, -1, expected_mac_address, sizeof(expected_mac_address)));

    /* MTU */
    g_assert_cmpint(nm_setting_wireless_get_mtu(s_wifi), ==, 0);

    ssid = nm_setting_wireless_get_ssid(s_wifi);
    g_assert(ssid);
    g_assert_cmpmem(g_bytes_get_data(ssid, NULL),
                    g_bytes_get_size(ssid),
                    expected_ssid,
                    strlen(expected_ssid));

    g_assert(!nm_setting_wireless_get_bssid(s_wifi));
    g_assert_cmpstr(nm_setting_wireless_get_mode(s_wifi), ==, "infrastructure");
    g_assert_cmpint(nm_setting_wireless_get_channel(s_wifi), ==, 1);

    s_wsec = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
    g_assert_cmpstr(nm_setting_wireless_security_get_key_mgmt(s_wsec), ==, "none");
    g_assert_cmpstr(nm_setting_wireless_security_get_auth_alg(s_wsec), ==, "shared");
    g_assert_cmpint(nm_setting_wireless_security_get_wep_tx_keyidx(s_wsec), ==, 0);

    key_type = nm_setting_wireless_security_get_wep_key_type(s_wsec);
    g_assert(key_type == NM_WEP_KEY_TYPE_UNKNOWN || key_type == NM_WEP_KEY_TYPE_KEY);

    g_assert_cmpstr(nm_setting_wireless_security_get_wep_key(s_wsec, 0),
                    ==,
                    "0123456789abcdef0123456789");
    g_assert(!nm_setting_wireless_security_get_wep_key(s_wsec, 1));
    g_assert(!nm_setting_wireless_security_get_wep_key(s_wsec, 2));
    g_assert(!nm_setting_wireless_security_get_wep_key(s_wsec, 3));

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);
}

static void
test_read_wifi_wep_adhoc(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingWireless            *s_wifi;
    NMSettingWirelessSecurity    *s_wsec;
    NMSettingIPConfig            *s_ip4;
    GBytes                       *ssid;
    const char                   *expected_ssid = "blahblah";

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wifi-wep-adhoc",
                                       NULL,
                                       TYPE_WIRELESS,
                                       NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con),
                    ==,
                    "System blahblah (test-wifi-wep-adhoc)");

    /* UUID can't be tested if the ifcfg does not contain the UUID key, because
     * the UUID is generated on the full path of the ifcfg file, which can change
     * depending on where the tests are run.
     */

    g_assert(!nm_setting_connection_get_autoconnect(s_con));

    s_wifi = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS);

    ssid = nm_setting_wireless_get_ssid(s_wifi);
    g_assert(ssid);
    g_assert_cmpmem(g_bytes_get_data(ssid, NULL),
                    g_bytes_get_size(ssid),
                    expected_ssid,
                    strlen(expected_ssid));

    g_assert(!nm_setting_wireless_get_bssid(s_wifi));
    g_assert_cmpstr(nm_setting_wireless_get_mode(s_wifi), ==, "adhoc");
    g_assert_cmpint(nm_setting_wireless_get_channel(s_wifi), ==, 11);

    s_wsec = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
    g_assert_cmpstr(nm_setting_wireless_security_get_key_mgmt(s_wsec), ==, "none");
    g_assert(!nm_setting_wireless_security_get_auth_alg(s_wsec));
    g_assert_cmpint(nm_setting_wireless_security_get_wep_tx_keyidx(s_wsec), ==, 0);

    g_assert_cmpstr(nm_setting_wireless_security_get_wep_key(s_wsec, 0),
                    ==,
                    "0123456789abcdef0123456789");
    g_assert(!nm_setting_wireless_security_get_wep_key(s_wsec, 1));
    g_assert(!nm_setting_wireless_security_get_wep_key(s_wsec, 2));
    g_assert(!nm_setting_wireless_security_get_wep_key(s_wsec, 3));

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);

    /* Ignore auto DNS */
    g_assert(nm_setting_ip_config_get_ignore_auto_dns(s_ip4));

    /* DNS Addresses */
    g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 2);
    g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip4, 0), ==, "4.2.2.1");
    g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip4, 1), ==, "4.2.2.2");
}

static void
test_read_wifi_wep_passphrase(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingWirelessSecurity    *s_wsec;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wifi-wep-passphrase",
                                       NULL,
                                       TYPE_WIRELESS,
                                       NULL);

    nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);

    nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS);

    s_wsec = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
    g_assert_cmpstr(nm_setting_wireless_security_get_key_mgmt(s_wsec), ==, "none");
    g_assert_cmpint(nm_setting_wireless_security_get_wep_tx_keyidx(s_wsec), ==, 0);
    g_assert_cmpint(nm_setting_wireless_security_get_wep_key_type(s_wsec),
                    ==,
                    NM_WEP_KEY_TYPE_UNKNOWN);
    g_assert_cmpstr(nm_setting_wireless_security_get_wep_key(s_wsec, 0), ==, "foobar222blahblah");
    g_assert(!nm_setting_wireless_security_get_wep_key(s_wsec, 1));
    g_assert(!nm_setting_wireless_security_get_wep_key(s_wsec, 2));
    g_assert(!nm_setting_wireless_security_get_wep_key(s_wsec, 3));
}

static void
test_read_wifi_wep_40_ascii(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingWirelessSecurity    *s_wsec;
    NMWepKeyType                  key_type;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wifi-wep-40-ascii",
                                       NULL,
                                       TYPE_WIRELESS,
                                       NULL);

    nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);

    nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS);

    s_wsec = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
    g_assert_cmpstr(nm_setting_wireless_security_get_key_mgmt(s_wsec), ==, "none");
    g_assert_cmpint(nm_setting_wireless_security_get_wep_tx_keyidx(s_wsec), ==, 0);

    key_type = nm_setting_wireless_security_get_wep_key_type(s_wsec);
    g_assert(key_type == NM_WEP_KEY_TYPE_UNKNOWN || key_type == NM_WEP_KEY_TYPE_KEY);

    g_assert_cmpstr(nm_setting_wireless_security_get_wep_key(s_wsec, 0), ==, "Lorem");
    g_assert(!nm_setting_wireless_security_get_wep_key(s_wsec, 1));
    g_assert(!nm_setting_wireless_security_get_wep_key(s_wsec, 2));
    g_assert(!nm_setting_wireless_security_get_wep_key(s_wsec, 3));
}

static void
test_read_wifi_wep_104_ascii(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingWirelessSecurity    *s_wsec;
    NMWepKeyType                  key_type;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wifi-wep-104-ascii",
                                       NULL,
                                       TYPE_WIRELESS,
                                       NULL);

    nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);

    nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS);

    s_wsec = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
    g_assert_cmpstr(nm_setting_wireless_security_get_key_mgmt(s_wsec), ==, "none");
    g_assert_cmpint(nm_setting_wireless_security_get_wep_tx_keyidx(s_wsec), ==, 0);

    key_type = nm_setting_wireless_security_get_wep_key_type(s_wsec);
    g_assert(key_type == NM_WEP_KEY_TYPE_UNKNOWN || key_type == NM_WEP_KEY_TYPE_KEY);

    g_assert_cmpstr(nm_setting_wireless_security_get_wep_key(s_wsec, 0), ==, "LoremIpsumSit");
    g_assert(!nm_setting_wireless_security_get_wep_key(s_wsec, 1));
    g_assert(!nm_setting_wireless_security_get_wep_key(s_wsec, 2));
    g_assert(!nm_setting_wireless_security_get_wep_key(s_wsec, 3));
}

static void
test_read_wifi_leap(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingWirelessSecurity    *s_wsec;

    connection =
        _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wifi-leap", NULL, TYPE_WIRELESS, NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "System blahblah (test-wifi-leap)");

    nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS);

    s_wsec = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
    g_assert_cmpstr(nm_setting_wireless_security_get_key_mgmt(s_wsec), ==, "ieee8021x");
    g_assert_cmpstr(nm_setting_wireless_security_get_auth_alg(s_wsec), ==, "leap");
    g_assert_cmpstr(nm_setting_wireless_security_get_leap_username(s_wsec), ==, "Bill Smith");
    g_assert_cmpstr(nm_setting_wireless_security_get_leap_password(s_wsec), ==, "foobarblah");
}

static void
test_read_wifi_leap_secret_flags(gconstpointer test_data)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingWirelessSecurity    *s_wsec;
    const char                   *file;
    gpointer                      expected_flags_p;

    nmtst_test_data_unpack(test_data, &file, &expected_flags_p);

    connection = _connection_from_file(file, NULL, TYPE_WIRELESS, NULL);

    nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS);

    s_wsec = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);

    g_assert(g_strcmp0(nm_setting_wireless_security_get_key_mgmt(s_wsec), "ieee8021x") == 0);
    g_assert(g_strcmp0(nm_setting_wireless_security_get_auth_alg(s_wsec), "leap") == 0);
    g_assert(g_strcmp0(nm_setting_wireless_security_get_leap_username(s_wsec), "Bill Smith") == 0);
    /* password blank as it's not system-owned */
    g_assert(nm_setting_wireless_security_get_leap_password_flags(s_wsec)
             == GPOINTER_TO_INT(expected_flags_p));
    g_assert(nm_setting_wireless_security_get_leap_password(s_wsec) == NULL);
}

static void
test_ifcfg_no_trailing_newline(void)
{
    shvarFile *sv;

    sv = _svOpenFile(TEST_IFCFG_DIR "/ifcfg-test-wifi-wpa-psk");
    _svGetValue_check(sv, "CTCPROT", "no-newline");
    svCloseFile(sv);
}

static void
test_read_wifi_wpa_psk(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingWireless            *s_wifi;
    NMSettingWirelessSecurity    *s_wsec;
    NMSettingIPConfig            *s_ip4;
    GBytes                       *ssid;
    const char                   *mac;
    char        expected_mac_address[ETH_ALEN] = {0x00, 0x16, 0x41, 0x11, 0x22, 0x33};
    const char *expected_ssid                  = "blahblah";
    guint32     n, i;
    gboolean    found_pair_tkip    = FALSE;
    gboolean    found_pair_ccmp    = FALSE;
    gboolean    found_group_tkip   = FALSE;
    gboolean    found_group_ccmp   = FALSE;
    gboolean    found_group_wep40  = FALSE;
    gboolean    found_group_wep104 = FALSE;
    gboolean    found_proto_wpa    = FALSE;
    gboolean    found_proto_rsn    = FALSE;

    connection =
        _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wifi-wpa-psk", NULL, TYPE_WIRELESS, NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "System blahblah (test-wifi-wpa-psk)");

    /* UUID can't be tested if the ifcfg does not contain the UUID key, because
     * the UUID is generated on the full path of the ifcfg file, which can change
     * depending on where the tests are run.
     */

    g_assert_cmpint(nm_setting_connection_get_timestamp(s_con), ==, 0);
    g_assert(nm_setting_connection_get_autoconnect(s_con));

    s_wifi = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS);

    mac = nm_setting_wireless_get_mac_address(s_wifi);
    g_assert(mac);
    g_assert(nm_utils_hwaddr_matches(mac, -1, expected_mac_address, sizeof(expected_mac_address)));

    g_assert_cmpint(nm_setting_wireless_get_mtu(s_wifi), ==, 0);

    ssid = nm_setting_wireless_get_ssid(s_wifi);
    g_assert(ssid);
    g_assert_cmpmem(g_bytes_get_data(ssid, NULL),
                    g_bytes_get_size(ssid),
                    expected_ssid,
                    strlen(expected_ssid));

    g_assert(!nm_setting_wireless_get_bssid(s_wifi));
    g_assert_cmpstr(nm_setting_wireless_get_mode(s_wifi), ==, "infrastructure");
    g_assert_cmpint(nm_setting_wireless_get_channel(s_wifi), ==, 1);

    s_wsec = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
    g_assert_cmpstr(nm_setting_wireless_security_get_key_mgmt(s_wsec), ==, "wpa-psk");
    g_assert_cmpstr(nm_setting_wireless_security_get_psk(s_wsec),
                    ==,
                    "I wonder what the king is doing tonight?");
    g_assert(!nm_setting_wireless_security_get_auth_alg(s_wsec));

    /* Pairwise ciphers */
    n = nm_setting_wireless_security_get_num_pairwise(s_wsec);
    g_assert_cmpint(n, ==, 2);
    for (i = 0; i < n; i++) {
        const char *tmp = nm_setting_wireless_security_get_pairwise(s_wsec, i);
        g_assert(tmp);
        if (strcmp(tmp, "tkip") == 0)
            found_pair_tkip = TRUE;
        else if (strcmp(tmp, "ccmp") == 0)
            found_pair_ccmp = TRUE;
    }
    g_assert(found_pair_tkip);
    g_assert(found_pair_ccmp);

    /* Group ciphers */
    n = nm_setting_wireless_security_get_num_groups(s_wsec);
    g_assert_cmpint(n, ==, 4);
    for (i = 0; i < n; i++) {
        const char *tmp = nm_setting_wireless_security_get_group(s_wsec, i);
        g_assert(tmp);
        if (strcmp(tmp, "tkip") == 0)
            found_group_tkip = TRUE;
        else if (strcmp(tmp, "ccmp") == 0)
            found_group_ccmp = TRUE;
        else if (strcmp(tmp, "wep40") == 0)
            found_group_wep40 = TRUE;
        else if (strcmp(tmp, "wep104") == 0)
            found_group_wep104 = TRUE;
    }
    g_assert(found_group_tkip);
    g_assert(found_group_ccmp);
    g_assert(found_group_wep40);
    g_assert(found_group_wep104);

    /* Protocols */
    n = nm_setting_wireless_security_get_num_protos(s_wsec);
    g_assert_cmpint(n, ==, 2);
    for (i = 0; i < n; i++) {
        const char *tmp = nm_setting_wireless_security_get_proto(s_wsec, i);
        g_assert(tmp);
        if (strcmp(tmp, "wpa") == 0)
            found_proto_wpa = TRUE;
        else if (strcmp(tmp, "rsn") == 0)
            found_proto_rsn = TRUE;
    }
    g_assert(found_proto_wpa);
    g_assert(found_proto_rsn);

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);
}

static void
test_read_wifi_sae(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingWireless            *s_wifi;
    NMSettingWirelessSecurity    *s_wsec;
    GBytes                       *ssid;
    const char                   *expected_ssid = "blahblah";

    connection =
        _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wifi-sae", NULL, TYPE_WIRELESS, NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "System blahblah (test-wifi-sae)");

    g_assert_cmpint(nm_setting_connection_get_timestamp(s_con), ==, 0);
    g_assert(nm_setting_connection_get_autoconnect(s_con));

    s_wifi = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS);

    g_assert_cmpint(nm_setting_wireless_get_mtu(s_wifi), ==, 0);

    ssid = nm_setting_wireless_get_ssid(s_wifi);
    g_assert(ssid);
    g_assert_cmpmem(g_bytes_get_data(ssid, NULL),
                    g_bytes_get_size(ssid),
                    expected_ssid,
                    strlen(expected_ssid));

    g_assert(!nm_setting_wireless_get_bssid(s_wifi));
    g_assert_cmpstr(nm_setting_wireless_get_mode(s_wifi), ==, "infrastructure");

    s_wsec = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
    g_assert_cmpstr(nm_setting_wireless_security_get_key_mgmt(s_wsec), ==, "sae");
    g_assert_cmpstr(nm_setting_wireless_security_get_psk(s_wsec), ==, "The king is dead.");
    g_assert(!nm_setting_wireless_security_get_auth_alg(s_wsec));
}

static void
test_read_wifi_owe(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingWireless            *s_wifi;
    NMSettingWirelessSecurity    *s_wsec;
    GBytes                       *ssid;
    const char                   *expected_ssid = "blahblah_owe";

    connection =
        _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wifi-owe", NULL, TYPE_WIRELESS, NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "System blahblah_owe (test-wifi-owe)");

    g_assert_cmpint(nm_setting_connection_get_timestamp(s_con), ==, 0);
    g_assert(nm_setting_connection_get_autoconnect(s_con));

    s_wifi = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS);

    g_assert_cmpint(nm_setting_wireless_get_mtu(s_wifi), ==, 0);

    ssid = nm_setting_wireless_get_ssid(s_wifi);
    g_assert(ssid);
    g_assert_cmpmem(g_bytes_get_data(ssid, NULL),
                    g_bytes_get_size(ssid),
                    expected_ssid,
                    strlen(expected_ssid));

    g_assert(!nm_setting_wireless_get_bssid(s_wifi));
    g_assert_cmpstr(nm_setting_wireless_get_mode(s_wifi), ==, "infrastructure");

    s_wsec = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
    g_assert_cmpstr(nm_setting_wireless_security_get_key_mgmt(s_wsec), ==, "owe");
    g_assert(!nm_setting_wireless_security_get_psk(s_wsec));
    g_assert(!nm_setting_wireless_security_get_auth_alg(s_wsec));
}

static void
test_read_wifi_wpa_psk_2(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingWirelessSecurity    *s_wsec;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wifi-wpa-psk-2",
                                       NULL,
                                       TYPE_WIRELESS,
                                       NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "System ipsum (test-wifi-wpa-psk-2)");

    nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS);

    s_wsec = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
    g_assert_cmpstr(nm_setting_wireless_security_get_psk(s_wsec),
                    ==,
                    "They're really saying I love you. >>`<< '");
}

static void
test_read_wifi_wpa_psk_unquoted(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingWirelessSecurity    *s_wsec;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wifi-wpa-psk-unquoted",
                                       NULL,
                                       TYPE_WIRELESS,
                                       NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con),
                    ==,
                    "System blahblah (test-wifi-wpa-psk-unquoted)");

    nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS);

    s_wsec = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
    g_assert_cmpstr(nm_setting_wireless_security_get_psk(s_wsec), ==, "54336845e2f3f321c4c7");
}

static void
test_read_wifi_wpa_psk_unquoted2(void)
{
    gs_unref_object NMConnection *connection = NULL;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wifi-wpa-psk-unquoted2",
                                       NULL,
                                       TYPE_WIRELESS,
                                       NULL);
}

static void
test_read_wifi_wpa_psk_adhoc(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingWireless            *s_wifi;
    NMSettingWirelessSecurity    *s_wsec;
    NMSettingIPConfig            *s_ip4;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wifi-wpa-psk-adhoc",
                                       NULL,
                                       TYPE_WIRELESS,
                                       NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con),
                    ==,
                    "System blahblah (test-wifi-wpa-psk-adhoc)");

    s_wifi = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS);

    g_assert_cmpstr(nm_setting_wireless_get_mode(s_wifi), ==, "adhoc");

    s_wsec = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
    g_assert_cmpstr(nm_setting_wireless_security_get_key_mgmt(s_wsec), ==, "wpa-psk");
    g_assert_cmpstr(nm_setting_wireless_security_get_psk(s_wsec),
                    ==,
                    "I wonder what the king is doing tonight?");

    g_assert_cmpint(nm_setting_wireless_security_get_num_pairwise(s_wsec), ==, 1);
    g_assert_cmpstr(nm_setting_wireless_security_get_pairwise(s_wsec, 0), ==, "ccmp");

    g_assert_cmpint(nm_setting_wireless_security_get_num_groups(s_wsec), ==, 1);
    g_assert_cmpstr(nm_setting_wireless_security_get_group(s_wsec, 0), ==, "ccmp");

    g_assert_cmpint(nm_setting_wireless_security_get_num_protos(s_wsec), ==, 1);
    g_assert_cmpstr(nm_setting_wireless_security_get_proto(s_wsec, 0), ==, "rsn");

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);
}

static void
test_read_wifi_wpa_psk_hex(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingWireless            *s_wifi;
    NMSettingWirelessSecurity    *s_wsec;
    NMSettingIPConfig            *s_ip4;
    GBytes                       *ssid;
    const char                   *expected_ssid = "blahblah";

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wifi-wpa-psk-hex",
                                       NULL,
                                       TYPE_WIRELESS,
                                       NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con),
                    ==,
                    "System blahblah (test-wifi-wpa-psk-hex)");

    s_wifi = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS);

    ssid = nm_setting_wireless_get_ssid(s_wifi);
    g_assert(ssid);
    g_assert(nm_g_bytes_equal_mem(ssid, expected_ssid, strlen(expected_ssid)));

    s_wsec = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
    g_assert_cmpstr(nm_setting_wireless_security_get_key_mgmt(s_wsec), ==, "wpa-psk");
    g_assert_cmpstr(nm_setting_wireless_security_get_psk(s_wsec),
                    ==,
                    "1da190379817bc360dda52e85c388c439a21ea5c7bf819c64e9da051807deae6");

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);
}

#define TEST_IFCFG_WIFI_WPA_EAP_TLS_CA_CERT     TEST_IFCFG_DIR "/test_ca_cert.pem"
#define TEST_IFCFG_WIFI_WPA_EAP_TLS_CLIENT_CERT TEST_IFCFG_DIR "/test1_key_and_cert.pem"
#define TEST_IFCFG_WIFI_WPA_EAP_TLS_PRIVATE_KEY TEST_IFCFG_DIR "/test1_key_and_cert.pem"

static void
test_read_wifi_wpa_eap_tls(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingIPConfig            *s_ip4;
    NMSetting8021x               *s_8021x;
    char                         *unmanaged                 = NULL;
    const char                   *expected_privkey_password = "test1";

    NMTST_EXPECT_NM_WARN("*key ONBOOT is duplicated and the early occurrence ignored*");
    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wifi-wpa-eap-tls",
                                       NULL,
                                       TYPE_ETHERNET,
                                       &unmanaged);
    g_test_assert_expected_messages();
    g_assert(!unmanaged);

    nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS);

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);

    s_8021x = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_802_1X);
    g_assert_cmpint(nm_setting_802_1x_get_num_eap_methods(s_8021x), ==, 1);
    g_assert_cmpstr(nm_setting_802_1x_get_eap_method(s_8021x, 0), ==, "tls");
    g_assert_cmpstr(nm_setting_802_1x_get_identity(s_8021x), ==, "Bill Smith");

    /* CA Cert */
    verify_cert_or_key(s_8021x,
                       TEST_IFCFG_WIFI_WPA_EAP_TLS_CA_CERT,
                       NULL,
                       NM_SETTING_802_1X_CA_CERT);

    /* Client Cert */
    verify_cert_or_key(s_8021x,
                       TEST_IFCFG_WIFI_WPA_EAP_TLS_CLIENT_CERT,
                       NULL,
                       NM_SETTING_802_1X_CLIENT_CERT);

    /* Private Key Password */
    g_assert_cmpstr(nm_setting_802_1x_get_private_key_password(s_8021x),
                    ==,
                    expected_privkey_password);

    /* Private key */
    verify_cert_or_key(s_8021x,
                       TEST_IFCFG_WIFI_WPA_EAP_TLS_PRIVATE_KEY,
                       expected_privkey_password,
                       NM_SETTING_802_1X_PRIVATE_KEY);
}

/* Also use TLS defines from the previous test */

static void
test_read_wifi_wpa_eap_ttls_tls(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingIPConfig            *s_ip4;
    NMSetting8021x               *s_8021x;
    char                         *unmanaged                 = NULL;
    const char                   *expected_privkey_password = "test1";

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wifi-wpa-eap-ttls-tls",
                                       NULL,
                                       TYPE_WIRELESS,
                                       &unmanaged);
    g_assert(!unmanaged);

    nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS);

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);

    s_8021x = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_802_1X);
    g_assert_cmpint(nm_setting_802_1x_get_num_eap_methods(s_8021x), ==, 1);
    g_assert_cmpstr(nm_setting_802_1x_get_eap_method(s_8021x, 0), ==, "ttls");
    g_assert_cmpstr(nm_setting_802_1x_get_identity(s_8021x), ==, "Chuck Shumer");

    /* CA Cert */
    verify_cert_or_key(s_8021x,
                       TEST_IFCFG_DIR "/test_ca_cert.pem",
                       NULL,
                       NM_SETTING_802_1X_CA_CERT);

    /* Inner auth method */
    g_assert_cmpstr(nm_setting_802_1x_get_phase2_autheap(s_8021x), ==, "tls");

    /* Inner CA Cert */
    verify_cert_or_key(s_8021x,
                       TEST_IFCFG_WIFI_WPA_EAP_TLS_CA_CERT,
                       NULL,
                       NM_SETTING_802_1X_PHASE2_CA_CERT);

    /* Inner Client Cert */
    verify_cert_or_key(s_8021x,
                       TEST_IFCFG_WIFI_WPA_EAP_TLS_CLIENT_CERT,
                       NULL,
                       NM_SETTING_802_1X_PHASE2_CLIENT_CERT);

    /* Inner Private Key Password */
    g_assert_cmpstr(nm_setting_802_1x_get_phase2_private_key_password(s_8021x),
                    ==,
                    expected_privkey_password);

    /* Inner private key */
    verify_cert_or_key(s_8021x,
                       TEST_IFCFG_WIFI_WPA_EAP_TLS_PRIVATE_KEY,
                       expected_privkey_password,
                       NM_SETTING_802_1X_PHASE2_PRIVATE_KEY);
}

static void
test_read_wifi_wpa_eap_suite_b_192_tls(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingWirelessSecurity    *s_wsec;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wifi-wpa-eap-suite-b-192-tls",
                                       NULL,
                                       TYPE_WIRELESS,
                                       NULL);

    nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS);

    s_wsec = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
    g_assert_cmpstr(nm_setting_wireless_security_get_key_mgmt(s_wsec), ==, "wpa-eap-suite-b-192");
}

static void
test_read_wifi_dynamic_wep_leap(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingWirelessSecurity    *s_wsec;
    NMSetting8021x               *s_8021x;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wifi-dynamic-wep-leap",
                                       NULL,
                                       TYPE_WIRELESS,
                                       NULL);

    nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS);

    s_wsec = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);

    /* Key management */
    g_assert_cmpstr(nm_setting_wireless_security_get_key_mgmt(s_wsec), ==, "ieee8021x");

    /* Auth alg should be NULL (open) for dynamic WEP with LEAP as the EAP method;
     * only "old-school" LEAP uses 'leap' for the auth alg.
     */
    g_assert_cmpstr(nm_setting_wireless_security_get_auth_alg(s_wsec), ==, NULL);

    /* Expect no old-school LEAP username/password, that'll be in the 802.1x setting */
    g_assert_cmpstr(nm_setting_wireless_security_get_leap_username(s_wsec), ==, NULL);
    g_assert_cmpstr(nm_setting_wireless_security_get_leap_password(s_wsec), ==, NULL);

    s_8021x = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_802_1X);

    /* EAP method should be "leap" */
    g_assert_cmpint(nm_setting_802_1x_get_num_eap_methods(s_8021x), ==, 1);
    g_assert_cmpstr(nm_setting_802_1x_get_eap_method(s_8021x, 0), ==, "leap");

    /* username & password */
    g_assert_cmpstr(nm_setting_802_1x_get_identity(s_8021x), ==, "bill smith");
    g_assert_cmpstr(nm_setting_802_1x_get_password(s_8021x), ==, "foobar baz");
}

static void
test_read_wifi_wep_eap_ttls_chap(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingWirelessSecurity    *s_wsec;
    NMSettingIPConfig            *s_ip4;
    NMSetting8021x               *s_8021x;
    char                         *unmanaged = NULL;

    NMTST_EXPECT_NM_WARN("*key ONBOOT is duplicated and the early occurrence ignored*");
    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wifi-wep-eap-ttls-chap",
                                       NULL,
                                       TYPE_WIRELESS,
                                       &unmanaged);
    g_test_assert_expected_messages();
    g_assert(!unmanaged);

    nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS);

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);

    s_wsec = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
    g_assert_cmpstr(nm_setting_wireless_security_get_key_mgmt(s_wsec), ==, "ieee8021x");

    s_8021x = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_802_1X);

    /* EAP methods */
    g_assert_cmpint(nm_setting_802_1x_get_num_eap_methods(s_8021x), ==, 1);
    g_assert_cmpstr(nm_setting_802_1x_get_eap_method(s_8021x, 0), ==, "ttls");

    /* CA Cert */
    verify_cert_or_key(s_8021x,
                       TEST_IFCFG_DIR "/test_ca_cert.pem",
                       NULL,
                       NM_SETTING_802_1X_CA_CERT);

    g_assert_cmpstr(nm_setting_802_1x_get_phase2_auth(s_8021x), ==, "chap");
    g_assert_cmpstr(nm_setting_802_1x_get_identity(s_8021x), ==, "David Smith");
    g_assert_cmpstr(nm_setting_802_1x_get_password(s_8021x), ==, "foobar baz");
}

static void
test_read_wired_wake_on_lan(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingWired               *s_wired;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wired-wake-on-lan",
                                       NULL,
                                       TYPE_WIRELESS,
                                       NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
                    ==,
                    NM_SETTING_WIRED_SETTING_NAME);

    s_wired = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);
    g_assert_cmpint(nm_setting_wired_get_wake_on_lan(s_wired),
                    ==,
                    NM_SETTING_WIRED_WAKE_ON_LAN_ARP | NM_SETTING_WIRED_WAKE_ON_LAN_PHY
                        | NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC);

    g_assert_cmpstr(nm_setting_wired_get_wake_on_lan_password(s_wired), ==, "00:11:22:33:44:55");
}

static void
test_read_wired_auto_negotiate_off(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingWired               *s_wired;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wired-wake-on-lan",
                                       NULL,
                                       TYPE_ETHERNET,
                                       NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
                    ==,
                    NM_SETTING_WIRED_SETTING_NAME);

    s_wired = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);

    g_assert(!nm_setting_wired_get_auto_negotiate(s_wired));
    g_assert_cmpint(nm_setting_wired_get_speed(s_wired), ==, 100);
    g_assert_cmpstr(nm_setting_wired_get_duplex(s_wired), ==, "full");
}

static void
test_read_wired_auto_negotiate_on(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingWired               *s_wired;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wired-auto-negotiate-on",
                                       NULL,
                                       TYPE_ETHERNET,
                                       NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
                    ==,
                    NM_SETTING_WIRED_SETTING_NAME);

    s_wired = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);

    g_assert(nm_setting_wired_get_auto_negotiate(s_wired));
    g_assert_cmpint(nm_setting_wired_get_speed(s_wired), ==, 0);
    g_assert_cmpstr(nm_setting_wired_get_duplex(s_wired), ==, NULL);
}

static void
test_read_wired_unknown_ethtool_opt(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingWired               *s_wired;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wired-unknown-ethtool-opt",
                                       NULL,
                                       TYPE_ETHERNET,
                                       NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
                    ==,
                    NM_SETTING_WIRED_SETTING_NAME);

    s_wired = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);

    g_assert(!nm_setting_wired_get_auto_negotiate(s_wired));
    g_assert(!nm_setting_wired_get_speed(s_wired));
    g_assert(!nm_setting_wired_get_duplex(s_wired));

    g_assert_cmpint(nm_setting_wired_get_wake_on_lan(s_wired),
                    ==,
                    NM_SETTING_WIRED_WAKE_ON_LAN_ARP | NM_SETTING_WIRED_WAKE_ON_LAN_PHY
                        | NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC);
    g_assert_cmpstr(nm_setting_wired_get_wake_on_lan_password(s_wired), ==, "00:11:22:33:44:55");
}

static void
test_roundtrip_ethtool(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSetting                    *s_ethtool;
    NMSetting                    *s_wired;
    int                           i_run;

    connection = nmtst_create_minimal_connection("test_roundtrip_ethtool",
                                                 NULL,
                                                 NM_SETTING_WIRED_SETTING_NAME,
                                                 NULL);
    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR,
                           TEST_IFCFG_DIR "/ifcfg-test_roundtrip_ethtool-1.cexpected",
                           NULL);
    g_clear_object(&connection);

    connection = nmtst_create_minimal_connection("test_roundtrip_ethtool",
                                                 NULL,
                                                 NM_SETTING_WIRED_SETTING_NAME,
                                                 NULL);

    s_ethtool = _nm_connection_new_setting(connection, NM_TYPE_SETTING_ETHTOOL);
    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR,
                           TEST_IFCFG_DIR "/ifcfg-test_roundtrip_ethtool-2.cexpected",
                           NULL);
    g_clear_object(&connection);

    connection = nmtst_create_minimal_connection("test_roundtrip_ethtool",
                                                 NULL,
                                                 NM_SETTING_WIRED_SETTING_NAME,
                                                 NULL);
    s_wired    = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);
    g_object_set(s_wired, NM_SETTING_WIRED_AUTO_NEGOTIATE, TRUE, NULL);
    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR,
                           TEST_IFCFG_DIR "/ifcfg-test_roundtrip_ethtool-3.cexpected",
                           NULL);
    g_clear_object(&connection);

    connection = nmtst_create_minimal_connection("test_roundtrip_ethtool",
                                                 NULL,
                                                 NM_SETTING_WIRED_SETTING_NAME,
                                                 NULL);

    s_ethtool = _nm_connection_new_setting(connection, NM_TYPE_SETTING_ETHTOOL);
    nm_setting_option_set_boolean(s_ethtool, NM_ETHTOOL_OPTNAME_FEATURE_RX, TRUE);
    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR,
                           TEST_IFCFG_DIR "/ifcfg-test_roundtrip_ethtool-4.cexpected",
                           NULL);
    g_clear_object(&connection);

    connection = nmtst_create_minimal_connection("test_roundtrip_ethtool",
                                                 NULL,
                                                 NM_SETTING_WIRED_SETTING_NAME,
                                                 NULL);
    s_wired    = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);
    g_object_set(s_wired, NM_SETTING_WIRED_AUTO_NEGOTIATE, TRUE, NULL);

    s_ethtool = _nm_connection_new_setting(connection, NM_TYPE_SETTING_ETHTOOL);
    nm_setting_option_set_boolean(s_ethtool, NM_ETHTOOL_OPTNAME_FEATURE_RX, TRUE);
    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR,
                           TEST_IFCFG_DIR "/ifcfg-test_roundtrip_ethtool-5.cexpected",
                           NULL);
    g_clear_object(&connection);

    connection = nmtst_create_minimal_connection("test_roundtrip_ethtool",
                                                 NULL,
                                                 NM_SETTING_WIRED_SETTING_NAME,
                                                 NULL);
    s_wired    = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);
    g_object_set(s_wired, NM_SETTING_WIRED_AUTO_NEGOTIATE, TRUE, NULL);

    s_ethtool = _nm_connection_new_setting(connection, NM_TYPE_SETTING_ETHTOOL);
    nm_setting_option_set_boolean(s_ethtool, NM_ETHTOOL_OPTNAME_PAUSE_AUTONEG, FALSE);
    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR,
                           TEST_IFCFG_DIR "/ifcfg-test_roundtrip_ethtool-6.cexpected",
                           NULL);
    g_clear_object(&connection);

    connection = nmtst_create_minimal_connection("test_roundtrip_ethtool",
                                                 NULL,
                                                 NM_SETTING_WIRED_SETTING_NAME,
                                                 NULL);
    s_wired    = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);
    g_object_set(s_wired, NM_SETTING_WIRED_AUTO_NEGOTIATE, TRUE, NULL);

    s_ethtool = _nm_connection_new_setting(connection, NM_TYPE_SETTING_ETHTOOL);
    nm_setting_option_set_uint32(s_ethtool, NM_ETHTOOL_OPTNAME_RING_RX, 512);
    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR,
                           TEST_IFCFG_DIR "/ifcfg-test_roundtrip_ethtool-7.cexpected",
                           NULL);
    g_clear_object(&connection);

    connection = nmtst_create_minimal_connection("test_roundtrip_ethtool",
                                                 NULL,
                                                 NM_SETTING_WIRED_SETTING_NAME,
                                                 NULL);
    s_wired    = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);
    g_object_set(s_wired, NM_SETTING_WIRED_AUTO_NEGOTIATE, TRUE, NULL);

    s_ethtool = _nm_connection_new_setting(connection, NM_TYPE_SETTING_ETHTOOL);
    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR,
                           TEST_IFCFG_DIR "/ifcfg-test_roundtrip_ethtool-8.cexpected",
                           NULL);
    g_clear_object(&connection);

    connection = nmtst_create_minimal_connection("test_roundtrip_ethtool",
                                                 NULL,
                                                 NM_SETTING_WIRED_SETTING_NAME,
                                                 NULL);
    s_wired    = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);
    g_object_set(s_wired, NM_SETTING_WIRED_AUTO_NEGOTIATE, TRUE, NULL);

    s_ethtool = _nm_connection_new_setting(connection, NM_TYPE_SETTING_ETHTOOL);
    nm_setting_option_set_boolean(s_ethtool, NM_ETHTOOL_OPTNAME_PAUSE_AUTONEG, FALSE);
    nm_setting_option_set_uint32(s_ethtool, NM_ETHTOOL_OPTNAME_RING_RX, 512);
    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR,
                           TEST_IFCFG_DIR "/ifcfg-test_roundtrip_ethtool-9.cexpected",
                           NULL);
    g_clear_object(&connection);

    for (i_run = 0; i_run < 20; i_run++) {
        gs_unref_object NMConnection *con2     = NULL;
        gs_unref_object NMConnection *reread   = NULL;
        nmtst_auto_unlinkfile char   *testfile = NULL;
        gboolean                      reread_same;
        gboolean                      v_bool;
        NMEthtoolID                   ethtool_ids[_NM_ETHTOOL_ID_NUM];
        guint                         i;
        guint                         l;
        NMSettingWiredWakeOnLan       wake_on_lan;

        con2    = nmtst_create_minimal_connection("test_roundtrip_ethtool",
                                               NULL,
                                               NM_SETTING_WIRED_SETTING_NAME,
                                               NULL);
        s_wired = nmtst_connection_assert_setting(con2, NM_TYPE_SETTING_WIRED);
        g_object_set(s_wired, NM_SETTING_WIRED_AUTO_NEGOTIATE, nmtst_get_rand_bool(), NULL);

        if (nmtst_get_rand_bool()) {
            g_object_set(s_wired,
                         NM_SETTING_WIRED_SPEED,
                         1000u,
                         NM_SETTING_WIRED_DUPLEX,
                         nmtst_get_rand_bool() ? "full" : "half",
                         NULL);
        }

        wake_on_lan = nmtst_get_rand_uint32();
        wake_on_lan = wake_on_lan & NM_SETTING_WIRED_WAKE_ON_LAN_ALL;
        wake_on_lan = nmtst_rand_select(wake_on_lan,
                                        NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT,
                                        NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE);
        g_object_set(s_wired, NM_SETTING_WIRED_WAKE_ON_LAN, (guint) wake_on_lan, NULL);

        if (NM_FLAGS_HAS(wake_on_lan, NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC)
            && nmtst_get_rand_bool()) {
            g_object_set(s_wired, NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD, "aa:bb:cc:dd:ee:ff", NULL);
        }

        l = nmtst_get_rand_uint32() % (G_N_ELEMENTS(ethtool_ids) + 2);
        if (l == 0) {
            /* pass. No ethtool setting. */
            goto check_roundtrip;
        }
        l--;

        s_ethtool = _nm_connection_new_setting(con2, NM_TYPE_SETTING_ETHTOOL);

        for (i = 0; i < (int) G_N_ELEMENTS(ethtool_ids); i++)
            ethtool_ids[i] = i;
        nmtst_rand_perm(NULL, ethtool_ids, NULL, sizeof(ethtool_ids[0]), G_N_ELEMENTS(ethtool_ids));

        for (i = 0; i < l; i++) {
            NMEthtoolID         ethtool_id = ethtool_ids[i];
            const GVariantType *vtype;
            const char         *optname;

            optname = nm_ethtool_data[ethtool_id]->optname;
            vtype   = nm_ethtool_id_get_variant_type(ethtool_id);

            if (nm_ethtool_optname_is_channels(optname) || nm_ethtool_optname_is_eee(optname)
                || nm_ethtool_optname_is_fec(optname)) {
                /* Not supported */
                continue;
            }

            if (NM_IN_SET(ethtool_id,
                          NM_ETHTOOL_ID_COALESCE_ADAPTIVE_RX,
                          NM_ETHTOOL_ID_COALESCE_ADAPTIVE_TX)) {
                nm_setting_option_set_uint32(s_ethtool, optname, nmtst_get_rand_uint32() % 2);
            } else if (g_variant_type_equal(vtype, G_VARIANT_TYPE_BOOLEAN))
                nm_setting_option_set_boolean(s_ethtool, optname, nmtst_get_rand_bool());
            else if (g_variant_type_equal(vtype, G_VARIANT_TYPE_UINT32))
                nm_setting_option_set_uint32(s_ethtool, optname, nmtst_get_rand_uint32());
            else
                g_assert_not_reached();
        }

        if ((nm_setting_option_get_boolean(s_ethtool, NM_ETHTOOL_OPTNAME_PAUSE_RX, NULL)
             || nm_setting_option_get_boolean(s_ethtool, NM_ETHTOOL_OPTNAME_PAUSE_TX, NULL))
            && nm_setting_option_get_boolean(s_ethtool, NM_ETHTOOL_OPTNAME_PAUSE_AUTONEG, &v_bool)
            && v_bool) {
            /* don't accidentally create an invalid profile. */
            nm_setting_option_set(s_ethtool,
                                  NM_ETHTOOL_OPTNAME_PAUSE_AUTONEG,
                                  nmtst_get_rand_bool() ? g_variant_new_boolean(FALSE) : NULL);
        }

check_roundtrip:
        _writer_new_connection_reread(con2,
                                      TEST_SCRATCH_DIR,
                                      &testfile,
                                      NO_EXPECTED,
                                      &reread,
                                      &reread_same);
        g_assert(NM_IS_CONNECTION(reread));
        g_assert(reread_same);
    }
}

static void
test_read_wifi_hidden(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingWireless            *s_wifi;

    connection =
        _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wifi-hidden", NULL, TYPE_WIRELESS, NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
                    ==,
                    NM_SETTING_WIRELESS_SETTING_NAME);

    s_wifi = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS);
    g_assert(nm_setting_wireless_get_hidden(s_wifi) == TRUE);
}

static void
test_write_wifi_hidden(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingWireless            *s_wifi;
    shvarFile                    *f;
    gs_unref_bytes GBytes        *ssid =
        nmtst_gbytes_from_arr(0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x53, 0x49, 0x44);

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Wi-Fi Hidden",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRELESS_SETTING_NAME,
                 NULL);

    s_wifi = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS);
    g_object_set(s_wifi, NM_SETTING_WIRELESS_SSID, ssid, NM_SETTING_WIRELESS_HIDDEN, TRUE, NULL);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR,
                           TEST_IFCFG_DIR "/ifcfg-Test_Write_WiFi_Hidden.cexpected",
                           &testfile);

    f = _svOpenFile(testfile);
    _svGetValue_check(f, "SSID_HIDDEN", "yes");
    svCloseFile(f);

    reread = _connection_from_file(testfile, NULL, TYPE_WIRELESS, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_read_wifi_mac_random(gconstpointer user_data)
{
    gs_unref_object NMConnection *connection = NULL;
    gs_free char                 *path       = NULL;
    NMSettingWireless            *s_wifi;
    const char                   *name;
    gpointer                      value_p;
    NMSettingMacRandomization     value;

    nmtst_test_data_unpack(user_data, &name, &value_p);
    value = GPOINTER_TO_INT(value_p);

    path       = g_strdup_printf(TEST_IFCFG_DIR "/ifcfg-test-wifi-mac-random-%s", name);
    connection = _connection_from_file(path, NULL, TYPE_WIRELESS, NULL);

    s_wifi = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS);
    g_assert_cmpint(nm_setting_wireless_get_mac_address_randomization(s_wifi), ==, value);
}

static void
test_write_wifi_mac_random(gconstpointer user_data)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingWireless            *s_wifi;
    gs_free char                 *val = NULL;
    shvarFile                    *f;
    gs_unref_bytes GBytes        *ssid =
        nmtst_gbytes_from_arr(0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x53, 0x49, 0x44);
    const char               *name, *write_expected;
    gpointer                  value_p;
    NMSettingMacRandomization value;
    char                      cexpected[NM_STRLEN(TEST_IFCFG_DIR) + 100];

    nmtst_test_data_unpack(user_data, &name, &value_p, &write_expected);
    value = GPOINTER_TO_INT(value_p);

    g_assert(write_expected);

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);

    val = g_strdup_printf("Test Write Wi-Fi MAC %s", name);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 val,
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRELESS_SETTING_NAME,
                 NULL);

    s_wifi = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS);
    g_object_set(s_wifi,
                 NM_SETTING_WIRELESS_SSID,
                 ssid,
                 NM_SETTING_WIRELESS_MODE,
                 "infrastructure",
                 NM_SETTING_WIRELESS_MAC_ADDRESS_RANDOMIZATION,
                 value,
                 NULL);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connec_exp(
        connection,
        TEST_SCRATCH_DIR,
        nm_sprintf_buf(cexpected, TEST_IFCFG_DIR "/ifcfg-Test_Write_WiFi_MAC_%s.cexpected", name),
        &testfile);

    f = _svOpenFile(testfile);
    _svGetValue_check(f, "MAC_ADDRESS_RANDOMIZATION", write_expected);
    svCloseFile(f);

    reread = _connection_from_file(testfile, NULL, TYPE_WIRELESS, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_write_wired_wake_on_lan(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingWired               *s_wired;
    gs_free char                 *val = NULL;
    shvarFile                    *f;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Wired Wake-on-LAN",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRED_SETTING_NAME,
                 NULL);

    s_wired = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRED);
    g_object_set(s_wired,
                 NM_SETTING_WIRED_WAKE_ON_LAN,
                 (guint) (NM_SETTING_WIRED_WAKE_ON_LAN_MULTICAST
                          | NM_SETTING_WIRED_WAKE_ON_LAN_UNICAST
                          | NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC),
                 NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD,
                 "00:00:00:11:22:33",
                 NULL);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR,
                           TEST_IFCFG_DIR "/ifcfg-Test_Write_Wired_Wake-on-LAN.cexpected",
                           &testfile);

    f   = _svOpenFile(testfile);
    val = svGetValueStr_cp(f, "ETHTOOL_OPTS");
    g_assert(val);
    g_assert(strstr(val, "wol"));
    g_assert(strstr(val, "sopass 00:00:00:11:22:33"));
    svCloseFile(f);

    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_write_wired_auto_negotiate_off(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingWired               *s_wired;
    gs_free char                 *val = NULL;
    shvarFile                    *f;

    connection = nmtst_create_minimal_connection("Test Write Wired Auto-Negotiate",
                                                 NULL,
                                                 NM_SETTING_WIRED_SETTING_NAME,
                                                 NULL);
    s_wired    = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);
    g_object_set(s_wired,
                 NM_SETTING_WIRED_AUTO_NEGOTIATE,
                 FALSE,
                 NM_SETTING_WIRED_DUPLEX,
                 "half",
                 NM_SETTING_WIRED_SPEED,
                 10,
                 NULL);

    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR,
                           TEST_IFCFG_DIR "/ifcfg-Test_Write_Wired_Auto-Negotiate.cexpected",
                           &testfile);

    f   = _svOpenFile(testfile);
    val = svGetValueStr_cp(f, "ETHTOOL_OPTS");
    g_assert(val);
    g_assert(strstr(val, "autoneg off"));
    g_assert(strstr(val, "speed 10"));
    g_assert(strstr(val, "duplex half"));
    svCloseFile(f);

    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_write_wired_auto_negotiate_on(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingWired               *s_wired;
    NMSettingEthtool             *s_ethtool;
    gs_free char                 *val = NULL;
    shvarFile                    *f;

    connection = nmtst_create_minimal_connection("Test Write Wired Auto-Negotiate",
                                                 NULL,
                                                 NM_SETTING_WIRED_SETTING_NAME,
                                                 NULL);
    s_wired    = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);
    g_object_set(s_wired, NM_SETTING_WIRED_AUTO_NEGOTIATE, TRUE, NULL);

    s_ethtool = _nm_connection_new_setting(connection, NM_TYPE_SETTING_ETHTOOL);
    nm_setting_ethtool_set_feature(s_ethtool, NM_ETHTOOL_OPTNAME_FEATURE_TX, NM_TERNARY_TRUE);
    nm_setting_ethtool_set_feature(s_ethtool, NM_ETHTOOL_OPTNAME_FEATURE_RXVLAN, NM_TERNARY_FALSE);

    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR,
                           TEST_IFCFG_DIR "/ifcfg-test_write_wired_auto_negotiate_on.cexpected",
                           &testfile);

    f   = _svOpenFile(testfile);
    val = svGetValueStr_cp(f, "ETHTOOL_OPTS");
    g_assert(val);
    g_assert(strstr(val, "autoneg on"));
    g_assert(!strstr(val, "speed"));
    g_assert(!strstr(val, "duplex"));
    svCloseFile(f);

    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);

    nmtst_assert_connection_verifies_without_normalization(reread);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);

    s_ethtool = nmtst_connection_assert_setting(reread, NM_TYPE_SETTING_ETHTOOL);
    g_assert_cmpint(nm_setting_ethtool_get_feature(s_ethtool, NM_ETHTOOL_OPTNAME_FEATURE_TX),
                    ==,
                    NM_TERNARY_TRUE);
    g_assert_cmpint(nm_setting_ethtool_get_feature(s_ethtool, NM_ETHTOOL_OPTNAME_FEATURE_RXVLAN),
                    ==,
                    NM_TERNARY_FALSE);
    g_assert_cmpint(nm_setting_ethtool_get_feature(s_ethtool, NM_ETHTOOL_OPTNAME_FEATURE_TXVLAN),
                    ==,
                    NM_TERNARY_DEFAULT);
}

static void
test_read_wifi_band_a(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingWireless            *s_wifi;

    connection =
        _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wifi-band-a", NULL, TYPE_WIRELESS, NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
                    ==,
                    NM_SETTING_WIRELESS_SETTING_NAME);

    s_wifi = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS);
    g_assert_cmpstr(nm_setting_wireless_get_band(s_wifi), ==, "a");
}

static void
test_write_wifi_band_a(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingWireless            *s_wifi;
    shvarFile                    *f;
    gs_unref_bytes GBytes        *ssid =
        nmtst_gbytes_from_arr(0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x53, 0x49, 0x44);

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Wi-Fi Band A",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRELESS_SETTING_NAME,
                 NULL);

    s_wifi = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS);
    g_object_set(s_wifi,
                 NM_SETTING_WIRELESS_SSID,
                 ssid,
                 NM_SETTING_WIRELESS_MODE,
                 "infrastructure",
                 NM_SETTING_WIRELESS_BAND,
                 "a",
                 NULL);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR,
                           TEST_IFCFG_DIR "/ifcfg-Test_Write_WiFi_Band_A.cexpected",
                           &testfile);

    f = _svOpenFile(testfile);
    _svGetValue_check(f, "BAND", "a");
    svCloseFile(f);

    reread = _connection_from_file(testfile, NULL, TYPE_WIRELESS, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_write_wifi_ap_mode(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingWireless            *s_wifi;
    gs_unref_bytes GBytes        *ssid = nmtst_gbytes_from_str("MySSID");

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Wi-Fi AP Mode",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRELESS_SETTING_NAME,
                 NULL);

    s_wifi = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS);
    g_object_set(s_wifi,
                 NM_SETTING_WIRELESS_SSID,
                 ssid,
                 NM_SETTING_WIRELESS_MODE,
                 "ap",
                 NM_SETTING_WIRELESS_BAND,
                 "a",
                 NM_SETTING_WIRELESS_CHANNEL,
                 (guint) 196,
                 NM_SETTING_WIRELESS_AP_ISOLATION,
                 NM_TERNARY_TRUE,
                 NULL);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR,
                           TEST_IFCFG_DIR "/ifcfg-Test_Write_WiFi_AP_Mode.cexpected",
                           &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_WIRELESS, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_read_wifi_band_a_channel_mismatch(void)
{
    gs_free_error GError *error = NULL;

    _connection_from_file_fail(TEST_IFCFG_DIR "/ifcfg-test-wifi-band-a-channel-mismatch",
                               NULL,
                               TYPE_WIRELESS,
                               &error);
    g_assert_error(error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION);
}

static void
test_read_wifi_band_bg_channel_mismatch(void)
{
    gs_free_error GError *error = NULL;

    _connection_from_file_fail(TEST_IFCFG_DIR "/ifcfg-test-wifi-band-bg-channel-mismatch",
                               NULL,
                               TYPE_WIRELESS,
                               &error);
    g_assert_error(error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION);
}

static void
test_read_wired_qeth_static(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingWired               *s_wired;
    NMSettingIPConfig            *s_ip4;
    char                         *unmanaged = NULL;
    const char *const            *subchannels;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wired-qeth-static",
                                       NULL,
                                       TYPE_ETHERNET,
                                       &unmanaged);
    g_assert(!unmanaged);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "System test-wired-qeth-static");

    s_wired = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);

    g_assert(!nm_setting_wired_get_mac_address(s_wired));

    /* Subchannels */
    subchannels = nm_setting_wired_get_s390_subchannels(s_wired);
    g_assert(subchannels);
    g_assert(subchannels[0] && subchannels[1] && subchannels[2] && !subchannels[3]);

    g_assert_cmpstr(subchannels[0], ==, "0.0.0600");
    g_assert_cmpstr(subchannels[1], ==, "0.0.0601");
    g_assert_cmpstr(subchannels[2], ==, "0.0.0602");

    g_assert_cmpstr(nm_setting_wired_get_s390_nettype(s_wired), ==, "qeth");
    g_assert_cmpstr(nm_setting_wired_get_s390_option_by_key(s_wired, "portname"), ==, "OSAPORT");
    g_assert_cmpstr(nm_setting_wired_get_s390_option_by_key(s_wired, "portno"), ==, "0");
    g_assert_cmpstr(nm_setting_wired_get_s390_option_by_key(s_wired, "layer2"), ==, "1");

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
                    ==,
                    NM_SETTING_IP4_CONFIG_METHOD_MANUAL);
}

static void
test_read_wired_ctc_static(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingWired               *s_wired;
    char                         *unmanaged = NULL;
    const char *const            *subchannels;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wired-ctc-static",
                                       NULL,
                                       TYPE_ETHERNET,
                                       &unmanaged);
    g_assert(unmanaged == NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "System test-wired-ctc-static");

    s_wired = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);

    g_assert(nm_setting_wired_get_mac_address(s_wired) == NULL);

    /* Subchannels */
    subchannels = nm_setting_wired_get_s390_subchannels(s_wired);
    g_assert(subchannels != NULL);
    g_assert(subchannels[0] && subchannels[1] && !subchannels[2]);

    g_assert_cmpstr(subchannels[0], ==, "0.0.1b00");
    g_assert_cmpstr(subchannels[1], ==, "0.0.1b01");

    g_assert_cmpstr(nm_setting_wired_get_s390_nettype(s_wired), ==, "ctc");
    g_assert_cmpstr(nm_setting_wired_get_s390_option_by_key(s_wired, "ctcprot"), ==, "0");
}

static void
test_read_wifi_wep_no_keys(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingWirelessSecurity    *s_wsec;
    NMWepKeyType                  key_type;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wifi-wep-no-keys",
                                       NULL,
                                       TYPE_WIRELESS,
                                       NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_id(s_con),
                    ==,
                    "System foobar (test-wifi-wep-no-keys)");

    /* UUID can't be tested if the ifcfg does not contain the UUID key, because
     * the UUID is generated on the full path of the ifcfg file, which can change
     * depending on where the tests are run.
     */

    nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS);

    s_wsec = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);

    /* Key management */
    g_assert_cmpstr(nm_setting_wireless_security_get_key_mgmt(s_wsec), ==, "none");

    /* WEP key index */
    g_assert_cmpint(nm_setting_wireless_security_get_wep_tx_keyidx(s_wsec), ==, 0);

    /* WEP key type */
    key_type = nm_setting_wireless_security_get_wep_key_type(s_wsec);
    g_assert(key_type == NM_WEP_KEY_TYPE_UNKNOWN || key_type == NM_WEP_KEY_TYPE_KEY);

    /* WEP key index 0; we don't expect it to be filled */
    g_assert(!nm_setting_wireless_security_get_wep_key(s_wsec, 0));
}

static void
test_read_permissions(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    gboolean                      success;
    guint32                       num;
    const char                   *tmp;

    connection =
        _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-permissions", NULL, TYPE_ETHERNET, NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);

    num = nm_setting_connection_get_num_permissions(s_con);
    g_assert_cmpint(num, ==, 3);

    /* verify each permission */
    tmp     = NULL;
    success = nm_setting_connection_get_permission(s_con, 0, NULL, &tmp, NULL);
    g_assert(success);
    g_assert_cmpstr(tmp, ==, "dcbw");

    tmp     = NULL;
    success = nm_setting_connection_get_permission(s_con, 1, NULL, &tmp, NULL);
    g_assert(success);
    g_assert_cmpstr(tmp, ==, "ssmith");

    tmp     = NULL;
    success = nm_setting_connection_get_permission(s_con, 2, NULL, &tmp, NULL);
    g_assert(success);
    g_assert_cmpstr(tmp, ==, "johnny5");
}

static void
test_read_wifi_wep_agent_keys(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingWirelessSecurity    *s_wsec;
    NMWepKeyType                  key_type;
    NMSettingSecretFlags          flags;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wifi-wep-agent-keys",
                                       NULL,
                                       TYPE_WIRELESS,
                                       NULL);

    /* Ensure the connection is still marked for wifi security even though
     * we don't have any WEP keys because they are agent owned.
     */

    nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS);

    s_wsec = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);

    g_assert(strcmp(nm_setting_wireless_security_get_key_mgmt(s_wsec), "none") == 0);
    g_assert(nm_setting_wireless_security_get_wep_tx_keyidx(s_wsec) == 0);

    key_type = nm_setting_wireless_security_get_wep_key_type(s_wsec);
    g_assert(key_type == NM_WEP_KEY_TYPE_UNKNOWN || key_type == NM_WEP_KEY_TYPE_KEY);

    /* We don't expect WEP key0 to be filled */
    g_assert(nm_setting_wireless_security_get_wep_key(s_wsec, 0) == NULL);

    flags = nm_setting_wireless_security_get_wep_key_flags(s_wsec);
    g_assert(flags & NM_SETTING_SECRET_FLAG_AGENT_OWNED);
}

static void
test_write_wired_static(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    nmtst_auto_unlinkfile char   *route4file = NULL;
    nmtst_auto_unlinkfile char   *route6file = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingWired               *s_wired;
    NMSettingIPConfig            *s_ip4, *reread_s_ip4;
    NMSettingIPConfig            *s_ip6, *reread_s_ip6;
    NMIPAddress                  *addr;
    NMIPAddress                  *addr6;
    NMIPRoute                    *route4;
    NMIPRoute                    *route6;
    GError                       *error = NULL;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Wired Static",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_AUTOCONNECT_RETRIES,
                 1,
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRED_SETTING_NAME,
                 NULL);

    s_wired = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRED);
    g_object_set(s_wired,
                 NM_SETTING_WIRED_MAC_ADDRESS,
                 "31:33:33:37:be:cd",
                 NM_SETTING_WIRED_MTU,
                 (guint32) 1492,
                 NULL);

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NM_SETTING_IP_CONFIG_GATEWAY,
                 "1.1.1.1",
                 NM_SETTING_IP_CONFIG_ROUTE_METRIC,
                 (gint64) 204,
                 NULL);

    addr = nm_ip_address_new(AF_INET, "1.1.1.3", 24, &error);
    g_assert_no_error(error);
    nm_setting_ip_config_add_address(s_ip4, addr);
    nm_ip_address_unref(addr);

    addr = nm_ip_address_new(AF_INET, "1.1.1.5", 24, &error);
    g_assert_no_error(error);
    nm_setting_ip_config_add_address(s_ip4, addr);
    nm_ip_address_unref(addr);

    nm_setting_ip_config_add_dns(s_ip4, "4.2.2.1");
    nm_setting_ip_config_add_dns(s_ip4, "4.2.2.2");

    nm_setting_ip_config_add_dns_search(s_ip4, "foobar.com");
    nm_setting_ip_config_add_dns_search(s_ip4, "lab.foobar.com");

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP6_CONFIG_METHOD_MANUAL,
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NM_SETTING_IP_CONFIG_ROUTE_METRIC,
                 (gint64) 206,
                 NULL);

    /* Add addresses */
    addr6 = nm_ip_address_new(AF_INET6, "1003:1234:abcd::1", 11, &error);
    g_assert_no_error(error);
    nm_setting_ip_config_add_address(s_ip6, addr6);
    nm_ip_address_unref(addr6);

    addr6 = nm_ip_address_new(AF_INET6, "2003:1234:abcd::2", 22, &error);
    g_assert_no_error(error);
    nm_setting_ip_config_add_address(s_ip6, addr6);
    nm_ip_address_unref(addr6);

    addr6 = nm_ip_address_new(AF_INET6, "3003:1234:abcd::3", 33, &error);
    g_assert_no_error(error);
    nm_setting_ip_config_add_address(s_ip6, addr6);
    nm_ip_address_unref(addr6);

    /* Add routes */
    route6 = nm_ip_route_new(AF_INET6,
                             "2222:aaaa:bbbb:cccc::",
                             64,
                             "2222:aaaa:bbbb:cccc:dddd:eeee:5555:6666",
                             99,
                             &error);
    g_assert_no_error(error);
    nm_setting_ip_config_add_route(s_ip6, route6);
    nm_ip_route_unref(route6);

    route6 = nm_ip_route_new(AF_INET6, "::", 128, "2222:aaaa::9999", 1, &error);
    g_assert_no_error(error);
    nm_ip_route_set_attribute(route6, NM_IP_ROUTE_ATTRIBUTE_CWND, g_variant_new_uint32(100));
    nm_ip_route_set_attribute(route6, NM_IP_ROUTE_ATTRIBUTE_MTU, g_variant_new_uint32(1280));
    nm_ip_route_set_attribute(route6, NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND, g_variant_new_boolean(TRUE));
    nm_ip_route_set_attribute(route6,
                              NM_IP_ROUTE_ATTRIBUTE_FROM,
                              g_variant_new_string("2222::bbbb/32"));
    nm_ip_route_set_attribute(route6, NM_IP_ROUTE_ATTRIBUTE_SRC, g_variant_new_string("::42"));
    nm_setting_ip_config_add_route(s_ip6, route6);
    nm_ip_route_unref(route6);

    route4 = nm_ip_route_new(AF_INET, "1.1.1.1", 24, "1.2.3.4", 99, &error);
    g_assert_no_error(error);
    nm_ip_route_set_attribute(route4, NM_IP_ROUTE_ATTRIBUTE_CWND, g_variant_new_uint32(100));
    nm_ip_route_set_attribute(route4, NM_IP_ROUTE_ATTRIBUTE_WEIGHT, g_variant_new_uint32(5));
    nm_setting_ip_config_add_route(s_ip4, route4);
    nm_ip_route_unref(route4);

    /* DNS servers */
    nm_setting_ip_config_add_dns(s_ip6, "fade:0102:0103::face");
    nm_setting_ip_config_add_dns(s_ip6, "cafe:ffff:eeee:dddd:cccc:bbbb:aaaa:feed");

    /* DNS domains */
    nm_setting_ip_config_add_dns_search(s_ip6, "foobar6.com");
    nm_setting_ip_config_add_dns_search(s_ip6, "lab6.foobar.com");

    nmtst_assert_connection_verifies(connection);

    _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile);

    route6file = utils_get_route6_path(testfile);
    route4file = utils_get_route_path(testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);

    reread_s_ip4 = nmtst_connection_assert_setting(reread, NM_TYPE_SETTING_IP4_CONFIG);
    reread_s_ip6 = nmtst_connection_assert_setting(reread, NM_TYPE_SETTING_IP6_CONFIG);

    g_assert_cmpint(nm_setting_ip_config_get_route_metric(reread_s_ip4), ==, 204);
    g_assert_cmpint(nm_setting_ip_config_get_route_metric(reread_s_ip6), ==, 206);

    _nm_connection_new_setting(connection, NM_TYPE_SETTING_PROXY);

    nmtst_assert_connection_equals(connection, FALSE, reread, FALSE);
}

static void
test_write_wired_static_with_generic(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    nmtst_auto_unlinkfile char   *route6file = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingWired               *s_wired;
    NMSettingIPConfig            *s_ip4, *reread_s_ip4;
    NMSettingIPConfig            *s_ip6, *reread_s_ip6;
    NMIPAddress                  *addr;
    NMIPAddress                  *addr6;
    NMIPRoute                    *route6;
    GError                       *error = NULL;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Wired Static",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_AUTOCONNECT_RETRIES,
                 1,
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRED_SETTING_NAME,
                 NULL);

    s_wired = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRED);
    g_object_set(s_wired,
                 NM_SETTING_WIRED_MAC_ADDRESS,
                 "31:33:33:37:be:cd",
                 NM_SETTING_WIRED_MTU,
                 (guint32) 1492,
                 NULL);

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NM_SETTING_IP_CONFIG_GATEWAY,
                 "1.1.1.1",
                 NM_SETTING_IP_CONFIG_ROUTE_METRIC,
                 (gint64) 204,
                 NULL);

    addr = nm_ip_address_new(AF_INET, "1.1.1.3", 24, &error);
    g_assert_no_error(error);
    nm_setting_ip_config_add_address(s_ip4, addr);
    nm_ip_address_unref(addr);

    addr = nm_ip_address_new(AF_INET, "1.1.1.5", 24, &error);
    g_assert_no_error(error);
    nm_setting_ip_config_add_address(s_ip4, addr);
    nm_ip_address_unref(addr);

    nm_setting_ip_config_add_dns(s_ip4, "4.2.2.1");
    nm_setting_ip_config_add_dns(s_ip4, "4.2.2.2");

    nm_setting_ip_config_add_dns_search(s_ip4, "foobar.com");
    nm_setting_ip_config_add_dns_search(s_ip4, "lab.foobar.com");

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP6_CONFIG_METHOD_MANUAL,
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NM_SETTING_IP_CONFIG_ROUTE_METRIC,
                 (gint64) 206,
                 NULL);

    /* Add addresses */
    addr6 = nm_ip_address_new(AF_INET6, "1003:1234:abcd::1", 11, &error);
    g_assert_no_error(error);
    nm_setting_ip_config_add_address(s_ip6, addr6);
    nm_ip_address_unref(addr6);

    addr6 = nm_ip_address_new(AF_INET6, "2003:1234:abcd::2", 22, &error);
    g_assert_no_error(error);
    nm_setting_ip_config_add_address(s_ip6, addr6);
    nm_ip_address_unref(addr6);

    addr6 = nm_ip_address_new(AF_INET6, "3003:1234:abcd::3", 33, &error);
    g_assert_no_error(error);
    nm_setting_ip_config_add_address(s_ip6, addr6);
    nm_ip_address_unref(addr6);

    /* Add routes */
    route6 = nm_ip_route_new(AF_INET6,
                             "2222:aaaa:bbbb:cccc::",
                             64,
                             "2222:aaaa:bbbb:cccc:dddd:eeee:5555:6666",
                             99,
                             &error);
    g_assert_no_error(error);
    nm_setting_ip_config_add_route(s_ip6, route6);
    nm_ip_route_unref(route6);

    route6 = nm_ip_route_new(AF_INET6, "::", 128, "2222:aaaa::9999", 1, &error);
    g_assert_no_error(error);
    nm_ip_route_set_attribute(route6, NM_IP_ROUTE_ATTRIBUTE_CWND, g_variant_new_uint32(100));
    nm_ip_route_set_attribute(route6, NM_IP_ROUTE_ATTRIBUTE_MTU, g_variant_new_uint32(1280));
    nm_ip_route_set_attribute(route6, NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND, g_variant_new_boolean(TRUE));
    nm_ip_route_set_attribute(route6,
                              NM_IP_ROUTE_ATTRIBUTE_FROM,
                              g_variant_new_string("2222::bbbb/32"));
    nm_ip_route_set_attribute(route6, NM_IP_ROUTE_ATTRIBUTE_SRC, g_variant_new_string("::42"));
    nm_setting_ip_config_add_route(s_ip6, route6);
    nm_ip_route_unref(route6);

    /* DNS servers */
    nm_setting_ip_config_add_dns(s_ip6, "fade:0102:0103::face");
    nm_setting_ip_config_add_dns(s_ip6, "cafe:ffff:eeee:dddd:cccc:bbbb:aaaa:feed");

    /* DNS domains */
    nm_setting_ip_config_add_dns_search(s_ip6, "foobar6.com");
    nm_setting_ip_config_add_dns_search(s_ip6, "lab6.foobar.com");

    _nm_connection_new_setting(connection, NM_TYPE_SETTING_GENERIC);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connection_FIXME(connection, TEST_SCRATCH_DIR, &testfile);
    route6file = utils_get_route6_path(testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);

    reread_s_ip4 = nmtst_connection_assert_setting(reread, NM_TYPE_SETTING_IP4_CONFIG);
    reread_s_ip6 = nmtst_connection_assert_setting(reread, NM_TYPE_SETTING_IP6_CONFIG);

    g_assert_cmpint(nm_setting_ip_config_get_route_metric(reread_s_ip4), ==, 204);
    g_assert_cmpint(nm_setting_ip_config_get_route_metric(reread_s_ip6), ==, 206);

    _nm_connection_new_setting(connection, NM_TYPE_SETTING_PROXY);

    {
        gs_unref_hashtable GHashTable *diffs = NULL;

        g_assert(!nm_connection_diff(connection, reread, NM_SETTING_COMPARE_FLAG_EXACT, &diffs));
        g_assert(diffs);
        g_assert(g_hash_table_size(diffs) == 1);
        g_assert(g_hash_table_lookup(diffs, "generic"));
        g_assert(!nm_connection_compare(connection, reread, NM_SETTING_COMPARE_FLAG_EXACT));
    }
    nmtst_connection_assert_no_setting(reread, NM_TYPE_SETTING_GENERIC);
    _nm_connection_new_setting(reread, NM_TYPE_SETTING_GENERIC);
    {
        gs_unref_hashtable GHashTable *diffs = NULL;

        g_assert(nm_connection_diff(connection, reread, NM_SETTING_COMPARE_FLAG_EXACT, &diffs));
        g_assert(!diffs);
        g_assert(nm_connection_compare(connection, reread, NM_SETTING_COMPARE_FLAG_EXACT));
    }
}

static void
test_write_wired_dhcp(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Wired DHCP",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRED_SETTING_NAME,
                 NULL);

    _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRED);

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP4_CONFIG_METHOD_AUTO,
                 NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID,
                 "random-client-id-00:22:33",
                 NM_SETTING_IP4_CONFIG_DHCP_FQDN,
                 "awesome.hostname",
                 NM_SETTING_IP_CONFIG_DHCP_HOSTNAME_FLAGS,
                 (guint) NM_DHCP_HOSTNAME_FLAG_FQDN_ENCODED,
                 NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES,
                 TRUE,
                 NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS,
                 TRUE,
                 NM_SETTING_IP_CONFIG_DHCP_IAID,
                 "2864434397",
                 NULL);

    nmtst_assert_connection_verifies(connection);

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP6_CONFIG_METHOD_DHCP,
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NM_SETTING_IP_CONFIG_DHCP_HOSTNAME,
                 "awesome.hostname",
                 NM_SETTING_IP_CONFIG_DHCP_HOSTNAME_FLAGS,
                 (guint) NM_DHCP_HOSTNAME_FLAG_FQDN_NO_UPDATE,
                 NULL);

    _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static NMIPRoutingRule *
_ip_routing_rule_new(int addr_family, const char *str)
{
    NMIPRoutingRuleAsStringFlags flags = NM_IP_ROUTING_RULE_AS_STRING_FLAGS_NONE;
    gs_free_error GError        *local = NULL;
    NMIPRoutingRule             *rule;

    if (addr_family != AF_UNSPEC) {
        if (addr_family == AF_INET)
            flags = NM_IP_ROUTING_RULE_AS_STRING_FLAGS_AF_INET;
        else {
            g_assert(addr_family == AF_INET6);
            flags = NM_IP_ROUTING_RULE_AS_STRING_FLAGS_AF_INET6;
        }
    }

    rule = nm_ip_routing_rule_from_string(str,
                                          NM_IP_ROUTING_RULE_AS_STRING_FLAGS_VALIDATE | flags,
                                          NULL,
                                          nmtst_get_rand_bool() ? &local : NULL);
    nmtst_assert_success(rule, local);

    if (addr_family != AF_UNSPEC)
        g_assert_cmpint(nm_ip_routing_rule_get_addr_family(rule), ==, addr_family);
    return rule;
}

static void
_ip_routing_rule_add_to_setting(NMSettingIPConfig *s_ip, const char *str)
{
    nm_auto_unref_ip_routing_rule NMIPRoutingRule *rule = NULL;

    rule = _ip_routing_rule_new(nm_setting_ip_config_get_addr_family(s_ip), str);
    nm_setting_ip_config_add_routing_rule(s_ip, rule);
}

static void
test_write_routing_rules(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Routing Rules",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRED_SETTING_NAME,
                 NULL);

    _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRED);

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP4_CONFIG_METHOD_AUTO,
                 NM_SETTING_IP4_CONFIG_LINK_LOCAL,
                 NM_SETTING_IP4_LL_ENABLED,
                 NULL);

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO, NULL);

    _ip_routing_rule_add_to_setting(s_ip4, "pref 10 from 0.0.0.0/0 table 1");
    _ip_routing_rule_add_to_setting(s_ip4, "priority 10 to 192.167.8.0/24 table 2");
    _ip_routing_rule_add_to_setting(s_ip6, "pref 10 from ::/0 table 10");
    _ip_routing_rule_add_to_setting(s_ip6, "pref 10 from ::/0 to 1:2:3::5/24 table 22");
    _ip_routing_rule_add_to_setting(s_ip6, "pref 10 from ::/0 to 1:3:3::5/128 table 55");

    nmtst_assert_connection_verifies(connection);

    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR,
                           TEST_IFCFG_DIR "/ifcfg-Test_Write_Routing_Rules.cexpected",
                           &testfile);
    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);
    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_write_wired_match(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingMatch               *s_match;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Wired with Match setting",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRED_SETTING_NAME,
                 NULL);

    _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRED);

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
                 NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE,
                 (int) NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64,
                 NULL);

    s_match = _nm_connection_new_setting(connection, NM_TYPE_SETTING_MATCH);
    nm_setting_match_add_interface_name(s_match, "ens*");
    nm_setting_match_add_interface_name(s_match, "eth 1?");
    nm_setting_match_add_interface_name(s_match, "!veth*");
    nm_setting_match_add_driver(s_match, "!virtio");
    nm_setting_match_add_driver(s_match, "e1000e");
    nm_setting_match_add_kernel_command_line(s_match, "!ip=");

    nmtst_assert_connection_verifies(connection);
    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR,
                           TEST_IFCFG_DIR "/ifcfg-Test_Write_Wired_match.cexpected",
                           &testfile);
    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);
    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_write_wired_dhcp_plus_ip(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wired-dhcp-plus-ip",
                                       NULL,
                                       TYPE_ETHERNET,
                                       NULL);

    _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_read_write_link_local(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingIPConfig            *s_ip4;

    connection =
        _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-link_local", NULL, TYPE_ETHERNET, NULL);

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert(nm_setting_ip4_config_get_link_local(NM_SETTING_IP4_CONFIG(s_ip4))
             == NM_SETTING_IP4_LL_ENABLED);

    g_object_set(s_ip4, NM_SETTING_IP4_CONFIG_LINK_LOCAL, NM_SETTING_IP4_LL_DISABLED, NULL);

    _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);

    s_ip4 = nmtst_connection_assert_setting(reread, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert(nm_setting_ip4_config_get_link_local(NM_SETTING_IP4_CONFIG(s_ip4))
             == NM_SETTING_IP4_LL_DISABLED);
}

static void
test_read_write_wired_dhcp_send_hostname(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    const char                   *dhcp_hostname = "kamil-patka";

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wired-dhcp-send-hostname",
                                       NULL,
                                       TYPE_ETHERNET,
                                       NULL);

    /* Check dhcp-hostname and dhcp-send-hostname */
    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    s_ip6 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_assert(nm_setting_ip_config_get_dhcp_send_hostname(s_ip4) == TRUE);
    g_assert_cmpstr(nm_setting_ip_config_get_dhcp_hostname(s_ip4), ==, "svata-pulec");
    g_assert(!nm_setting_ip_config_get_dhcp_hostname(s_ip6));

    /* Set dhcp-send-hostname=false dhcp-hostname="kamil-patka" and write the connection. */
    g_object_set(s_ip4, NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME, FALSE, NULL);
    g_object_set(s_ip4, NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, dhcp_hostname, NULL);
    g_object_set(s_ip6, NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, dhcp_hostname, NULL);

    _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);

    /* Check dhcp-hostname and dhcp-send-hostname from the re-read connection. */
    s_ip4 = nmtst_connection_assert_setting(reread, NM_TYPE_SETTING_IP4_CONFIG);
    s_ip6 = nmtst_connection_assert_setting(reread, NM_TYPE_SETTING_IP6_CONFIG);
    g_assert(nm_setting_ip_config_get_dhcp_send_hostname(s_ip4) == FALSE);
    g_assert_cmpstr(nm_setting_ip_config_get_dhcp_hostname(s_ip4), ==, dhcp_hostname);
    g_assert_cmpstr(nm_setting_ip_config_get_dhcp_hostname(s_ip6), ==, dhcp_hostname);
}

static void
test_read_wired_dhcpv6_hostname_fallback(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingIPConfig            *s_ip6;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wired-dhcpv6-hostname-fallback",
                                       NULL,
                                       TYPE_ETHERNET,
                                       NULL);

    s_ip6 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_assert(nm_setting_ip_config_get_dhcp_send_hostname(s_ip6) == TRUE);
    g_assert_cmpstr(nm_setting_ip_config_get_dhcp_hostname(s_ip6), ==, "fully.qualified.domain");
}

static void
test_write_wired_static_ip6_only(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingWired               *s_wired;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    NMIPAddress                  *addr6;
    GError                       *error = NULL;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Wired Static IP6 Only",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRED_SETTING_NAME,
                 NULL);

    s_wired = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRED);
    g_object_set(s_wired, NM_SETTING_WIRED_MAC_ADDRESS, "31:33:33:37:be:cd", NULL);

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_DISABLED, NULL);

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_MANUAL, NULL);

    /* Add addresses */
    addr6 = nm_ip_address_new(AF_INET6, "1003:1234:abcd::1", 11, &error);
    g_assert_no_error(error);
    nm_setting_ip_config_add_address(s_ip6, addr6);
    nm_ip_address_unref(addr6);

    /* DNS server */
    nm_setting_ip_config_add_dns(s_ip6, "fade:0102:0103::face");

    nmtst_assert_connection_verifies(connection);

    _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_write_ip6_disabled(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;

    connection = nmtst_create_minimal_connection("Test Write Wired Disabled IP6",
                                                 NULL,
                                                 NM_SETTING_WIRED_SETTING_NAME,
                                                 &s_con);

    _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRED);

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP6_CONFIG_METHOD_DISABLED,
                 NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE,
                 (int) NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64,
                 NULL);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR_TMP,
                           TEST_IFCFG_DIR "/ifcfg-test-ip6-disabled.cexpected",
                           &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);
    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

/* Test writing an IPv6 config with varying gateway address.
 * For missing gateway (::), we expect no IPV6_DEFAULTGW to be written
 * to ifcfg-rh.
 *
 * As user_data pass the IPv6 address of the gateway as string. NULL means
 * not to explicitly set the gateway in the configuration before writing it.
 * That way, the gateway actually defaults to "::".
 */
static void
test_write_wired_static_ip6_only_gw(gconstpointer user_data)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingWired               *s_wired;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    NMIPAddress                  *addr6;
    GError                       *error                 = NULL;
    gs_free char                 *id                    = NULL;
    gs_free char                 *written_ifcfg_gateway = NULL;
    const char                   *gateway6              = user_data;
    shvarFile                    *ifcfg;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);

    id = g_strdup_printf("Test Write Wired Static IP6 Only With Gateway %s", gateway6 ?: "NULL");
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 id,
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRED_SETTING_NAME,
                 NULL);

    s_wired = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRED);
    g_object_set(s_wired, NM_SETTING_WIRED_MAC_ADDRESS, "31:33:33:37:be:cd", NULL);

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_DISABLED, NULL);

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP6_CONFIG_METHOD_MANUAL,
                 NM_SETTING_IP_CONFIG_GATEWAY,
                 gateway6,
                 NULL);

    /* Add addresses */
    addr6 = nm_ip_address_new(AF_INET6, "1003:1234:abcd::1", 11, &error);
    g_assert_no_error(error);
    nm_setting_ip_config_add_address(s_ip6, addr6);
    nm_ip_address_unref(addr6);

    /* DNS server */
    nm_setting_ip_config_add_dns(s_ip6, "fade:0102:0103::face");

    nmtst_assert_connection_verifies(connection);

    _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);

    ifcfg                 = _svOpenFile(testfile);
    written_ifcfg_gateway = svGetValueStr_cp(ifcfg, "IPV6_DEFAULTGW");
    svCloseFile(ifcfg);

    /* access the gateway from the loaded connection. */
    s_ip6 = nmtst_connection_assert_setting(reread, NM_TYPE_SETTING_IP6_CONFIG);
    g_assert(nm_setting_ip_config_get_num_addresses(s_ip6) == 1);
    addr6 = nm_setting_ip_config_get_address(s_ip6, 0);
    g_assert(addr6);

    /* assert that the gateway was written and reloaded as expected */
    if (!gateway6 || !strcmp(gateway6, "::")) {
        g_assert_cmpstr(nm_setting_ip_config_get_gateway(s_ip6), ==, NULL);
        g_assert(written_ifcfg_gateway == NULL);
    } else {
        g_assert(nm_setting_ip_config_get_gateway(s_ip6) != NULL);
        g_assert_cmpstr(nm_setting_ip_config_get_gateway(s_ip6), ==, gateway6);
        g_assert_cmpstr(written_ifcfg_gateway, ==, gateway6);
    }
}

static void
test_read_write_static_routes_legacy(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    nmtst_auto_unlinkfile char   *routefile  = NULL;
    gs_free char                 *route6file = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingIPConfig            *s_ip4;
    const char                   *tmp;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-static-routes-legacy",
                                       NULL,
                                       TYPE_ETHERNET,
                                       NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);

    /* ID */
    tmp = nm_setting_connection_get_id(s_con);
    g_assert(tmp);

    /* Autoconnect */
    g_assert(nm_setting_connection_get_autoconnect(s_con));

    nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);

    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);

    g_assert(!nm_setting_ip_config_get_never_default(s_ip4));

    /* Save the ifcfg; use a special different scratch dir to ensure that
     * we can clean up after the written connection in both the original
     * source tree and for 'make distcheck'.
     */
    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR_TMP,
                           TEST_IFCFG_DIR "/ifcfg-test-static-routes-legacy.cexpected",
                           &testfile);

    reread     = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);
    routefile  = utils_get_route_path(testfile);
    route6file = utils_get_route6_path(testfile);
    g_assert(!g_file_test(route6file, G_FILE_TEST_EXISTS));

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_write_wired_static_routes(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    nmtst_auto_unlinkfile char   *routefile  = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingWired               *s_wired;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    NMIPAddress                  *addr;
    NMIPRoute                    *route;
    GError                       *error       = NULL;
    gboolean                      reread_same = FALSE;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Wired Static Routes",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRED_SETTING_NAME,
                 NULL);

    s_wired = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRED);
    g_object_set(s_wired,
                 NM_SETTING_WIRED_MAC_ADDRESS,
                 "31:33:33:37:be:cd",
                 NM_SETTING_WIRED_MTU,
                 (guint32) 1492,
                 NULL);

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
                 NM_SETTING_IP_CONFIG_GATEWAY,
                 "1.1.1.1",
                 NM_SETTING_IP_CONFIG_DAD_TIMEOUT,
                 400,
                 NULL);

    addr = nm_ip_address_new(AF_INET, "1.1.1.3", 24, &error);
    g_assert_no_error(error);
    nm_setting_ip_config_add_address(s_ip4, addr);
    nm_ip_address_unref(addr);

    addr = nm_ip_address_new(AF_INET, "1.1.1.5", 24, &error);
    g_assert_no_error(error);
    nm_setting_ip_config_add_address(s_ip4, addr);
    nm_ip_address_unref(addr);

    /* Write out routes */
    route = nm_ip_route_new(AF_INET, "1.2.3.0", 24, "222.173.190.239", 0, &error);
    nm_ip_route_set_attribute(route, NM_IP_ROUTE_ATTRIBUTE_WINDOW, g_variant_new_uint32(3455));
    nm_ip_route_set_attribute(route, NM_IP_ROUTE_ATTRIBUTE_ONLINK, g_variant_new_boolean(TRUE));
    g_assert_no_error(error);
    nm_setting_ip_config_add_route(s_ip4, route);
    nm_ip_route_unref(route);

    route = nm_ip_route_new(AF_INET, "3.2.1.0", 24, "202.254.186.190", 77, &error);
    nm_ip_route_set_attribute(route, NM_IP_ROUTE_ATTRIBUTE_WINDOW, g_variant_new_uint32(30000));
    nm_ip_route_set_attribute(route, NM_IP_ROUTE_ATTRIBUTE_ONLINK, g_variant_new_boolean(FALSE));
    g_assert_no_error(error);
    nm_setting_ip_config_add_route(s_ip4, route);
    nm_ip_route_unref(route);

    nm_setting_ip_config_add_dns(s_ip4, "4.2.2.1");
    nm_setting_ip_config_add_dns(s_ip4, "4.2.2.2");

    nm_setting_ip_config_add_dns_search(s_ip4, "foobar.com");
    nm_setting_ip_config_add_dns_search(s_ip4, "lab.foobar.com");

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE,
                 (int) NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64,
                 NULL);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connection_reread(connection,
                                  TEST_SCRATCH_DIR,
                                  &testfile,
                                  TEST_IFCFG_DIR "/ifcfg-Test_Write_Wired_Static_Routes.cexpected",
                                  &reread,
                                  &reread_same);
    /* ifcfg does not support setting onlink=0. It gets lost during write+re-read.
     * Assert that it's missing, and patch it to check whether the rest of the
     * connection equals. */
    g_assert(!reread_same);
    nmtst_assert_connection_verifies_without_normalization(reread);
    s_ip4 = nmtst_connection_assert_setting(reread, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip4), ==, 2);
    route = nm_setting_ip_config_get_route(s_ip4, 1);
    g_assert(route);
    g_assert(!nm_ip_route_get_attribute(route, NM_IP_ROUTE_ATTRIBUTE_ONLINK));
    nm_ip_route_set_attribute(route, NM_IP_ROUTE_ATTRIBUTE_ONLINK, g_variant_new_boolean(FALSE));

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);

    routefile = utils_get_route_path(testfile);
}

static void
test_write_wired_dhcp_8021x_peap_mschapv2(void)
{
    nmtst_auto_unlinkfile char   *keyfile    = NULL;
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    NMSetting8021x               *s_8021x;
    gboolean                      success;
    GError                       *error = NULL;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Wired DHCP 802.1x PEAP MSCHAPv2",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRED_SETTING_NAME,
                 NULL);

    _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRED);

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE,
                 (int) NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64,
                 NULL);

    s_8021x = _nm_connection_new_setting(connection, NM_TYPE_SETTING_802_1X);
    g_object_set(s_8021x,
                 NM_SETTING_802_1X_IDENTITY,
                 "Bob Saget",
                 NM_SETTING_802_1X_ANONYMOUS_IDENTITY,
                 "barney",
                 NM_SETTING_802_1X_PASSWORD,
                 "Kids, it was back in October 2008...",
                 NM_SETTING_802_1X_PHASE1_PEAPVER,
                 "1",
                 NM_SETTING_802_1X_PHASE1_PEAPLABEL,
                 "1",
                 NM_SETTING_802_1X_PHASE2_AUTH,
                 "mschapv2",
                 NM_SETTING_802_1X_OPENSSL_CIPHERS,
                 "DEFAULT@SECLEVEL=0",
                 NULL);
    nm_setting_802_1x_add_eap_method(s_8021x, "peap");

    success = nm_setting_802_1x_set_ca_cert(s_8021x,
                                            TEST_IFCFG_WIRED_8021x_PEAP_MSCHAPV2_CA_CERT,
                                            NM_SETTING_802_1X_CK_SCHEME_PATH,
                                            NULL,
                                            &error);
    nmtst_assert_success(success, error);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);

    keyfile = utils_get_keys_path(testfile);
}

static void
test_write_wired_8021x_tls(gconstpointer test_data)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_free char                 *keyfile    = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    NMSetting8021x               *s_8021x;
    gboolean                      success;
    GError                       *error  = NULL;
    NMSetting8021xCKFormat        format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
    const char                   *pw;
    gs_free char                 *tmp1 = NULL;
    gs_free char                 *tmp2 = NULL;
    gs_free char                 *tmp3 = NULL;
    gpointer                      scheme_p, flags_p;
    NMSetting8021xCKScheme        scheme;
    NMSettingSecretFlags          flags;

    nmtst_test_data_unpack(test_data, &scheme_p, &flags_p);
    scheme = GPOINTER_TO_INT(scheme_p);
    flags  = GPOINTER_TO_INT(flags_p);

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Wired 802.1x TLS Blobs",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRED_SETTING_NAME,
                 NULL);

    _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRED);

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NULL);

    s_8021x = _nm_connection_new_setting(connection, NM_TYPE_SETTING_802_1X);
    g_object_set(s_8021x, NM_SETTING_802_1X_IDENTITY, "Bill Smith", NULL);
    nm_setting_802_1x_add_eap_method(s_8021x, "tls");

    /* CA cert */
    success = nm_setting_802_1x_set_ca_cert(s_8021x,
                                            TEST_IFCFG_DIR "/test_ca_cert.pem",
                                            scheme,
                                            &format,
                                            &error);
    g_assert_no_error(error);
    g_assert(success);
    g_assert(format == NM_SETTING_802_1X_CK_FORMAT_X509);

    /* Client cert */
    format  = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
    success = nm_setting_802_1x_set_client_cert(s_8021x,
                                                TEST_IFCFG_DIR "/test1_key_and_cert.pem",
                                                scheme,
                                                &format,
                                                &error);
    g_assert_no_error(error);
    g_assert(success);
    g_assert(format == NM_SETTING_802_1X_CK_FORMAT_X509);

    /* Private key */
    format  = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
    success = nm_setting_802_1x_set_private_key(s_8021x,
                                                TEST_IFCFG_DIR "/test1_key_and_cert.pem",
                                                "test1",
                                                scheme,
                                                &format,
                                                &error);
    g_assert_no_error(error);
    g_assert(success);
    g_assert(format == NM_SETTING_802_1X_CK_FORMAT_RAW_KEY);

    /* Set secret flags */
    g_object_set(s_8021x, NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD_FLAGS, flags, NULL);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connection_FIXME(connection, TEST_SCRATCH_DIR, &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_WIRELESS, NULL);

    keyfile = utils_get_keys_path(testfile);
    nmtst_file_unlink_if_exists(keyfile);

    /* Ensure the reread connection's certificates and private key are paths; no
     * matter what scheme was used in the original connection they will be read
     * back in as paths.
     */
    s_8021x = nmtst_connection_assert_setting(reread, NM_TYPE_SETTING_802_1X);
    g_assert_cmpint(nm_setting_802_1x_get_ca_cert_scheme(s_8021x),
                    ==,
                    NM_SETTING_802_1X_CK_SCHEME_PATH);
    g_assert_cmpint(nm_setting_802_1x_get_client_cert_scheme(s_8021x),
                    ==,
                    NM_SETTING_802_1X_CK_SCHEME_PATH);
    g_assert_cmpint(nm_setting_802_1x_get_private_key_scheme(s_8021x),
                    ==,
                    NM_SETTING_802_1X_CK_SCHEME_PATH);

    g_assert_cmpint(nm_setting_802_1x_get_private_key_password_flags(s_8021x), ==, flags);
    pw = nm_setting_802_1x_get_private_key_password(s_8021x);
    if (flags == NM_SETTING_SECRET_FLAG_NONE) {
        /* Ensure the private key password is still set */
        g_assert(pw != NULL);
        g_assert_cmpstr(pw, ==, "test1");
    } else {
        /* If the secret isn't owned by system settings, make sure its no longer there */
        g_assert(pw == NULL);
    }

    if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) {
        /* Do a direct compare if using the path scheme since then the
         * certificate and key properties should be the same.  If using blob
         * scheme the original connection cert/key properties will be blobs
         * but the re-read connection is always path scheme, so we wouldn't
         * expect it to compare successfully.
         */
        if (flags != NM_SETTING_SECRET_FLAG_NONE) {
            /* Clear original connection's private key password because flags
             * say it's not system-owned, and therefore it should not show up
             * in the re-read connection.
             */
            s_8021x = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_802_1X);
            g_object_set(s_8021x, NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD, NULL, NULL);
        }

        nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
    }

    /* Clean up created certs and keys */
    tmp1 = utils_cert_path(testfile, "ca-cert", "der");
    nmtst_file_unlink_if_exists(tmp1);

    tmp2 = utils_cert_path(testfile, "client-cert", "der");
    nmtst_file_unlink_if_exists(tmp2);

    tmp3 = utils_cert_path(testfile, "private-key", "pem");
    nmtst_file_unlink_if_exists(tmp3);
}

static void
test_write_wired_aliases(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingIPConfig            *s_ip4;
    int                           num_addresses = 4;
    const char                   *ip[]          = {"1.1.1.1", "1.1.1.2", "1.1.1.3", "1.1.1.4"};
    const char                   *label[]       = {NULL, "alias0:2", NULL, "alias0:3"};
    NMIPAddress                  *addr;
    GError                       *error = NULL;
    shvarFile                    *ifcfg;
    int                           i, j;

    nmtst_file_unlink_if_exists(TEST_SCRATCH_ALIAS_BASE ":2");
    nmtst_file_unlink_if_exists(TEST_SCRATCH_ALIAS_BASE ":3");
    nmtst_file_unlink_if_exists(TEST_SCRATCH_ALIAS_BASE ":5");

    connection = nm_simple_connection_new();
    g_assert(connection);

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "alias0",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRED_SETTING_NAME,
                 NULL);

    _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRED);

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
                 NM_SETTING_IP_CONFIG_GATEWAY,
                 "1.1.1.1",
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NULL);

    for (i = 0; i < num_addresses; i++) {
        addr = nm_ip_address_new(AF_INET, ip[i], 24, &error);
        g_assert_no_error(error);
        if (label[i])
            nm_ip_address_set_attribute(addr,
                                        NM_IP_ADDRESS_ATTRIBUTE_LABEL,
                                        g_variant_new_string(label[i]));
        nm_setting_ip_config_add_address(s_ip4, addr);
        nm_ip_address_unref(addr);
    }

    nmtst_assert_connection_verifies(connection);

    /* Create some pre-existing alias files, to make sure they get overwritten / deleted. */
    ifcfg = svCreateFile(TEST_SCRATCH_ALIAS_BASE ":2");
    svSetValueStr(ifcfg, "DEVICE", "alias0:2");
    svSetValueStr(ifcfg, "IPADDR", "192.168.1.2");
    svWriteFile(ifcfg, 0644, NULL);
    svCloseFile(ifcfg);
    g_assert(g_file_test(TEST_SCRATCH_ALIAS_BASE ":2", G_FILE_TEST_EXISTS));

    ifcfg = svCreateFile(TEST_SCRATCH_ALIAS_BASE ":5");
    svSetValueStr(ifcfg, "DEVICE", "alias0:5");
    svSetValueStr(ifcfg, "IPADDR", "192.168.1.5");
    svWriteFile(ifcfg, 0644, NULL);
    svCloseFile(ifcfg);
    g_assert(g_file_test(TEST_SCRATCH_ALIAS_BASE ":5", G_FILE_TEST_EXISTS));

    _writer_new_connection_FIXME(connection, TEST_SCRATCH_DIR, &testfile);

    /* Re-check the alias files */
    g_assert(g_file_test(TEST_SCRATCH_ALIAS_BASE ":2", G_FILE_TEST_EXISTS));
    g_assert(g_file_test(TEST_SCRATCH_ALIAS_BASE ":3", G_FILE_TEST_EXISTS));
    g_assert(!g_file_test(TEST_SCRATCH_ALIAS_BASE ":5", G_FILE_TEST_EXISTS));

    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);
    nmtst_file_unlink(TEST_SCRATCH_ALIAS_BASE ":2");
    nmtst_file_unlink(TEST_SCRATCH_ALIAS_BASE ":3");

    /* nm_connection_compare() is not guaranteed to succeed, because the
     * aliases get read back in essentially random order. So just
     * verify the aliases manually.
     */
    s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_assert(nm_setting_ip_config_get_num_addresses(s_ip4) == num_addresses);

    /* Addresses */
    for (i = 0; i < num_addresses; i++) {
        const char *addrstr;

        addr = nm_setting_ip_config_get_address(s_ip4, i);
        g_assert(addr != NULL);

        addrstr = nm_ip_address_get_address(addr);
        for (j = 0; j < num_addresses; j++) {
            if (!g_strcmp0(addrstr, ip[j]))
                break;
        }
        if (j >= num_addresses)
            g_assert_not_reached();
        else {
            g_assert_cmpint(nm_ip_address_get_prefix(addr), ==, 24);
            if (label[j])
                g_assert_cmpstr(
                    g_variant_get_string(
                        nm_ip_address_get_attribute(addr, NM_IP_ADDRESS_ATTRIBUTE_LABEL),
                        NULL),
                    ==,
                    label[j]);
            else
                g_assert(nm_ip_address_get_attribute(addr, NM_IP_ADDRESS_ATTRIBUTE_LABEL) == NULL);
            ip[j] = NULL;
        }
    }

    for (i = 0; i < num_addresses; i++)
        g_assert(!ip[i]);

    /* Gateway */
    g_assert_cmpstr(nm_setting_ip_config_get_gateway(s_ip4), ==, "1.1.1.1");
}

static void
test_write_gateway(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingIPConfig            *s_ip4;
    GError                       *error = NULL;
    shvarFile                    *f;
    NMIPAddress                  *addr;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Static Addresses Gateway",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRED_SETTING_NAME,
                 NULL);

    _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRED);

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
                 NM_SETTING_IP_CONFIG_GATEWAY,
                 "1.1.1.254",
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NULL);

    addr = nm_ip_address_new(AF_INET, "1.1.1.3", 24, &error);
    g_assert_no_error(error);
    nm_setting_ip_config_add_address(s_ip4, addr);
    nm_ip_address_unref(addr);

    addr = nm_ip_address_new(AF_INET, "2.2.2.5", 24, &error);
    g_assert_no_error(error);
    nm_setting_ip_config_add_address(s_ip4, addr);
    nm_ip_address_unref(addr);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile);

    f = _svOpenFile(testfile);
    _svGetValue_check(f, "IPADDR", "1.1.1.3");
    _svGetValue_check(f, "IPADDR1", "2.2.2.5");
    _svGetValue_check(f, "IPADDR0", NULL);
    _svGetValue_check(f, "PREFIX", "24");
    _svGetValue_check(f, "PREFIX1", "24");
    _svGetValue_check(f, "PREFIX0", NULL);
    _svGetValue_check(f, "GATEWAY", "1.1.1.254");
    _svGetValue_check(f, "GATEWAY0", NULL);
    _svGetValue_check(f, "GATEWAY1", NULL);
    svCloseFile(f);

    reread = _connection_from_file(testfile, NULL, TYPE_WIRELESS, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_write_wifi_open(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingWireless            *s_wifi;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    gs_unref_bytes GBytes        *ssid =
        nmtst_gbytes_from_arr(0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x53, 0x49, 0x44);
    shvarFile *ifcfg;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Wifi Open",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRELESS_SETTING_NAME,
                 NULL);

    s_wifi = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS);
    g_object_set(s_wifi,
                 NM_SETTING_WIRELESS_SSID,
                 ssid,
                 NM_SETTING_WIRELESS_BSSID,
                 "11:22:33:44:55:66",
                 NM_SETTING_WIRELESS_MAC_ADDRESS,
                 "aa:bb:cc:dd:ee:ff",
                 NM_SETTING_WIRELESS_MODE,
                 "infrastructure",
                 NM_SETTING_WIRELESS_BAND,
                 "bg",
                 NM_SETTING_WIRELESS_CHANNEL,
                 (guint32) 9,
                 NM_SETTING_WIRELESS_MTU,
                 (guint32) 1345,
                 NULL);

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE,
                 (int) NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64,
                 NULL);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_WIRELESS, NULL);

    ifcfg = _svOpenFile(testfile);
    _svGetValue_check(ifcfg, "ESSID", "Test SSID");
    svCloseFile(ifcfg);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_write_wifi_open_hex_ssid(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingWireless            *s_wifi;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    gs_unref_bytes GBytes        *ssid = nmtst_gbytes_from_arr(0x11,
                                                        0x22,
                                                        0x33,
                                                        0x44,
                                                        0x55,
                                                        0x66,
                                                        0x77,
                                                        0x88,
                                                        0x99,
                                                        0xaa,
                                                        0xbb,
                                                        0xcc,
                                                        0xdd);

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Wifi Open Hex SSID",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRELESS_SETTING_NAME,
                 NULL);

    s_wifi = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS);
    g_object_set(s_wifi,
                 NM_SETTING_WIRELESS_SSID,
                 ssid,
                 NM_SETTING_WIRELESS_MODE,
                 "infrastructure",
                 NULL);

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NULL);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_WIRELESS, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_write_wifi_wep(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    nmtst_auto_unlinkfile char   *keyfile    = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingWireless            *s_wifi;
    NMSettingWirelessSecurity    *s_wsec;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    gs_unref_bytes GBytes        *ssid = nmtst_gbytes_from_str("blahblah");
    struct stat                   statbuf;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Wifi WEP",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRELESS_SETTING_NAME,
                 NULL);

    s_wifi = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS);
    g_object_set(s_wifi,
                 NM_SETTING_WIRELESS_SSID,
                 ssid,
                 NM_SETTING_WIRELESS_MODE,
                 "infrastructure",
                 NULL);

    s_wsec = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
    g_object_set(s_wsec,
                 NM_SETTING_WIRELESS_SECURITY_KEY_MGMT,
                 "none",
                 NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX,
                 2,
                 NM_SETTING_WIRELESS_SECURITY_AUTH_ALG,
                 "shared",
                 NULL);
    nm_setting_wireless_security_set_wep_key(s_wsec, 0, "0123456789abcdef0123456789");
    nm_setting_wireless_security_set_wep_key(s_wsec, 1, "11111111111111111111111111");
    nm_setting_wireless_security_set_wep_key(s_wsec, 2, "aaaaaaaaaaaaaaaaaaaaaaaaaa");
    nm_setting_wireless_security_set_wep_key(s_wsec, 3, "BBBBBBBBBBBBBBBBBBBBBBBBBB");

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE,
                 (int) NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64,
                 NULL);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_WIRELESS, NULL);

    keyfile = utils_get_keys_path(testfile);
    g_assert_cmpint(stat(keyfile, &statbuf), ==, 0);
    g_assert(S_ISREG(statbuf.st_mode));
    g_assert_cmpint((statbuf.st_mode & 0077), ==, 0);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_write_wifi_wep_adhoc(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    nmtst_auto_unlinkfile char   *keyfile    = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingWireless            *s_wifi;
    NMSettingWirelessSecurity    *s_wsec;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    GError                       *error = NULL;
    gs_unref_bytes GBytes        *ssid  = nmtst_gbytes_from_str("blahblah");
    struct stat                   statbuf;
    NMIPAddress                  *addr;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Wifi WEP AdHoc",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRELESS_SETTING_NAME,
                 NULL);

    s_wifi = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS);
    g_object_set(s_wifi, NM_SETTING_WIRELESS_SSID, ssid, NM_SETTING_WIRELESS_MODE, "adhoc", NULL);

    s_wsec = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
    g_object_set(s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none", NULL);
    nm_setting_wireless_security_set_wep_key(s_wsec, 0, "0123456789abcdef0123456789");

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
                 NM_SETTING_IP_CONFIG_GATEWAY,
                 "1.1.1.1",
                 NULL);

    /* IP Address */
    addr = nm_ip_address_new(AF_INET, "1.1.1.3", 24, &error);
    g_assert_no_error(error);
    nm_setting_ip_config_add_address(s_ip4, addr);
    nm_ip_address_unref(addr);

    nm_setting_ip_config_add_dns(s_ip4, "4.2.2.1");

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NULL);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_WIRELESS, NULL);

    keyfile = utils_get_keys_path(testfile);
    g_assert_cmpint(stat(keyfile, &statbuf), ==, 0);
    g_assert(S_ISREG(statbuf.st_mode));
    g_assert_cmpint((statbuf.st_mode & 0077), ==, 0);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_write_wifi_wep_passphrase(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    nmtst_auto_unlinkfile char   *keyfile    = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingWireless            *s_wifi;
    NMSettingWirelessSecurity    *s_wsec;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    gs_unref_bytes GBytes        *ssid = nmtst_gbytes_from_str("blahblah");
    struct stat                   statbuf;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Wifi WEP Passphrase",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRELESS_SETTING_NAME,
                 NULL);

    s_wifi = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS);
    g_object_set(s_wifi,
                 NM_SETTING_WIRELESS_SSID,
                 ssid,
                 NM_SETTING_WIRELESS_MODE,
                 "infrastructure",
                 NULL);

    s_wsec = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
    g_object_set(s_wsec,
                 NM_SETTING_WIRELESS_SECURITY_KEY_MGMT,
                 "none",
                 NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX,
                 0,
                 NM_SETTING_WIRELESS_SECURITY_AUTH_ALG,
                 "shared",
                 NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE,
                 NM_WEP_KEY_TYPE_PASSPHRASE,
                 NULL);
    nm_setting_wireless_security_set_wep_key(s_wsec, 0, "asdfdjaslfjasd;flasjdfl;aksdf");

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NULL);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_WIRELESS, NULL);

    keyfile = utils_get_keys_path(testfile);
    g_assert_cmpint(stat(keyfile, &statbuf), ==, 0);
    g_assert(S_ISREG(statbuf.st_mode));
    g_assert_cmpint((statbuf.st_mode & 0077), ==, 0);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_write_wifi_wep_40_ascii(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    nmtst_auto_unlinkfile char   *keyfile    = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingWireless            *s_wifi;
    NMSettingWirelessSecurity    *s_wsec;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    gs_unref_bytes GBytes        *ssid = nmtst_gbytes_from_str("blahblah40");
    struct stat                   statbuf;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Wifi WEP 40 ASCII",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRELESS_SETTING_NAME,
                 NULL);

    s_wifi = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS);
    g_object_set(s_wifi,
                 NM_SETTING_WIRELESS_SSID,
                 ssid,
                 NM_SETTING_WIRELESS_MODE,
                 "infrastructure",
                 NULL);

    s_wsec = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
    g_object_set(s_wsec,
                 NM_SETTING_WIRELESS_SECURITY_KEY_MGMT,
                 "none",
                 NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX,
                 2,
                 NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE,
                 NM_WEP_KEY_TYPE_KEY,
                 NM_SETTING_WIRELESS_SECURITY_AUTH_ALG,
                 "shared",
                 NULL);
    nm_setting_wireless_security_set_wep_key(s_wsec, 0, "lorem");
    nm_setting_wireless_security_set_wep_key(s_wsec, 1, "ipsum");
    nm_setting_wireless_security_set_wep_key(s_wsec, 2, "dolor");
    nm_setting_wireless_security_set_wep_key(s_wsec, 3, "donec");

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NULL);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_WIRELESS, NULL);

    keyfile = utils_get_keys_path(testfile);
    g_assert_cmpint(stat(keyfile, &statbuf), ==, 0);
    g_assert(S_ISREG(statbuf.st_mode));
    g_assert_cmpint((statbuf.st_mode & 0077), ==, 0);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_write_wifi_wep_104_ascii(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    nmtst_auto_unlinkfile char   *keyfile    = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingWireless            *s_wifi;
    NMSettingWirelessSecurity    *s_wsec;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    gs_unref_bytes GBytes        *ssid = nmtst_gbytes_from_str("blahblah104");
    struct stat                   statbuf;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Wifi WEP 104 ASCII",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRELESS_SETTING_NAME,
                 NULL);

    s_wifi = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS);
    g_object_set(s_wifi,
                 NM_SETTING_WIRELESS_SSID,
                 ssid,
                 NM_SETTING_WIRELESS_MODE,
                 "infrastructure",
                 NULL);

    s_wsec = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
    g_object_set(s_wsec,
                 NM_SETTING_WIRELESS_SECURITY_KEY_MGMT,
                 "none",
                 NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX,
                 0,
                 NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE,
                 NM_WEP_KEY_TYPE_UNKNOWN,
                 NM_SETTING_WIRELESS_SECURITY_AUTH_ALG,
                 "open",
                 NULL);
    nm_setting_wireless_security_set_wep_key(s_wsec, 0, "LoremIpsumSit");
    nm_setting_wireless_security_set_wep_key(s_wsec, 1, "AlfaBetaGamma");
    nm_setting_wireless_security_set_wep_key(s_wsec, 2, "WEP-104 ASCII");
    nm_setting_wireless_security_set_wep_key(s_wsec, 3, "thisismyascii");

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NULL);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR,
                           TEST_IFCFG_DIR "/ifcfg-Test_Write_Wifi_WEP_104_ASCII.cexpected",
                           &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_WIRELESS, NULL);

    keyfile = utils_get_keys_path(testfile);
    g_assert_cmpint(stat(keyfile, &statbuf), ==, 0);
    g_assert(S_ISREG(statbuf.st_mode));
    g_assert_cmpint((statbuf.st_mode & 0077), ==, 0);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_write_wifi_leap(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    nmtst_auto_unlinkfile char   *keyfile    = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingWireless            *s_wifi;
    NMSettingWirelessSecurity    *s_wsec;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    gs_unref_bytes GBytes        *ssid = nmtst_gbytes_from_str("blahblah");
    struct stat                   statbuf;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Wifi LEAP",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRELESS_SETTING_NAME,
                 NULL);

    s_wifi = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS);
    g_object_set(s_wifi,
                 NM_SETTING_WIRELESS_SSID,
                 ssid,
                 NM_SETTING_WIRELESS_MODE,
                 "infrastructure",
                 NULL);

    s_wsec = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
    g_object_set(s_wsec,
                 NM_SETTING_WIRELESS_SECURITY_KEY_MGMT,
                 "ieee8021x",
                 NM_SETTING_WIRELESS_SECURITY_AUTH_ALG,
                 "leap",
                 NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME,
                 "Bill Smith",
                 NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD,
                 "foobar22",
                 NULL);

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NULL);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR,
                           TEST_IFCFG_DIR "/ifcfg-Test_Write_Wifi_LEAP.cexpected",
                           &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_WIRELESS, NULL);

    keyfile = utils_get_keys_path(testfile);
    g_assert_cmpint(stat(keyfile, &statbuf), ==, 0);
    g_assert(S_ISREG(statbuf.st_mode));
    g_assert_cmpint((statbuf.st_mode & 0077), ==, 0);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_write_wifi_leap_secret_flags(gconstpointer data)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_free char                 *keyfile    = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingWireless            *s_wifi;
    NMSettingWirelessSecurity    *s_wsec;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    gs_unref_bytes GBytes        *ssid  = nmtst_gbytes_from_str("blahblah");
    NMSettingSecretFlags          flags = GPOINTER_TO_UINT(data);

    connection = nm_simple_connection_new();
    g_assert(connection);

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Wifi LEAP Secret Flags",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRELESS_SETTING_NAME,
                 NULL);

    s_wifi = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS);
    g_object_set(s_wifi,
                 NM_SETTING_WIRELESS_SSID,
                 ssid,
                 NM_SETTING_WIRELESS_MODE,
                 "infrastructure",
                 NULL);

    s_wsec = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
    g_object_set(s_wsec,
                 NM_SETTING_WIRELESS_SECURITY_KEY_MGMT,
                 "ieee8021x",
                 NM_SETTING_WIRELESS_SECURITY_AUTH_ALG,
                 "leap",
                 NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME,
                 "Bill Smith",
                 NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD,
                 "foobar22",
                 NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD_FLAGS,
                 flags,
                 NULL);

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NULL);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connection_FIXME(connection, TEST_SCRATCH_DIR, &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_WIRELESS, NULL);

    /* No key should be written out since the secret is not system owned */
    keyfile = utils_get_keys_path(testfile);
    g_assert(g_file_test(keyfile, G_FILE_TEST_EXISTS) == FALSE);

    /* Remove the LEAP password from the original connection since it wont' be
     * in the reread connection, as the password is not system owned.
     */
    g_object_set(s_wsec, NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD, NULL, NULL);
    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_write_wifi_wpa_psk(gconstpointer test_data)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    nmtst_auto_unlinkfile char   *keyfile    = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingWireless            *s_wifi;
    NMSettingWirelessSecurity    *s_wsec;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    gs_unref_bytes GBytes        *ssid = nmtst_gbytes_from_str("blahblah");
    struct {
        const char *name, *psk;
        gpointer    wep_group_p, wpa_p, wpa2_p;
    } args;

    nmtst_test_data_unpack(test_data,
                           &args.name,
                           &args.wep_group_p,
                           &args.wpa_p,
                           &args.wpa2_p,
                           &args.psk);

    g_assert(args.psk);

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 args.name,
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRELESS_SETTING_NAME,
                 NULL);

    s_wifi = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS);
    g_object_set(s_wifi,
                 NM_SETTING_WIRELESS_SSID,
                 ssid,
                 NM_SETTING_WIRELESS_MODE,
                 "infrastructure",
                 NULL);

    s_wsec = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
    g_object_set(s_wsec,
                 NM_SETTING_WIRELESS_SECURITY_KEY_MGMT,
                 "wpa-psk",
                 NM_SETTING_WIRELESS_SECURITY_PSK,
                 args.psk,
                 NM_SETTING_WIRELESS_SECURITY_PMF,
                 (int) NM_SETTING_WIRELESS_SECURITY_PMF_REQUIRED,
                 NULL);

    if (GPOINTER_TO_INT(args.wep_group_p)) {
        nm_setting_wireless_security_add_group(s_wsec, "wep40");
        nm_setting_wireless_security_add_group(s_wsec, "wep104");
    }
    if (GPOINTER_TO_INT(args.wpa_p)) {
        nm_setting_wireless_security_add_proto(s_wsec, "wpa");
        nm_setting_wireless_security_add_pairwise(s_wsec, "tkip");
        nm_setting_wireless_security_add_group(s_wsec, "tkip");
    }
    if (GPOINTER_TO_INT(args.wpa2_p)) {
        nm_setting_wireless_security_add_proto(s_wsec, "rsn");
        nm_setting_wireless_security_add_pairwise(s_wsec, "ccmp");
        nm_setting_wireless_security_add_group(s_wsec, "ccmp");
    }

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NULL);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_WIRELESS, NULL);

    keyfile = utils_get_keys_path(testfile);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_write_wifi_wpa_psk_adhoc(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    nmtst_auto_unlinkfile char   *keyfile    = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingWireless            *s_wifi;
    NMSettingWirelessSecurity    *s_wsec;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    GError                       *error = NULL;
    gs_unref_bytes GBytes        *ssid  = nmtst_gbytes_from_str("blahblah");
    NMIPAddress                  *addr;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Wifi WPA PSK",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRELESS_SETTING_NAME,
                 NULL);

    s_wifi = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS);
    g_object_set(s_wifi,
                 NM_SETTING_WIRELESS_SSID,
                 ssid,
                 NM_SETTING_WIRELESS_MODE,
                 "adhoc",
                 NM_SETTING_WIRELESS_CHANNEL,
                 11,
                 NM_SETTING_WIRELESS_BAND,
                 "bg",
                 NULL);

    s_wsec = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
    g_object_set(s_wsec,
                 NM_SETTING_WIRELESS_SECURITY_KEY_MGMT,
                 "wpa-psk",
                 NM_SETTING_WIRELESS_SECURITY_PSK,
                 "7d308b11df1b4243b0f78e5f3fc68cdbb9a264ed0edf4c188edf329ff5b467f0",
                 NULL);

    nm_setting_wireless_security_add_proto(s_wsec, "rsn");
    nm_setting_wireless_security_add_pairwise(s_wsec, "ccmp");
    nm_setting_wireless_security_add_group(s_wsec, "ccmp");

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
                 NM_SETTING_IP_CONFIG_GATEWAY,
                 "1.1.1.1",
                 NULL);

    /* IP Address */
    addr = nm_ip_address_new(AF_INET, "1.1.1.3", 25, &error);
    g_assert_no_error(error);
    nm_setting_ip_config_add_address(s_ip4, addr);
    nm_ip_address_unref(addr);

    nm_setting_ip_config_add_dns(s_ip4, "4.2.2.1");

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NULL);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_WIRELESS, NULL);

    keyfile = utils_get_keys_path(testfile);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_write_wifi_wpa_eap_tls(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    nmtst_auto_unlinkfile char   *keyfile    = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingWireless            *s_wifi;
    NMSettingWirelessSecurity    *s_wsec;
    NMSetting8021x               *s_8021x;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    gboolean                      success;
    GError                       *error = NULL;
    gs_unref_bytes GBytes        *ssid  = nmtst_gbytes_from_str("blahblah");

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Wifi WPA EAP-TLS",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRELESS_SETTING_NAME,
                 NULL);

    s_wifi = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS);
    g_object_set(s_wifi,
                 NM_SETTING_WIRELESS_SSID,
                 ssid,
                 NM_SETTING_WIRELESS_MODE,
                 "infrastructure",
                 NULL);

    s_wsec = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
    g_object_set(s_wsec,
                 NM_SETTING_WIRELESS_SECURITY_KEY_MGMT,
                 "wpa-eap",
                 NM_SETTING_WIRELESS_SECURITY_FILS,
                 (int) NM_SETTING_WIRELESS_SECURITY_FILS_REQUIRED,
                 NULL);
    nm_setting_wireless_security_add_proto(s_wsec, "wpa");
    nm_setting_wireless_security_add_pairwise(s_wsec, "tkip");
    nm_setting_wireless_security_add_group(s_wsec, "tkip");

    s_8021x = _nm_connection_new_setting(connection, NM_TYPE_SETTING_802_1X);
    g_object_set(s_8021x,
                 NM_SETTING_802_1X_IDENTITY,
                 "Bill Smith",
                 NM_SETTING_802_1X_PHASE1_AUTH_FLAGS,
                 (guint) (NM_SETTING_802_1X_AUTH_FLAGS_TLS_1_0_DISABLE
                          | NM_SETTING_802_1X_AUTH_FLAGS_TLS_1_1_DISABLE),
                 NULL);
    nm_setting_802_1x_add_eap_method(s_8021x, "tls");

    success = nm_setting_802_1x_set_ca_cert(s_8021x,
                                            TEST_IFCFG_WIFI_WPA_EAP_TLS_CA_CERT,
                                            NM_SETTING_802_1X_CK_SCHEME_PATH,
                                            NULL,
                                            &error);
    nmtst_assert_success(success, error);

    success = nm_setting_802_1x_set_client_cert(s_8021x,
                                                TEST_IFCFG_WIFI_WPA_EAP_TLS_CLIENT_CERT,
                                                NM_SETTING_802_1X_CK_SCHEME_PATH,
                                                NULL,
                                                &error);
    nmtst_assert_success(success, error);

    success = nm_setting_802_1x_set_private_key(s_8021x,
                                                TEST_IFCFG_WIFI_WPA_EAP_TLS_PRIVATE_KEY,
                                                "test1",
                                                NM_SETTING_802_1X_CK_SCHEME_PATH,
                                                NULL,
                                                &error);
    nmtst_assert_success(success, error);

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NULL);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_WIRELESS, NULL);

    keyfile = utils_get_keys_path(testfile);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_write_wifi_wpa_eap_ttls_tls(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    nmtst_auto_unlinkfile char   *keyfile    = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingWireless            *s_wifi;
    NMSettingWirelessSecurity    *s_wsec;
    NMSetting8021x               *s_8021x;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    gboolean                      success;
    GError                       *error = NULL;
    gs_unref_bytes GBytes        *ssid  = nmtst_gbytes_from_str("blahblah");

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Wifi WPA EAP-TTLS (TLS)",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRELESS_SETTING_NAME,
                 NULL);

    s_wifi = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS);
    g_object_set(s_wifi,
                 NM_SETTING_WIRELESS_SSID,
                 ssid,
                 NM_SETTING_WIRELESS_MODE,
                 "infrastructure",
                 NULL);

    s_wsec = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
    g_object_set(s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-eap", NULL);
    nm_setting_wireless_security_add_proto(s_wsec, "rsn");
    nm_setting_wireless_security_add_pairwise(s_wsec, "ccmp");
    nm_setting_wireless_security_add_group(s_wsec, "ccmp");

    s_8021x = _nm_connection_new_setting(connection, NM_TYPE_SETTING_802_1X);
    nm_setting_802_1x_add_eap_method(s_8021x, "ttls");
    g_object_set(s_8021x,
                 NM_SETTING_802_1X_IDENTITY,
                 "Bill Smith",
                 NM_SETTING_802_1X_ANONYMOUS_IDENTITY,
                 "foobar22",
                 NM_SETTING_802_1X_PHASE2_AUTHEAP,
                 "tls",
                 NULL);

    success = nm_setting_802_1x_set_ca_cert(s_8021x,
                                            TEST_IFCFG_WIFI_WPA_EAP_TLS_CA_CERT,
                                            NM_SETTING_802_1X_CK_SCHEME_PATH,
                                            NULL,
                                            &error);
    nmtst_assert_success(success, error);

    /* Phase 2 TLS stuff */

    /* phase2 CA cert */
    success = nm_setting_802_1x_set_phase2_ca_cert(s_8021x,
                                                   TEST_IFCFG_WIFI_WPA_EAP_TLS_CA_CERT,
                                                   NM_SETTING_802_1X_CK_SCHEME_PATH,
                                                   NULL,
                                                   &error);
    nmtst_assert_success(success, error);

    /* phase2 client cert */
    success = nm_setting_802_1x_set_phase2_client_cert(s_8021x,
                                                       TEST_IFCFG_WIFI_WPA_EAP_TLS_CLIENT_CERT,
                                                       NM_SETTING_802_1X_CK_SCHEME_PATH,
                                                       NULL,
                                                       &error);
    nmtst_assert_success(success, error);

    /* phase2 private key */
    success = nm_setting_802_1x_set_phase2_private_key(s_8021x,
                                                       TEST_IFCFG_WIFI_WPA_EAP_TLS_PRIVATE_KEY,
                                                       "test1",
                                                       NM_SETTING_802_1X_CK_SCHEME_PATH,
                                                       NULL,
                                                       &error);
    nmtst_assert_success(success, error);

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NULL);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_WIRELESS, NULL);

    keyfile = utils_get_keys_path(testfile);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_write_wifi_wpa_eap_ttls_mschapv2(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    nmtst_auto_unlinkfile char   *keyfile    = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingWireless            *s_wifi;
    NMSettingWirelessSecurity    *s_wsec;
    NMSetting8021x               *s_8021x;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    gboolean                      success;
    GError                       *error = NULL;
    gs_unref_bytes GBytes        *ssid  = nmtst_gbytes_from_str("blahblah");

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Wifi WPA EAP-TTLS (MSCHAPv2)",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRELESS_SETTING_NAME,
                 NULL);

    s_wifi = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS);
    g_object_set(s_wifi,
                 NM_SETTING_WIRELESS_SSID,
                 ssid,
                 NM_SETTING_WIRELESS_MODE,
                 "infrastructure",
                 NULL);

    s_wsec = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
    g_object_set(s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-eap", NULL);
    nm_setting_wireless_security_add_proto(s_wsec, "wpa");
    nm_setting_wireless_security_add_proto(s_wsec, "rsn");
    nm_setting_wireless_security_add_pairwise(s_wsec, "tkip");
    nm_setting_wireless_security_add_pairwise(s_wsec, "ccmp");
    nm_setting_wireless_security_add_group(s_wsec, "tkip");
    nm_setting_wireless_security_add_group(s_wsec, "ccmp");

    s_8021x = _nm_connection_new_setting(connection, NM_TYPE_SETTING_802_1X);
    nm_setting_802_1x_add_eap_method(s_8021x, "ttls");
    g_object_set(s_8021x,
                 NM_SETTING_802_1X_IDENTITY,
                 "Bill Smith",
                 NM_SETTING_802_1X_PASSWORD,
                 ";alkdfja;dslkfjsad;lkfjsadf",
                 NM_SETTING_802_1X_ANONYMOUS_IDENTITY,
                 "foobar22",
                 NM_SETTING_802_1X_PHASE2_AUTHEAP,
                 "mschapv2",
                 NULL);

    success = nm_setting_802_1x_set_ca_cert(s_8021x,
                                            TEST_IFCFG_WIFI_WPA_EAP_TLS_CA_CERT,
                                            NM_SETTING_802_1X_CK_SCHEME_PATH,
                                            NULL,
                                            &error);
    nmtst_assert_success(success, error);

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NULL);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_WIRELESS, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);

    keyfile = utils_get_keys_path(testfile);
}

static void
test_write_wifi_wpa_then_open(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_free char                 *keyfile    = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread1    = NULL;
    gs_unref_object NMConnection *reread2    = NULL;
    NMSettingConnection          *s_con;
    NMSettingWireless            *s_wifi;
    NMSettingWirelessSecurity    *s_wsec;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    gs_unref_bytes GBytes        *ssid = nmtst_gbytes_from_str("blahblah");

    /* Test that writing out a WPA config then changing that to an open
     * config doesn't leave various WPA-related keys lying around in the ifcfg.
     */

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "random wifi connection",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRELESS_SETTING_NAME,
                 NULL);

    s_wifi = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS);
    g_object_set(s_wifi,
                 NM_SETTING_WIRELESS_SSID,
                 ssid,
                 NM_SETTING_WIRELESS_MODE,
                 "infrastructure",
                 NULL);

    s_wsec = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
    g_object_set(s_wsec,
                 NM_SETTING_WIRELESS_SECURITY_KEY_MGMT,
                 "wpa-psk",
                 NM_SETTING_WIRELESS_SECURITY_PSK,
                 "some cool PSK",
                 NULL);

    nm_setting_wireless_security_add_proto(s_wsec, "wpa");
    nm_setting_wireless_security_add_pairwise(s_wsec, "tkip");
    nm_setting_wireless_security_add_group(s_wsec, "tkip");

    nm_setting_wireless_security_add_proto(s_wsec, "rsn");
    nm_setting_wireless_security_add_pairwise(s_wsec, "ccmp");
    nm_setting_wireless_security_add_group(s_wsec, "ccmp");

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE,
                 (int) NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64,
                 NULL);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile);

    reread1 = _connection_from_file(testfile, NULL, TYPE_WIRELESS, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread1, FALSE);

    nmtst_connection_normalize(connection);

    /* Now change the connection to open and recheck */
    nm_connection_remove_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);

    /* Write it back out */
    _writer_update_connection(connection,
                              TEST_SCRATCH_DIR,
                              testfile,
                              TEST_IFCFG_DIR "/ifcfg-random_wifi_connection.cexpected");
    keyfile = utils_get_keys_path(testfile);
    g_assert(!g_file_test(keyfile, G_FILE_TEST_EXISTS));

    reread2 = _connection_from_file(testfile, NULL, TYPE_WIRELESS, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread2, FALSE);
}

static void
test_write_wifi_wpa_then_wep_with_perms(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    nmtst_auto_unlinkfile char   *keyfile    = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread1    = NULL;
    gs_unref_object NMConnection *reread2    = NULL;
    NMSettingConnection          *s_con;
    NMSettingWireless            *s_wifi;
    NMSettingWirelessSecurity    *s_wsec;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    gboolean                      success;
    gs_unref_bytes GBytes        *ssid = nmtst_gbytes_from_str("SomeSSID");

    /* Test that writing out a WPA config then changing that to a WEP
     * config works and doesn't cause infinite loop or other issues.
     */

    connection = nm_simple_connection_new();
    g_assert(connection);

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "random wifi connection 2",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_PERMISSIONS,
                 NM_MAKE_STRV("user:superman:"),
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRELESS_SETTING_NAME,
                 NULL);
    g_assert_cmpint(nm_setting_connection_get_num_permissions(s_con), ==, 1);

    s_wifi = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS);
    g_object_set(s_wifi,
                 NM_SETTING_WIRELESS_SSID,
                 ssid,
                 NM_SETTING_WIRELESS_MODE,
                 "infrastructure",
                 NULL);

    s_wsec = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
    g_object_set(s_wsec,
                 NM_SETTING_WIRELESS_SECURITY_KEY_MGMT,
                 "wpa-psk",
                 NM_SETTING_WIRELESS_SECURITY_PSK,
                 "My cool PSK",
                 NULL);

    nm_setting_wireless_security_add_proto(s_wsec, "wpa");
    nm_setting_wireless_security_add_pairwise(s_wsec, "tkip");
    nm_setting_wireless_security_add_group(s_wsec, "tkip");

    nm_setting_wireless_security_add_proto(s_wsec, "rsn");
    nm_setting_wireless_security_add_pairwise(s_wsec, "ccmp");
    nm_setting_wireless_security_add_group(s_wsec, "ccmp");

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE,
                 (int) NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64,
                 NULL);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile);

    reread1 = _connection_from_file(testfile, NULL, TYPE_WIRELESS, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread1, FALSE);

    nmtst_connection_normalize(connection);

    /* Now change the connection to WEP and recheck */
    s_wsec = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);

    g_object_set(s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none", NULL);
    nm_setting_wireless_security_set_wep_key(s_wsec, 0, "abraka  dabra");

    /* Write it back out */
    _writer_update_connection(connection,
                              TEST_SCRATCH_DIR,
                              testfile,
                              TEST_IFCFG_DIR "/ifcfg-random_wifi_connection_2.cexpected");

    reread2 = _connection_from_file(testfile, NULL, TYPE_WIRELESS, NULL);

    nmtst_connection_normalize(connection);
    success = nm_connection_compare(connection,
                                    reread2,
                                    NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS
                                        | NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS);
    g_assert(success);

    keyfile = utils_get_keys_path(testfile);
}

static void
test_write_wifi_dynamic_wep_leap(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    nmtst_auto_unlinkfile char   *keyfile    = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingWireless            *s_wifi;
    NMSettingWirelessSecurity    *s_wsec;
    NMSetting8021x               *s_8021x;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    gs_unref_bytes GBytes        *ssid = nmtst_gbytes_from_str("blahblah");
    shvarFile                    *ifcfg;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Wifi Dynamic WEP LEAP",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRELESS_SETTING_NAME,
                 NULL);

    s_wifi = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS);
    g_object_set(s_wifi,
                 NM_SETTING_WIRELESS_SSID,
                 ssid,
                 NM_SETTING_WIRELESS_MODE,
                 "infrastructure",
                 NULL);

    s_wsec = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
    g_object_set(s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", NULL);

    s_8021x = _nm_connection_new_setting(connection, NM_TYPE_SETTING_802_1X);
    nm_setting_802_1x_add_eap_method(s_8021x, "leap");
    g_object_set(s_8021x,
                 NM_SETTING_802_1X_IDENTITY,
                 "Bill Smith",
                 NM_SETTING_802_1X_PASSWORD,
                 ";alkdfja;dslkfjsad;lkfjsadf",
                 NULL);

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NULL);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_WIRELESS, NULL);

    keyfile = utils_get_keys_path(testfile);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);

    /* Check and make sure that an "old-school" LEAP (Network EAP) connection
     * did not get written.  Check first that the auth alg is not set to "LEAP"
     * and next that the only IEEE 802.1x EAP method is "LEAP".
     */
    ifcfg = _svOpenFile(testfile);
    _svGetValue_check(ifcfg, "SECURITYMODE", NULL);
    _svGetValue_check(ifcfg, "IEEE_8021X_EAP_METHODS", "LEAP");
    svCloseFile(ifcfg);
}

static void
test_write_wired_qeth_dhcp(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingWired               *s_wired;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Wired qeth Static",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRED_SETTING_NAME,
                 NULL);

    s_wired = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRED);
    g_object_set(s_wired,
                 NM_SETTING_WIRED_S390_SUBCHANNELS,
                 NM_MAKE_STRV("0.0.600", "0.0.601", "0.0.602"),
                 NM_SETTING_WIRED_S390_NETTYPE,
                 "qeth",
                 NULL);

    nm_setting_wired_add_s390_option(s_wired, "portname", "FOOBAR");
    nm_setting_wired_add_s390_option(s_wired, "portno", "1");
    nm_setting_wired_add_s390_option(s_wired, "layer2", "0");
    nm_setting_wired_add_s390_option(s_wired, "protocol", "blahbalh");

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NULL);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_write_wired_ctc_dhcp(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingWired               *s_wired;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    shvarFile                    *ifcfg;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Wired ctc Static",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRED_SETTING_NAME,
                 NULL);

    s_wired = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRED);
    g_object_set(s_wired,
                 NM_SETTING_WIRED_S390_SUBCHANNELS,
                 NM_MAKE_STRV("0.0.600", "0.0.601"),
                 NM_SETTING_WIRED_S390_NETTYPE,
                 "ctc",
                 NULL);
    nm_setting_wired_add_s390_option(s_wired, "ctcprot", "0");

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NULL);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile);

    /* Ensure the CTCPROT item gets written out as its own option */
    ifcfg = _svOpenFile(testfile);

    _svGetValue_check(ifcfg, "CTCPROT", "0");

    /* And that it's not in the generic OPTIONS string */
    _svGetValue_check(ifcfg, "OPTIONS", NULL);

    svCloseFile(ifcfg);

    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_write_permissions(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Permissions",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRED_SETTING_NAME,
                 NULL);

    nm_setting_connection_add_permission(s_con, "user", "blahblah", NULL);
    nm_setting_connection_add_permission(s_con, "user", "foobar", NULL);
    nm_setting_connection_add_permission(s_con, "user", "asdfasdf", NULL);

    _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRED);

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NULL);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR,
                           TEST_IFCFG_DIR "/ifcfg-Test_Write_Permissions.cexpected",
                           &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_write_wifi_wep_agent_keys(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingWireless            *s_wifi;
    NMSettingWirelessSecurity    *s_wsec;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    gs_unref_bytes GBytes        *ssid = nmtst_gbytes_from_str("foobarbaz");

    connection = nm_simple_connection_new();
    g_assert(connection != NULL);

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Wifi WEP Agent Owned",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRELESS_SETTING_NAME,
                 NULL);

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE,
                 (int) NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64,
                 NULL);

    s_wifi = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS);
    g_object_set(s_wifi,
                 NM_SETTING_WIRELESS_SSID,
                 ssid,
                 NM_SETTING_WIRELESS_MODE,
                 "infrastructure",
                 NULL);

    s_wsec = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
    g_object_set(s_wsec,
                 NM_SETTING_WIRELESS_SECURITY_KEY_MGMT,
                 "none",
                 NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE,
                 NM_WEP_KEY_TYPE_PASSPHRASE,
                 NM_SETTING_WIRELESS_SECURITY_WEP_KEY_FLAGS,
                 NM_SETTING_SECRET_FLAG_AGENT_OWNED,
                 NULL);
    nm_setting_wireless_security_set_wep_key(s_wsec, 0, "asdfdjaslfjasd;flasjdfl;aksdf");

    nmtst_assert_connection_verifies(connection);

    _writer_new_connection_FIXME(connection, TEST_SCRATCH_DIR, &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_WIRELESS, NULL);

    /* Remove the WEP key from the original, because it should not have been
     * written out to disk as it was agent-owned.  The new connection should
     * not have any WEP keys set.
     * Also the new connection should not have WEP key type set.
     */
    nm_setting_wireless_security_set_wep_key(s_wsec, 0, NULL);
    g_object_set(s_wsec, NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, NM_WEP_KEY_TYPE_UNKNOWN, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_write_wired_pppoe(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingIPConfig            *s_ip4;
    NMSettingPppoe               *s_pppoe;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Wired PPPoE",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRED_SETTING_NAME,
                 NULL);

    _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRED);

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);

    s_pppoe = _nm_connection_new_setting(connection, NM_TYPE_SETTING_PPPOE);
    g_object_set(s_pppoe,
                 NM_SETTING_PPPOE_SERVICE,
                 "stupid-service",
                 NM_SETTING_PPPOE_USERNAME,
                 "Bill Smith",
                 NM_SETTING_PPPOE_PASSWORD,
                 "test1",
                 NULL);

    _nm_connection_new_setting(connection, NM_TYPE_SETTING_PPP);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connection_fail(connection, TEST_SCRATCH_DIR, NULL);
}

static void
test_write_vpn(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingIPConfig            *s_ip4;
    NMSettingVpn                 *s_vpn;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write VPN",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_VPN_SETTING_NAME,
                 NULL);

    s_vpn = _nm_connection_new_setting(connection, NM_TYPE_SETTING_VPN);
    g_object_set(s_vpn,
                 NM_SETTING_VPN_SERVICE_TYPE,
                 "awesomevpn",
                 NM_SETTING_VPN_USER_NAME,
                 "Bill Smith",
                 NULL);

    nm_setting_vpn_add_data_item(s_vpn, "server", "vpn.somewhere.com");
    nm_setting_vpn_add_secret(s_vpn, "password", "sup3rs3cr3t");

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connection_fail(connection, TEST_SCRATCH_DIR, NULL);
}

static void
test_write_mobile_broadband(gconstpointer data)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingIPConfig            *s_ip4;
    NMSettingCdma                *s_cdma;
    NMSettingSerial              *s_serial;
    gboolean                      gsm = GPOINTER_TO_UINT(data);

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 gsm ? "Test Write GSM" : "Test Write CDMA",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_TYPE,
                 gsm ? NM_SETTING_GSM_SETTING_NAME : NM_SETTING_CDMA_SETTING_NAME,
                 NULL);

    if (gsm)
        _nm_connection_new_setting(connection, NM_TYPE_SETTING_GSM);
    else {
        s_cdma = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CDMA);
        g_object_set(s_cdma, NM_SETTING_CDMA_NUMBER, "#777", NULL);
    }

    s_serial = _nm_connection_new_setting(connection, NM_TYPE_SETTING_SERIAL);
    g_object_set(s_serial,
                 NM_SETTING_SERIAL_BAUD,
                 115200,
                 NM_SETTING_SERIAL_BITS,
                 8,
                 NM_SETTING_SERIAL_PARITY,
                 NM_SETTING_SERIAL_PARITY_NONE,
                 NM_SETTING_SERIAL_STOPBITS,
                 1,
                 NULL);

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);

    _nm_connection_new_setting(connection, NM_TYPE_SETTING_PPP);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connection_fail(connection, TEST_SCRATCH_DIR, NULL);
}

static void
test_read_bridge_main(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingBridge              *s_bridge;
    NMSettingWired               *s_wired;
    const char                   *mac;
    char expected_mac_address[ETH_ALEN] = {0x00, 0x16, 0x41, 0x11, 0x22, 0x33};

    connection =
        _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-bridge-main", NULL, TYPE_ETHERNET, NULL);

    g_assert_cmpstr(nm_connection_get_interface_name(connection), ==, "br0");

    s_bridge = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_BRIDGE);
    g_assert_cmpuint(nm_setting_bridge_get_forward_delay(s_bridge), ==, 2);
    g_assert(nm_setting_bridge_get_stp(s_bridge));
    g_assert_cmpuint(nm_setting_bridge_get_priority(s_bridge), ==, 32744);
    g_assert_cmpuint(nm_setting_bridge_get_hello_time(s_bridge), ==, 7);
    g_assert_cmpuint(nm_setting_bridge_get_max_age(s_bridge), ==, 39);
    g_assert_cmpuint(nm_setting_bridge_get_ageing_time(s_bridge), ==, 235352);
    g_assert_cmpuint(nm_setting_bridge_get_group_forward_mask(s_bridge), ==, 24);
    g_assert(!nm_setting_bridge_get_multicast_snooping(s_bridge));
    g_assert_cmpint(nm_setting_bridge_get_vlan_filtering(s_bridge), ==, TRUE);
    g_assert_cmpint(nm_setting_bridge_get_vlan_default_pvid(s_bridge), ==, 99);

    s_wired = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);
    mac     = nm_setting_wired_get_cloned_mac_address(s_wired);
    g_assert(mac);
    g_assert(nm_utils_hwaddr_matches(mac, -1, expected_mac_address, ETH_ALEN));
}

static void
test_write_bridge_main(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingBridge              *s_bridge;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    NMIPAddress                  *addr;
    static const char            *mac   = "31:33:33:37:be:cd";
    GError                       *error = NULL;
    gs_unref_ptrarray GPtrArray  *vlans = NULL;
    NMBridgeVlan                 *vlan;

    connection = nm_simple_connection_new();
    g_assert(connection);

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Bridge Main",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_INTERFACE_NAME,
                 "br0",
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_BRIDGE_SETTING_NAME,
                 NULL);

    s_bridge = _nm_connection_new_setting(connection, NM_TYPE_SETTING_BRIDGE);

    vlans = g_ptr_array_new_with_free_func((GDestroyNotify) nm_bridge_vlan_unref);
    vlan  = nm_bridge_vlan_new(10, 16);
    nm_bridge_vlan_set_untagged(vlan, TRUE);
    g_ptr_array_add(vlans, vlan);
    vlan = nm_bridge_vlan_new(22, 22);
    nm_bridge_vlan_set_pvid(vlan, TRUE);
    nm_bridge_vlan_set_untagged(vlan, TRUE);
    g_ptr_array_add(vlans, vlan);
    vlan = nm_bridge_vlan_new(44, 0);
    g_ptr_array_add(vlans, vlan);

    g_object_set(s_bridge,
                 NM_SETTING_BRIDGE_MAC_ADDRESS,
                 mac,
                 NM_SETTING_BRIDGE_GROUP_FORWARD_MASK,
                 19008,
                 NM_SETTING_BRIDGE_VLAN_FILTERING,
                 TRUE,
                 NM_SETTING_BRIDGE_VLAN_DEFAULT_PVID,
                 4000,
                 NM_SETTING_BRIDGE_VLANS,
                 vlans,
                 NULL);

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
                 NM_SETTING_IP_CONFIG_GATEWAY,
                 "1.1.1.1",
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NULL);

    addr = nm_ip_address_new(AF_INET, "1.1.1.3", 24, &error);
    g_assert_no_error(error);
    nm_setting_ip_config_add_address(s_ip4, addr);
    nm_ip_address_unref(addr);

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, NULL);

    _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRED);

    _nm_connection_new_setting(connection, NM_TYPE_SETTING_PROXY);

    nmtst_assert_connection_verifies_without_normalization(connection);

    _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_BRIDGE, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_read_bridge_component(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingBridgePort          *s_port;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-bridge-component",
                                       NULL,
                                       TYPE_ETHERNET,
                                       NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_controller(s_con), ==, "br0");
    g_assert_cmpstr(nm_setting_connection_get_port_type(s_con), ==, NM_SETTING_BRIDGE_SETTING_NAME);

    s_port = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_BRIDGE_PORT);
    g_assert(nm_setting_bridge_port_get_hairpin_mode(s_port));
    g_assert_cmpuint(nm_setting_bridge_port_get_priority(s_port), ==, 28);
    g_assert_cmpuint(nm_setting_bridge_port_get_path_cost(s_port), ==, 100);
}

static void
test_write_bridge_component(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingWired               *s_wired;
    NMSetting                    *s_port;
    static const char            *mac   = "31:33:33:37:be:cd";
    guint32                       mtu   = 1492;
    gs_unref_ptrarray GPtrArray  *vlans = NULL;
    NMBridgeVlan                 *vlan;

    connection = nm_simple_connection_new();
    g_assert(connection);

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Bridge Component",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRED_SETTING_NAME,
                 NM_SETTING_CONNECTION_MASTER,
                 "br0",
                 NM_SETTING_CONNECTION_SLAVE_TYPE,
                 NM_SETTING_BRIDGE_SETTING_NAME,
                 NULL);

    s_wired = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRED);
    g_object_set(s_wired, NM_SETTING_WIRED_MAC_ADDRESS, mac, NM_SETTING_WIRED_MTU, mtu, NULL);

    /* Bridge port */
    vlans = g_ptr_array_new_with_free_func((GDestroyNotify) nm_bridge_vlan_unref);
    vlan  = nm_bridge_vlan_new(1, 0);
    nm_bridge_vlan_set_untagged(vlan, TRUE);
    g_ptr_array_add(vlans, vlan);
    vlan = nm_bridge_vlan_new(4, 4094);
    nm_bridge_vlan_set_untagged(vlan, TRUE);
    g_ptr_array_add(vlans, vlan);
    vlan = nm_bridge_vlan_new(2, 2);
    nm_bridge_vlan_set_pvid(vlan, TRUE);
    g_ptr_array_add(vlans, vlan);

    s_port = _nm_connection_new_setting(connection, NM_TYPE_SETTING_BRIDGE_PORT);
    g_object_set(s_port,
                 NM_SETTING_BRIDGE_PORT_PRIORITY,
                 50,
                 NM_SETTING_BRIDGE_PORT_PATH_COST,
                 33,
                 NM_SETTING_BRIDGE_PORT_VLANS,
                 vlans,
                 NULL);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR,
                           TEST_IFCFG_DIR "/ifcfg-Test_Write_Bridge_Component.cexpected",
                           &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_read_bridge_missing_stp(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingBridge              *s_bridge;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-bridge-missing-stp",
                                       NULL,
                                       TYPE_BRIDGE,
                                       NULL);

    g_assert_cmpstr(nm_connection_get_interface_name(connection), ==, "br0");

    s_bridge = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_BRIDGE);
    g_assert(nm_setting_bridge_get_stp(s_bridge) == FALSE);
}

#define TEST_IFCFG_VLAN_INTERFACE TEST_IFCFG_DIR "/ifcfg-test-vlan-interface"

static void
test_read_vlan_interface(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingVlan                *s_vlan;
    guint32                       from = 0;
    guint32                       to   = 0;

    connection = _connection_from_file(TEST_IFCFG_VLAN_INTERFACE, NULL, TYPE_ETHERNET, NULL);

    g_assert_cmpstr(nm_connection_get_interface_name(connection), ==, "vlan43");

    s_vlan = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_VLAN);

    g_assert_cmpstr(nm_setting_vlan_get_parent(s_vlan), ==, "eth9");
    g_assert_cmpint(nm_setting_vlan_get_id(s_vlan), ==, 43);
    g_assert_cmpstr(nm_setting_vlan_get_protocol(s_vlan), ==, "802.1ad");
    g_assert_cmpint(nm_setting_vlan_get_flags(s_vlan),
                    ==,
                    NM_VLAN_FLAG_GVRP | NM_VLAN_FLAG_LOOSE_BINDING | NM_VLAN_FLAG_REORDER_HEADERS);

    /* Ingress map */
    g_assert_cmpint(nm_setting_vlan_get_num_priorities(s_vlan, NM_VLAN_INGRESS_MAP), ==, 2);

    g_assert(nm_setting_vlan_get_priority(s_vlan, NM_VLAN_INGRESS_MAP, 0, &from, &to));
    g_assert_cmpint(from, ==, 0);
    g_assert_cmpint(to, ==, 1);

    g_assert(nm_setting_vlan_get_priority(s_vlan, NM_VLAN_INGRESS_MAP, 1, &from, &to));
    g_assert_cmpint(from, ==, 2);
    g_assert_cmpint(to, ==, 5);

    /* Egress map */
    g_assert_cmpint(nm_setting_vlan_get_num_priorities(s_vlan, NM_VLAN_EGRESS_MAP), ==, 3);

    g_assert(nm_setting_vlan_get_priority(s_vlan, NM_VLAN_EGRESS_MAP, 0, &from, &to));
    g_assert_cmpint(from, ==, 3);
    g_assert_cmpint(to, ==, 1);

    g_assert(nm_setting_vlan_get_priority(s_vlan, NM_VLAN_EGRESS_MAP, 1, &from, &to));
    g_assert_cmpint(from, ==, 12);
    g_assert_cmpint(to, ==, 3);

    g_assert(nm_setting_vlan_get_priority(s_vlan, NM_VLAN_EGRESS_MAP, 2, &from, &to));
    g_assert_cmpint(from, ==, 14);
    g_assert_cmpint(to, ==, 7);
}

#define TEST_IFCFG_VLAN_ONLY_VLANID TEST_IFCFG_DIR "/ifcfg-test-vlan-only-vlanid"

static void
test_read_vlan_only_vlan_id(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingVlan                *s_vlan;

    connection = _connection_from_file(TEST_IFCFG_VLAN_ONLY_VLANID, NULL, TYPE_ETHERNET, NULL);

    g_assert(nm_connection_get_interface_name(connection) == NULL);

    s_vlan = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_VLAN);

    g_assert_cmpstr(nm_setting_vlan_get_parent(s_vlan), ==, "eth9");
    g_assert_cmpint(nm_setting_vlan_get_id(s_vlan), ==, 43);
    g_assert_cmpint(nm_setting_vlan_get_flags(s_vlan), ==, NM_VLAN_FLAG_REORDER_HEADERS);
}

static void
test_read_vlan_vlanid_use(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingVlan                *s_vlan;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-vlan-vlanid-use",
                                       NULL,
                                       TYPE_ETHERNET,
                                       NULL);

    g_assert_cmpstr(nm_connection_get_interface_name(connection), ==, "eth0.9");

    s_vlan = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_VLAN);

    g_assert_cmpstr(nm_setting_vlan_get_parent(s_vlan), ==, "eth0");
    g_assert_cmpint(nm_setting_vlan_get_id(s_vlan), ==, 10);
    g_assert_cmpint(nm_setting_vlan_get_flags(s_vlan), ==, NM_VLAN_FLAG_REORDER_HEADERS);

    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR,
                           TEST_IFCFG_DIR "/ifcfg-test-vlan-vlanid-use.cexpected",
                           &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_read_vlan_only_device(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingVlan                *s_vlan;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-vlan-only-device",
                                       NULL,
                                       TYPE_ETHERNET,
                                       NULL);

    g_assert_cmpstr(nm_connection_get_interface_name(connection), ==, "eth0.9");

    s_vlan = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_VLAN);

    g_assert_cmpstr(nm_setting_vlan_get_parent(s_vlan), ==, "eth0");
    g_assert_cmpint(nm_setting_vlan_get_id(s_vlan), ==, 9);
}

static void
test_read_vlan_physdev(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingVlan                *s_vlan;

    connection =
        _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-vlan-physdev", NULL, TYPE_ETHERNET, NULL);

    g_assert_cmpstr(nm_connection_get_interface_name(connection), ==, "vlan0.3");

    s_vlan = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_VLAN);

    g_assert_cmpstr(nm_setting_vlan_get_parent(s_vlan), ==, "eth0");
    g_assert_cmpint(nm_setting_vlan_get_id(s_vlan), ==, 3);
}

static void
test_read_vlan_reorder_hdr_1(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingVlan                *s_vlan;

    NMTST_EXPECT_NM_WARN("*REORDER_HDR key is deprecated, use VLAN_FLAGS*");
    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-vlan-reorder-hdr-1",
                                       NULL,
                                       TYPE_ETHERNET,
                                       NULL);
    g_test_assert_expected_messages();

    g_assert_cmpstr(nm_connection_get_interface_name(connection), ==, "vlan0.3");

    s_vlan = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_VLAN);

    g_assert_cmpstr(nm_setting_vlan_get_parent(s_vlan), ==, "eth0");
    g_assert_cmpint(nm_setting_vlan_get_id(s_vlan), ==, 3);
    /* Check that REORDER_HDR=0 is ignored */
    g_assert_cmpint(nm_setting_vlan_get_flags(s_vlan), ==, NM_VLAN_FLAG_REORDER_HEADERS);
}

static void
test_read_vlan_reorder_hdr_2(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingVlan                *s_vlan;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-vlan-reorder-hdr-2",
                                       NULL,
                                       TYPE_ETHERNET,
                                       NULL);

    g_assert_cmpstr(nm_connection_get_interface_name(connection), ==, "vlan0.3");

    s_vlan = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_VLAN);

    g_assert_cmpstr(nm_setting_vlan_get_parent(s_vlan), ==, "eth0");
    g_assert_cmpint(nm_setting_vlan_get_id(s_vlan), ==, 3);
    /* Check that VLAN_FLAGS=NO_REORDER_HDR works */
    g_assert_cmpint(nm_setting_vlan_get_flags(s_vlan), ==, NM_VLAN_FLAG_LOOSE_BINDING);
}

static void
test_read_vlan_flags_1(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingVlan                *s_vlan;

    connection =
        _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-vlan-flags-1", NULL, TYPE_ETHERNET, NULL);

    g_assert_cmpstr(nm_connection_get_interface_name(connection), ==, "super-vlan");

    s_vlan = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_VLAN);

    g_assert_cmpstr(nm_setting_vlan_get_parent(s_vlan), ==, "eth9");
    g_assert_cmpint(nm_setting_vlan_get_id(s_vlan), ==, 44);
    g_assert_cmpstr(nm_setting_vlan_get_protocol(s_vlan), ==, NULL);
    g_assert_cmpint(nm_setting_vlan_get_flags(s_vlan),
                    ==,
                    NM_VLAN_FLAG_LOOSE_BINDING | NM_VLAN_FLAG_REORDER_HEADERS);
}

static void
test_read_vlan_flags_2(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingVlan                *s_vlan;

    connection =
        _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-vlan-flags-2", NULL, TYPE_ETHERNET, NULL);

    g_assert_cmpstr(nm_connection_get_interface_name(connection), ==, "super-vlan");

    s_vlan = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_VLAN);

    g_assert_cmpstr(nm_setting_vlan_get_parent(s_vlan), ==, "eth9");
    g_assert_cmpint(nm_setting_vlan_get_id(s_vlan), ==, 44);
    g_assert_cmpint(nm_setting_vlan_get_flags(s_vlan),
                    ==,
                    NM_VLAN_FLAG_GVRP | NM_VLAN_FLAG_LOOSE_BINDING | NM_VLAN_FLAG_REORDER_HEADERS);
}

static void
test_write_vlan(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;

    connection = _connection_from_file(TEST_IFCFG_VLAN_INTERFACE, NULL, TYPE_VLAN, NULL);

    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR,
                           TEST_IFCFG_DIR "/ifcfg-Vlan_test-vlan-interface.cexpected",
                           &testfile);
}

static void
test_write_vlan_flags(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;

    connection =
        _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-vlan-flags-2", NULL, TYPE_VLAN, NULL);

    _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_write_vlan_only_vlanid(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;

    connection = _connection_from_file(TEST_IFCFG_VLAN_ONLY_VLANID, NULL, TYPE_VLAN, NULL);

    _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_write_vlan_reorder_hdr(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingVlan                *s_vlan;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write VLAN reorder_hdr",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 FALSE,
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_VLAN_SETTING_NAME,
                 NULL);

    _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRED);

    s_vlan = _nm_connection_new_setting(connection, NM_TYPE_SETTING_VLAN);
    g_object_set(s_vlan,
                 NM_SETTING_VLAN_PARENT,
                 "eth0",
                 NM_SETTING_VLAN_ID,
                 444,
                 NM_SETTING_VLAN_FLAGS,
                 1,
                 NULL);

    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR,
                           TEST_IFCFG_DIR "/ifcfg-Test_Write_VLAN_reorder_hdr.cexpected",
                           &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_write_ethernet_missing_ipv6(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingIPConfig            *s_ip4;

    connection = nm_simple_connection_new();
    g_assert(connection);

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Ethernet Without IPv6 Setting",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRED_SETTING_NAME,
                 NULL);

    _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRED);

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP4_CONFIG_METHOD_AUTO,
                 NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID,
                 "random-client-id-00:22:33",
                 NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES,
                 TRUE,
                 NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS,
                 TRUE,
                 NULL);

    /* IP6 setting */
    /*
     * We intentionally don't add IPv6 setting here. ifcfg-rh plugin should regard
     * missing IPv6 as IPv6 with NM_SETTING_IP6_CONFIG_METHOD_AUTO method.
     */

    nmtst_assert_connection_verifies(connection);

    _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_read_ibft_ignored(void)
{
    gs_free_error GError *error = NULL;

    _connection_from_file_fail(TEST_IFCFG_DIR "/ifcfg-test-ibft", NULL, TYPE_ETHERNET, &error);
    g_assert_error(error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION);
}

static void
test_read_bond_main(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingBond                *s_bond;

    connection =
        _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-bond-main", NULL, TYPE_ETHERNET, NULL);

    g_assert_cmpstr(nm_connection_get_interface_name(connection), ==, "bond0");

    s_bond = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_BOND);

    g_assert_cmpstr(nm_setting_bond_get_option_by_name(s_bond, NM_SETTING_BOND_OPTION_MIIMON),
                    ==,
                    "100");
}

static void
test_read_bond_eth_type(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingBond                *s_bond;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-bond-eth-type",
                                       NULL,
                                       TYPE_ETHERNET,
                                       NULL);

    g_assert_cmpstr(nm_connection_get_interface_name(connection), ==, "bond0");

    s_bond = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_BOND);

    g_assert_cmpstr(nm_setting_bond_get_option_by_name(s_bond, NM_SETTING_BOND_OPTION_MIIMON),
                    ==,
                    "213");
    g_assert_cmpstr(nm_setting_bond_get_option_by_name(s_bond, NM_SETTING_BOND_OPTION_LACP_RATE),
                    ==,
                    "1");
}

static void
test_write_bond_main(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingBond                *s_bond;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    NMIPAddress                  *addr;
    GError                       *error = NULL;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Bond Main",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_INTERFACE_NAME,
                 "bond0",
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_BOND_SETTING_NAME,
                 NULL);

    _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRED);

    s_bond = _nm_connection_new_setting(connection, NM_TYPE_SETTING_BOND);
    nm_setting_bond_add_option(s_bond, NM_SETTING_BOND_OPTION_DOWNDELAY, "5");
    nm_setting_bond_add_option(s_bond, NM_SETTING_BOND_OPTION_UPDELAY, "10");
    nm_setting_bond_add_option(s_bond, NM_SETTING_BOND_OPTION_MIIMON, "100");

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
                 NM_SETTING_IP_CONFIG_GATEWAY,
                 "1.1.1.1",
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NULL);

    addr = nm_ip_address_new(AF_INET, "1.1.1.3", 24, &error);
    g_assert_no_error(error);
    nm_setting_ip_config_add_address(s_ip4, addr);
    nm_ip_address_unref(addr);

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, NULL);

    _nm_connection_new_setting(connection, NM_TYPE_SETTING_PROXY);

    nmtst_assert_connection_verifies_without_normalization(connection);

    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR,
                           TEST_IFCFG_DIR "/ifcfg-Test_Write_Bond_Main.cexpected",
                           &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_BOND, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_read_bond_port(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-bond-port-bond0",
                                       NULL,
                                       TYPE_ETHERNET,
                                       NULL);
    g_test_assert_expected_messages();

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);

    g_assert_cmpstr(nm_setting_connection_get_controller(s_con), ==, "bond0");

    g_assert_cmpstr(nm_setting_connection_get_port_type(s_con), ==, NM_SETTING_BOND_SETTING_NAME);
}

static void
test_write_bond_port(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingWired               *s_wired;
    static const char            *mac = "31:33:33:37:be:cd";
    guint32                       mtu = 1492;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Bond Slave",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRED_SETTING_NAME,
                 NM_SETTING_CONNECTION_MASTER,
                 "bond0",
                 NM_SETTING_CONNECTION_SLAVE_TYPE,
                 NM_SETTING_BOND_SETTING_NAME,
                 NULL);

    s_wired = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRED);
    g_object_set(s_wired, NM_SETTING_WIRED_MAC_ADDRESS, mac, NM_SETTING_WIRED_MTU, mtu, NULL);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_read_bond_port_setting(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con      = NULL;
    NMSettingBondPort            *s_port     = NULL;

    connection =
        _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-bond-port", NULL, TYPE_ETHERNET, NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_controller(s_con), ==, "bond99");
    g_assert_cmpstr(nm_setting_connection_get_port_type(s_con), ==, NM_SETTING_BOND_SETTING_NAME);

    s_port = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_BOND_PORT);
    g_assert_cmpuint(nm_setting_bond_port_get_queue_id(s_port), ==, 1);
}

static void
test_write_bond_port_setting(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingBondPort            *s_bond_port;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Bond Port",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRED_SETTING_NAME,
                 NM_SETTING_CONNECTION_MASTER,
                 "bond0",
                 NM_SETTING_CONNECTION_SLAVE_TYPE,
                 NM_SETTING_BOND_SETTING_NAME,
                 NULL);

    _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRED);

    s_bond_port = _nm_connection_new_setting(connection, NM_TYPE_SETTING_BOND_PORT);
    g_object_set(s_bond_port, NM_SETTING_BOND_PORT_QUEUE_ID, 1, NULL);
    g_object_set(s_bond_port, NM_SETTING_BOND_PORT_PRIO, 10, NULL);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_read_infiniband(gconstpointer test_data)
{
    const guint                   TEST_IDX   = GPOINTER_TO_UINT(test_data);
    gs_unref_object NMConnection *connection = NULL;
    NMSettingInfiniband          *s_infiniband;
    char                         *unmanaged = NULL;
    const char                   *mac;
    char        expected_mac_address[INFINIBAND_ALEN] = {0x80, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
                                                         0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc,
                                                         0xdd, 0xee, 0xff, 0x00, 0x11, 0x22};
    const char *transport_mode;
    const char *test_files[] = {
        TEST_IFCFG_DIR "/ifcfg-test-infiniband0",
        TEST_IFCFG_DIR "/ifcfg-test-infiniband1",
        TEST_IFCFG_DIR "/ifcfg-test-infiniband2",
    };

    g_assert(TEST_IDX < G_N_ELEMENTS(test_files));

    connection = _connection_from_file(test_files[TEST_IDX], NULL, TYPE_INFINIBAND, &unmanaged);
    g_assert(!unmanaged);

    s_infiniband = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_INFINIBAND);

    mac = nm_setting_infiniband_get_mac_address(s_infiniband);
    g_assert(mac);
    g_assert(nm_utils_hwaddr_matches(mac, -1, expected_mac_address, sizeof(expected_mac_address)));

    transport_mode = nm_setting_infiniband_get_transport_mode(s_infiniband);
    g_assert(transport_mode);
    g_assert_cmpstr(transport_mode, ==, "connected");

    nmtst_assert_connection_verifies_without_normalization(connection);

    switch (TEST_IDX) {
    case 0:
        g_assert_cmpint(nm_setting_infiniband_get_p_key(s_infiniband), ==, -1);
        g_assert_cmpstr(nm_setting_infiniband_get_parent(s_infiniband), ==, NULL);
        g_assert_cmpstr(nm_connection_get_interface_name(connection), ==, "ib0");
        break;
    case 1:
    case 2:
        g_assert_cmpint(nm_setting_infiniband_get_p_key(s_infiniband), ==, 0x80c1);
        g_assert_cmpstr(nm_setting_infiniband_get_parent(s_infiniband), ==, "ib0");
        g_assert_cmpstr(nm_connection_get_interface_name(connection), ==, "ib0.80c1");
        break;
    default:
        g_assert_not_reached();
        break;
    }
}

static void
test_read_ipoib(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingInfiniband          *s_infiniband;
    char                         *unmanaged = NULL;
    const char                   *transport_mode;
    int                           pkey;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-ipoib",
                                       NULL,
                                       TYPE_INFINIBAND,
                                       &unmanaged);
    g_assert(!unmanaged);

    s_infiniband = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_INFINIBAND);

    pkey = nm_setting_infiniband_get_p_key(s_infiniband);
    g_assert_cmpint(pkey, ==, 0x800c);

    transport_mode = nm_setting_infiniband_get_transport_mode(s_infiniband);
    g_assert_cmpstr(transport_mode, ==, "connected");
}

static void
test_write_infiniband(gconstpointer test_data)
{
    const int                     TEST_IDX    = GPOINTER_TO_INT(test_data);
    nmtst_auto_unlinkfile char   *testfile    = NULL;
    gs_unref_object NMConnection *connection  = NULL;
    gs_unref_object NMConnection *reread      = NULL;
    gboolean                      reread_same = FALSE;
    NMSettingConnection          *s_con;
    NMSettingInfiniband          *s_infiniband;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    const char  *mac = "80:00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00:11:22";
    guint32      mtu = 65520;
    NMIPAddress *addr;
    GError      *error          = NULL;
    const char  *interface_name = NULL;
    int          p_key;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Infiniband",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_INFINIBAND_SETTING_NAME,
                 NULL);

    if (NM_IN_SET(TEST_IDX, 1, 2))
        p_key = nmtst_get_rand_bool() ? 0x000c : 0x800c;
    else
        p_key = -1;

    if (NM_IN_SET(TEST_IDX, 1, 3)) {
        if (p_key >= 0x8000)
            interface_name = "ib0.800c";
    }

    g_object_set(s_con, NM_SETTING_CONNECTION_INTERFACE_NAME, interface_name, NULL);

    s_infiniband = _nm_connection_new_setting(connection, NM_TYPE_SETTING_INFINIBAND);
    g_object_set(s_infiniband, NM_SETTING_INFINIBAND_TRANSPORT_MODE, "connected", NULL);
    if (p_key == -1) {
        g_object_set(s_infiniband,
                     NM_SETTING_INFINIBAND_MAC_ADDRESS,
                     mac,
                     NM_SETTING_INFINIBAND_MTU,
                     mtu,
                     NULL);
    } else {
        g_object_set(s_infiniband,
                     NM_SETTING_INFINIBAND_P_KEY,
                     p_key,
                     NM_SETTING_INFINIBAND_PARENT,
                     "ib0",
                     NULL);
    }

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
                 NM_SETTING_IP_CONFIG_GATEWAY,
                 "1.1.1.1",
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NULL);

    addr = nm_ip_address_new(AF_INET, "1.1.1.3", 24, &error);
    g_assert_no_error(error);
    nm_setting_ip_config_add_address(s_ip4, addr);
    nm_ip_address_unref(addr);

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, NULL);

    if (nmtst_get_rand_bool())
        nmtst_connection_normalize(connection);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connection_reread(connection,
                                  TEST_SCRATCH_DIR,
                                  &testfile,
                                  NO_EXPECTED,
                                  &reread,
                                  &reread_same);
    _assert_reread_same(connection, reread);
    g_assert(reread_same);

    g_assert_cmpstr(interface_name, ==, nm_connection_get_interface_name(reread));
    g_assert_cmpint(nm_setting_infiniband_get_p_key(
                        _nm_connection_get_setting(reread, NM_TYPE_SETTING_INFINIBAND)),
                    ==,
                    p_key);
}

static void
test_read_bond_port_ib(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-bond-port-ib", NULL, NULL, NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);

    g_assert_cmpstr(nm_setting_connection_get_controller(s_con), ==, "bond0");
    g_assert_cmpstr(nm_setting_connection_get_port_type(s_con), ==, NM_SETTING_BOND_SETTING_NAME);
}

static void
test_write_bond_port_ib(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingInfiniband          *s_infiniband;
    static const char *mac = "80:00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00:11:22";

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Bond Slave InfiniBand",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_INFINIBAND_SETTING_NAME,
                 NM_SETTING_CONNECTION_MASTER,
                 "bond0",
                 NM_SETTING_CONNECTION_SLAVE_TYPE,
                 NM_SETTING_BOND_SETTING_NAME,
                 NULL);

    s_infiniband = _nm_connection_new_setting(connection, NM_TYPE_SETTING_INFINIBAND);
    g_object_set(s_infiniband,
                 NM_SETTING_INFINIBAND_MAC_ADDRESS,
                 mac,
                 NM_SETTING_INFINIBAND_MTU,
                 2044,
                 NM_SETTING_INFINIBAND_TRANSPORT_MODE,
                 "datagram",
                 NULL);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile);

    reread = _connection_from_file(testfile, NULL, NULL, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_read_bond_opts_mode_numeric(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingBond                *s_bond;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-bond-mode-numeric",
                                       NULL,
                                       TYPE_ETHERNET,
                                       NULL);

    g_assert_cmpstr(nm_connection_get_interface_name(connection), ==, "bond0");

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
                    ==,
                    NM_SETTING_BOND_SETTING_NAME);

    s_bond = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_BOND);
    g_assert_cmpstr(nm_setting_bond_get_option_by_name(s_bond, NM_SETTING_BOND_OPTION_MODE),
                    ==,
                    "802.3ad");
}

#define DCB_ALL_FLAGS \
    (NM_SETTING_DCB_FLAG_ENABLE | NM_SETTING_DCB_FLAG_ADVERTISE | NM_SETTING_DCB_FLAG_WILLING)

static void
test_read_dcb_basic(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingDcb                 *s_dcb;
    guint                         i;
    guint                         expected_group_ids[8]        = {0, 0, 0, 0, 1, 1, 1, 0xF};
    guint                         expected_group_bandwidths[8] = {25, 0, 0, 75, 0, 0, 0, 0};
    guint                         expected_bandwidths[8]       = {5, 10, 30, 25, 10, 50, 5, 0};
    gboolean expected_strict[8]          = {FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE};
    guint    expected_traffic_classes[8] = {7, 6, 5, 4, 3, 2, 1, 0};
    gboolean expected_pfcs[8]            = {TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, FALSE};

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-dcb", NULL, TYPE_ETHERNET, NULL);

    s_dcb = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_DCB);

    g_assert_cmpint(nm_setting_dcb_get_app_fcoe_flags(s_dcb), ==, DCB_ALL_FLAGS);
    g_assert_cmpint(nm_setting_dcb_get_app_fcoe_priority(s_dcb), ==, 7);

    g_assert_cmpint(nm_setting_dcb_get_app_iscsi_flags(s_dcb), ==, DCB_ALL_FLAGS);
    g_assert_cmpint(nm_setting_dcb_get_app_iscsi_priority(s_dcb), ==, 6);

    g_assert_cmpint(nm_setting_dcb_get_app_fip_flags(s_dcb), ==, DCB_ALL_FLAGS);
    g_assert_cmpint(nm_setting_dcb_get_app_fip_priority(s_dcb), ==, 2);

    g_assert_cmpint(nm_setting_dcb_get_priority_flow_control_flags(s_dcb),
                    ==,
                    (NM_SETTING_DCB_FLAG_ENABLE | NM_SETTING_DCB_FLAG_ADVERTISE));
    for (i = 0; i < 8; i++)
        g_assert_cmpint(nm_setting_dcb_get_priority_flow_control(s_dcb, i), ==, expected_pfcs[i]);

    g_assert_cmpint(nm_setting_dcb_get_priority_group_flags(s_dcb), ==, DCB_ALL_FLAGS);

    /* Group IDs */
    for (i = 0; i < 8; i++)
        g_assert_cmpint(nm_setting_dcb_get_priority_group_id(s_dcb, i), ==, expected_group_ids[i]);

    /* Group bandwidth */
    for (i = 0; i < 8; i++)
        g_assert_cmpint(nm_setting_dcb_get_priority_group_bandwidth(s_dcb, i),
                        ==,
                        expected_group_bandwidths[i]);

    /* User priority bandwidth */
    for (i = 0; i < 8; i++)
        g_assert_cmpint(nm_setting_dcb_get_priority_bandwidth(s_dcb, i),
                        ==,
                        expected_bandwidths[i]);

    /* Strict bandwidth */
    for (i = 0; i < 8; i++)
        g_assert_cmpint(nm_setting_dcb_get_priority_strict_bandwidth(s_dcb, i),
                        ==,
                        expected_strict[i]);

    /* Traffic class */
    for (i = 0; i < 8; i++)
        g_assert_cmpint(nm_setting_dcb_get_priority_traffic_class(s_dcb, i),
                        ==,
                        expected_traffic_classes[i]);
}

static void
test_write_dcb_basic(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingDcb                 *s_dcb;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    guint                         i;
    const guint                   group_ids[8]        = {4, 0xF, 6, 0xF, 1, 7, 3, 0xF};
    const guint                   group_bandwidths[8] = {10, 20, 15, 10, 2, 3, 35, 5};
    const guint                   bandwidths[8]       = {10, 20, 30, 40, 50, 10, 0, 25};
    const gboolean                strict[8] = {TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE};
    const guint                   traffic_classes[8] = {3, 4, 7, 2, 1, 0, 5, 6};
    const gboolean                pfcs[8] = {TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, FALSE};

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "dcb-test",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRED_SETTING_NAME,
                 NM_SETTING_CONNECTION_INTERFACE_NAME,
                 "eth0",
                 NULL);

    _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRED);

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO, NULL);

    s_dcb = _nm_connection_new_setting(connection, NM_TYPE_SETTING_DCB);
    g_object_set(s_dcb,
                 NM_SETTING_DCB_APP_FCOE_FLAGS,
                 DCB_ALL_FLAGS,
                 NM_SETTING_DCB_APP_FCOE_PRIORITY,
                 5,
                 NM_SETTING_DCB_APP_ISCSI_FLAGS,
                 DCB_ALL_FLAGS,
                 NM_SETTING_DCB_APP_ISCSI_PRIORITY,
                 1,
                 NM_SETTING_DCB_APP_FIP_FLAGS,
                 DCB_ALL_FLAGS,
                 NM_SETTING_DCB_APP_FIP_PRIORITY,
                 3,
                 NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS,
                 DCB_ALL_FLAGS,
                 NM_SETTING_DCB_PRIORITY_GROUP_FLAGS,
                 DCB_ALL_FLAGS,
                 NULL);

    for (i = 0; i < 8; i++) {
        nm_setting_dcb_set_priority_flow_control(s_dcb, i, pfcs[i]);
        nm_setting_dcb_set_priority_group_id(s_dcb, i, group_ids[i]);
        nm_setting_dcb_set_priority_group_bandwidth(s_dcb, i, group_bandwidths[i]);
        nm_setting_dcb_set_priority_bandwidth(s_dcb, i, bandwidths[i]);
        nm_setting_dcb_set_priority_strict_bandwidth(s_dcb, i, strict[i]);
        nm_setting_dcb_set_priority_traffic_class(s_dcb, i, traffic_classes[i]);
    }

    nmtst_assert_connection_verifies(connection);

    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR,
                           TEST_IFCFG_DIR "//ifcfg-dcb-test.cexpected",
                           &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_read_dcb_default_app_priorities(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingDcb                 *s_dcb;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-dcb-default-app-priorities",
                                       NULL,
                                       TYPE_ETHERNET,
                                       NULL);

    s_dcb = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_DCB);

    g_assert_cmpint(nm_setting_dcb_get_app_fcoe_flags(s_dcb), ==, NM_SETTING_DCB_FLAG_ENABLE);
    g_assert_cmpint(nm_setting_dcb_get_app_fcoe_priority(s_dcb), ==, -1);

    g_assert_cmpint(nm_setting_dcb_get_app_iscsi_flags(s_dcb), ==, NM_SETTING_DCB_FLAG_ENABLE);
    g_assert_cmpint(nm_setting_dcb_get_app_iscsi_priority(s_dcb), ==, -1);

    g_assert_cmpint(nm_setting_dcb_get_app_fip_flags(s_dcb), ==, NM_SETTING_DCB_FLAG_ENABLE);
    g_assert_cmpint(nm_setting_dcb_get_app_fip_priority(s_dcb), ==, -1);
}

static void
test_read_dcb_bad_booleans(void)
{
    gs_free_error GError *error = NULL;

    NMTST_EXPECT_NM_WARN("*invalid DCB_PG_STRICT value*not all 0s and 1s*");
    _connection_from_file_fail(TEST_IFCFG_DIR "/ifcfg-test-dcb-bad-booleans",
                               NULL,
                               TYPE_ETHERNET,
                               &error);
    g_test_assert_expected_messages();

    g_assert_error(error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION);
    g_assert(strstr(error->message, "invalid boolean digit"));
}

static void
test_read_dcb_short_booleans(void)
{
    gs_free_error GError *error = NULL;

    NMTST_EXPECT_NM_WARN("*DCB_PG_STRICT value*8 characters*");
    _connection_from_file_fail(TEST_IFCFG_DIR "/ifcfg-test-dcb-short-booleans",
                               NULL,
                               TYPE_ETHERNET,
                               &error);
    g_test_assert_expected_messages();

    g_assert_error(error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION);
    g_assert(strstr(error->message, "boolean array must be 8 characters"));
}

static void
test_read_dcb_bad_uints(void)
{
    gs_free_error GError *error = NULL;

    NMTST_EXPECT_NM_WARN("*invalid DCB_PG_UP2TC value*not 0 - 7*");
    _connection_from_file_fail(TEST_IFCFG_DIR "/ifcfg-test-dcb-bad-uints",
                               NULL,
                               TYPE_ETHERNET,
                               &error);
    g_test_assert_expected_messages();

    g_assert_error(error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION);
    g_assert(strstr(error->message, "invalid uint digit"));
}

static void
test_read_dcb_short_uints(void)
{
    gs_free_error GError *error = NULL;

    NMTST_EXPECT_NM_WARN("*DCB_PG_UP2TC value*8 characters*");
    _connection_from_file_fail(TEST_IFCFG_DIR "/ifcfg-test-dcb-short-uints",
                               NULL,
                               TYPE_ETHERNET,
                               &error);
    g_test_assert_expected_messages();

    g_assert_error(error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION);
    g_assert(strstr(error->message, "uint array must be 8 characters"));
}

static void
test_read_dcb_bad_percent(void)
{
    gs_free_error GError *error = NULL;

    NMTST_EXPECT_NM_WARN("*invalid DCB_PG_PCT percentage value*");
    _connection_from_file_fail(TEST_IFCFG_DIR "/ifcfg-test-dcb-bad-percent",
                               NULL,
                               TYPE_ETHERNET,
                               &error);
    g_test_assert_expected_messages();

    g_assert_error(error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION);
    g_assert(strstr(error->message, "invalid percent element"));
}

static void
test_read_dcb_short_percent(void)
{
    gs_free_error GError *error = NULL;

    NMTST_EXPECT_NM_WARN("*invalid DCB_PG_PCT percentage list value*");
    _connection_from_file_fail(TEST_IFCFG_DIR "/ifcfg-test-dcb-short-percent",
                               NULL,
                               TYPE_ETHERNET,
                               &error);
    g_test_assert_expected_messages();

    g_assert_error(error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION);
    g_assert(strstr(error->message, "percent array must be 8 elements"));
}

static void
test_read_dcb_pgpct_not_100(void)
{
    gs_free_error GError *error = NULL;

    NMTST_EXPECT_NM_WARN("*DCB_PG_PCT percentages do not equal 100*");
    _connection_from_file_fail(TEST_IFCFG_DIR "/ifcfg-test-dcb-pgpct-not-100",
                               NULL,
                               TYPE_ETHERNET,
                               &error);
    g_test_assert_expected_messages();

    g_assert_error(error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION);
    g_assert(strstr(error->message, "invalid percentage sum"));
}

static void
test_read_fcoe_mode(gconstpointer user_data)
{
    gs_unref_object NMConnection *connection    = NULL;
    gs_free char                 *file          = NULL;
    const char                   *expected_mode = user_data;
    NMSettingDcb                 *s_dcb;

    file       = g_strdup_printf(TEST_IFCFG_DIR "/ifcfg-test-fcoe-%s", expected_mode);
    connection = _connection_from_file(file, NULL, TYPE_ETHERNET, NULL);

    s_dcb = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_DCB);

    g_assert_cmpint(nm_setting_dcb_get_app_fcoe_flags(s_dcb), ==, NM_SETTING_DCB_FLAG_ENABLE);
    g_assert_cmpstr(nm_setting_dcb_get_app_fcoe_mode(s_dcb), ==, expected_mode);
}

static void
test_write_fcoe_mode(gconstpointer user_data)
{
    nmtst_auto_unlinkfile char   *testfile      = NULL;
    gs_unref_object NMConnection *connection    = NULL;
    gs_unref_object NMConnection *reread        = NULL;
    const char                   *expected_mode = user_data;
    NMSettingConnection          *s_con;
    NMSettingDcb                 *s_dcb;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    shvarFile                    *ifcfg;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "fcoe-test",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRED_SETTING_NAME,
                 NM_SETTING_CONNECTION_INTERFACE_NAME,
                 "eth0",
                 NULL);

    _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRED);

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO, NULL);

    s_dcb = _nm_connection_new_setting(connection, NM_TYPE_SETTING_DCB);
    g_object_set(s_dcb,
                 NM_SETTING_DCB_APP_FCOE_FLAGS,
                 NM_SETTING_DCB_FLAG_ENABLE,
                 NM_SETTING_DCB_APP_FCOE_MODE,
                 expected_mode,
                 NULL);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile);

    ifcfg = _svOpenFile(testfile);
    _svGetValue_check(ifcfg, "DCB_APP_FCOE_MODE", expected_mode);
    svCloseFile(ifcfg);

    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_read_team_controller(gconstpointer user_data)
{
    const char *const             PATH_NAME  = user_data;
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingTeam                *s_team;
    const char                   *expected_config =
        "{\"device\": \"team0\", \"link_watch\": {\"name\": \"ethtool\"}}";

    connection = _connection_from_file(PATH_NAME, NULL, TYPE_ETHERNET, NULL);

    g_assert_cmpstr(nm_connection_get_interface_name(connection), ==, "team0");

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
                    ==,
                    NM_SETTING_TEAM_SETTING_NAME);

    s_team = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_TEAM);
    g_assert_cmpstr(nm_setting_team_get_config(s_team), ==, expected_config);
}

static void
test_read_team_controller_invalid(gconstpointer user_data)
{
    const char *const             PATH_NAME  = user_data;
    gs_free_error GError         *error      = NULL;
    gs_unref_object NMConnection *connection = NULL;

    if (nm_json_vt()) {
        _connection_from_file_fail(PATH_NAME, NULL, TYPE_ETHERNET, &error);

        g_assert_error(error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY);
        g_assert(strstr(error->message, _("invalid json")));
    } else
        connection = _connection_from_file(PATH_NAME, NULL, TYPE_ETHERNET, NULL);
}

static void
test_write_team_controller(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingTeam                *s_team;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    const char                   *expected_config =
        "{\"device\": \"team0\", \"link_watch\": {\"name\": \"ethtool\"}}";
    shvarFile *f;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Team Master",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_INTERFACE_NAME,
                 "team0",
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_TEAM_SETTING_NAME,
                 NULL);

    s_team = _nm_connection_new_setting(connection, NM_TYPE_SETTING_TEAM);
    g_object_set(s_team, NM_SETTING_TEAM_CONFIG, expected_config, NULL);

    _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRED);

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO, NULL);

    _nm_connection_new_setting(connection, NM_TYPE_SETTING_PROXY);

    nmtst_assert_connection_verifies_without_normalization(connection);

    _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile);

    f = _svOpenFile(testfile);
    _svGetValue_check(f, "DEVICETYPE", "Team");
    _svGetValue_check(f, "TEAM_CONFIG", expected_config);
    svCloseFile(f);

    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_read_team_port(gconstpointer user_data)
{
    const char *const             PATH_NAME  = user_data;
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingTeamPort            *s_team_port;
    const char                   *expected_config = "{\"p4p1\": {\"prio\": -10, \"sticky\": true}}";

    connection = _connection_from_file(PATH_NAME, NULL, TYPE_ETHERNET, NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
                    ==,
                    NM_SETTING_WIRED_SETTING_NAME);
    g_assert_cmpstr(nm_setting_connection_get_controller(s_con), ==, "team0");

    s_team_port = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_TEAM_PORT);
    g_assert_cmpstr(nm_setting_team_port_get_config(s_team_port), ==, expected_config);
}

static void
test_write_team_port(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingTeamPort            *s_team_port;
    const char                   *expected_config = "{\"p4p1\": {\"prio\": -10, \"sticky\": true}}";
    shvarFile                    *f;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Team Port",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRED_SETTING_NAME,
                 NM_SETTING_CONNECTION_MASTER,
                 "team0",
                 NM_SETTING_CONNECTION_SLAVE_TYPE,
                 NM_SETTING_TEAM_SETTING_NAME,
                 NULL);

    s_team_port = _nm_connection_new_setting(connection, NM_TYPE_SETTING_TEAM_PORT);
    g_object_set(s_team_port, NM_SETTING_TEAM_PORT_CONFIG, expected_config, NULL);

    _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRED);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR,
                           TEST_IFCFG_DIR "/ifcfg-Test_Write_Team_Port.cexpected",
                           &testfile);

    f = _svOpenFile(testfile);
    _svGetValue_check(f, "TYPE", NULL);
    _svGetValue_check(f, "DEVICETYPE", "TeamPort");
    _svGetValue_check(f, "TEAM_PORT_CONFIG", expected_config);
    _svGetValue_check(f, "TEAM_MASTER", "team0");
    svCloseFile(f);

    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_write_team_infiniband_port(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingTeamPort            *s_team_port;
    NMSettingInfiniband          *s_infiniband;
    const char                   *expected_config = "{\"inf1\": {\"prio\": -10, \"sticky\": true}}";
    shvarFile                    *f;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Team Infiniband Port",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_INFINIBAND_SETTING_NAME,
                 NM_SETTING_CONNECTION_MASTER,
                 "team0",
                 NM_SETTING_CONNECTION_SLAVE_TYPE,
                 NM_SETTING_TEAM_SETTING_NAME,
                 NM_SETTING_CONNECTION_INTERFACE_NAME,
                 "inf1",
                 NULL);

    s_team_port = _nm_connection_new_setting(connection, NM_TYPE_SETTING_TEAM_PORT);
    g_object_set(s_team_port, NM_SETTING_TEAM_PORT_CONFIG, expected_config, NULL);

    s_infiniband = _nm_connection_new_setting(connection, NM_TYPE_SETTING_INFINIBAND);
    g_object_set(s_infiniband, NM_SETTING_INFINIBAND_TRANSPORT_MODE, "datagram", NULL);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR,
                           TEST_IFCFG_DIR "/ifcfg-Test_Write_Team_Infiniband_Port.cexpected",
                           &testfile);

    f = _svOpenFile(testfile);
    _svGetValue_check(f, "TYPE", "InfiniBand");
    _svGetValue_check(f, "DEVICETYPE", "TeamPort");
    _svGetValue_check(f, "TEAM_PORT_CONFIG", expected_config);
    _svGetValue_check(f, "TEAM_MASTER", "team0");
    svCloseFile(f);

    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

static void
test_read_team_port_empty_config(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingConnection          *s_con;
    NMSettingTeamPort            *s_team_port;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-team-port-empty-config",
                                       NULL,
                                       TYPE_ETHERNET,
                                       NULL);

    s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
                    ==,
                    NM_SETTING_WIRED_SETTING_NAME);
    g_assert_cmpstr(nm_setting_connection_get_controller(s_con), ==, "team0");

    /* Normalization adds a team-port setting */
    s_team_port = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_TEAM_PORT);

    /* empty/missing config */
    g_assert(!nm_setting_team_port_get_config(s_team_port));
}

static void
test_team_reread_port(void)
{
    nmtst_auto_unlinkfile char   *testfile     = NULL;
    gs_unref_object NMConnection *connection_1 = NULL;
    gs_unref_object NMConnection *connection_2 = NULL;
    gs_unref_object NMConnection *reread       = NULL;
    gboolean                      reread_same  = FALSE;
    NMSettingConnection          *s_con;

    connection_1 =
        nmtst_create_connection_from_keyfile("[connection]\n"
                                             "id=team-port-enp31s0f1-142\n"
                                             "uuid=74f435bb-ede4-415a-9d48-f580b60eba04\n"
                                             "type=vlan\n"
                                             "autoconnect=false\n"
                                             "interface-name=enp31s0f1-142\n"
                                             "controller=team142\n"
                                             "permissions=\n"
                                             "port-type=team\n"
                                             "\n"
                                             "[vlan]\n"
                                             "egress-priority-map=\n"
                                             "flags=1\n"
                                             "id=142\n"
                                             "ingress-priority-map=\n"
                                             "parent=enp31s0f1\n",
                                             "/test_team_reread_port");

    /* to double-check keyfile syntax, re-create the connection by hand. */
    connection_2 = nmtst_create_minimal_connection("team-port-enp31s0f1-142",
                                                   "74f435bb-ede4-415a-9d48-f580b60eba04",
                                                   NM_SETTING_VLAN_SETTING_NAME,
                                                   &s_con);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 FALSE,
                 NM_SETTING_CONNECTION_INTERFACE_NAME,
                 "enp31s0f1-142",
                 NM_SETTING_CONNECTION_MASTER,
                 "team142",
                 NM_SETTING_CONNECTION_SLAVE_TYPE,
                 "team",
                 NULL);
    g_object_set(nmtst_connection_assert_setting(connection_2, NM_TYPE_SETTING_VLAN),
                 NM_SETTING_VLAN_FLAGS,
                 1,
                 NM_SETTING_VLAN_ID,
                 142,
                 NM_SETTING_VLAN_PARENT,
                 "enp31s0f1",
                 NULL);

    _nm_connection_new_setting(connection_2, NM_TYPE_SETTING_TEAM_PORT);

    nmtst_connection_normalize(connection_2);

    nmtst_assert_connection_equals(connection_1, FALSE, connection_2, FALSE);

    _writer_new_connection_reread((nmtst_get_rand_uint32() % 2) ? connection_1 : connection_2,
                                  TEST_SCRATCH_DIR,
                                  &testfile,
                                  TEST_IFCFG_DIR "/ifcfg-team-port-enp31s0f1-142.cexpected",
                                  &reread,
                                  &reread_same);
    _assert_reread_same((nmtst_get_rand_uint32() % 2) ? connection_1 : connection_2, reread);
    g_assert(reread_same);
    g_clear_object(&reread);

    reread = _connection_from_file(testfile, NULL, TYPE_VLAN, NULL);
    nmtst_assert_connection_equals((nmtst_get_rand_uint32() % 2) ? connection_1 : connection_2,
                                   FALSE,
                                   reread,
                                   FALSE);
}

static void
test_read_proxy_basic(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingProxy               *s_proxy;

    /* Test basic proxy configuration */

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-read-proxy-basic",
                                       NULL,
                                       TYPE_ETHERNET,
                                       NULL);

    s_proxy = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_PROXY);

    g_assert_cmpint(nm_setting_proxy_get_method(s_proxy), ==, NM_SETTING_PROXY_METHOD_AUTO);
    g_assert(nm_setting_proxy_get_browser_only(s_proxy));
    g_assert_cmpstr(nm_setting_proxy_get_pac_url(s_proxy),
                    ==,
                    "http://wpad.mycompany.com/wpad.dat");
}

static void
test_write_proxy_basic(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingProxy               *s_proxy;
    const char                   *expected_url = "https://wpad.neverland.org/wpad.dat";
    shvarFile                    *f;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write Proxy Basic",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRED_SETTING_NAME,
                 NULL);

    s_proxy = _nm_connection_new_setting(connection, NM_TYPE_SETTING_PROXY);
    g_object_set(s_proxy, NM_SETTING_PROXY_METHOD, NM_SETTING_PROXY_METHOD_AUTO, NULL);
    g_object_set(s_proxy, NM_SETTING_PROXY_PAC_URL, expected_url, NULL);

    _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRED);

    nmtst_assert_connection_verifies(connection);

    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR,
                           TEST_IFCFG_DIR "/ifcfg-Test_Write_Proxy_Basic.cexpected",
                           &testfile);

    f = _svOpenFile(testfile);
    _svGetValue_check(f, "TYPE", "Ethernet");
    _svGetValue_check(f, "PROXY_METHOD", "auto");
    _svGetValue_check(f, "PAC_URL", expected_url);
    svCloseFile(f);

    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

/*****************************************************************************/

static const char *
_svUnescape(const char *str, char **to_free)
{
    const char   *s;
    gs_free char *str_free = NULL;

    g_assert(str);
    g_assert(to_free);

    if (str[0] == '\0') {
        /* avoid static string "" */
        str = (str_free = g_strdup(str));
    }

    s = svUnescape_full(str, to_free, FALSE);
    if (*to_free) {
        g_assert(s == *to_free);
        g_assert(s[0]);
    } else {
        g_assert(s == NULL || (!s[0] && (s < str || s > strchr(str, '\0')))
                 || (s[0] && s >= str && s <= strchr(str, '\0')));
    }

    {
        const char   *s2;
        gs_free char *to_free2 = NULL;

        gboolean is_utf8 = s && g_utf8_validate(s, -1, NULL);

        s2 = svUnescape_full(str, &to_free2, TRUE);
        if (NM_IN_STRSET(str, "$'\\U0x'", "$'\\x0'", "$'\\008'", "$'\\08'")) {
            g_assert_cmpstr(s2, ==, NULL);
            g_assert(!to_free2);
            g_assert_cmpstr(s, ==, "");
            g_assert(!*to_free);
        } else if (NM_IN_STRSET(str, "$'x\\U0'")) {
            g_assert_cmpstr(s2, ==, NULL);
            g_assert(!to_free2);
            g_assert_cmpstr(s, ==, "x");
            g_assert(*to_free == s);
        } else if (!is_utf8) {
            g_assert(!s2);
            g_assert(!to_free2);
        } else if (!to_free2) {
            g_assert_cmpstr(s, ==, s2);
            g_assert(s == s2);
        } else {
            g_assert_cmpstr(s, ==, s2);
            g_assert(s != s2);
            g_assert(s2 == to_free2);
        }
    }

    return s;
}

typedef struct {
    const char *val;
    const char *exp;
    bool        can_concat : 1;
    bool        needs_ascii_separator : 1;
} UnescapeTestData;

static void
do_svUnescape_assert(const char *str, const char *expected)
{
    gs_free char *to_free = NULL;
    const char   *s;

    s = _svUnescape(str, &to_free);
    g_assert_cmpstr(s, ==, expected);

    /* check we can make a round-trip */
    if (expected) {
        gs_free char *s1_free = NULL;
        gs_free char *s2_free = NULL;
        const char   *s1, *s2;

        s1 = svEscape(expected, &s1_free);
        g_assert(s1);

        s2 = _svUnescape(s1, &s2_free);
        g_assert(s2);

        g_assert_cmpstr(s2, ==, expected);
    }
}

static void
do_svUnescape_combine_ansi_append(GString                *str_val,
                                  GString                *str_exp,
                                  const UnescapeTestData *data,
                                  gboolean                honor_needs_ascii_separator)
{
    g_string_append(str_val, data->val);
    g_string_append(str_exp, data->exp);
    if (honor_needs_ascii_separator && data->needs_ascii_separator) {
        /* the string has an open escape sequence. We must ensure that when
         * combining it with another sequence, that they don't merge into
         * something different. for example "\xa" + "a" must not result in
         * "\xaa". Instead, we add a space in between to get "\xa a". */
        g_string_append(str_val, " ");
        g_string_append(str_exp, " ");
    }
}

static void
do_svUnescape_combine_ansi(GString                *str_val,
                           GString                *str_exp,
                           const UnescapeTestData *data_ansi,
                           gsize                   data_len,
                           gssize                  idx)
{
    gsize i, j;

    g_string_set_size(str_val, 0);
    g_string_set_size(str_exp, 0);
    g_string_append(str_val, "$'");
    if (idx < 0) {
        for (i = -idx; i > 0; i--) {
            j = nmtst_get_rand_uint32() % data_len;
            if (!data_ansi[j].can_concat) {
                i++;
                continue;
            }
            do_svUnescape_combine_ansi_append(str_val, str_exp, &data_ansi[j], i > 1);
        }
    } else {
        g_assert_cmpint(idx, <, data_len);
        do_svUnescape_combine_ansi_append(str_val, str_exp, &data_ansi[idx], FALSE);
    }
    g_string_append(str_val, "'");
}

static void
test_svUnescape(void)
{
#define V0(v_value, v_expected)      \
    {                                \
        .val        = "" v_value "", \
        .exp        = v_expected,    \
        .can_concat = FALSE,         \
    }
#define V1(v_value, v_expected)      \
    {                                \
        .val        = "" v_value "", \
        .exp        = v_expected,    \
        .can_concat = !!v_expected,  \
    }
#define V2(v_value, v_expected)                                      \
    {                                                                \
        .val = "" v_value "", .exp = v_expected, .can_concat = TRUE, \
        .needs_ascii_separator = TRUE,                               \
    }
    const UnescapeTestData data_full[] = {
        V1("", ""),
        V0("'", NULL),
        V1("'x'", "x"),
        V1("'  '", "  "),
        V1("'x'", "x"),
        V0("\"", NULL),
        V0("\\", NULL),
        V0(" ", ""),
        V0("   ", ""),
        V0("a;   #", "a"),
        V0(" ;   #", ""),
        V0(";   ", ""),
        V0("; ;", NULL),
        V0(" ; a #", NULL),
        V0(" ; a;;  #", NULL),
        V0("a; ; #", NULL),
        V0("\t  # ", ""),
        V0("\t  #a", ""),
        V0("\t  #a\r", ""),
        V0("\r", ""),
        V1("\\\"", "\""),
        V1("\\`", "`"),
        V1("\\$", "$"),
        V1("\\\\", "\\"),
        V1("\\a", "a"),
        V1("\\b", "b"),
        V1("\\'", "'"),
        V1("\\~", "~"),
        V1("\\\t", "\t"),
        V1("\"\\\"\"", "\""),
        V1("\"\\`\"", "`"),
        V1("\"\\$\"", "$"),
        V1("\"\\\\\"", "\\"),
        V1("\"\\a\"", "\\a"),
        V1("\"\\b\"", "\\b"),
        V1("\"\\\t\"", "\\\t"),
        V0("ab\r", "ab"),
        V0("a'b'\r ", "ab"),
        V0("a'b' \r", "ab"),
        V0("a#b", "a#b"),
        V0("#b", "#b"),
        V1("\'some string\'", "some string"),
        V0("Bob outside LAN", NULL),
        V1("x", "x"),
        V1("'{ \"device\": \"team0\", \"link_watch\": { \"name\": \"ethtool\" } }'",
           "{ \"device\": \"team0\", \"link_watch\": { \"name\": \"ethtool\" } }"),
        V1("'{\"device\": \"team0\", \"link_watch\": {\"name\": \"ethtool\"}}'",
           "{\"device\": \"team0\", \"link_watch\": {\"name\": \"ethtool\"}}"),
        V1("x\"\"b", "xb"),
        V1("x\"c\"b", "xcb"),
        V1("\"c\"b", "cb"),
        V1("\"c\"\\'b", "c'b"),
        V1("$''", ""),
        V1("$'\\n'", "\n"),
        V0("$'\\'", NULL),
        V1("$'\\x'", "\\x"),
        V1("$'\\xa'", "\xa"),
        V0("$'\\x0'", ""),
        V1("$'\\x12'", "\x12"),
        V1("$'\\x12A'",
           "\x12"
           "A"),
        V1("$'\\x12t'", "\x12t"),
        V1("\"aa\\\"\"", "aa\""),
        V1("\"aa\\\"b\"c", "aa\"bc"),
        V1("\"aa\\\"\"b", "aa\"b"),

        /* the following is not shell behavior, but kept for backward compatibility
         * with old svEscape(). */
        V0("\"\\'\"", "'"),
        V0("\"\\~\"", "~"),
        V0("\"b\\~b\"", "b~b"),
        V0("\"\\~\\~\"", "~~"),
        V0("\"\\~\\'\"", "~'"),

        /* the following is shell-behavior, because it doesn't look like written
         * by old svEscape(). */
        V1("\"\\~~\"", "\\~~"),
        V1("\"\\a\\'\"", "\\a\\'"),
        V1("x\"\\~\"", "x\\~"),
        V1("\"\\'\"''", "\\'"),
        V0("\"b\\~b\" ", "b\\~b"),
        V1("\"b\\~b\"x", "b\\~bx"),

        V0("$'x\\U0'", "x"),
        V0("$'\\U0x'", ""),
    };
    const UnescapeTestData data_ansi[] = {
        /* strings inside $''. They cannot be compared directly, but must
         * be wrapped by do_svUnescape_combine_ansi(). */
        V1("", ""),
        V1("a", "a"),
        V1("b", "b"),
        V1("x", "x"),
        V1(" ", " "),
        V1("\\a", "\a"),
        V1("\\b", "\b"),
        V1("\\e", "\e"),
        V1("\\E", "\E"),
        V1("\\f", "\f"),
        V1("\\n", "\n"),
        V1("\\r", "\r"),
        V1("\\t", "\t"),
        V1("\\v", "\v"),
        V1("\\\\", "\\"),
        V1("\\'", "'"),
        V1("\\\"", "\""),
        V1("\\?", "\?"),
        V1("\\?", "?"),
        V2("\\8", "\\8"),
        V2("\\1", "\1"),
        V1("\\1A", "\1A"),
        V1("\\18", "\18"),
        V2("\\01", "\1"),
        V1("\\001", "\1"),
        V0("\\008", ""),
        V1("\\018", "\0018"),
        V0("\\08", ""),
        V1("\\18", "\0018"),
        V1("\\x", "\\x"),
        V2("\\xa", "\xa"),
        V1("\\x12", "\x12"),
        V1("\\x12A",
           "\x12"
           "A"),
        V1("\\x12a",
           "\x12"
           "a"),
        V1("\\x12t", "\x12t"),
        V1("\\x1a", "\x1a"),
        V1("\\x1A", "\x1A"),
        V1("\\ut", "\\ut"),
        V2("\\ua", "\xa"),
        V1("\\uat", "\xat"),
        V2("\\uab", "\xc2\xab"),
        V1("\\uabt", "\xc2\xabt"),
        V2("\\uabc", "\xe0\xaa\xbc"),
        V1("\\uabct", "\xe0\xaa\xbct"),
        V2("\\uabcd", "\xea\xaf\x8d"),
        V1("\\uabcdt", "\xea\xaf\x8dt"),
        V2("\\uabcde",
           "\xea\xaf\x8d"
           "e"),
        V1("\\uabcdet",
           "\xea\xaf\x8d"
           "et"),
        V1("\\Ut", "\\Ut"),
        V2("\\Ua", "\xa"),
        V1("\\Uat", "\xat"),
        V2("\\Uab", "\xc2\xab"),
        V1("\\Uabt", "\xc2\xabt"),
        V2("\\Uabc", "\xe0\xaa\xbc"),
        V1("\\Uabct", "\xe0\xaa\xbct"),
        V2("\\Uabcd", "\xea\xaf\x8d"),
        V1("\\Uabcdt", "\xea\xaf\x8dt"),
        V2("\\Uabcde", "\xf2\xab\xb3\x9e"),
        V1("\\Uabcdet", "\xf2\xab\xb3\x9et"),
        V2("\\Uabcde0", "\xf8\xaa\xbc\xb7\xa0"),
        V1("\\Uabcde0t", "\xf8\xaa\xbc\xb7\xa0t"),
        V2("\\Uabcde01", "\xfc\x8a\xaf\x8d\xb8\x81"),
        V1("\\Uabcde01t", "\xfc\x8a\xaf\x8d\xb8\x81t"),
        V2("\\U0abcde01", "\xfc\x8a\xaf\x8d\xb8\x81"),
        V1("\\U0abcde01t", "\xfc\x8a\xaf\x8d\xb8\x81t"),
        V1("\\U00abcde01",
           "\xf8\xaa\xbc\xb7\xa0"
           "1"),
        V1("\\U00abcde01t",
           "\xf8\xaa\xbc\xb7\xa0"
           "1t"),

        /* control-x sequence is not supported */
        V1("\\c", "\\c"),
        V1("\\c1", "\\c1"),
    };
#undef V0
#undef V1
#undef V2
    gsize                         i;
    nm_auto_free_gstring GString *str_val  = g_string_new(NULL);
    nm_auto_free_gstring GString *str_val2 = g_string_new(NULL);
    nm_auto_free_gstring GString *str_exp  = g_string_new(NULL);
    nm_auto_free_gstring GString *str_exp2 = g_string_new(NULL);

    do_svUnescape_assert("'  ''  '", "    ");

    for (i = 0; i < G_N_ELEMENTS(data_full); i++)
        do_svUnescape_assert(data_full[i].val, data_full[i].exp);

    for (i = 0; i < G_N_ELEMENTS(data_ansi); i++) {
        do_svUnescape_combine_ansi(str_val, str_exp, data_ansi, G_N_ELEMENTS(data_ansi), i);
        do_svUnescape_assert(str_val->str, str_exp->str);
    }

    /* different values can be just concatenated... */
    for (i = 0; i < 200; i++) {
        gsize num_concat = (nmtst_get_rand_uint32() % 5) + 2;

        g_string_set_size(str_val, 0);
        g_string_set_size(str_exp, 0);

        while (num_concat > 0) {
            gsize idx;

            if ((nmtst_get_rand_uint32() % 3 == 0)) {
                do_svUnescape_combine_ansi(str_val2,
                                           str_exp2,
                                           data_ansi,
                                           G_N_ELEMENTS(data_ansi),
                                           -((int) ((nmtst_get_rand_uint32() % 5) + 1)));
                continue;
            }

            idx = nmtst_get_rand_uint32() % G_N_ELEMENTS(data_full);
            if (!data_full[idx].can_concat)
                continue;
            g_string_append(str_val, data_full[idx].val);
            g_string_append(str_exp, data_full[idx].exp);
            num_concat--;
        }

        switch (nmtst_get_rand_uint32() % 3) {
        case 0:
            g_string_append(str_val, " ");
            break;
        case 1:
            g_string_append(str_val, "    ");
            break;
        }
        switch (nmtst_get_rand_uint32() % 3) {
        case 0:
            g_string_append(str_val, " #");
            break;
        case 1:
            g_string_append(str_val, " #foo");
            break;
        }
        do_svUnescape_assert(str_val->str, str_exp->str);
    }
}

/*****************************************************************************/

static void
test_write_unknown(gconstpointer test_data)
{
    nmtst_auto_unlinkfile char *filename_tmp_1    = g_strdup(TEST_SCRATCH_DIR_TMP "/tmp-1");
    const char                 *testfile          = test_data;
    gs_free char               *testfile_expected = g_strconcat(testfile, ".expected", NULL);
    shvarFile                  *sv;
    gs_free_error GError       *error = NULL;
    gboolean                    success;
    gs_free char               *file_contents_out = NULL;
    gs_free char               *file_contents_exp = NULL;

    sv = _svOpenFile(testfile);

    _nmtst_svFileSetName(sv, filename_tmp_1);
    _nmtst_svFileSetModified(sv);

    if (g_str_has_suffix(testfile, "ifcfg-test-write-unknown-4")) {
        _svGetValue_check(sv, "IPADDR", "l4x");
        _svGetValue_check(sv, "IPADDR2", "");
        _svGetValue_check(sv, "IPADDR3", "name3-value");

        svSetValue(sv, "IPADDR", "set-by-test1");
        svSetValue(sv, "IPADDR2", NULL);
        svSetValue(sv, "IPADDR2", "set-by-test2");
        svSetValue(sv, "IPADDR3", "set-by-test3");

        _svGetValue_check(sv, "METRIC", NULL);
        _svGetValue_check(sv, "METRIC1", "");
        _svGetValue_check(sv, "METRIC2", "");
        _svGetValue_check(sv, "METRIC3", "");

        _svGetValue_check(sv, "IPADDR", "set-by-test1");
        _svGetValue_check(sv, "IPADDR2", "set-by-test2");
        _svGetValue_check(sv, "IPADDR3", "set-by-test3");
    }

    success = svWriteFile(sv, 0644, &error);
    nmtst_assert_success(success, error);

    file_contents_out = nmtst_file_get_contents(filename_tmp_1);
    file_contents_exp = nmtst_file_get_contents(testfile_expected);

    g_assert_cmpstr(file_contents_out, ==, file_contents_exp);

    svCloseFile(sv);
}

/*****************************************************************************/

static void
test_read_vlan_trailing_spaces(void)
{
    const char                   *testfile   = TEST_IFCFG_DIR "/ifcfg-test-vlan-trailing-spaces";
    gs_unref_object NMConnection *connection = NULL;
    gboolean                      success;
    GError                       *error = NULL;
    NMSettingVlan                *s_vlan;
    gs_free char                 *contents = NULL;

    /* Ensure there is whitespace at the end of the VLAN interface name,
     * to prevent the whitespace getting stripped off and committed mistakenly
     * by something in the future.
     */
    success = g_file_get_contents(testfile, &contents, NULL, &error);
    g_assert_no_error(error);
    g_assert(success);
    g_assert(contents && contents[0]);
    g_assert(strstr(contents, "DEVICE=\"vlan201\"  \n"));

    connection = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);

    s_vlan = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_VLAN);

    g_assert_cmpstr(nm_connection_get_interface_name(connection), ==, "vlan201");
    g_assert_cmpstr(nm_setting_vlan_get_parent(s_vlan), ==, "enccw0.0.fb00");
    g_assert_cmpint(nm_setting_vlan_get_id(s_vlan), ==, 201);
    g_assert_cmpint(nm_setting_vlan_get_flags(s_vlan), ==, NM_VLAN_FLAG_REORDER_HEADERS);
}

/*****************************************************************************/

static void
test_sit_read_ignore(void)
{
    gs_free_error GError *error = NULL;

    _connection_from_file_fail(TEST_IFCFG_DIR "/ifcfg-test-sit-ignore",
                               NULL,
                               TYPE_ETHERNET,
                               &error);
    nmtst_assert_error(error, 0, 0, "*Ignoring unsupported connection due to IPV6TUNNELIPV4*");
}

/*****************************************************************************/

static void
do_test_utils_name(const char *desc, const char *path, gboolean only_ifcfg, const char *expected)
{
    const char *result;

    result = utils_get_ifcfg_name(path, only_ifcfg);
    g_assert_cmpstr(result, ==, expected);
}

static void
test_utils_name(void)
{
    do_test_utils_name("get-ifcfg-name-bad", "/foo/bar/adfasdfadf", FALSE, NULL);
    do_test_utils_name("get-ifcfg-name-good", "/foo/bar/ifcfg-FooBar", FALSE, "FooBar");
    do_test_utils_name("get-ifcfg-name-keys", "/foo/bar/keys-BlahLbah", FALSE, "BlahLbah");
    do_test_utils_name("get-ifcfg-name-route", "/foo/bar/route-Lalalala", FALSE, "Lalalala");
    do_test_utils_name("get-ifcfg-name-only-ifcfg-route", "/foo/bar/route-Lalalala", TRUE, NULL);
    do_test_utils_name("get-ifcfg-name-only-ifcfg-keys", "/foo/bar/keys-Lalalala", TRUE, NULL);
    do_test_utils_name("get-ifcfg-name-no-path-ifcfg", "ifcfg-Lalalala", FALSE, "Lalalala");
    do_test_utils_name("get-ifcfg-name-no-path-keys", "keys-Lalalala", FALSE, "Lalalala");
    do_test_utils_name("get-ifcfg-name-no-path-route", "route-Lalalala", FALSE, "Lalalala");

    do_test_utils_name("get-ifcfg-name-bad2-ifcfg", "/foo/bar/asdfasifcfg-Foobar", FALSE, NULL);
    do_test_utils_name("get-ifcfg-name-bad2-keys", "/foo/bar/asdfaskeys-Foobar", FALSE, NULL);
    do_test_utils_name("get-ifcfg-name-bad2-route", "/foo/bar/asdfasroute-Foobar", FALSE, NULL);
}

/*****************************************************************************/

static void
do_test_utils_path_ifcfg(const char *desc, const char *path, const char *expected)
{
    gs_free char *result = NULL;

    result = utils_get_ifcfg_path(path);
    g_assert_cmpstr(result, ==, expected);
}

static void
do_test_utils_path_keys(const char *desc, const char *path, const char *expected)
{
    gs_free char *result = NULL;

    result = utils_get_keys_path(path);
    g_assert_cmpstr(result, ==, expected);
}

static void
do_test_utils_path_route(const char *desc, const char *path, const char *expected)
{
    gs_free char *result = NULL;

    result = utils_get_route_path(path);
    g_assert_cmpstr(result, ==, expected);
}

static void
test_utils_path(void)
{
    do_test_utils_path_ifcfg("ifcfg-path-bad", "/foo/bar/adfasdfasdf", NULL);
    do_test_utils_path_ifcfg("ifcfg-path-from-keys-no-path", "keys-BlahBlah", "ifcfg-BlahBlah");
    do_test_utils_path_ifcfg("ifcfg-path-from-keys",
                             "/foo/bar/keys-BlahBlah",
                             "/foo/bar/ifcfg-BlahBlah");
    do_test_utils_path_ifcfg("ifcfg-path-from-route",
                             "/foo/bar/route-BlahBlah",
                             "/foo/bar/ifcfg-BlahBlah");

    do_test_utils_path_keys("keys-path-bad", "/foo/bar/asdfasdfasdfasdf", NULL);
    do_test_utils_path_keys("keys-path-from-ifcfg-no-path", "ifcfg-FooBar", "keys-FooBar");
    do_test_utils_path_keys("keys-path-from-ifcfg",
                            "/foo/bar/ifcfg-FooBar",
                            "/foo/bar/keys-FooBar");
    do_test_utils_path_keys("keys-path-from-route",
                            "/foo/bar/route-FooBar",
                            "/foo/bar/keys-FooBar");

    do_test_utils_path_route("route-path-bad", "/foo/bar/asdfasdfasdfasdf", NULL);
    do_test_utils_path_route("route-path-from-ifcfg-no-path", "ifcfg-FooBar", "route-FooBar");
    do_test_utils_path_route("route-path-from-ifcfg",
                             "/foo/bar/ifcfg-FooBar",
                             "/foo/bar/route-FooBar");
    do_test_utils_path_route("route-path-from-keys",
                             "/foo/bar/keys-FooBar",
                             "/foo/bar/route-FooBar");
}

/*****************************************************************************/

static void
do_test_utils_ignored(const char *desc, const char *path, gboolean expected_ignored)
{
    gboolean result;

    result = utils_should_ignore_file(path, FALSE);
    g_assert(result == expected_ignored);
}

static void
test_utils_ignore(void)
{
    do_test_utils_ignored("ignored-ifcfg", "ifcfg-FooBar", FALSE);
    do_test_utils_ignored("ignored-keys", "keys-FooBar", FALSE);
    do_test_utils_ignored("ignored-route", "route-FooBar", FALSE);
    do_test_utils_ignored("ignored-bak", "ifcfg-FooBar" BAK_TAG, TRUE);
    do_test_utils_ignored("ignored-tilde", "ifcfg-FooBar" TILDE_TAG, TRUE);
    do_test_utils_ignored("ignored-orig", "ifcfg-FooBar" ORIG_TAG, TRUE);
    do_test_utils_ignored("ignored-rej", "ifcfg-FooBar" REJ_TAG, TRUE);
    do_test_utils_ignored("ignored-rpmnew", "ifcfg-FooBar" RPMNEW_TAG, TRUE);
    do_test_utils_ignored("ignored-augnew", "ifcfg-FooBar" AUGNEW_TAG, TRUE);
    do_test_utils_ignored("ignored-augtmp", "ifcfg-FooBar" AUGTMP_TAG, TRUE);
}

/*****************************************************************************/

static void
test_sriov_read(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingSriov               *s_sriov;
    NMSriovVF                    *vf;
    GVariant                     *variant;
    GError                       *error = NULL;
    gs_free char                 *str1  = NULL;
    gs_free char                 *str2  = NULL;

    connection =
        _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-sriov", NULL, TYPE_ETHERNET, NULL);

    g_assert_cmpstr(nm_connection_get_interface_name(connection), ==, "eth0");

    s_sriov = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_SRIOV);

    g_assert_cmpint(nm_setting_sriov_get_total_vfs(s_sriov), ==, 16);
    g_assert_cmpint(nm_setting_sriov_get_num_vfs(s_sriov), ==, 3);
    g_assert_cmpint(nm_setting_sriov_get_autoprobe_drivers(s_sriov), ==, NM_TERNARY_FALSE);

    /* VF 3 */
    vf = nm_setting_sriov_get_vf(s_sriov, 0);
    g_assert(vf);
    g_assert_cmpint(nm_sriov_vf_get_index(vf), ==, 3);

    variant = nm_sriov_vf_get_attribute(vf, NM_SRIOV_VF_ATTRIBUTE_MAC);
    g_assert(variant);
    g_assert(g_variant_is_of_type(variant, G_VARIANT_TYPE_STRING));
    g_assert_cmpstr(g_variant_get_string(variant, NULL), ==, "55:44:33:22:11:00");

    variant = nm_sriov_vf_get_attribute(vf, NM_SRIOV_VF_ATTRIBUTE_SPOOF_CHECK);
    g_assert(variant);
    g_assert(g_variant_is_of_type(variant, G_VARIANT_TYPE_BOOLEAN));
    g_assert_cmpint(g_variant_get_boolean(variant), ==, TRUE);

    /* VF 12 */
    vf   = nm_setting_sriov_get_vf(s_sriov, 1);
    str1 = nm_utils_sriov_vf_to_str(vf, FALSE, &error);
    g_assert_no_error(error);
    g_assert_cmpstr(str1, ==, "12 min-tx-rate=100 trust=false vlans=1.200.ad");

    /* VF 15 */
    vf   = nm_setting_sriov_get_vf(s_sriov, 2);
    str2 = nm_utils_sriov_vf_to_str(vf, FALSE, &error);
    g_assert_no_error(error);
    g_assert_cmpstr(str2, ==, "15 mac=01:23:45:67:89:ab max-tx-rate=200 vlans=2");
}

static void
test_sriov_write(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    NMSettingSriov               *s_sriov;
    NMSriovVF                    *vf;
    gs_unref_ptrarray GPtrArray  *vfs = NULL;
    NMIPAddress                  *addr;
    GError                       *error = NULL;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write SR-IOV config",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_INTERFACE_NAME,
                 "eth0",
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRED_SETTING_NAME,
                 NULL);

    _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRED);

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
                 NM_SETTING_IP_CONFIG_GATEWAY,
                 "1.1.1.1",
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NULL);

    addr = nm_ip_address_new(AF_INET, "1.1.1.3", 24, &error);
    g_assert_no_error(error);
    nm_setting_ip_config_add_address(s_ip4, addr);
    nm_ip_address_unref(addr);

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, NULL);

    s_sriov = _nm_connection_new_setting(connection, NM_TYPE_SETTING_SRIOV);

    vfs = g_ptr_array_new_with_free_func((GDestroyNotify) nm_sriov_vf_unref);

    vf = nm_utils_sriov_vf_from_str("2 mac=55:55:55:55:55:55 vlans=3.10.ad;10", &error);
    nmtst_assert_success(vf, error);
    g_ptr_array_add(vfs, vf);

    vf = nm_utils_sriov_vf_from_str("19 spoof-check=true", &error);
    nmtst_assert_success(vf, error);
    g_ptr_array_add(vfs, vf);

    g_object_set(s_sriov,
                 NM_SETTING_SRIOV_TOTAL_VFS,
                 64,
                 NM_SETTING_SRIOV_VFS,
                 vfs,
                 NM_SETTING_SRIOV_AUTOPROBE_DRIVERS,
                 NM_TERNARY_TRUE,
                 NULL);

    _nm_connection_new_setting(connection, NM_TYPE_SETTING_PROXY);

    nmtst_assert_connection_verifies_without_normalization(connection);

    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR,
                           TEST_IFCFG_DIR "/ifcfg-test-sriov-write.cexpected",
                           &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

/*****************************************************************************/

static void
test_tc_read(void)
{
    gs_unref_object NMConnection *connection = NULL;
    NMSettingTCConfig            *s_tc;
    NMTCQdisc                    *qdisc;
    NMTCTfilter                  *filter;
    gs_free char                 *str = NULL;

    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-tc", NULL, TYPE_ETHERNET, NULL);

    g_assert_cmpstr(nm_connection_get_interface_name(connection), ==, "eth0");

    s_tc = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_TC_CONFIG);

    g_assert_cmpint(nm_setting_tc_config_get_num_qdiscs(s_tc), ==, 1);
    qdisc = nm_setting_tc_config_get_qdisc(s_tc, 0);
    g_assert(qdisc);
    g_assert_cmpint(nm_tc_qdisc_get_parent(qdisc), ==, TC_H_ROOT);
    g_assert_cmpint(nm_tc_qdisc_get_handle(qdisc), ==, TC_H_UNSPEC);
    g_assert_cmpstr(nm_tc_qdisc_get_kind(qdisc), ==, "fq_codel");

    g_assert_cmpint(nm_setting_tc_config_get_num_tfilters(s_tc), ==, 1);
    filter = nm_setting_tc_config_get_tfilter(s_tc, 0);
    g_assert(filter);
    str = nm_utils_tc_tfilter_to_str(filter, NULL);
    g_assert_cmpstr(str, ==, "parent 1234: matchall action simple sdata Hello");
}

static void
test_tc_write_empty(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    NMIPAddress                  *addr;
    GError                       *error = NULL;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write TC config",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_INTERFACE_NAME,
                 "eth0",
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRED_SETTING_NAME,
                 NULL);

    _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRED);

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
                 NM_SETTING_IP_CONFIG_GATEWAY,
                 "1.1.1.1",
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NULL);

    addr = nm_ip_address_new(AF_INET, "1.1.1.3", 24, &error);
    g_assert_no_error(error);
    nm_setting_ip_config_add_address(s_ip4, addr);
    nm_ip_address_unref(addr);

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, NULL);

    _nm_connection_new_setting(connection, NM_TYPE_SETTING_TC_CONFIG);

    _nm_connection_new_setting(connection, NM_TYPE_SETTING_PROXY);

    nmtst_assert_connection_verifies_without_normalization(connection);

    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR,
                           TEST_IFCFG_DIR "/ifcfg-test-tc-write-empty.cexpected",
                           &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_BOND, NULL);

    nmtst_assert_connection_equals(connection, FALSE, reread, FALSE);
}

static void
test_tc_write(void)
{
    nmtst_auto_unlinkfile char   *testfile   = NULL;
    gs_unref_object NMConnection *connection = NULL;
    gs_unref_object NMConnection *reread     = NULL;
    NMSettingConnection          *s_con;
    NMSettingIPConfig            *s_ip4;
    NMSettingIPConfig            *s_ip6;
    NMSettingTCConfig            *s_tc;
    NMTCQdisc                    *qdisc;
    NMTCTfilter                  *tfilter;
    NMIPAddress                  *addr;
    GError                       *error = NULL;

    connection = nm_simple_connection_new();

    s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
    g_object_set(s_con,
                 NM_SETTING_CONNECTION_ID,
                 "Test Write TC config",
                 NM_SETTING_CONNECTION_UUID,
                 nm_uuid_generate_random_str_a(),
                 NM_SETTING_CONNECTION_AUTOCONNECT,
                 TRUE,
                 NM_SETTING_CONNECTION_INTERFACE_NAME,
                 "eth0",
                 NM_SETTING_CONNECTION_TYPE,
                 NM_SETTING_WIRED_SETTING_NAME,
                 NULL);

    _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRED);

    s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG);
    g_object_set(s_ip4,
                 NM_SETTING_IP_CONFIG_METHOD,
                 NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
                 NM_SETTING_IP_CONFIG_GATEWAY,
                 "1.1.1.1",
                 NM_SETTING_IP_CONFIG_MAY_FAIL,
                 TRUE,
                 NULL);

    addr = nm_ip_address_new(AF_INET, "1.1.1.3", 24, &error);
    g_assert_no_error(error);
    nm_setting_ip_config_add_address(s_ip4, addr);
    nm_ip_address_unref(addr);

    s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG);
    g_object_set(s_ip6, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, NULL);

    s_tc = _nm_connection_new_setting(connection, NM_TYPE_SETTING_TC_CONFIG);

    qdisc = nm_tc_qdisc_new("pfifo_fast", TC_H_MAKE(0x2468 << 16, 0x2), &error);
    g_assert_no_error(error);
    nm_setting_tc_config_add_qdisc(s_tc, qdisc);
    nm_tc_qdisc_unref(qdisc);

    tfilter =
        nm_utils_tc_tfilter_from_str("parent 1234: matchall action simple sdata Hello", &error);
    g_assert_no_error(error);
    nm_setting_tc_config_add_tfilter(s_tc, tfilter);
    nm_tc_tfilter_unref(tfilter);

    _nm_connection_new_setting(connection, NM_TYPE_SETTING_PROXY);

    nmtst_assert_connection_verifies_without_normalization(connection);

    _writer_new_connec_exp(connection,
                           TEST_SCRATCH_DIR,
                           TEST_IFCFG_DIR "/ifcfg-test-tc-write.cexpected",
                           &testfile);

    reread = _connection_from_file(testfile, NULL, TYPE_BOND, NULL);

    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
}

/*****************************************************************************/

static void
test_well_known_keys(void)
{
    gsize i;

    for (i = 0; i < G_N_ELEMENTS(nms_ifcfg_well_known_keys); i++) {
        const NMSIfcfgKeyTypeInfo *ti = &nms_ifcfg_well_known_keys[i];

        g_assert(ti->key_name);
        g_assert(ti->key_name[0]);
        g_assert(NM_FLAGS_HAS(ti->key_flags, NMS_IFCFG_KEY_TYPE_WELL_KNOWN));
        g_assert(
            nm_utils_is_power_of_two(ti->key_flags
                                     & (NMS_IFCFG_KEY_TYPE_IS_PLAIN | NMS_IFCFG_KEY_TYPE_IS_NUMBERED
                                        | NMS_IFCFG_KEY_TYPE_IS_PREFIX)));
    }

    for (i = 1; i < G_N_ELEMENTS(nms_ifcfg_well_known_keys); i++) {
        const NMSIfcfgKeyTypeInfo *ti_prev = &nms_ifcfg_well_known_keys[i - 1];
        const NMSIfcfgKeyTypeInfo *ti      = &nms_ifcfg_well_known_keys[i];

        g_assert_cmpstr(ti_prev->key_name, <, ti->key_name);
    }

    for (i = 0; i < G_N_ELEMENTS(nms_ifcfg_well_known_keys); i++) {
        const NMSIfcfgKeyTypeInfo *ti       = &nms_ifcfg_well_known_keys[i];
        gs_free char              *key_name = NULL;
        gssize                     idx;

        g_assert(ti == nms_ifcfg_well_known_key_find_info(ti->key_name, &idx));
        g_assert_cmpint(i, ==, idx);

        key_name = g_strdup(ti->key_name);
        g_assert(ti == nms_ifcfg_well_known_key_find_info(key_name, &idx));
        g_assert_cmpint(i, ==, idx);
    }

#define _test_well_known(key, expected)                        \
    G_STMT_START                                               \
    {                                                          \
        const NMSIfcfgKeyTypeInfo *_ti;                        \
        const char                *_expected = (expected);     \
                                                               \
        _ti = nms_ifcfg_rh_utils_is_well_known_key("" key ""); \
        if (!_expected) {                                      \
            g_assert(!_ti);                                    \
        } else {                                               \
            g_assert(_ti);                                     \
            g_assert_cmpstr(_ti->key_name, ==, _expected);     \
        }                                                      \
    }                                                          \
    G_STMT_END

#define _test_well_known_plain(key) _test_well_known("" key "", "" key "")

    _test_well_known_plain("ONBOOT");
    _test_well_known("NM_USER_", NULL);
    _test_well_known("NM_USER_x", "NM_USER_");
    _test_well_known("IPADDR", "IPADDR");
    _test_well_known("IPADDR1", "IPADDR");
    _test_well_known("IPADDRx", NULL);
}

/*****************************************************************************/

static void
_do_utils_has_route_file_new_syntax_size(gboolean    has_new_syntax,
                                         const char *content,
                                         gssize      content_len)
{
    nmtst_auto_unlinkfile char *testfile =
        g_strdup(TEST_SCRATCH_DIR "/utils-has-route-file-new-syntax-test.txt");
    gboolean val;

    nmtst_file_set_contents_size(testfile, content, content_len);

    val = utils_has_route_file_new_syntax(testfile);

    g_assert_cmpint(val, ==, has_new_syntax);
}
#define _do_utils_has_route_file_new_syntax(has_new_syntax, content) \
    _do_utils_has_route_file_new_syntax_size(has_new_syntax, (content), NM_STRLEN(content))

static void
test_utils_has_route_file_new_syntax(void)
{
    _do_utils_has_route_file_new_syntax(TRUE, "");
    _do_utils_has_route_file_new_syntax(FALSE, "\0");
    _do_utils_has_route_file_new_syntax(FALSE, "\n");
    _do_utils_has_route_file_new_syntax(FALSE, "ADDRESS=bogus");
    _do_utils_has_route_file_new_syntax(FALSE, "ADDRESS=bogus\0");
    _do_utils_has_route_file_new_syntax(TRUE, "ADDRESS1=b\0ogus\0");
    _do_utils_has_route_file_new_syntax(TRUE, "ADDRESS1=bogus\0");
    _do_utils_has_route_file_new_syntax(TRUE, "\n\n\tADDRESS1=bogus\0");
    _do_utils_has_route_file_new_syntax(FALSE, "\n\n\tADDRESS=bogus\n");
    _do_utils_has_route_file_new_syntax(TRUE, "\n\n\tADDRESS=bogus\n  ADDRESS000=\n");
    _do_utils_has_route_file_new_syntax(FALSE, "\n\n\tROUTE1=bogus\n  ADDRES=\n");
    _do_utils_has_route_file_new_syntax(FALSE, "\n\n\tADDRESS=bogus\n  ADDRESS\000000=\n");
}

/*****************************************************************************/

static void
test_ethtool_names(void)
{
    static const struct {
        NMEthtoolID ethtool_id;
        const char *kernel_name;
    } kernel_names[] = {
        {NM_ETHTOOL_ID_FEATURE_GRO, "rx-gro"},
        {NM_ETHTOOL_ID_FEATURE_GSO, "tx-generic-segmentation"},
        {NM_ETHTOOL_ID_FEATURE_LRO, "rx-lro"},
        {NM_ETHTOOL_ID_FEATURE_NTUPLE, "rx-ntuple-filter"},
        {NM_ETHTOOL_ID_FEATURE_RX, "rx-checksum"},
        {NM_ETHTOOL_ID_FEATURE_RXHASH, "rx-hashing"},
        {NM_ETHTOOL_ID_FEATURE_RXVLAN, "rx-vlan-hw-parse"},
        {NM_ETHTOOL_ID_FEATURE_TXVLAN, "tx-vlan-hw-insert"},
    };
    const struct {
        guint nm_ethtool_id_first;
        guint nm_ethtool_id_last;
    } s_idxs[] = {
        {_NM_ETHTOOL_ID_FEATURE_FIRST, _NM_ETHTOOL_ID_FEATURE_LAST},
        {_NM_ETHTOOL_ID_COALESCE_FIRST, _NM_ETHTOOL_ID_COALESCE_LAST},
        {_NM_ETHTOOL_ID_PAUSE_FIRST, _NM_ETHTOOL_ID_PAUSE_LAST},
        {_NM_ETHTOOL_ID_RING_FIRST, _NM_ETHTOOL_ID_RING_LAST},
    };
    const NMEthtoolData *data;
    NMEthtoolID          id;
    guint                i, k;

    for (k = 0; k < sizeof(s_idxs) / sizeof(*s_idxs); ++k) {
        for (id = s_idxs[k].nm_ethtool_id_first; id <= s_idxs[k].nm_ethtool_id_last; id++) {
            const char *ifcfg_rh_name;

            g_assert(id >= 0);
            g_assert(id < G_N_ELEMENTS(_nm_ethtool_ifcfg_names));
            ifcfg_rh_name = _nm_ethtool_ifcfg_names[id];
            g_assert(ifcfg_rh_name && ifcfg_rh_name[0]);

            for (i = s_idxs[k].nm_ethtool_id_first; i < s_idxs[k].nm_ethtool_id_last; i++) {
                if (i != id)
                    g_assert_cmpstr(ifcfg_rh_name, !=, _nm_ethtool_ifcfg_names[i]);
            }

            g_assert_cmpstr(nms_ifcfg_rh_utils_get_ethtool_name(id), ==, ifcfg_rh_name);

            data = nms_ifcfg_rh_utils_get_ethtool_by_name(ifcfg_rh_name, nm_ethtool_id_to_type(id));

            g_assert(data);
            g_assert(data->id == id);
        }
    }

    for (i = 0; i < G_N_ELEMENTS(kernel_names); i++) {
        const char *name = kernel_names[i].kernel_name;

        id = kernel_names[i].ethtool_id;

        data = nms_ifcfg_rh_utils_get_ethtool_by_name(name, nm_ethtool_id_to_type(id));

        g_assert(data);
        g_assert(data->id == id);
        g_assert_cmpstr(nms_ifcfg_rh_utils_get_ethtool_name(id), !=, name);
    }
}

/*****************************************************************************/

#define TPATH "/settings/plugins/ifcfg-rh/"

#define TEST_IFCFG_WIFI_OPEN_SSID_LONG_QUOTED \
    TEST_IFCFG_DIR "/ifcfg-test-wifi-open-ssid-long-quoted"
#define TEST_IFCFG_WIFI_OPEN_SSID_LONG_HEX TEST_IFCFG_DIR "/ifcfg-test-wifi-open-ssid-long-hex"

#define DEFAULT_HEX_PSK "7d308b11df1b4243b0f78e5f3fc68cdbb9a264ed0edf4c188edf329ff5b467f0"

NMTST_DEFINE();

int
main(int argc, char **argv)
{
    int errsv;

    nmtst_init_assert_logging(&argc, &argv, "INFO", "DEFAULT");

    if (g_mkdir_with_parents(TEST_SCRATCH_DIR_TMP, 0755) != 0) {
        errsv = errno;
        g_error("failure to create test directory \"%s\": %s",
                TEST_SCRATCH_DIR_TMP,
                nm_strerror_native(errsv));
    }

    g_test_add_func(TPATH "svUnescape", test_svUnescape);

    g_test_add_data_func(TPATH "write-unknown/1",
                         TEST_IFCFG_DIR "/ifcfg-test-write-unknown-1",
                         test_write_unknown);
    g_test_add_data_func(TPATH "write-unknown/2",
                         TEST_IFCFG_DIR "/ifcfg-test-write-unknown-2",
                         test_write_unknown);
    g_test_add_data_func(TPATH "write-unknown/3",
                         TEST_IFCFG_DIR "/ifcfg-test-write-unknown-3",
                         test_write_unknown);
    g_test_add_data_func(TPATH "write-unknown/4",
                         TEST_IFCFG_DIR "/ifcfg-test-write-unknown-4",
                         test_write_unknown);

    g_test_add_func(TPATH "vlan-trailing-spaces", test_read_vlan_trailing_spaces);

    g_test_add_func(TPATH "unmanaged", test_read_unmanaged);
    g_test_add_func(TPATH "unmanaged-unrecognized", test_read_unmanaged_unrecognized);
    g_test_add_func(TPATH "unrecognized", test_read_unrecognized);
    g_test_add_func(TPATH "basic", test_read_basic);
    g_test_add_func(TPATH "miscellaneous-variables", test_read_miscellaneous_variables);
    g_test_add_func(TPATH "variables-corner-cases", test_read_variables_corner_cases);
    g_test_add_data_func(TPATH "no-prefix/8",
                         GUINT_TO_POINTER(8),
                         test_read_wired_static_no_prefix);
    g_test_add_data_func(TPATH "no-prefix/16",
                         GUINT_TO_POINTER(16),
                         test_read_wired_static_no_prefix);
    g_test_add_data_func(TPATH "no-prefix/24",
                         GUINT_TO_POINTER(24),
                         test_read_wired_static_no_prefix);
    g_test_add_data_func(TPATH "static-ip6-only-gw/_NULL_",
                         NULL,
                         test_write_wired_static_ip6_only_gw);
    g_test_add_data_func(TPATH "static-ip6-only-gw/::", "::", test_write_wired_static_ip6_only_gw);
    g_test_add_data_func(TPATH "static-ip6-only-gw/2001:db8:8:4::2",
                         "2001:db8:8:4::2",
                         test_write_wired_static_ip6_only_gw);
    g_test_add_data_func(TPATH "static-ip6-only-gw/::ffff:255.255.255.255",
                         "::ffff:255.255.255.255",
                         test_write_wired_static_ip6_only_gw);
    g_test_add_func(TPATH "ip6/disabled", test_write_ip6_disabled);
    g_test_add_func(TPATH "read-dns-options", test_read_dns_options);
    g_test_add_func(TPATH "clear-controller", test_clear_controller);

    nmtst_add_test_func(TPATH "read-static",
                        test_read_wired_static,
                        TEST_IFCFG_DIR "/ifcfg-test-wired-static",
                        "System test-wired-static",
                        GINT_TO_POINTER(TRUE));
    nmtst_add_test_func(TPATH "read-static-bootproto",
                        test_read_wired_static,
                        TEST_IFCFG_DIR "/ifcfg-test-wired-static-bootproto",
                        "System test-wired-static-bootproto",
                        GINT_TO_POINTER(FALSE));

    g_test_add_func(TPATH "read-netmask-1", test_read_netmask_1);

    g_test_add_func(TPATH "read-dhcp", test_read_wired_dhcp);
    g_test_add_func(TPATH "read-dhcp-plus-ip", test_read_wired_dhcp_plus_ip);
    g_test_add_func(TPATH "read-shared-plus-ip", test_read_wired_shared_plus_ip);
    g_test_add_func(TPATH "read-write-link-local", test_read_write_link_local);
    g_test_add_func(TPATH "read-dhcp-send-hostname", test_read_write_wired_dhcp_send_hostname);
    g_test_add_func(TPATH "read-dhcpv6-hostname-fallback",
                    test_read_wired_dhcpv6_hostname_fallback);
    g_test_add_func(TPATH "read-global-gateway", test_read_wired_global_gateway);
    g_test_add_func(TPATH "read-global-gateway-ignore", test_read_wired_global_gateway_ignore);
    g_test_add_func(TPATH "read-obsolete-gateway-n", test_read_wired_obsolete_gateway_n);
    g_test_add_func(TPATH "read-never-default", test_read_wired_never_default);
    g_test_add_func(TPATH "read-defroute-no", test_read_wired_defroute_no);
    g_test_add_func(TPATH "read-defroute-no-gatewaydev-yes",
                    test_read_wired_defroute_no_gatewaydev_yes);
    g_test_add_func(TPATH "routes/read-static", test_read_wired_static_routes);
    g_test_add_func(TPATH "routes/read-static-legacy", test_read_wired_static_routes_legacy);

    nmtst_add_test_func(TPATH "wired/read/manual/1",
                        test_read_wired_ipv4_manual,
                        TEST_IFCFG_DIR "/ifcfg-test-wired-ipv4-manual-1",
                        "System test-wired-ipv4-manual-1");
    nmtst_add_test_func(TPATH "wired/read/manual/2",
                        test_read_wired_ipv4_manual,
                        TEST_IFCFG_DIR "/ifcfg-test-wired-ipv4-manual-2",
                        "System test-wired-ipv4-manual-2");
    nmtst_add_test_func(TPATH "wired/read/manual/3",
                        test_read_wired_ipv4_manual,
                        TEST_IFCFG_DIR "/ifcfg-test-wired-ipv4-manual-3",
                        "System test-wired-ipv4-manual-3");
    nmtst_add_test_func(TPATH "wired/read/manual/4",
                        test_read_wired_ipv4_manual,
                        TEST_IFCFG_DIR "/ifcfg-test-wired-ipv4-manual-4",
                        "System test-wired-ipv4-manual-4");

    g_test_add_func(TPATH "user/1", test_user_1);

    g_test_add_func(TPATH "wired/ipv6-manual", test_read_wired_ipv6_manual);

    nmtst_add_test_func(TPATH "wired-ipv6-only/0",
                        test_read_wired_ipv6_only,
                        TEST_IFCFG_DIR "/ifcfg-test-wired-ipv6-only",
                        "System test-wired-ipv6-only");
    nmtst_add_test_func(TPATH "wired-ipv6-only/1",
                        test_read_wired_ipv6_only,
                        TEST_IFCFG_DIR "/ifcfg-test-wired-ipv6-only-1",
                        "System test-wired-ipv6-only-1");

    g_test_add_func(TPATH "wired/dhcpv6-only", test_read_wired_dhcp6_only);
    g_test_add_func(TPATH "wired/autoip", test_read_wired_autoip);
    g_test_add_func(TPATH "wired/onboot/no", test_read_onboot_no);
    g_test_add_func(TPATH "wired/no-ip", test_read_noip);
    g_test_add_func(TPATH "802-1x/peap/mschapv2", test_read_wired_8021x_peap_mschapv2);

    nmtst_add_test_func(TPATH "test-wired-8021x-tls/agent",
                        test_read_wired_8021x_tls_secret_flags,
                        TEST_IFCFG_DIR "/ifcfg-test-wired-8021x-tls-agent",
                        GINT_TO_POINTER(NM_SETTING_SECRET_FLAG_AGENT_OWNED));
    nmtst_add_test_func(
        TPATH "test-wired-8021x-tls/always",
        test_read_wired_8021x_tls_secret_flags,
        TEST_IFCFG_DIR "/ifcfg-test-wired-8021x-tls-always",
        GINT_TO_POINTER(NM_SETTING_SECRET_FLAG_AGENT_OWNED | NM_SETTING_SECRET_FLAG_NOT_SAVED));

    g_test_add_func(TPATH "802-1x/subj-matches", test_read_write_802_1X_subj_matches);
    g_test_add_func(TPATH "802-1x/ttls-eapgtc", test_read_802_1x_ttls_eapgtc);
    g_test_add_func(TPATH "802-1x/password_raw", test_read_write_802_1x_password_raw);
    g_test_add_func(TPATH "802-1x/tls-p12-no-client-cert", test_read_802_1x_tls_p12_no_client_cert);

    g_test_add_func(TPATH "wired/roundtrip/ethtool", test_roundtrip_ethtool);

    g_test_add_data_func(TPATH "wired/read/aliases/good/0",
                         GINT_TO_POINTER(0),
                         test_read_wired_aliases_good);
    g_test_add_data_func(TPATH "wired/read/aliases/good/3",
                         GINT_TO_POINTER(3),
                         test_read_wired_aliases_good);
    g_test_add_func(TPATH "wired/read/aliases/bad1", test_read_wired_aliases_bad_1);
    g_test_add_func(TPATH "wired/read/aliases/bad2", test_read_wired_aliases_bad_2);
    g_test_add_func(TPATH "wifi/read/open", test_read_wifi_open);
    g_test_add_func(TPATH "wifi/read/open/auto", test_read_wifi_open_auto);
    g_test_add_func(TPATH "wifi/read/open/hex-ssid", test_read_wifi_open_ssid_hex);
    g_test_add_func(TPATH "wifi/read/open-ssid/bad-hex", test_read_wifi_open_ssid_hex_bad);
    g_test_add_data_func(TPATH "wifi/read/open-ssid/long-hex",
                         TEST_IFCFG_WIFI_OPEN_SSID_LONG_HEX,
                         test_read_wifi_open_ssid_bad);
    g_test_add_data_func(TPATH "wifi/read/open-ssid/long-quoted",
                         TEST_IFCFG_WIFI_OPEN_SSID_LONG_QUOTED,
                         test_read_wifi_open_ssid_bad);
    g_test_add_func(TPATH "wifi/read/open/quoted-ssid", test_read_wifi_open_ssid_quoted);
    g_test_add_func(TPATH "wifi/read/wep", test_read_wifi_wep);
    g_test_add_func(TPATH "wifi/read/wep/adhoc", test_read_wifi_wep_adhoc);
    g_test_add_func(TPATH "wifi/read/wep/passphrase", test_read_wifi_wep_passphrase);
    g_test_add_func(TPATH "wifi/read/wep/40-ascii", test_read_wifi_wep_40_ascii);
    g_test_add_func(TPATH "wifi/read/wep/104-ascii", test_read_wifi_wep_104_ascii);
    g_test_add_func(TPATH "wifi/read/leap", test_read_wifi_leap);

    nmtst_add_test_func(TPATH "wifi-leap-secret-flags/agent",
                        test_read_wifi_leap_secret_flags,
                        TEST_IFCFG_DIR "/ifcfg-test-wifi-leap-agent",
                        GINT_TO_POINTER(NM_SETTING_SECRET_FLAG_AGENT_OWNED));
    nmtst_add_test_func(
        TPATH "wifi-leap-secret-flags/ask",
        test_read_wifi_leap_secret_flags,
        TEST_IFCFG_DIR "/ifcfg-test-wifi-leap-always-ask",
        GINT_TO_POINTER(NM_SETTING_SECRET_FLAG_AGENT_OWNED | NM_SETTING_SECRET_FLAG_NOT_SAVED));

    g_test_add_func(TPATH "wifi/read/wpa-psk", test_read_wifi_wpa_psk);
    g_test_add_func(TPATH "wifi/read/wpa-psk/2", test_read_wifi_wpa_psk_2);
    g_test_add_func(TPATH "wifi/read/wpa-psk/unquoted", test_read_wifi_wpa_psk_unquoted);
    g_test_add_func(TPATH "wifi/read/wpa-psk/unquoted2", test_read_wifi_wpa_psk_unquoted2);
    g_test_add_func(TPATH "wifi/read/wpa-psk/adhoc", test_read_wifi_wpa_psk_adhoc);
    g_test_add_func(TPATH "wifi/read/wpa-psk/hex", test_read_wifi_wpa_psk_hex);
    g_test_add_func(TPATH "wifi/read/sae", test_read_wifi_sae);
    g_test_add_func(TPATH "wifi/read/owe", test_read_wifi_owe);
    g_test_add_func(TPATH "wifi/read/dynamic-wep/leap", test_read_wifi_dynamic_wep_leap);
    g_test_add_func(TPATH "wifi/read/wpa/eap/tls", test_read_wifi_wpa_eap_tls);
    g_test_add_func(TPATH "wifi/read/wpa/eap/ttls/tls", test_read_wifi_wpa_eap_ttls_tls);
    g_test_add_func(TPATH "wifi/read/wpa/eap-suite-b-192/tls",
                    test_read_wifi_wpa_eap_suite_b_192_tls);
    g_test_add_func(TPATH "wifi/read/dynamic-wep/eap/ttls/chap", test_read_wifi_wep_eap_ttls_chap);
    g_test_add_func(TPATH "wifi/read-band-a", test_read_wifi_band_a);
    g_test_add_func(TPATH "wifi/read-band-a-channel-mismatch",
                    test_read_wifi_band_a_channel_mismatch);
    g_test_add_func(TPATH "wifi/read-band-bg-channel-mismatch",
                    test_read_wifi_band_bg_channel_mismatch);
    g_test_add_func(TPATH "wifi/read-hidden", test_read_wifi_hidden);

    nmtst_add_test_func(TPATH "wifi/read-mac-random-always",
                        test_read_wifi_mac_random,
                        "always",
                        GINT_TO_POINTER(NM_SETTING_MAC_RANDOMIZATION_ALWAYS));
    nmtst_add_test_func(TPATH "wifi/read-mac-random-never",
                        test_read_wifi_mac_random,
                        "never",
                        GINT_TO_POINTER(NM_SETTING_MAC_RANDOMIZATION_NEVER));
    nmtst_add_test_func(TPATH "wifi/read-mac-random-default",
                        test_read_wifi_mac_random,
                        "default",
                        GINT_TO_POINTER(NM_SETTING_MAC_RANDOMIZATION_DEFAULT));
    nmtst_add_test_func(TPATH "wifi/read-mac-random-missing",
                        test_read_wifi_mac_random,
                        "missing",
                        GINT_TO_POINTER(NM_SETTING_MAC_RANDOMIZATION_DEFAULT));

    nmtst_add_test_func(TPATH "wifi/write-mac-random-always",
                        test_write_wifi_mac_random,
                        "always",
                        GINT_TO_POINTER(NM_SETTING_MAC_RANDOMIZATION_ALWAYS),
                        "always");
    nmtst_add_test_func(TPATH "wifi/write-mac-random-never",
                        test_write_wifi_mac_random,
                        "never",
                        GINT_TO_POINTER(NM_SETTING_MAC_RANDOMIZATION_NEVER),
                        "never");
    nmtst_add_test_func(TPATH "wifi/write-mac-random-default",
                        test_write_wifi_mac_random,
                        "default",
                        GINT_TO_POINTER(NM_SETTING_MAC_RANDOMIZATION_DEFAULT),
                        "default");
    nmtst_add_test_func(TPATH "wifi/write-mac-random-missing",
                        test_write_wifi_mac_random,
                        "missing",
                        GINT_TO_POINTER(NM_SETTING_MAC_RANDOMIZATION_NEVER),
                        "never");

    g_test_add_func(TPATH "wifi/read/wep-no-keys", test_read_wifi_wep_no_keys);
    g_test_add_func(TPATH "wifi/read/wep-agent-keys", test_read_wifi_wep_agent_keys);
    g_test_add_data_func(TPATH "infiniband/read/0", GUINT_TO_POINTER(0), test_read_infiniband);
    g_test_add_data_func(TPATH "infiniband/read/1", GUINT_TO_POINTER(1), test_read_infiniband);
    g_test_add_data_func(TPATH "infiniband/read/2", GUINT_TO_POINTER(2), test_read_infiniband);
    g_test_add_func(TPATH "ipoib/read", test_read_ipoib);
    g_test_add_func(TPATH "vlan/read", test_read_vlan_interface);
    g_test_add_func(TPATH "vlan/read-flags-1", test_read_vlan_flags_1);
    g_test_add_func(TPATH "vlan/read-flags-2", test_read_vlan_flags_2);
    g_test_add_func(TPATH "vlan/read/only-vlanid", test_read_vlan_only_vlan_id);
    g_test_add_func(TPATH "vlan/read/only-device", test_read_vlan_only_device);
    g_test_add_func(TPATH "vlan/read/physdev", test_read_vlan_physdev);
    g_test_add_func(TPATH "vlan/read/reorder-hdr-1", test_read_vlan_reorder_hdr_1);
    g_test_add_func(TPATH "vlan/read/reorder-hdr-2", test_read_vlan_reorder_hdr_2);
    g_test_add_func(TPATH "vlan/read/vlanid-use", test_read_vlan_vlanid_use);
    g_test_add_func(TPATH "wired/read/read-wake-on-lan", test_read_wired_wake_on_lan);
    g_test_add_func(TPATH "wired/read/read-auto-negotiate-off", test_read_wired_auto_negotiate_off);
    g_test_add_func(TPATH "wired/read/read-auto-negotiate-on", test_read_wired_auto_negotiate_on);
    g_test_add_func(TPATH "wired/read/unkwnown-ethtool-opt", test_read_wired_unknown_ethtool_opt);

    g_test_add_func(TPATH "wired/write/static", test_write_wired_static);
    g_test_add_func(TPATH "wired/write/static-with-generic", test_write_wired_static_with_generic);
    g_test_add_func(TPATH "wired/write/static-ip6-only", test_write_wired_static_ip6_only);
    g_test_add_func(TPATH "wired/write-static-routes", test_write_wired_static_routes);
    g_test_add_func(TPATH "wired/read-write-static-routes-legacy",
                    test_read_write_static_routes_legacy);
    g_test_add_func(TPATH "wired/write/dhcp", test_write_wired_dhcp);
    g_test_add_func(TPATH "wired/write-dhcp-plus-ip", test_write_wired_dhcp_plus_ip);
    g_test_add_func(TPATH "wired/write/dhcp-8021x-peap-mschapv2",
                    test_write_wired_dhcp_8021x_peap_mschapv2);
    g_test_add_func(TPATH "wired/write/match", test_write_wired_match);
    g_test_add_func(TPATH "wired/write/routing-rules", test_write_routing_rules);

#define _add_test_write_wired_8021x_tls(testpath, scheme, flags) \
    nmtst_add_test_func(testpath,                                \
                        test_write_wired_8021x_tls,              \
                        GINT_TO_POINTER(scheme),                 \
                        GINT_TO_POINTER(flags))
    _add_test_write_wired_8021x_tls(TPATH "wired-8021x-tls/1",
                                    NM_SETTING_802_1X_CK_SCHEME_PATH,
                                    NM_SETTING_SECRET_FLAG_AGENT_OWNED);
    _add_test_write_wired_8021x_tls(TPATH "wired-8021x-tls/2",
                                    NM_SETTING_802_1X_CK_SCHEME_PATH,
                                    NM_SETTING_SECRET_FLAG_NOT_SAVED);
    _add_test_write_wired_8021x_tls(TPATH "wired-8021x-tls/3",
                                    NM_SETTING_802_1X_CK_SCHEME_PATH,
                                    NM_SETTING_SECRET_FLAG_AGENT_OWNED
                                        | NM_SETTING_SECRET_FLAG_NOT_SAVED);
    _add_test_write_wired_8021x_tls(TPATH "wired-8021x-tls/4",
                                    NM_SETTING_802_1X_CK_SCHEME_BLOB,
                                    NM_SETTING_SECRET_FLAG_NONE);

    g_test_add_func(TPATH "wired/write-aliases", test_write_wired_aliases);
    g_test_add_func(TPATH "ipv4/write-static-addresses-GATEWAY", test_write_gateway);
    g_test_add_func(TPATH "wired/write-wake-on-lan", test_write_wired_wake_on_lan);
    g_test_add_func(TPATH "wired/write-auto-negotiate-off", test_write_wired_auto_negotiate_off);
    g_test_add_func(TPATH "wired/write-auto-negotiate-on", test_write_wired_auto_negotiate_on);
    g_test_add_func(TPATH "wifi/write/open", test_write_wifi_open);
    g_test_add_func(TPATH "wifi/write/open/hex-ssid", test_write_wifi_open_hex_ssid);
    g_test_add_func(TPATH "wifi/write/wep", test_write_wifi_wep);
    g_test_add_func(TPATH "wifi/write/wep/adhoc", test_write_wifi_wep_adhoc);
    g_test_add_func(TPATH "wifi/write/wep/passphrase", test_write_wifi_wep_passphrase);
    g_test_add_func(TPATH "wifi/write/wep/40-ascii", test_write_wifi_wep_40_ascii);
    g_test_add_func(TPATH "wifi/write/wep/104-ascii", test_write_wifi_wep_104_ascii);
    g_test_add_func(TPATH "wifi/write/leap", test_write_wifi_leap);
    g_test_add_data_func(TPATH "wifi/write/leap/flags/agent",
                         GUINT_TO_POINTER(NM_SETTING_SECRET_FLAG_AGENT_OWNED),
                         test_write_wifi_leap_secret_flags);
    g_test_add_data_func(TPATH "wifi/write/leap/flags/not-saved",
                         GUINT_TO_POINTER(NM_SETTING_SECRET_FLAG_NOT_SAVED),
                         test_write_wifi_leap_secret_flags);
    g_test_add_data_func(
        TPATH "wifi/write/leap/flags/agent-and-not-saved",
        GUINT_TO_POINTER(NM_SETTING_SECRET_FLAG_AGENT_OWNED | NM_SETTING_SECRET_FLAG_NOT_SAVED),
        test_write_wifi_leap_secret_flags);

#define _add_test_write_wifi_wpa_psk(testpath, name, wep_group, wpa, wpa2, psk) \
    nmtst_add_test_func(testpath,                                               \
                        test_write_wifi_wpa_psk,                                \
                        name,                                                   \
                        GPOINTER_TO_INT(wep_group),                             \
                        GPOINTER_TO_INT(wpa),                                   \
                        GPOINTER_TO_INT(wpa2),                                  \
                        psk)
    _add_test_write_wifi_wpa_psk(TPATH "wifi-wpa-psk/wpa-psk-write",
                                 "Test Write Wifi WPA PSK",
                                 FALSE,
                                 TRUE,
                                 FALSE,
                                 DEFAULT_HEX_PSK);
    _add_test_write_wifi_wpa_psk(TPATH "wifi-wpa-psk/wpa2-psk-write",
                                 "Test Write Wifi WPA2 PSK",
                                 FALSE,
                                 FALSE,
                                 TRUE,
                                 DEFAULT_HEX_PSK);
    _add_test_write_wifi_wpa_psk(TPATH "wifi-wpa-psk/wpa-wpa2-psk-write",
                                 "Test Write Wifi WPA WPA2 PSK",
                                 FALSE,
                                 TRUE,
                                 TRUE,
                                 DEFAULT_HEX_PSK);
    _add_test_write_wifi_wpa_psk(TPATH "wifi-wpa-psk/wep-wpa-wpa2-psk-write",
                                 "Test Write Wifi WEP WPA WPA2 PSK",
                                 TRUE,
                                 TRUE,
                                 TRUE,
                                 DEFAULT_HEX_PSK);
    _add_test_write_wifi_wpa_psk(TPATH "wifi-wpa-psk/wpa-wpa2-psk-passphrase-write",
                                 "Test Write Wifi WPA WPA2 PSK Passphrase",
                                 FALSE,
                                 TRUE,
                                 TRUE,
                                 "really insecure passphrase04!");
    _add_test_write_wifi_wpa_psk(TPATH "wifi-wpa-psk/wpa-wpa2-psk-passphrase-write-spec-chars",
                                 "Test Write Wifi WPA WPA2 PSK Passphrase Special Chars",
                                 FALSE,
                                 TRUE,
                                 TRUE,
                                 "blah`oops\"grr'$*@~!%\\");

    g_test_add_func(TPATH "wifi/write/wpa/psk/adhoc", test_write_wifi_wpa_psk_adhoc);
    g_test_add_func(TPATH "wifi/write/wpa/eap/tls", test_write_wifi_wpa_eap_tls);
    g_test_add_func(TPATH "wifi/write/wpa/eap/ttls/tls", test_write_wifi_wpa_eap_ttls_tls);
    g_test_add_func(TPATH "wifi/write/wpa/eap/ttls/mschapv2",
                    test_write_wifi_wpa_eap_ttls_mschapv2);
    g_test_add_func(TPATH "wifi/write/dynamic-wep/leap", test_write_wifi_dynamic_wep_leap);
    g_test_add_func(TPATH "wifi/write-wpa-then-open", test_write_wifi_wpa_then_open);
    g_test_add_func(TPATH "wifi/write-wpa-then-wep-with-perms",
                    test_write_wifi_wpa_then_wep_with_perms);
    g_test_add_func(TPATH "wifi/write-hidden", test_write_wifi_hidden);
    g_test_add_func(TPATH "wifi/write-band-a", test_write_wifi_band_a);
    g_test_add_func(TPATH "wifi/write-ap-mode", test_write_wifi_ap_mode);

    g_test_add_func(TPATH "s390/read-qeth-static", test_read_wired_qeth_static);
    g_test_add_func(TPATH "s390/write-qeth-dhcp", test_write_wired_qeth_dhcp);
    g_test_add_func(TPATH "s390/read-ctc-static", test_read_wired_ctc_static);
    g_test_add_func(TPATH "s390/write-ctc-dhcp", test_write_wired_ctc_dhcp);

    g_test_add_func(TPATH "permissions/read", test_read_permissions);
    g_test_add_func(TPATH "permissions/write", test_write_permissions);
    g_test_add_func(TPATH "wifi/write-wep-agent-keys", test_write_wifi_wep_agent_keys);
    g_test_add_data_func(TPATH "infiniband/write/1", GINT_TO_POINTER(1), test_write_infiniband);
    g_test_add_data_func(TPATH "infiniband/write/2", GINT_TO_POINTER(2), test_write_infiniband);
    g_test_add_data_func(TPATH "infiniband/write/3", GINT_TO_POINTER(3), test_write_infiniband);
    g_test_add_data_func(TPATH "infiniband/write/4", GINT_TO_POINTER(4), test_write_infiniband);
    g_test_add_func(TPATH "vlan/write", test_write_vlan);
    g_test_add_func(TPATH "vlan/write-flags", test_write_vlan_flags);
    g_test_add_func(TPATH "vlan/write-only-vlanid", test_write_vlan_only_vlanid);
    g_test_add_func(TPATH "vlan/write-vlan-reorder-hdr", test_write_vlan_reorder_hdr);
    g_test_add_func(TPATH "wired/write-missing-ipv6", test_write_ethernet_missing_ipv6);
    g_test_add_func(TPATH "write-dns-options", test_write_dns_options);

    g_test_add_func(TPATH "ibft/ignored", test_read_ibft_ignored);

    g_test_add_func(TPATH "dcb/read-basic", test_read_dcb_basic);
    g_test_add_func(TPATH "dcb/write-basic", test_write_dcb_basic);
    g_test_add_func(TPATH "dcb/default-app-priorities", test_read_dcb_default_app_priorities);
    g_test_add_func(TPATH "dcb/bad-booleans", test_read_dcb_bad_booleans);
    g_test_add_func(TPATH "dcb/short-booleans", test_read_dcb_short_booleans);
    g_test_add_func(TPATH "dcb/bad-uints", test_read_dcb_bad_uints);
    g_test_add_func(TPATH "dcb/short-uints", test_read_dcb_short_uints);
    g_test_add_func(TPATH "dcb/bad-percent", test_read_dcb_bad_percent);
    g_test_add_func(TPATH "dcb/short-percent", test_read_dcb_short_percent);
    g_test_add_func(TPATH "dcb/pgpct-not-100", test_read_dcb_pgpct_not_100);
    g_test_add_data_func(TPATH "fcoe/fabric",
                         (gpointer) NM_SETTING_DCB_FCOE_MODE_FABRIC,
                         test_read_fcoe_mode);
    g_test_add_data_func(TPATH "fcoe/vn2vn",
                         (gpointer) NM_SETTING_DCB_FCOE_MODE_VN2VN,
                         test_read_fcoe_mode);
    g_test_add_data_func(TPATH "fcoe/write-fabric",
                         (gpointer) NM_SETTING_DCB_FCOE_MODE_FABRIC,
                         test_write_fcoe_mode);
    g_test_add_data_func(TPATH "fcoe/write-vn2vn",
                         (gpointer) NM_SETTING_DCB_FCOE_MODE_VN2VN,
                         test_write_fcoe_mode);

    g_test_add_func(TPATH "bond/read-controller", test_read_bond_main);
    g_test_add_func(TPATH "bond/read-controller-eth-type", test_read_bond_eth_type);
    g_test_add_func(TPATH "bond/read-port", test_read_bond_port);
    g_test_add_func(TPATH "bond/read-port-ib", test_read_bond_port_ib);
    g_test_add_func(TPATH "bond/write-controller", test_write_bond_main);
    g_test_add_func(TPATH "bond/write-port", test_write_bond_port);
    g_test_add_func(TPATH "bond/write-port-ib", test_write_bond_port_ib);
    g_test_add_func(TPATH "bond/bonding-opts-numeric-mode", test_read_bond_opts_mode_numeric);
    g_test_add_func(TPATH "bond/read-bond-port", test_read_bond_port_setting);
    g_test_add_func(TPATH "bond/write-bond-port_setting", test_write_bond_port_setting);

    g_test_add_func(TPATH "bridge/read-controller", test_read_bridge_main);
    g_test_add_func(TPATH "bridge/write-controller", test_write_bridge_main);
    g_test_add_func(TPATH "bridge/read-component", test_read_bridge_component);
    g_test_add_func(TPATH "bridge/write-component", test_write_bridge_component);
    g_test_add_func(TPATH "bridge/read-missing-stp", test_read_bridge_missing_stp);

    g_test_add_data_func(TPATH "team/read-controller-1",
                         TEST_IFCFG_DIR "/ifcfg-test-team-controller-1",
                         test_read_team_controller);
    g_test_add_data_func(TPATH "team/read-controller-2",
                         TEST_IFCFG_DIR "/ifcfg-test-team-controller-2",
                         test_read_team_controller);
    g_test_add_data_func(TPATH "team/read-controller-invalid",
                         TEST_IFCFG_DIR "/ifcfg-test-team-controller-invalid",
                         test_read_team_controller_invalid);
    g_test_add_func(TPATH "team/write-controller", test_write_team_controller);
    g_test_add_data_func(TPATH "team/read-port-1",
                         TEST_IFCFG_DIR "/ifcfg-test-team-port-1",
                         test_read_team_port);
    g_test_add_data_func(TPATH "team/read-port-2",
                         TEST_IFCFG_DIR "/ifcfg-test-team-port-2",
                         test_read_team_port);
    g_test_add_func(TPATH "team/write-port", test_write_team_port);
    g_test_add_func(TPATH "team/write-infiniband-port", test_write_team_infiniband_port);
    g_test_add_func(TPATH "team/read-port-empty-config", test_read_team_port_empty_config);
    g_test_add_func(TPATH "team/reread-port", test_team_reread_port);

    g_test_add_func(TPATH "proxy/read-proxy-basic", test_read_proxy_basic);
    g_test_add_func(TPATH "proxy/write-proxy-basic", test_write_proxy_basic);

    g_test_add_func(TPATH "sit/read/ignore", test_sit_read_ignore);

    /* Stuff we expect to fail for now */
    g_test_add_func(TPATH "pppoe/write-wired", test_write_wired_pppoe);
    g_test_add_func(TPATH "vpn/write", test_write_vpn);
    g_test_add_data_func(TPATH "wwan/write-gsm",
                         GUINT_TO_POINTER(TRUE),
                         test_write_mobile_broadband);
    g_test_add_data_func(TPATH "wwan/write-cdma",
                         GUINT_TO_POINTER(FALSE),
                         test_write_mobile_broadband);

    g_test_add_func(TPATH "no-trailing-newline", test_ifcfg_no_trailing_newline);

    g_test_add_func(TPATH "utils/name", test_utils_name);
    g_test_add_func(TPATH "utils/path", test_utils_path);
    g_test_add_func(TPATH "utils/ignore", test_utils_ignore);

    g_test_add_func(TPATH "sriov/read", test_sriov_read);
    g_test_add_func(TPATH "sriov/write", test_sriov_write);

    g_test_add_func(TPATH "tc/read", test_tc_read);
    g_test_add_func(TPATH "tc/write", test_tc_write);
    g_test_add_func(TPATH "tc/write_empty", test_tc_write_empty);
    g_test_add_func(TPATH "utils/test_well_known_keys", test_well_known_keys);
    g_test_add_func(TPATH "utils/test_utils_has_route_file_new_syntax",
                    test_utils_has_route_file_new_syntax);

    g_test_add_func(TPATH "utils/test_ethtool_names", test_ethtool_names);

    return g_test_run();
}
