mirror of
				https://git.proxmox.com/git/fwupd
				synced 2025-10-31 14:14:46 +00:00 
			
		
		
		
	 41957a4eaf
			
		
	
	
		41957a4eaf
		
	
	
	
	
		
			
			These add over 1000ms to the run time, and also do not work well when virtualized via qemu. Fixes https://github.com/fwupd/fwupd/issues/5547
		
			
				
	
	
		
			3892 lines
		
	
	
		
			130 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			3892 lines
		
	
	
		
			130 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
 | |
|  *
 | |
|  * SPDX-License-Identifier: LGPL-2.1+
 | |
|  */
 | |
| 
 | |
| #include "config.h"
 | |
| 
 | |
| #include <fwupdplugin.h>
 | |
| 
 | |
| #include <glib/gstdio.h>
 | |
| #include <libgcab.h>
 | |
| #include <string.h>
 | |
| 
 | |
| #include "fwupd-bios-setting-private.h"
 | |
| #include "fwupd-security-attr-private.h"
 | |
| 
 | |
| #include "fu-bios-settings-private.h"
 | |
| #include "fu-cabinet.h"
 | |
| #include "fu-common-private.h"
 | |
| #include "fu-context-private.h"
 | |
| #include "fu-coswid-firmware.h"
 | |
| #include "fu-device-private.h"
 | |
| #include "fu-device-progress.h"
 | |
| #include "fu-plugin-private.h"
 | |
| #include "fu-security-attrs-private.h"
 | |
| #include "fu-smbios-private.h"
 | |
| 
 | |
| static GMainLoop *_test_loop = NULL;
 | |
| static guint _test_loop_timeout_id = 0;
 | |
| 
 | |
| static gboolean
 | |
| fu_test_hang_check_cb(gpointer user_data)
 | |
| {
 | |
| 	g_main_loop_quit(_test_loop);
 | |
| 	_test_loop_timeout_id = 0;
 | |
| 	return G_SOURCE_REMOVE;
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_test_loop_run_with_timeout(guint timeout_ms)
 | |
| {
 | |
| 	g_assert_cmpint(_test_loop_timeout_id, ==, 0);
 | |
| 	g_assert_null(_test_loop);
 | |
| 	_test_loop = g_main_loop_new(NULL, FALSE);
 | |
| 	_test_loop_timeout_id = g_timeout_add(timeout_ms, fu_test_hang_check_cb, NULL);
 | |
| 	g_main_loop_run(_test_loop);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_test_loop_quit(void)
 | |
| {
 | |
| 	if (_test_loop_timeout_id > 0) {
 | |
| 		g_source_remove(_test_loop_timeout_id);
 | |
| 		_test_loop_timeout_id = 0;
 | |
| 	}
 | |
| 	if (_test_loop != NULL) {
 | |
| 		g_main_loop_quit(_test_loop);
 | |
| 		g_main_loop_unref(_test_loop);
 | |
| 		_test_loop = NULL;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_archive_invalid_func(void)
 | |
| {
 | |
| 	g_autofree gchar *filename = NULL;
 | |
| 	g_autoptr(FuArchive) archive = NULL;
 | |
| 	g_autoptr(GBytes) data = NULL;
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 
 | |
| #ifndef HAVE_LIBARCHIVE
 | |
| 	g_test_skip("no libarchive support");
 | |
| 	return;
 | |
| #endif
 | |
| 
 | |
| 	filename = g_test_build_filename(G_TEST_DIST, "tests", "metadata.xml", NULL);
 | |
| 	data = fu_bytes_get_contents(filename, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(data);
 | |
| 
 | |
| 	archive = fu_archive_new(data, FU_ARCHIVE_FLAG_NONE, &error);
 | |
| 	g_assert_error(error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
 | |
| 	g_assert_null(archive);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_archive_cab_func(void)
 | |
| {
 | |
| 	g_autofree gchar *checksum1 = NULL;
 | |
| 	g_autofree gchar *checksum2 = NULL;
 | |
| 	g_autofree gchar *filename = NULL;
 | |
| 	g_autoptr(FuArchive) archive = NULL;
 | |
| 	g_autoptr(GBytes) data = NULL;
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 	GBytes *data_tmp;
 | |
| 
 | |
| #ifndef HAVE_LIBARCHIVE
 | |
| 	g_test_skip("no libarchive support");
 | |
| 	return;
 | |
| #endif
 | |
| 
 | |
| 	filename = g_test_build_filename(G_TEST_BUILT,
 | |
| 					 "tests",
 | |
| 					 "colorhug",
 | |
| 					 "colorhug-als-3.0.2.cab",
 | |
| 					 NULL);
 | |
| 	data = fu_bytes_get_contents(filename, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(data);
 | |
| 
 | |
| 	archive = fu_archive_new(data, FU_ARCHIVE_FLAG_NONE, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(archive);
 | |
| 
 | |
| 	data_tmp = fu_archive_lookup_by_fn(archive, "firmware.metainfo.xml", &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(data_tmp);
 | |
| 	checksum1 = g_compute_checksum_for_bytes(G_CHECKSUM_SHA1, data_tmp);
 | |
| 	g_assert_cmpstr(checksum1, ==, "8611114f51f7151f190de86a5c9259d79ff34216");
 | |
| 
 | |
| 	data_tmp = fu_archive_lookup_by_fn(archive, "firmware.bin", &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(data_tmp);
 | |
| 	checksum2 = g_compute_checksum_for_bytes(G_CHECKSUM_SHA1, data_tmp);
 | |
| 	g_assert_cmpstr(checksum2, ==, "7c0ae84b191822bcadbdcbe2f74a011695d783c7");
 | |
| 
 | |
| 	data_tmp = fu_archive_lookup_by_fn(archive, "NOTGOINGTOEXIST.xml", &error);
 | |
| 	g_assert_error(error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
 | |
| 	g_assert_null(data_tmp);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_volume_gpt_type_func(void)
 | |
| {
 | |
| 	g_assert_cmpstr(fu_volume_kind_convert_to_gpt("0xef"),
 | |
| 			==,
 | |
| 			"c12a7328-f81f-11d2-ba4b-00a0c93ec93b");
 | |
| 	g_assert_cmpstr(fu_volume_kind_convert_to_gpt("0x0b"),
 | |
| 			==,
 | |
| 			"ebd0a0a2-b9e5-4433-87c0-68b6b72699c7");
 | |
| 	g_assert_cmpstr(fu_volume_kind_convert_to_gpt("fat32lba"),
 | |
| 			==,
 | |
| 			"ebd0a0a2-b9e5-4433-87c0-68b6b72699c7");
 | |
| 	g_assert_cmpstr(fu_volume_kind_convert_to_gpt("0x00"), ==, "0x00");
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_common_align_up_func(void)
 | |
| {
 | |
| 	g_assert_cmpint(fu_common_align_up(0, 0), ==, 0);
 | |
| 	g_assert_cmpint(fu_common_align_up(5, 0), ==, 5);
 | |
| 	g_assert_cmpint(fu_common_align_up(5, 3), ==, 8);
 | |
| 	g_assert_cmpint(fu_common_align_up(1023, 10), ==, 1024);
 | |
| 	g_assert_cmpint(fu_common_align_up(1024, 10), ==, 1024);
 | |
| 	g_assert_cmpint(fu_common_align_up(G_MAXSIZE - 1, 10), ==, G_MAXSIZE);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_common_byte_array_func(void)
 | |
| {
 | |
| 	g_autofree gchar *str = NULL;
 | |
| 	g_autoptr(GByteArray) array = g_byte_array_new();
 | |
| 
 | |
| 	fu_byte_array_append_uint8(array, (guint8)'h');
 | |
| 	fu_byte_array_append_uint8(array, (guint8)'e');
 | |
| 	fu_byte_array_append_uint8(array, (guint8)'l');
 | |
| 	fu_byte_array_append_uint8(array, (guint8)'l');
 | |
| 	fu_byte_array_append_uint8(array, (guint8)'o');
 | |
| 	g_assert_cmpint(array->len, ==, 5);
 | |
| 	g_assert_cmpint(memcmp(array->data, "hello", array->len), ==, 0);
 | |
| 
 | |
| 	fu_byte_array_set_size(array, 10, 0x00);
 | |
| 	g_assert_cmpint(array->len, ==, 10);
 | |
| 	g_assert_cmpint(memcmp(array->data, "hello\0\0\0\0\0", array->len), ==, 0);
 | |
| 
 | |
| 	str = fu_byte_array_to_string(array);
 | |
| 	g_assert_cmpstr(str, ==, "68656c6c6f0000000000");
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_common_crc_func(void)
 | |
| {
 | |
| 	guint8 buf[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09};
 | |
| 	g_assert_cmpint(fu_crc8(buf, sizeof(buf)), ==, 0x7A);
 | |
| 	g_assert_cmpint(fu_crc16(buf, sizeof(buf)), ==, 0x4DF1);
 | |
| 	g_assert_cmpint(fu_crc32(buf, sizeof(buf)), ==, 0x40EFAB9E);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_string_append_func(void)
 | |
| {
 | |
| 	g_autoptr(GString) str = g_string_new(NULL);
 | |
| 	fu_string_append(str, 0, "hdr", NULL);
 | |
| 	fu_string_append(str, 0, "key", "value");
 | |
| 	fu_string_append(str, 0, "key1", "value1");
 | |
| 	fu_string_append(str, 1, "key2", "value2");
 | |
| 	fu_string_append(str, 1, "", "value2");
 | |
| 	fu_string_append(str, 2, "key3", "value3");
 | |
| 	g_assert_cmpstr(str->str,
 | |
| 			==,
 | |
| 			"hdr:\n"
 | |
| 			"key:                    value\n"
 | |
| 			"key1:                   value1\n"
 | |
| 			"  key2:                 value2\n"
 | |
| 			"                        value2\n"
 | |
| 			"    key3:               value3\n");
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_version_guess_format_func(void)
 | |
| {
 | |
| 	g_assert_cmpint(fu_version_guess_format(NULL), ==, FWUPD_VERSION_FORMAT_UNKNOWN);
 | |
| 	g_assert_cmpint(fu_version_guess_format(""), ==, FWUPD_VERSION_FORMAT_UNKNOWN);
 | |
| 	g_assert_cmpint(fu_version_guess_format("1234ac"), ==, FWUPD_VERSION_FORMAT_PLAIN);
 | |
| 	g_assert_cmpint(fu_version_guess_format("1.2"), ==, FWUPD_VERSION_FORMAT_PAIR);
 | |
| 	g_assert_cmpint(fu_version_guess_format("1.2.3"), ==, FWUPD_VERSION_FORMAT_TRIPLET);
 | |
| 	g_assert_cmpint(fu_version_guess_format("1.2.3.4"), ==, FWUPD_VERSION_FORMAT_QUAD);
 | |
| 	g_assert_cmpint(fu_version_guess_format("1.2.3.4.5"), ==, FWUPD_VERSION_FORMAT_UNKNOWN);
 | |
| 	g_assert_cmpint(fu_version_guess_format("1a.2b.3"), ==, FWUPD_VERSION_FORMAT_PLAIN);
 | |
| 	g_assert_cmpint(fu_version_guess_format("1"), ==, FWUPD_VERSION_FORMAT_NUMBER);
 | |
| 	g_assert_cmpint(fu_version_guess_format("0x10201"), ==, FWUPD_VERSION_FORMAT_NUMBER);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_device_version_format_func(void)
 | |
| {
 | |
| 	g_autoptr(FuDevice) device = fu_device_new(NULL);
 | |
| 	fu_device_add_internal_flag(device, FU_DEVICE_INTERNAL_FLAG_ENSURE_SEMVER);
 | |
| 	fu_device_set_version_format(device, FWUPD_VERSION_FORMAT_TRIPLET);
 | |
| 	fu_device_set_version(device, "Ver1.2.3 RELEASE");
 | |
| 	g_assert_cmpstr(fu_device_get_version(device), ==, "1.2.3");
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_device_open_refcount_func(void)
 | |
| {
 | |
| 	gboolean ret;
 | |
| 	g_autoptr(FuDevice) device = fu_device_new(NULL);
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 	fu_device_set_id(device, "test_device");
 | |
| 	ret = fu_device_open(device, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	ret = fu_device_open(device, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	ret = fu_device_close(device, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	ret = fu_device_close(device, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	ret = fu_device_close(device, &error);
 | |
| 	g_assert_error(error, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO);
 | |
| 	g_assert_false(ret);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_device_name_func(void)
 | |
| {
 | |
| 	g_autoptr(FuDevice) device1 = fu_device_new(NULL);
 | |
| 	g_autoptr(FuDevice) device2 = fu_device_new(NULL);
 | |
| 
 | |
| 	/* vendor then name */
 | |
| 	fu_device_set_vendor(device1, "  Hughski  ");
 | |
| 	fu_device_set_name(device1, "HUGHSKI  ColorHug(TM)__Pro  ");
 | |
| 	g_assert_cmpstr(fu_device_get_vendor(device1), ==, "Hughski");
 | |
| 	g_assert_cmpstr(fu_device_get_name(device1), ==, "ColorHug™ Pro");
 | |
| 
 | |
| 	/* name then vendor */
 | |
| 	fu_device_set_name(device2, "Hughski ColorHug(TM)_Pro");
 | |
| 	fu_device_set_vendor(device2, "Hughski");
 | |
| 	g_assert_cmpstr(fu_device_get_vendor(device2), ==, "Hughski");
 | |
| 	g_assert_cmpstr(fu_device_get_name(device2), ==, "ColorHug™ Pro");
 | |
| 
 | |
| 	/* a real example */
 | |
| 	fu_device_set_name(device2, "Intel(R) Core(TM) i7-10850H CPU @ 2.70GHz");
 | |
| 	fu_device_set_vendor(device2, "Intel");
 | |
| 	g_assert_cmpstr(fu_device_get_name(device2), ==, "Core™ i7-10850H CPU @ 2.70GHz");
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_device_cfi_device_func(void)
 | |
| {
 | |
| 	gboolean ret;
 | |
| 	guint8 cmd = 0;
 | |
| 	g_autoptr(FuContext) ctx = fu_context_new();
 | |
| 	g_autoptr(FuCfiDevice) cfi_device = NULL;
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 
 | |
| 	ret = fu_context_load_quirks(ctx, FU_QUIRKS_LOAD_FLAG_NO_CACHE, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 
 | |
| 	cfi_device = fu_cfi_device_new(ctx, "3730");
 | |
| 	ret = fu_device_setup(FU_DEVICE(cfi_device), &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 
 | |
| 	/* fallback */
 | |
| 	ret = fu_cfi_device_get_cmd(cfi_device, FU_CFI_DEVICE_CMD_READ_DATA, &cmd, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	g_assert_cmpint(cmd, ==, 0x03);
 | |
| 
 | |
| 	/* from quirk */
 | |
| 	ret = fu_cfi_device_get_cmd(cfi_device, FU_CFI_DEVICE_CMD_CHIP_ERASE, &cmd, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	g_assert_cmpint(cmd, ==, 0xC7);
 | |
| 	g_assert_cmpint(fu_cfi_device_get_size(cfi_device), ==, 0x10000);
 | |
| 	g_assert_cmpint(fu_cfi_device_get_page_size(cfi_device), ==, 0x200);
 | |
| 	g_assert_cmpint(fu_cfi_device_get_sector_size(cfi_device), ==, 0x2000);
 | |
| 	g_assert_cmpint(fu_cfi_device_get_block_size(cfi_device), ==, 0x8000);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_device_metadata_func(void)
 | |
| {
 | |
| 	g_autoptr(FuDevice) device = fu_device_new(NULL);
 | |
| 
 | |
| 	/* string */
 | |
| 	fu_device_set_metadata(device, "foo", "bar");
 | |
| 	g_assert_cmpstr(fu_device_get_metadata(device, "foo"), ==, "bar");
 | |
| 	fu_device_set_metadata(device, "foo", "baz");
 | |
| 	g_assert_cmpstr(fu_device_get_metadata(device, "foo"), ==, "baz");
 | |
| 	g_assert_null(fu_device_get_metadata(device, "unknown"));
 | |
| 
 | |
| 	/* boolean */
 | |
| 	fu_device_set_metadata_boolean(device, "baz", TRUE);
 | |
| 	g_assert_cmpstr(fu_device_get_metadata(device, "baz"), ==, "true");
 | |
| 	g_assert_true(fu_device_get_metadata_boolean(device, "baz"));
 | |
| 	g_assert_false(fu_device_get_metadata_boolean(device, "unknown"));
 | |
| 
 | |
| 	/* integer */
 | |
| 	fu_device_set_metadata_integer(device, "bam", 12345);
 | |
| 	g_assert_cmpstr(fu_device_get_metadata(device, "bam"), ==, "12345");
 | |
| 	g_assert_cmpint(fu_device_get_metadata_integer(device, "bam"), ==, 12345);
 | |
| 	g_assert_cmpint(fu_device_get_metadata_integer(device, "unknown"), ==, G_MAXUINT);
 | |
| 
 | |
| 	/* broken integer */
 | |
| 	fu_device_set_metadata(device, "bam", "123junk");
 | |
| 	g_assert_cmpint(fu_device_get_metadata_integer(device, "bam"), ==, G_MAXUINT);
 | |
| 	fu_device_set_metadata(device, "huge", "4294967296"); /* not 32 bit */
 | |
| 	g_assert_cmpint(fu_device_get_metadata_integer(device, "huge"), ==, G_MAXUINT);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_smbios_func(void)
 | |
| {
 | |
| 	const gchar *str;
 | |
| 	gboolean ret;
 | |
| 	g_autofree gchar *dump = NULL;
 | |
| 	g_autofree gchar *testdatadir = NULL;
 | |
| 	g_autoptr(FuSmbios) smbios = NULL;
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 
 | |
| #ifdef _WIN32
 | |
| 	g_test_skip("Windows uses GetSystemFirmwareTable rather than parsing the fake test data");
 | |
| 	return;
 | |
| #endif
 | |
| 
 | |
| 	/* these tests will not write */
 | |
| 	testdatadir = g_test_build_filename(G_TEST_DIST, "tests", NULL);
 | |
| 	(void)g_setenv("FWUPD_SYSFSFWDIR", testdatadir, TRUE);
 | |
| 
 | |
| 	smbios = fu_smbios_new();
 | |
| 	ret = fu_smbios_setup(smbios, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	dump = fu_firmware_to_string(FU_FIRMWARE(smbios));
 | |
| 	if (g_getenv("FWUPD_VERBOSE") != NULL)
 | |
| 		g_debug("%s", dump);
 | |
| 
 | |
| 	/* test for missing table */
 | |
| 	str = fu_smbios_get_string(smbios, 0xff, 0, &error);
 | |
| 	g_assert_error(error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE);
 | |
| 	g_assert_null(str);
 | |
| 	g_clear_error(&error);
 | |
| 
 | |
| 	/* check for invalid offset */
 | |
| 	str = fu_smbios_get_string(smbios, FU_SMBIOS_STRUCTURE_TYPE_BIOS, 0xff, &error);
 | |
| 	g_assert_error(error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE);
 | |
| 	g_assert_null(str);
 | |
| 	g_clear_error(&error);
 | |
| 
 | |
| 	/* get vendor */
 | |
| 	str = fu_smbios_get_string(smbios, FU_SMBIOS_STRUCTURE_TYPE_BIOS, 0x04, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_cmpstr(str, ==, "LENOVO");
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_smbios3_func(void)
 | |
| {
 | |
| 	const gchar *str;
 | |
| 	gboolean ret;
 | |
| 	g_autofree gchar *path = NULL;
 | |
| 	g_autoptr(FuSmbios) smbios = NULL;
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 
 | |
| 	path = g_test_build_filename(G_TEST_DIST, "tests", "dmi", "tables64", NULL);
 | |
| 	smbios = fu_smbios_new();
 | |
| 	ret = fu_smbios_setup_from_path(smbios, path, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	if (g_getenv("FWUPD_VERBOSE") != NULL) {
 | |
| 		g_autofree gchar *dump = fu_firmware_to_string(FU_FIRMWARE(smbios));
 | |
| 		g_debug("%s", dump);
 | |
| 	}
 | |
| 
 | |
| 	/* get vendor */
 | |
| 	str = fu_smbios_get_string(smbios, FU_SMBIOS_STRUCTURE_TYPE_BIOS, 0x04, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_cmpstr(str, ==, "Dell Inc.");
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_context_flags_func(void)
 | |
| {
 | |
| 	g_autoptr(FuContext) ctx = fu_context_new();
 | |
| 
 | |
| 	g_assert_false(fu_context_has_flag(ctx, FU_CONTEXT_FLAG_SAVE_EVENTS));
 | |
| 	fu_context_add_flag(ctx, FU_CONTEXT_FLAG_SAVE_EVENTS);
 | |
| 	g_assert_true(fu_context_has_flag(ctx, FU_CONTEXT_FLAG_SAVE_EVENTS));
 | |
| 	fu_context_remove_flag(ctx, FU_CONTEXT_FLAG_SAVE_EVENTS);
 | |
| 	fu_context_remove_flag(ctx, FU_CONTEXT_FLAG_SAVE_EVENTS);
 | |
| 	g_assert_false(fu_context_has_flag(ctx, FU_CONTEXT_FLAG_SAVE_EVENTS));
 | |
| 	fu_context_add_flag(ctx, FU_CONTEXT_FLAG_SAVE_EVENTS);
 | |
| 	fu_context_add_flag(ctx, FU_CONTEXT_FLAG_SAVE_EVENTS);
 | |
| 	g_assert_true(fu_context_has_flag(ctx, FU_CONTEXT_FLAG_SAVE_EVENTS));
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_context_hwids_dmi_func(void)
 | |
| {
 | |
| 	g_autoptr(FuContext) ctx = fu_context_new();
 | |
| 	g_autoptr(FuProgress) progress = fu_progress_new(G_STRLOC);
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 	gboolean ret;
 | |
| 
 | |
| 	ret = fu_context_load_hwinfo(ctx, progress, FU_CONTEXT_HWID_FLAG_LOAD_DMI, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	if (g_getenv("FWUPD_VERBOSE") != NULL) {
 | |
| 		g_autofree gchar *dump =
 | |
| 		    fu_firmware_to_string(FU_FIRMWARE(fu_context_get_smbios(ctx)));
 | |
| 		g_debug("%s", dump);
 | |
| 	}
 | |
| 
 | |
| 	g_assert_cmpstr(fu_context_get_hwid_value(ctx, FU_HWIDS_KEY_MANUFACTURER), ==, "FwupdTest");
 | |
| 	g_assert_cmpuint(fu_context_get_chassis_kind(ctx), ==, 16);
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| _strnsplit_add_cb(GString *token, guint token_idx, gpointer user_data, GError **error)
 | |
| {
 | |
| 	GPtrArray *array = (GPtrArray *)user_data;
 | |
| 	g_debug("TOKEN: [%s] (%u)", token->str, token_idx);
 | |
| 	g_ptr_array_add(array, g_strdup(token->str));
 | |
| 	return TRUE;
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| _strnsplit_nop_cb(GString *token, guint token_idx, gpointer user_data, GError **error)
 | |
| {
 | |
| 	guint *cnt = (guint *)user_data;
 | |
| 	(*cnt)++;
 | |
| 	return TRUE;
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_common_memmem_func(void)
 | |
| {
 | |
| 	const guint8 haystack[] = {'H', 'A', 'Y', 'S'};
 | |
| 	const guint8 needle[] = {'A', 'Y'};
 | |
| 	gboolean ret;
 | |
| 	gsize offset = 0;
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 
 | |
| 	ret = fu_memmem_safe(haystack, sizeof(haystack), needle, sizeof(needle), &offset, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	g_assert_cmpint(offset, ==, 0x1);
 | |
| 
 | |
| 	ret = fu_memmem_safe(haystack + 2,
 | |
| 			     sizeof(haystack) - 2,
 | |
| 			     needle,
 | |
| 			     sizeof(needle),
 | |
| 			     &offset,
 | |
| 			     &error);
 | |
| 	g_assert_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND);
 | |
| 	g_assert_false(ret);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_strsplit_func(void)
 | |
| {
 | |
| 	const gchar *str = "123foo123bar123";
 | |
| 	const guint bigsz = 1024 * 1024;
 | |
| 	gboolean ret;
 | |
| 	guint cnt = 0;
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 	g_autoptr(GPtrArray) array = g_ptr_array_new_with_free_func(g_free);
 | |
| 	g_autoptr(GString) bigstr = g_string_sized_new(bigsz * 2);
 | |
| 
 | |
| 	/* works for me */
 | |
| 	ret = fu_strsplit_full(str, -1, "123", _strnsplit_add_cb, array, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	g_assert_cmpint(array->len, ==, 3);
 | |
| 	g_assert_cmpstr(g_ptr_array_index(array, 0), ==, "");
 | |
| 	g_assert_cmpstr(g_ptr_array_index(array, 1), ==, "foo");
 | |
| 	g_assert_cmpstr(g_ptr_array_index(array, 2), ==, "bar");
 | |
| 
 | |
| 	/* lets try something insane */
 | |
| 	for (guint i = 0; i < bigsz; i++)
 | |
| 		g_string_append(bigstr, "X\n");
 | |
| 	ret = fu_strsplit_full(bigstr->str, -1, "\n", _strnsplit_nop_cb, &cnt, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	g_assert_cmpint(cnt, ==, bigsz);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_strsafe_func(void)
 | |
| {
 | |
| 	struct {
 | |
| 		const gchar *in;
 | |
| 		const gchar *op;
 | |
| 	} strs[] = {{"dave123", "dave123"},
 | |
| 		    {"dave123XXX", "dave123"},
 | |
| 		    {"dave\x03XXX", "dave.XX"},
 | |
| 		    {"dave\x03\x04XXX", "dave..X"},
 | |
| 		    {"\x03\x03", NULL},
 | |
| 		    {NULL, NULL}};
 | |
| 	GPtrArray *instance_ids;
 | |
| 	gboolean ret;
 | |
| 	g_autoptr(FuContext) ctx = fu_context_new();
 | |
| 	g_autoptr(FuDevice) dev = fu_device_new(ctx);
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 
 | |
| 	/* check bespoke legacy instance ID behavior */
 | |
| 	fu_device_add_instance_strsafe(dev, "KEY", "_ _LEN&VO&\\&");
 | |
| 	ret = fu_device_build_instance_id(dev, &error, "SUB", "KEY", NULL);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	instance_ids = fu_device_get_instance_ids(dev);
 | |
| 	g_assert_cmpint(instance_ids->len, ==, 1);
 | |
| 	g_assert_cmpstr(g_ptr_array_index(instance_ids, 0), ==, "SUB\\KEY_LEN-VO");
 | |
| 
 | |
| 	for (guint i = 0; strs[i].in != NULL; i++) {
 | |
| 		g_autofree gchar *tmp = fu_strsafe(strs[i].in, 7);
 | |
| 		g_assert_cmpstr(tmp, ==, strs[i].op);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_hwids_func(void)
 | |
| {
 | |
| 	g_autofree gchar *testdatadir = NULL;
 | |
| 	g_autoptr(FuContext) context = NULL;
 | |
| 	g_autoptr(FuProgress) progress = fu_progress_new(G_STRLOC);
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 	gboolean ret;
 | |
| 
 | |
| 	struct {
 | |
| 		const gchar *key;
 | |
| 		const gchar *value;
 | |
| 	} guids[] = {{"Manufacturer", "6de5d951-d755-576b-bd09-c5cf66b27234"},
 | |
| 		     {"HardwareID-14", "6de5d951-d755-576b-bd09-c5cf66b27234"},
 | |
| 		     {"HardwareID-13", "f8e1de5f-b68c-5f52-9d1a-f1ba52f1f773"},
 | |
| 		     {"HardwareID-12", "e093d715-70f7-51f4-b6c8-b4a7e31def85"},
 | |
| 		     {"HardwareID-11", "db73af4c-4612-50f7-b8a7-787cf4871847"},
 | |
| 		     {"HardwareID-10", "f4275c1f-6130-5191-845c-3426247eb6a1"},
 | |
| 		     {"HardwareID-9", "0cf8618d-9eff-537c-9f35-46861406eb9c"},
 | |
| 		     {"HardwareID-8", "059eb22d-6dc7-59af-abd3-94bbe017f67c"},
 | |
| 		     {"HardwareID-7", "da1da9b6-62f5-5f22-8aaa-14db7eeda2a4"},
 | |
| 		     {"HardwareID-6", "178cd22d-ad9f-562d-ae0a-34009822cdbe"},
 | |
| 		     {"HardwareID-5", "8dc9b7c5-f5d5-5850-9ab3-bd6f0549d814"},
 | |
| 		     {"HardwareID-4", "660ccba8-1b78-5a33-80e6-9fb8354ee873"},
 | |
| 		     {"HardwareID-3", "3faec92a-3ae3-5744-be88-495e90a7d541"},
 | |
| 		     {"HardwareID-2", "f5ff077f-3eeb-5bae-be1c-e98ffe8ce5f8"},
 | |
| 		     {"HardwareID-1", "b7cceb67-774c-537e-bf8b-22c6107e9a74"},
 | |
| 		     {"HardwareID-0", "147efce9-f201-5fc8-ab0c-c859751c3440"},
 | |
| 		     {NULL, NULL}};
 | |
| 
 | |
| #ifdef _WIN32
 | |
| 	g_test_skip("Windows uses GetSystemFirmwareTable rather than parsing the fake test data");
 | |
| 	return;
 | |
| #endif
 | |
| 
 | |
| 	/* these tests will not write */
 | |
| 	testdatadir = g_test_build_filename(G_TEST_DIST, "tests", NULL);
 | |
| 	(void)g_setenv("FWUPD_SYSFSFWDIR", testdatadir, TRUE);
 | |
| 
 | |
| 	context = fu_context_new();
 | |
| 	ret = fu_context_load_hwinfo(context, progress, FU_CONTEXT_HWID_FLAG_LOAD_SMBIOS, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 
 | |
| 	g_assert_cmpstr(fu_context_get_hwid_value(context, FU_HWIDS_KEY_MANUFACTURER),
 | |
| 			==,
 | |
| 			"LENOVO");
 | |
| 	g_assert_cmpstr(fu_context_get_hwid_value(context, FU_HWIDS_KEY_ENCLOSURE_KIND), ==, "a");
 | |
| 	g_assert_cmpstr(fu_context_get_hwid_value(context, FU_HWIDS_KEY_FAMILY),
 | |
| 			==,
 | |
| 			"ThinkPad T440s");
 | |
| 	g_assert_cmpstr(fu_context_get_hwid_value(context, FU_HWIDS_KEY_PRODUCT_NAME),
 | |
| 			==,
 | |
| 			"20ARS19C0C");
 | |
| 	g_assert_cmpstr(fu_context_get_hwid_value(context, FU_HWIDS_KEY_BIOS_VENDOR), ==, "LENOVO");
 | |
| 	g_assert_cmpstr(fu_context_get_hwid_value(context, FU_HWIDS_KEY_BIOS_VERSION),
 | |
| 			==,
 | |
| 			"GJET75WW (2.25 )");
 | |
| 	g_assert_cmpstr(fu_context_get_hwid_value(context, FU_HWIDS_KEY_BIOS_MAJOR_RELEASE),
 | |
| 			==,
 | |
| 			"02");
 | |
| 	g_assert_cmpstr(fu_context_get_hwid_value(context, FU_HWIDS_KEY_BIOS_MINOR_RELEASE),
 | |
| 			==,
 | |
| 			"19");
 | |
| 	g_assert_cmpstr(fu_context_get_hwid_value(context, FU_HWIDS_KEY_PRODUCT_SKU),
 | |
| 			==,
 | |
| 			"LENOVO_MT_20AR_BU_Think_FM_ThinkPad T440s");
 | |
| 	for (guint i = 0; guids[i].key != NULL; i++) {
 | |
| 		FuHwids *hwids = fu_context_get_hwids(context);
 | |
| 		g_autofree gchar *guid = fu_hwids_get_guid(hwids, guids[i].key, &error);
 | |
| 		g_assert_no_error(error);
 | |
| 		g_assert_cmpstr(guid, ==, guids[i].value);
 | |
| 	}
 | |
| 	for (guint i = 0; guids[i].key != NULL; i++)
 | |
| 		g_assert_true(fu_context_has_hwid_guid(context, guids[i].value));
 | |
| }
 | |
| 
 | |
| static void
 | |
| _plugin_device_added_cb(FuPlugin *plugin, FuDevice *device, gpointer user_data)
 | |
| {
 | |
| 	FuDevice **dev = (FuDevice **)user_data;
 | |
| 	*dev = g_object_ref(device);
 | |
| 	fu_test_loop_quit();
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_plugin_config_func(void)
 | |
| {
 | |
| 	GStatBuf statbuf = {0};
 | |
| 	gboolean ret;
 | |
| 	gint rc;
 | |
| 	g_autofree gchar *conf_dir = NULL;
 | |
| 	g_autofree gchar *conf_file = NULL;
 | |
| 	g_autofree gchar *fn = NULL;
 | |
| 	g_autofree gchar *testdatadir = NULL;
 | |
| 	g_autofree gchar *value = NULL;
 | |
| 	g_autoptr(FuPlugin) plugin = fu_plugin_new(NULL);
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 
 | |
| 	/* this is a build file */
 | |
| 	testdatadir = g_test_build_filename(G_TEST_BUILT, "tests", NULL);
 | |
| 	(void)g_setenv("FWUPD_SYSCONFDIR", testdatadir, TRUE);
 | |
| 	conf_dir = fu_path_from_kind(FU_PATH_KIND_SYSCONFDIR_PKG);
 | |
| 
 | |
| 	/* remove existing file */
 | |
| 	fu_plugin_set_name(plugin, "test");
 | |
| 	conf_file = g_strdup_printf("%s.conf", fu_plugin_get_name(plugin));
 | |
| 	fn = g_build_filename(conf_dir, conf_file, NULL);
 | |
| 	ret = fu_path_mkdir_parent(fn, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	g_remove(fn);
 | |
| 	ret = g_file_set_contents(fn, "", -1, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 
 | |
| 	/* set a value */
 | |
| 	ret = fu_plugin_set_config_value(plugin, "Key", "True", &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	g_assert_true(g_file_test(fn, G_FILE_TEST_EXISTS));
 | |
| 
 | |
| 	/* check it is world readable */
 | |
| 	rc = g_stat(fn, &statbuf);
 | |
| 	g_assert_cmpint(rc, ==, 0);
 | |
| 	g_assert_cmpint(statbuf.st_mode & 0777, ==, 0644);
 | |
| 
 | |
| 	/* read back the value */
 | |
| 	value = fu_plugin_get_config_value(plugin, "Key");
 | |
| 	g_assert_cmpstr(value, ==, "True");
 | |
| 	g_assert_true(fu_plugin_get_config_value_boolean(plugin, "Key"));
 | |
| 
 | |
| 	/* write it private, i.e. only readable by the user/group */
 | |
| 	fu_plugin_add_flag(plugin, FWUPD_PLUGIN_FLAG_SECURE_CONFIG);
 | |
| 	ret = fu_plugin_set_config_value(plugin, "Key", "False", &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	rc = g_stat(fn, &statbuf);
 | |
| 	g_assert_cmpint(rc, ==, 0);
 | |
| 	g_assert_cmpint(statbuf.st_mode & 0777, ==, 0640);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_plugin_devices_func(void)
 | |
| {
 | |
| 	g_autoptr(FuDevice) device = fu_device_new(NULL);
 | |
| 	g_autoptr(FuDevice) child = fu_device_new(NULL);
 | |
| 	g_autoptr(FuPlugin) plugin = fu_plugin_new(NULL);
 | |
| 	GPtrArray *devices;
 | |
| 
 | |
| 	devices = fu_plugin_get_devices(plugin);
 | |
| 	g_assert_nonnull(devices);
 | |
| 	g_assert_cmpint(devices->len, ==, 0);
 | |
| 
 | |
| 	fu_device_set_id(device, "testdev");
 | |
| 	fu_device_set_name(device, "testdev");
 | |
| 	fu_plugin_device_add(plugin, device);
 | |
| 	g_assert_cmpint(devices->len, ==, 1);
 | |
| 	fu_plugin_device_remove(plugin, device);
 | |
| 	g_assert_cmpint(devices->len, ==, 0);
 | |
| 
 | |
| 	/* add a child after adding the parent to the plugin */
 | |
| 	fu_device_set_id(child, "child");
 | |
| 	fu_device_set_name(child, "child");
 | |
| 	fu_device_add_child(device, child);
 | |
| 	g_assert_cmpint(devices->len, ==, 1);
 | |
| 
 | |
| 	/* remove said child */
 | |
| 	fu_device_remove_child(device, child);
 | |
| 	g_assert_cmpint(devices->len, ==, 0);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_plugin_device_inhibit_children_func(void)
 | |
| {
 | |
| 	g_autoptr(FuDevice) parent = fu_device_new(NULL);
 | |
| 	g_autoptr(FuDevice) child1 = fu_device_new(NULL);
 | |
| 	g_autoptr(FuDevice) child2 = fu_device_new(NULL);
 | |
| 
 | |
| 	fu_device_set_id(parent, "testdev");
 | |
| 	fu_device_set_name(parent, "testdev");
 | |
| 	fu_device_add_flag(parent, FWUPD_DEVICE_FLAG_UPDATABLE);
 | |
| 	fu_device_set_id(child1, "child1");
 | |
| 	fu_device_set_name(child1, "child1");
 | |
| 	fu_device_add_flag(child1, FWUPD_DEVICE_FLAG_UPDATABLE);
 | |
| 	fu_device_add_child(parent, child1);
 | |
| 
 | |
| 	/* inhibit the parent */
 | |
| 	fu_device_inhibit(parent, "test", "because");
 | |
| 	g_assert_false(fu_device_has_flag(parent, FWUPD_DEVICE_FLAG_UPDATABLE));
 | |
| 	g_assert_true(fu_device_has_flag(child1, FWUPD_DEVICE_FLAG_UPDATABLE));
 | |
| 	fu_device_uninhibit(parent, "test");
 | |
| 
 | |
| 	/* make the inhibit propagate to children */
 | |
| 	fu_device_add_internal_flag(parent, FU_DEVICE_INTERNAL_FLAG_INHIBIT_CHILDREN);
 | |
| 	fu_device_inhibit(parent, "test", "because");
 | |
| 	g_assert_false(fu_device_has_flag(parent, FWUPD_DEVICE_FLAG_UPDATABLE));
 | |
| 	g_assert_false(fu_device_has_flag(child1, FWUPD_DEVICE_FLAG_UPDATABLE));
 | |
| 
 | |
| 	/* add a child after the inhibit, which should also be inhibited too */
 | |
| 	fu_device_set_id(child2, "child2");
 | |
| 	fu_device_set_name(child2, "child2");
 | |
| 	fu_device_add_flag(child2, FWUPD_DEVICE_FLAG_UPDATABLE);
 | |
| 	fu_device_add_child(parent, child2);
 | |
| 	g_assert_false(fu_device_has_flag(parent, FWUPD_DEVICE_FLAG_UPDATABLE));
 | |
| 	g_assert_false(fu_device_has_flag(child1, FWUPD_DEVICE_FLAG_UPDATABLE));
 | |
| 	g_assert_false(fu_device_has_flag(child2, FWUPD_DEVICE_FLAG_UPDATABLE));
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_plugin_delay_func(void)
 | |
| {
 | |
| 	FuDevice *device_tmp;
 | |
| 	g_autoptr(FuPlugin) plugin = NULL;
 | |
| 	g_autoptr(FuDevice) device = NULL;
 | |
| 
 | |
| 	plugin = fu_plugin_new(NULL);
 | |
| 	g_signal_connect(FU_PLUGIN(plugin),
 | |
| 			 "device-added",
 | |
| 			 G_CALLBACK(_plugin_device_added_cb),
 | |
| 			 &device_tmp);
 | |
| 	g_signal_connect(FU_PLUGIN(plugin),
 | |
| 			 "device-removed",
 | |
| 			 G_CALLBACK(_plugin_device_added_cb),
 | |
| 			 &device_tmp);
 | |
| 
 | |
| 	/* add device straight away */
 | |
| 	device = fu_device_new(NULL);
 | |
| 	fu_device_set_id(device, "testdev");
 | |
| 	fu_plugin_device_add(plugin, device);
 | |
| 	g_assert_nonnull(device_tmp);
 | |
| 	g_assert_cmpstr(fu_device_get_id(device_tmp),
 | |
| 			==,
 | |
| 			"b7eccd0059d6d7dc2ef76c35d6de0048cc8c029d");
 | |
| 	g_clear_object(&device_tmp);
 | |
| 
 | |
| 	/* remove device */
 | |
| 	fu_plugin_device_remove(plugin, device);
 | |
| 	g_assert_nonnull(device_tmp);
 | |
| 	g_assert_cmpstr(fu_device_get_id(device_tmp),
 | |
| 			==,
 | |
| 			"b7eccd0059d6d7dc2ef76c35d6de0048cc8c029d");
 | |
| 	g_clear_object(&device_tmp);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_plugin_fdt_func(void)
 | |
| {
 | |
| 	gboolean ret;
 | |
| 	g_autofree gchar *compatible = NULL;
 | |
| 	g_autoptr(FuContext) ctx = fu_context_new();
 | |
| 	g_autoptr(FuFirmware) fdt = NULL;
 | |
| 	g_autoptr(FuFirmware) fdt_root = NULL;
 | |
| 	g_autoptr(FuFirmware) fdt_tmp = fu_fdt_firmware_new();
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 	g_autoptr(GFile) file =
 | |
| 	    g_file_new_for_path("/tmp/fwupd-self-test/var/lib/fwupd/system.dtb");
 | |
| 
 | |
| 	/* write file */
 | |
| 	ret = fu_firmware_build_from_xml(
 | |
| 	    FU_FIRMWARE(fdt_tmp),
 | |
| 	    "<firmware gtype=\"FuFdtFirmware\">\n"
 | |
| 	    "  <firmware gtype=\"FuFdtImage\">\n"
 | |
| 	    "    <metadata key=\"compatible\" format=\"str\">pine64,rockpro64-v2.1</metadata>\n"
 | |
| 	    "  </firmware>\n"
 | |
| 	    "</firmware>\n",
 | |
| 	    &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	ret = fu_firmware_write_file(FU_FIRMWARE(fdt_tmp), file, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 
 | |
| 	/* get compatible from the context */
 | |
| 	fdt = fu_context_get_fdt(ctx, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(fdt);
 | |
| 	fdt_root = fu_firmware_get_image_by_id(fdt, NULL, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(fdt_root);
 | |
| 	ret = fu_fdt_image_get_attr_str(FU_FDT_IMAGE(fdt_root), "compatible", &compatible, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	g_assert_cmpstr(compatible, ==, "pine64,rockpro64-v2.1");
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_plugin_quirks_func(void)
 | |
| {
 | |
| 	const gchar *tmp;
 | |
| 	gboolean ret;
 | |
| 	g_autoptr(FuContext) ctx = fu_context_new();
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 
 | |
| 	ret = fu_context_load_quirks(ctx, FU_QUIRKS_LOAD_FLAG_NO_CACHE, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 
 | |
| 	/* USB\\VID_0A5C&PID_6412 */
 | |
| 	tmp = fu_context_lookup_quirk_by_id(ctx, "7a1ba7b9-6bcd-54a4-8a36-d60cc5ee935c", "Flags");
 | |
| 	g_assert_cmpstr(tmp, ==, "ignore-runtime");
 | |
| 
 | |
| 	/* ACME Inc.=True */
 | |
| 	tmp = fu_context_lookup_quirk_by_id(ctx, "ec77e295-7c63-5935-9957-be0472d9593a", "Name");
 | |
| 	g_assert_cmpstr(tmp, ==, "awesome");
 | |
| 
 | |
| 	/* CORP* */
 | |
| 	tmp = fu_context_lookup_quirk_by_id(ctx, "3731cce4-484c-521f-a652-892c8e0a65c7", "Name");
 | |
| 	g_assert_cmpstr(tmp, ==, "town");
 | |
| 
 | |
| 	/* baz */
 | |
| 	tmp = fu_context_lookup_quirk_by_id(ctx, "579a3b1c-d1db-5bdc-b6b9-e2c1b28d5b8a", "Unfound");
 | |
| 	g_assert_cmpstr(tmp, ==, NULL);
 | |
| 
 | |
| 	/* unfound */
 | |
| 	tmp = fu_context_lookup_quirk_by_id(ctx, "8ff2ed23-b37e-5f61-b409-b7fe9563be36", "tests");
 | |
| 	g_assert_cmpstr(tmp, ==, NULL);
 | |
| 
 | |
| 	/* unfound */
 | |
| 	tmp = fu_context_lookup_quirk_by_id(ctx, "8ff2ed23-b37e-5f61-b409-b7fe9563be36", "unfound");
 | |
| 	g_assert_cmpstr(tmp, ==, NULL);
 | |
| 
 | |
| 	/* GUID */
 | |
| 	tmp = fu_context_lookup_quirk_by_id(ctx, "bb9ec3e2-77b3-53bc-a1f1-b05916715627", "Flags");
 | |
| 	g_assert_cmpstr(tmp, ==, "clever");
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_plugin_quirks_performance_func(void)
 | |
| {
 | |
| 	gboolean ret;
 | |
| 	g_autoptr(FuQuirks) quirks = fu_quirks_new();
 | |
| 	g_autoptr(GTimer) timer = g_timer_new();
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 	const gchar *keys[] = {"Name", "Children", "Flags", NULL};
 | |
| 
 | |
| 	ret = fu_quirks_load(quirks, FU_QUIRKS_LOAD_FLAG_NO_CACHE, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 
 | |
| 	/* lookup */
 | |
| 	g_timer_reset(timer);
 | |
| 	for (guint j = 0; j < 1000; j++) {
 | |
| 		const gchar *group = "bb9ec3e2-77b3-53bc-a1f1-b05916715627";
 | |
| 		for (guint i = 0; keys[i] != NULL; i++) {
 | |
| 			const gchar *tmp = fu_quirks_lookup_by_id(quirks, group, keys[i]);
 | |
| 			g_assert_cmpstr(tmp, !=, NULL);
 | |
| 		}
 | |
| 	}
 | |
| 	g_print("lookup=%.3fms ", g_timer_elapsed(timer, NULL) * 1000.f);
 | |
| }
 | |
| 
 | |
| typedef struct {
 | |
| 	gboolean seen_one;
 | |
| 	gboolean seen_two;
 | |
| } FuPluginQuirksAppendHelper;
 | |
| 
 | |
| static void
 | |
| fu_plugin_quirks_append_cb(FuQuirks *quirks,
 | |
| 			   const gchar *key,
 | |
| 			   const gchar *value,
 | |
| 			   gpointer user_data)
 | |
| {
 | |
| 	FuPluginQuirksAppendHelper *helper = (FuPluginQuirksAppendHelper *)user_data;
 | |
| 	g_debug("key=%s, value=%s", key, value);
 | |
| 	if (g_strcmp0(key, "Plugin") == 0 && g_strcmp0(value, "one") == 0) {
 | |
| 		helper->seen_one = TRUE;
 | |
| 		return;
 | |
| 	}
 | |
| 	if (g_strcmp0(key, "Plugin") == 0 && g_strcmp0(value, "two") == 0) {
 | |
| 		helper->seen_two = TRUE;
 | |
| 		return;
 | |
| 	}
 | |
| 	g_assert_not_reached();
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_plugin_device_progress_func(void)
 | |
| {
 | |
| 	g_autoptr(FuContext) ctx = fu_context_new();
 | |
| 	g_autoptr(FuDevice) device = fu_device_new(ctx);
 | |
| 	g_autoptr(FuProgress) progress = fu_progress_new(G_STRLOC);
 | |
| 	g_autoptr(FuDeviceProgress) device_progress = fu_device_progress_new(device, progress);
 | |
| 
 | |
| 	/* proxy */
 | |
| 	fu_progress_set_percentage(progress, 50);
 | |
| 	fu_progress_set_status(progress, FWUPD_STATUS_SHUTDOWN);
 | |
| 	g_assert_cmpint(fu_device_get_percentage(device), ==, 50);
 | |
| 	g_assert_cmpint(fu_device_get_status(device), ==, FWUPD_STATUS_SHUTDOWN);
 | |
| 
 | |
| 	/* clear */
 | |
| 	g_clear_object(&device_progress);
 | |
| 	g_assert_cmpint(fu_device_get_percentage(device), ==, 0);
 | |
| 	g_assert_cmpint(fu_device_get_status(device), ==, FWUPD_STATUS_IDLE);
 | |
| 
 | |
| 	/* do not proxy */
 | |
| 	fu_progress_set_percentage(progress, 100);
 | |
| 	fu_progress_set_status(progress, FWUPD_STATUS_DEVICE_BUSY);
 | |
| 	g_assert_cmpint(fu_device_get_percentage(device), ==, 0);
 | |
| 	g_assert_cmpint(fu_device_get_status(device), ==, FWUPD_STATUS_IDLE);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_plugin_quirks_append_func(void)
 | |
| {
 | |
| 	FuPluginQuirksAppendHelper helper = {0};
 | |
| 	gboolean ret;
 | |
| 	g_autoptr(FuQuirks) quirks = fu_quirks_new();
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 
 | |
| 	/* lookup a duplicate group name */
 | |
| 	ret = fu_quirks_load(quirks, FU_QUIRKS_LOAD_FLAG_NO_CACHE, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	ret = fu_quirks_lookup_by_id_iter(quirks,
 | |
| 					  "b19d1c67-a29a-51ce-9cae-f7b40fe5505b",
 | |
| 					  fu_plugin_quirks_append_cb,
 | |
| 					  &helper);
 | |
| 	g_assert_true(ret);
 | |
| 	g_assert_true(helper.seen_one);
 | |
| 	g_assert_true(helper.seen_two);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_plugin_quirks_device_func(void)
 | |
| {
 | |
| 	FuDevice *device_tmp;
 | |
| 	GPtrArray *children;
 | |
| 	gboolean ret;
 | |
| 	g_autoptr(FuDevice) device = fu_device_new(NULL);
 | |
| 	g_autoptr(FuContext) ctx = fu_context_new();
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 
 | |
| 	ret = fu_context_load_quirks(ctx, FU_QUIRKS_LOAD_FLAG_NO_CACHE, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 
 | |
| 	/* use quirk file to set device attributes */
 | |
| 	fu_device_set_physical_id(device, "usb:00:05");
 | |
| 	fu_device_set_context(device, ctx);
 | |
| 	fu_device_add_flag(device, FWUPD_DEVICE_FLAG_UPDATABLE);
 | |
| 	fu_device_add_instance_id(device, "USB\\VID_0BDA&PID_1100");
 | |
| 	fu_device_convert_instance_ids(device);
 | |
| 	g_assert_cmpstr(fu_device_get_name(device), ==, "Hub");
 | |
| 
 | |
| 	/* ensure children are created */
 | |
| 	children = fu_device_get_children(device);
 | |
| 	g_assert_cmpint(children->len, ==, 1);
 | |
| 	device_tmp = g_ptr_array_index(children, 0);
 | |
| 	g_assert_cmpstr(fu_device_get_name(device_tmp), ==, "HDMI");
 | |
| 	g_assert_true(fu_device_has_flag(device_tmp, FWUPD_DEVICE_FLAG_UPDATABLE));
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_common_kernel_lockdown_func(void)
 | |
| {
 | |
| 	gboolean ret;
 | |
| 	g_autofree gchar *locked_dir = NULL;
 | |
| 	g_autofree gchar *none_dir = NULL;
 | |
| 	g_autofree gchar *old_kernel_dir = NULL;
 | |
| 
 | |
| #ifndef __linux__
 | |
| 	g_test_skip("only works on Linux");
 | |
| 	return;
 | |
| #endif
 | |
| 
 | |
| 	old_kernel_dir = g_test_build_filename(G_TEST_DIST, "tests", "lockdown", NULL);
 | |
| 	(void)g_setenv("FWUPD_SYSFSSECURITYDIR", old_kernel_dir, TRUE);
 | |
| 	ret = fu_kernel_locked_down();
 | |
| 	g_assert_false(ret);
 | |
| 
 | |
| 	locked_dir = g_test_build_filename(G_TEST_DIST, "tests", "lockdown", "locked", NULL);
 | |
| 	(void)g_setenv("FWUPD_SYSFSSECURITYDIR", locked_dir, TRUE);
 | |
| 	ret = fu_kernel_locked_down();
 | |
| 	g_assert_true(ret);
 | |
| 
 | |
| 	none_dir = g_test_build_filename(G_TEST_DIST, "tests", "lockdown", "none", NULL);
 | |
| 	(void)g_setenv("FWUPD_SYSFSSECURITYDIR", none_dir, TRUE);
 | |
| 	ret = fu_kernel_locked_down();
 | |
| 	g_assert_false(ret);
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| _open_cb(GObject *device, GError **error)
 | |
| {
 | |
| 	g_assert_cmpstr(g_object_get_data(device, "state"), ==, "closed");
 | |
| 	g_object_set_data(device, "state", (gpointer) "opened");
 | |
| 	return TRUE;
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| _close_cb(GObject *device, GError **error)
 | |
| {
 | |
| 	g_assert_cmpstr(g_object_get_data(device, "state"), ==, "opened");
 | |
| 	g_object_set_data(device, "state", (gpointer) "closed-on-unref");
 | |
| 	return TRUE;
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_device_locker_func(void)
 | |
| {
 | |
| 	g_autoptr(FuDeviceLocker) locker = NULL;
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 	g_autoptr(GObject) device = g_object_new(G_TYPE_OBJECT, NULL);
 | |
| 
 | |
| 	g_object_set_data(device, "state", (gpointer) "closed");
 | |
| 	locker = fu_device_locker_new_full(device, _open_cb, _close_cb, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(locker);
 | |
| 	g_clear_object(&locker);
 | |
| 	g_assert_cmpstr(g_object_get_data(device, "state"), ==, "closed-on-unref");
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| _fail_open_cb(FuDevice *device, GError **error)
 | |
| {
 | |
| 	fu_device_set_metadata_boolean(device, "Test::Open", TRUE);
 | |
| 	g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_FAILED, "fail");
 | |
| 	return FALSE;
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| _fail_close_cb(FuDevice *device, GError **error)
 | |
| {
 | |
| 	fu_device_set_metadata_boolean(device, "Test::Close", TRUE);
 | |
| 	g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_BUSY, "busy");
 | |
| 	return FALSE;
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_device_locker_fail_func(void)
 | |
| {
 | |
| 	g_autoptr(FuDeviceLocker) locker = NULL;
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 	g_autoptr(FuDevice) device = fu_device_new(NULL);
 | |
| 	locker = fu_device_locker_new_full(device,
 | |
| 					   (FuDeviceLockerFunc)_fail_open_cb,
 | |
| 					   (FuDeviceLockerFunc)_fail_close_cb,
 | |
| 					   &error);
 | |
| 	g_assert_error(error, G_IO_ERROR, G_IO_ERROR_FAILED);
 | |
| 	g_assert_null(locker);
 | |
| 	g_assert_true(fu_device_get_metadata_boolean(device, "Test::Open"));
 | |
| 	g_assert_true(fu_device_get_metadata_boolean(device, "Test::Close"));
 | |
| 	g_assert_false(fu_device_has_internal_flag(device, FU_DEVICE_INTERNAL_FLAG_IS_OPEN));
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_common_endian_func(void)
 | |
| {
 | |
| 	guint8 buf[3];
 | |
| 
 | |
| 	fu_memwrite_uint16(buf, 0x1234, G_LITTLE_ENDIAN);
 | |
| 	g_assert_cmpint(buf[0], ==, 0x34);
 | |
| 	g_assert_cmpint(buf[1], ==, 0x12);
 | |
| 	g_assert_cmpint(fu_memread_uint16(buf, G_LITTLE_ENDIAN), ==, 0x1234);
 | |
| 
 | |
| 	fu_memwrite_uint16(buf, 0x1234, G_BIG_ENDIAN);
 | |
| 	g_assert_cmpint(buf[0], ==, 0x12);
 | |
| 	g_assert_cmpint(buf[1], ==, 0x34);
 | |
| 	g_assert_cmpint(fu_memread_uint16(buf, G_BIG_ENDIAN), ==, 0x1234);
 | |
| 
 | |
| 	fu_memwrite_uint24(buf, 0x123456, G_LITTLE_ENDIAN);
 | |
| 	g_assert_cmpint(buf[0], ==, 0x56);
 | |
| 	g_assert_cmpint(buf[1], ==, 0x34);
 | |
| 	g_assert_cmpint(buf[2], ==, 0x12);
 | |
| 	g_assert_cmpint(fu_memread_uint24(buf, G_LITTLE_ENDIAN), ==, 0x123456);
 | |
| 
 | |
| 	fu_memwrite_uint24(buf, 0x123456, G_BIG_ENDIAN);
 | |
| 	g_assert_cmpint(buf[0], ==, 0x12);
 | |
| 	g_assert_cmpint(buf[1], ==, 0x34);
 | |
| 	g_assert_cmpint(buf[2], ==, 0x56);
 | |
| 	g_assert_cmpint(fu_memread_uint24(buf, G_BIG_ENDIAN), ==, 0x123456);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_common_cabinet_func(void)
 | |
| {
 | |
| 	g_autoptr(FuCabinet) cabinet = fu_cabinet_new();
 | |
| 	g_autoptr(GBytes) blob1 = NULL;
 | |
| 	g_autoptr(GBytes) blob2 = NULL;
 | |
| 	g_autoptr(GBytes) jcat_blob1 = g_bytes_new_static("hello", 6);
 | |
| 	g_autoptr(GBytes) jcat_blob2 = g_bytes_new_static("hellX", 6);
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 
 | |
| 	/* add */
 | |
| 	fu_cabinet_add_file(cabinet, "firmware.jcat", jcat_blob1);
 | |
| 
 | |
| 	/* replace */
 | |
| 	fu_cabinet_add_file(cabinet, "firmware.jcat", jcat_blob2);
 | |
| 
 | |
| 	/* get data */
 | |
| 	blob1 = fu_cabinet_get_file(cabinet, "firmware.jcat", &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(blob1);
 | |
| 	g_assert_cmpstr(g_bytes_get_data(blob1, NULL), ==, "hellX");
 | |
| 
 | |
| 	/* get data that does not exist */
 | |
| 	blob2 = fu_cabinet_get_file(cabinet, "foo.jcat", &error);
 | |
| 	g_assert_error(error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE);
 | |
| 	g_assert_null(blob2);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_common_bytes_get_data_func(void)
 | |
| {
 | |
| 	const gchar *fn = "/tmp/fwupdzero";
 | |
| 	const guint8 *buf;
 | |
| 	gboolean ret;
 | |
| 	g_autoptr(GBytes) bytes1 = NULL;
 | |
| 	g_autoptr(GBytes) bytes2 = NULL;
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 	g_autoptr(GMappedFile) mmap = NULL;
 | |
| 
 | |
| 	/* create file with zero size */
 | |
| 	ret = g_file_set_contents(fn, NULL, 0, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 
 | |
| 	/* check we got zero sized data */
 | |
| 	bytes1 = fu_bytes_get_contents(fn, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(bytes1);
 | |
| 	g_assert_cmpint(g_bytes_get_size(bytes1), ==, 0);
 | |
| 	g_assert_nonnull(g_bytes_get_data(bytes1, NULL));
 | |
| 
 | |
| 	/* do the same with an mmap mapping, which returns NULL on empty file */
 | |
| 	mmap = g_mapped_file_new(fn, FALSE, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(mmap);
 | |
| 	bytes2 = g_mapped_file_get_bytes(mmap);
 | |
| 	g_assert_nonnull(bytes2);
 | |
| 	g_assert_cmpint(g_bytes_get_size(bytes2), ==, 0);
 | |
| 	g_assert_null(g_bytes_get_data(bytes2, NULL));
 | |
| 
 | |
| 	/* use the safe function */
 | |
| 	buf = fu_bytes_get_data_safe(bytes2, NULL, &error);
 | |
| 	g_assert_error(error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA);
 | |
| 	g_assert_null(buf);
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| fu_device_poll_cb(FuDevice *device, GError **error)
 | |
| {
 | |
| 	guint64 cnt = fu_device_get_metadata_integer(device, "cnt");
 | |
| 	g_debug("poll cnt=%" G_GUINT64_FORMAT, cnt);
 | |
| 	fu_device_set_metadata_integer(device, "cnt", cnt + 1);
 | |
| 	return TRUE;
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_device_poll_func(void)
 | |
| {
 | |
| 	g_autoptr(FuDevice) device = fu_device_new(NULL);
 | |
| 	FuDeviceClass *klass = FU_DEVICE_GET_CLASS(device);
 | |
| 	guint cnt;
 | |
| 
 | |
| 	/* set up a 10ms poll */
 | |
| 	klass->poll = fu_device_poll_cb;
 | |
| 	fu_device_set_metadata_integer(device, "cnt", 0);
 | |
| 	fu_device_set_poll_interval(device, 10);
 | |
| 	fu_test_loop_run_with_timeout(100);
 | |
| 	fu_test_loop_quit();
 | |
| 	cnt = fu_device_get_metadata_integer(device, "cnt");
 | |
| 	g_assert_cmpint(cnt, >=, 8);
 | |
| 
 | |
| 	/* disable the poll */
 | |
| 	fu_device_set_poll_interval(device, 0);
 | |
| 	fu_test_loop_run_with_timeout(100);
 | |
| 	fu_test_loop_quit();
 | |
| 	g_assert_cmpint(fu_device_get_metadata_integer(device, "cnt"), ==, cnt);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_device_func(void)
 | |
| {
 | |
| 	g_autoptr(FuDevice) device = fu_device_new(NULL);
 | |
| 	g_autoptr(GPtrArray) possible_plugins = NULL;
 | |
| 
 | |
| 	/* only add one plugin name of the same type */
 | |
| 	fu_device_add_possible_plugin(device, "test");
 | |
| 	fu_device_add_possible_plugin(device, "test");
 | |
| 	possible_plugins = fu_device_get_possible_plugins(device);
 | |
| 	g_assert_cmpint(possible_plugins->len, ==, 1);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_device_instance_ids_func(void)
 | |
| {
 | |
| 	gboolean ret;
 | |
| 	g_autoptr(FuContext) ctx = fu_context_new();
 | |
| 	g_autoptr(FuDevice) device = fu_device_new(ctx);
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 
 | |
| 	/* do not save silo */
 | |
| 	ret = fu_context_load_quirks(ctx, FU_QUIRKS_LOAD_FLAG_NO_CACHE, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 
 | |
| 	/* sanity check */
 | |
| 	g_assert_false(fu_device_has_guid(device, "c0a26214-223b-572a-9477-cde897fe8619"));
 | |
| 
 | |
| 	/* add a deferred instance ID that only gets converted on ->setup */
 | |
| 	fu_device_add_instance_id(device, "foobarbaz");
 | |
| 	g_assert_false(fu_device_has_guid(device, "c0a26214-223b-572a-9477-cde897fe8619"));
 | |
| 
 | |
| 	ret = fu_device_setup(device, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	g_assert_true(fu_device_has_guid(device, "c0a26214-223b-572a-9477-cde897fe8619"));
 | |
| 
 | |
| 	/* this gets added immediately */
 | |
| 	fu_device_add_instance_id(device, "bazbarfoo");
 | |
| 	g_assert_true(fu_device_has_guid(device, "77e49bb0-2cd6-5faf-bcee-5b7fbe6e944d"));
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_device_composite_id_func(void)
 | |
| {
 | |
| 	g_autoptr(FuDevice) dev1 = fu_device_new(NULL);
 | |
| 	g_autoptr(FuDevice) dev2 = fu_device_new(NULL);
 | |
| 	g_autoptr(FuDevice) dev3 = fu_device_new(NULL);
 | |
| 	g_autoptr(FuDevice) dev4 = fu_device_new(NULL);
 | |
| 
 | |
| 	/* single device */
 | |
| 	fu_device_set_id(dev1, "dev1");
 | |
| 	g_assert_cmpstr(fu_device_get_composite_id(dev1),
 | |
| 			==,
 | |
| 			"3b42553c4e3241e8f3f8fbc19a69fa2f95708a9d");
 | |
| 	fu_device_set_id(dev2, "dev2");
 | |
| 
 | |
| 	/* one child */
 | |
| 	fu_device_add_child(dev1, dev2);
 | |
| 	g_assert_cmpstr(fu_device_get_composite_id(dev1),
 | |
| 			==,
 | |
| 			"3b42553c4e3241e8f3f8fbc19a69fa2f95708a9d");
 | |
| 	g_assert_cmpstr(fu_device_get_composite_id(dev2),
 | |
| 			==,
 | |
| 			"3b42553c4e3241e8f3f8fbc19a69fa2f95708a9d");
 | |
| 
 | |
| 	/* add a different "family" */
 | |
| 	fu_device_set_id(dev3, "dev3");
 | |
| 	fu_device_set_id(dev4, "dev4");
 | |
| 	fu_device_add_child(dev3, dev4);
 | |
| 	fu_device_add_child(dev2, dev3);
 | |
| 	g_assert_cmpstr(fu_device_get_composite_id(dev1),
 | |
| 			==,
 | |
| 			"3b42553c4e3241e8f3f8fbc19a69fa2f95708a9d");
 | |
| 	g_assert_cmpstr(fu_device_get_composite_id(dev2),
 | |
| 			==,
 | |
| 			"3b42553c4e3241e8f3f8fbc19a69fa2f95708a9d");
 | |
| 	g_assert_cmpstr(fu_device_get_composite_id(dev3),
 | |
| 			==,
 | |
| 			"3b42553c4e3241e8f3f8fbc19a69fa2f95708a9d");
 | |
| 	g_assert_cmpstr(fu_device_get_composite_id(dev4),
 | |
| 			==,
 | |
| 			"3b42553c4e3241e8f3f8fbc19a69fa2f95708a9d");
 | |
| 
 | |
| 	/* change the parent ID */
 | |
| 	fu_device_set_id(dev1, "dev1-NEW");
 | |
| 	g_assert_cmpstr(fu_device_get_composite_id(dev1),
 | |
| 			==,
 | |
| 			"a4c8efc6a0a58c2dc14c05fd33186703f7352997");
 | |
| 	g_assert_cmpstr(fu_device_get_composite_id(dev2),
 | |
| 			==,
 | |
| 			"a4c8efc6a0a58c2dc14c05fd33186703f7352997");
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_device_inhibit_func(void)
 | |
| {
 | |
| 	g_autoptr(FuDevice) device = fu_device_new(NULL);
 | |
| 
 | |
| 	fu_device_add_flag(device, FWUPD_DEVICE_FLAG_UPDATABLE);
 | |
| 	fu_device_set_battery_threshold(device, 25);
 | |
| 	g_assert_true(fu_device_has_flag(device, FWUPD_DEVICE_FLAG_UPDATABLE));
 | |
| 	g_assert_false(fu_device_has_flag(device, FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN));
 | |
| 
 | |
| 	/* does not exist -> fine */
 | |
| 	fu_device_uninhibit(device, "NOTGOINGTOEXIST");
 | |
| 	g_assert_false(fu_device_has_inhibit(device, "NOTGOINGTOEXIST"));
 | |
| 
 | |
| 	/* first one */
 | |
| 	fu_device_inhibit(device, "needs-activation", "Device is pending activation");
 | |
| 	g_assert_true(fu_device_has_inhibit(device, "needs-activation"));
 | |
| 	g_assert_true(fu_device_has_flag(device, FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN));
 | |
| 	g_assert_false(fu_device_has_flag(device, FWUPD_DEVICE_FLAG_UPDATABLE));
 | |
| 
 | |
| 	/* another */
 | |
| 	fu_device_set_battery_level(device, 5);
 | |
| 	g_assert_true(fu_device_has_flag(device, FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN));
 | |
| 	g_assert_false(fu_device_has_flag(device, FWUPD_DEVICE_FLAG_UPDATABLE));
 | |
| 
 | |
| 	/* activated, power still too low */
 | |
| 	fu_device_uninhibit(device, "needs-activation");
 | |
| 	g_assert_false(fu_device_has_inhibit(device, "needs-activation"));
 | |
| 	g_assert_true(fu_device_has_flag(device, FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN));
 | |
| 	g_assert_false(fu_device_has_flag(device, FWUPD_DEVICE_FLAG_UPDATABLE));
 | |
| 
 | |
| 	/* we got some more power -> fine */
 | |
| 	fu_device_set_battery_level(device, 95);
 | |
| 	g_assert_true(fu_device_has_flag(device, FWUPD_DEVICE_FLAG_UPDATABLE));
 | |
| 	g_assert_false(fu_device_has_flag(device, FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN));
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_device_inhibit_updateable_func(void)
 | |
| {
 | |
| 	g_autoptr(FuDevice) device = fu_device_new(NULL);
 | |
| 
 | |
| 	g_assert_false(fu_device_has_flag(device, FWUPD_DEVICE_FLAG_UPDATABLE));
 | |
| 	g_assert_false(fu_device_has_flag(device, FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN));
 | |
| 	g_assert_cmpstr(fu_device_get_update_error(device), ==, NULL);
 | |
| 
 | |
| 	/* first one */
 | |
| 	fu_device_inhibit(device, "needs-activation", "Device is pending activation");
 | |
| 	g_assert_false(fu_device_has_flag(device, FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN));
 | |
| 	g_assert_false(fu_device_has_flag(device, FWUPD_DEVICE_FLAG_UPDATABLE));
 | |
| 	g_assert_cmpstr(fu_device_get_update_error(device), ==, "Device is pending activation");
 | |
| 
 | |
| 	/* activated, but still not updatable */
 | |
| 	fu_device_uninhibit(device, "needs-activation");
 | |
| 	g_assert_false(fu_device_has_flag(device, FWUPD_DEVICE_FLAG_UPDATABLE));
 | |
| 	g_assert_false(fu_device_has_flag(device, FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN));
 | |
| 	g_assert_cmpstr(fu_device_get_update_error(device), ==, NULL);
 | |
| }
 | |
| 
 | |
| #define TEST_FLAG_FOO (1 << 0)
 | |
| #define TEST_FLAG_BAR (1 << 1)
 | |
| #define TEST_FLAG_BAZ (1 << 2)
 | |
| 
 | |
| static void
 | |
| fu_device_private_flags_func(void)
 | |
| {
 | |
| 	g_autofree gchar *tmp = NULL;
 | |
| 	g_autoptr(FuDevice) device = fu_device_new(NULL);
 | |
| 
 | |
| 	fu_device_register_private_flag(device, TEST_FLAG_FOO, "foo");
 | |
| 	fu_device_register_private_flag(device, TEST_FLAG_BAR, "bar");
 | |
| 
 | |
| 	fu_device_set_custom_flags(device, "foo");
 | |
| 	g_assert_cmpint(fu_device_get_private_flags(device), ==, TEST_FLAG_FOO);
 | |
| 	fu_device_set_custom_flags(device, "bar");
 | |
| 	g_assert_cmpint(fu_device_get_private_flags(device), ==, TEST_FLAG_FOO | TEST_FLAG_BAR);
 | |
| 	fu_device_set_custom_flags(device, "~bar");
 | |
| 	g_assert_cmpint(fu_device_get_private_flags(device), ==, TEST_FLAG_FOO);
 | |
| 	fu_device_set_custom_flags(device, "baz");
 | |
| 	g_assert_cmpint(fu_device_get_private_flags(device), ==, TEST_FLAG_FOO);
 | |
| 	fu_device_add_private_flag(device, TEST_FLAG_BAZ);
 | |
| 	g_assert_cmpint(fu_device_get_private_flags(device), ==, TEST_FLAG_FOO | TEST_FLAG_BAZ);
 | |
| 
 | |
| 	tmp = fu_device_to_string(device);
 | |
| 	g_assert_cmpstr(tmp,
 | |
| 			==,
 | |
| 			"FuDevice:\n"
 | |
| 			"  Flags:                none\n"
 | |
| 			"  AcquiesceDelay:       50\n"
 | |
| 			"  CustomFlags:          baz\n"
 | |
| 			"  PrivateFlags:         foo\n");
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_device_flags_func(void)
 | |
| {
 | |
| 	g_autoptr(FuDevice) device = fu_device_new(NULL);
 | |
| 	g_autoptr(FuDevice) proxy = fu_device_new(NULL);
 | |
| 
 | |
| 	/* bitfield */
 | |
| 	for (guint64 i = 1; i < FU_DEVICE_INTERNAL_FLAG_UNKNOWN; i *= 2) {
 | |
| 		const gchar *tmp = fu_device_internal_flag_to_string(i);
 | |
| 		if (tmp == NULL)
 | |
| 			break;
 | |
| 		g_assert_cmpint(fu_device_internal_flag_from_string(tmp), ==, i);
 | |
| 	}
 | |
| 
 | |
| 	g_assert_cmpint(fu_device_get_flags(device), ==, FWUPD_DEVICE_FLAG_NONE);
 | |
| 
 | |
| 	/* remove IS_BOOTLOADER if is a BOOTLOADER */
 | |
| 	fu_device_add_flag(device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER);
 | |
| 	fu_device_add_flag(device, FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER);
 | |
| 	g_assert_cmpint(fu_device_get_flags(device), ==, FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER);
 | |
| 	fu_device_remove_flag(device, FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER);
 | |
| 
 | |
| 	/* check implication */
 | |
| 	fu_device_add_flag(device, FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE);
 | |
| 	g_assert_cmpint(fu_device_get_flags(device),
 | |
| 			==,
 | |
| 			FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE | FWUPD_DEVICE_FLAG_CAN_VERIFY);
 | |
| 	fu_device_remove_flag(device,
 | |
| 			      FWUPD_DEVICE_FLAG_CAN_VERIFY | FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE);
 | |
| 
 | |
| 	/* negation */
 | |
| 	fu_device_set_custom_flags(device, "is-bootloader,updatable");
 | |
| 	g_assert_cmpint(fu_device_get_flags(device),
 | |
| 			==,
 | |
| 			FWUPD_DEVICE_FLAG_IS_BOOTLOADER | FWUPD_DEVICE_FLAG_UPDATABLE);
 | |
| 	fu_device_set_custom_flags(device, "~is-bootloader");
 | |
| 	g_assert_cmpint(fu_device_get_flags(device), ==, FWUPD_DEVICE_FLAG_UPDATABLE);
 | |
| 
 | |
| 	/* setting flags on the proxy should propagate to the device that *uses* the proxy */
 | |
| 	fu_device_set_proxy(device, proxy);
 | |
| 	fu_device_add_flag(proxy, FWUPD_DEVICE_FLAG_EMULATED);
 | |
| 	g_assert_true(fu_device_has_flag(device, FWUPD_DEVICE_FLAG_EMULATED));
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_device_children_func(void)
 | |
| {
 | |
| 	gboolean ret;
 | |
| 	g_autoptr(FuContext) ctx = fu_context_new();
 | |
| 	g_autoptr(FuDevice) child = fu_device_new(NULL);
 | |
| 	g_autoptr(FuDevice) parent = fu_device_new(ctx);
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 
 | |
| 	/* do not save silo */
 | |
| 	ret = fu_context_load_quirks(ctx, FU_QUIRKS_LOAD_FLAG_NO_CACHE, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 
 | |
| 	fu_device_set_physical_id(child, "dummy");
 | |
| 	fu_device_set_physical_id(parent, "dummy");
 | |
| 
 | |
| 	/* set up family */
 | |
| 	fu_device_add_child(parent, child);
 | |
| 
 | |
| 	/* set an instance ID that will be converted to a GUID when the parent
 | |
| 	 * calls ->setup */
 | |
| 	fu_device_add_instance_id(child, "foo");
 | |
| 	g_assert_false(fu_device_has_guid(child, "b84ed8ed-a7b1-502f-83f6-90132e68adef"));
 | |
| 
 | |
| 	/* setup parent, which also calls setup on child too (and thus also
 | |
| 	 * converts the instance ID to a GUID) */
 | |
| 	ret = fu_device_setup(parent, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	g_assert_true(fu_device_has_guid(child, "b84ed8ed-a7b1-502f-83f6-90132e68adef"));
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_device_parent_func(void)
 | |
| {
 | |
| 	g_autoptr(FuDevice) child = fu_device_new(NULL);
 | |
| 	g_autoptr(FuDevice) child_root = NULL;
 | |
| 	g_autoptr(FuDevice) grandparent = fu_device_new(NULL);
 | |
| 	g_autoptr(FuDevice) grandparent_root = NULL;
 | |
| 	g_autoptr(FuDevice) parent = fu_device_new(NULL);
 | |
| 	g_autoptr(FuDevice) parent_root = NULL;
 | |
| 
 | |
| 	fu_device_set_physical_id(child, "dummy");
 | |
| 	fu_device_set_physical_id(grandparent, "dummy");
 | |
| 	fu_device_set_physical_id(parent, "dummy");
 | |
| 
 | |
| 	/* set up three layer family */
 | |
| 	fu_device_add_child(grandparent, parent);
 | |
| 	fu_device_add_child(parent, child);
 | |
| 
 | |
| 	/* check parents */
 | |
| 	g_assert_true(fu_device_get_parent(child) == parent);
 | |
| 	g_assert_true(fu_device_get_parent(parent) == grandparent);
 | |
| 	g_assert_true(fu_device_get_parent(grandparent) == NULL);
 | |
| 
 | |
| 	/* check root */
 | |
| 	child_root = fu_device_get_root(child);
 | |
| 	g_assert_true(child_root == grandparent);
 | |
| 	parent_root = fu_device_get_root(parent);
 | |
| 	g_assert_true(parent_root == grandparent);
 | |
| 	grandparent_root = fu_device_get_root(child);
 | |
| 	g_assert_true(grandparent_root == grandparent);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_device_incorporate_func(void)
 | |
| {
 | |
| 	gboolean ret;
 | |
| 	g_autoptr(FuContext) ctx = fu_context_new();
 | |
| 	g_autoptr(FuDevice) device = fu_device_new(ctx);
 | |
| 	g_autoptr(FuDevice) donor = fu_device_new(ctx);
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 
 | |
| 	/* load quirks */
 | |
| 	ret = fu_context_load_quirks(ctx, FU_QUIRKS_LOAD_FLAG_NO_CACHE, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 
 | |
| 	/* set up donor device */
 | |
| 	fu_device_set_alternate_id(donor, "alt-id");
 | |
| 	fu_device_set_equivalent_id(donor, "equiv-id");
 | |
| 	fu_device_set_metadata(donor, "test", "me");
 | |
| 	fu_device_set_metadata(donor, "test2", "me");
 | |
| 	fu_device_add_instance_str(donor, "VID", "0A5C");
 | |
| 	fu_device_add_instance_str(donor, "PID", "6412");
 | |
| 
 | |
| 	/* match a quirk entry, and then clear to ensure encorporate uses the quirk instance ID */
 | |
| 	ret = fu_device_build_instance_id_quirk(donor, &error, "USB", "VID", "PID", NULL);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	g_assert_cmpstr(fu_device_get_custom_flags(donor), ==, "ignore-runtime");
 | |
| 	fu_device_set_custom_flags(donor, "SHOULD_BE_REPLACED_WITH_QUIRK_VALUE");
 | |
| 
 | |
| 	/* base properties */
 | |
| 	fu_device_add_flag(donor, FWUPD_DEVICE_FLAG_REQUIRE_AC);
 | |
| 	fu_device_set_created(donor, 123);
 | |
| 	fu_device_set_modified(donor, 456);
 | |
| 	fu_device_add_icon(donor, "computer");
 | |
| 
 | |
| 	/* existing properties */
 | |
| 	fu_device_set_equivalent_id(device, "DO_NOT_OVERWRITE");
 | |
| 	fu_device_set_metadata(device, "test2", "DO_NOT_OVERWRITE");
 | |
| 	fu_device_set_modified(device, 789);
 | |
| 
 | |
| 	/* incorporate properties from donor to device */
 | |
| 	fu_device_incorporate(device, donor);
 | |
| 	g_assert_cmpstr(fu_device_get_alternate_id(device), ==, "alt-id");
 | |
| 	g_assert_cmpstr(fu_device_get_equivalent_id(device), ==, "DO_NOT_OVERWRITE");
 | |
| 	g_assert_cmpstr(fu_device_get_metadata(device, "test"), ==, "me");
 | |
| 	g_assert_cmpstr(fu_device_get_metadata(device, "test2"), ==, "DO_NOT_OVERWRITE");
 | |
| 	g_assert_true(fu_device_has_flag(device, FWUPD_DEVICE_FLAG_REQUIRE_AC));
 | |
| 	g_assert_cmpint(fu_device_get_created(device), ==, 123);
 | |
| 	g_assert_cmpint(fu_device_get_modified(device), ==, 789);
 | |
| 	g_assert_cmpint(fu_device_get_icons(device)->len, ==, 1);
 | |
| 	ret = fu_device_build_instance_id(device, &error, "USB", "VID", NULL);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	g_assert_true(fu_device_has_instance_id(device, "USB\\VID_0A5C"));
 | |
| 	g_assert_cmpstr(fu_device_get_custom_flags(device), ==, "ignore-runtime");
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_backend_func(void)
 | |
| {
 | |
| 	FuDevice *dev;
 | |
| 	gboolean ret;
 | |
| 	g_autoptr(FuBackend) backend = g_object_new(FU_TYPE_BACKEND, NULL);
 | |
| 	g_autoptr(FuDevice) dev1 = fu_device_new(NULL);
 | |
| 	g_autoptr(FuDevice) dev2 = fu_device_new(NULL);
 | |
| 	g_autoptr(FuProgress) progress = fu_progress_new(G_STRLOC);
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 	g_autoptr(GPtrArray) devices = NULL;
 | |
| 
 | |
| 	/* defaults */
 | |
| 	g_assert_null(fu_backend_get_name(backend));
 | |
| 	g_assert_true(fu_backend_get_enabled(backend));
 | |
| 
 | |
| 	/* load */
 | |
| 	ret = fu_backend_setup(backend, progress, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	ret = fu_backend_coldplug(backend, progress, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 
 | |
| 	/* add two devices, then remove one of them */
 | |
| 	fu_device_set_physical_id(dev1, "dev1");
 | |
| 	fu_backend_device_added(backend, dev1);
 | |
| 	fu_device_set_physical_id(dev2, "dev2");
 | |
| 	fu_backend_device_added(backend, dev2);
 | |
| 	fu_backend_device_changed(backend, dev2);
 | |
| 	fu_backend_device_removed(backend, dev2);
 | |
| 
 | |
| 	dev = fu_backend_lookup_by_id(backend, "dev1");
 | |
| 	g_assert_nonnull(dev);
 | |
| 	g_assert_true(dev == dev1);
 | |
| 
 | |
| 	/* should have been removed */
 | |
| 	dev = fu_backend_lookup_by_id(backend, "dev2");
 | |
| 	g_assert_null(dev);
 | |
| 
 | |
| 	/* get linear array */
 | |
| 	devices = fu_backend_get_devices(backend);
 | |
| 	g_assert_nonnull(devices);
 | |
| 	g_assert_cmpint(devices->len, ==, 1);
 | |
| 	dev = g_ptr_array_index(devices, 0);
 | |
| 	g_assert_nonnull(dev);
 | |
| 	g_assert_true(dev == dev1);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_chunk_func(void)
 | |
| {
 | |
| 	g_autofree gchar *chunked1_str = NULL;
 | |
| 	g_autofree gchar *chunked2_str = NULL;
 | |
| 	g_autofree gchar *chunked3_str = NULL;
 | |
| 	g_autofree gchar *chunked4_str = NULL;
 | |
| 	g_autoptr(GPtrArray) chunked1 = NULL;
 | |
| 	g_autoptr(GPtrArray) chunked2 = NULL;
 | |
| 	g_autoptr(GPtrArray) chunked3 = NULL;
 | |
| 	g_autoptr(GPtrArray) chunked4 = NULL;
 | |
| 
 | |
| 	chunked3 = fu_chunk_array_new((const guint8 *)"123456", 6, 0x0, 3, 3);
 | |
| 	chunked3_str = fu_chunk_array_to_string(chunked3);
 | |
| 	g_assert_cmpstr(chunked3_str,
 | |
| 			==,
 | |
| 			"<chunks>\n"
 | |
| 			"  <chunk>\n"
 | |
| 			"    <data size=\"0x3\">123</data>\n"
 | |
| 			"  </chunk>\n"
 | |
| 			"  <chunk>\n"
 | |
| 			"    <idx>0x1</idx>\n"
 | |
| 			"    <page>0x1</page>\n"
 | |
| 			"    <data size=\"0x3\">456</data>\n"
 | |
| 			"  </chunk>\n"
 | |
| 			"</chunks>\n");
 | |
| 
 | |
| 	chunked4 = fu_chunk_array_new((const guint8 *)"123456", 6, 0x4, 4, 4);
 | |
| 	chunked4_str = fu_chunk_array_to_string(chunked4);
 | |
| 	g_assert_cmpstr(chunked4_str,
 | |
| 			==,
 | |
| 			"<chunks>\n"
 | |
| 			"  <chunk>\n"
 | |
| 			"    <page>0x1</page>\n"
 | |
| 			"    <data size=\"0x4\">1234</data>\n"
 | |
| 			"  </chunk>\n"
 | |
| 			"  <chunk>\n"
 | |
| 			"    <idx>0x1</idx>\n"
 | |
| 			"    <page>0x2</page>\n"
 | |
| 			"    <data size=\"0x2\">56</data>\n"
 | |
| 			"  </chunk>\n"
 | |
| 			"</chunks>\n");
 | |
| 
 | |
| 	chunked1 = fu_chunk_array_new((const guint8 *)"0123456789abcdef", 16, 0x0, 10, 4);
 | |
| 	chunked1_str = fu_chunk_array_to_string(chunked1);
 | |
| 	g_assert_cmpstr(chunked1_str,
 | |
| 			==,
 | |
| 			"<chunks>\n"
 | |
| 			"  <chunk>\n"
 | |
| 			"    <data size=\"0x4\">0123</data>\n"
 | |
| 			"  </chunk>\n"
 | |
| 			"  <chunk>\n"
 | |
| 			"    <idx>0x1</idx>\n"
 | |
| 			"    <addr>0x4</addr>\n"
 | |
| 			"    <data size=\"0x4\">4567</data>\n"
 | |
| 			"  </chunk>\n"
 | |
| 			"  <chunk>\n"
 | |
| 			"    <idx>0x2</idx>\n"
 | |
| 			"    <addr>0x8</addr>\n"
 | |
| 			"    <data size=\"0x2\">89</data>\n"
 | |
| 			"  </chunk>\n"
 | |
| 			"  <chunk>\n"
 | |
| 			"    <idx>0x3</idx>\n"
 | |
| 			"    <page>0x1</page>\n"
 | |
| 			"    <data size=\"0x4\">abcd</data>\n"
 | |
| 			"  </chunk>\n"
 | |
| 			"  <chunk>\n"
 | |
| 			"    <idx>0x4</idx>\n"
 | |
| 			"    <page>0x1</page>\n"
 | |
| 			"    <addr>0x4</addr>\n"
 | |
| 			"    <data size=\"0x2\">ef</data>\n"
 | |
| 			"  </chunk>\n"
 | |
| 			"</chunks>\n");
 | |
| 	chunked2 = fu_chunk_array_new((const guint8 *)"XXXXXXYYYYYYZZZZZZ", 18, 0x0, 6, 4);
 | |
| 	chunked2_str = fu_chunk_array_to_string(chunked2);
 | |
| 	g_print("\n%s", chunked2_str);
 | |
| 	g_assert_cmpstr(chunked2_str,
 | |
| 			==,
 | |
| 			"<chunks>\n"
 | |
| 			"  <chunk>\n"
 | |
| 			"    <data size=\"0x4\">XXXX</data>\n"
 | |
| 			"  </chunk>\n"
 | |
| 			"  <chunk>\n"
 | |
| 			"    <idx>0x1</idx>\n"
 | |
| 			"    <addr>0x4</addr>\n"
 | |
| 			"    <data size=\"0x2\">XX</data>\n"
 | |
| 			"  </chunk>\n"
 | |
| 			"  <chunk>\n"
 | |
| 			"    <idx>0x2</idx>\n"
 | |
| 			"    <page>0x1</page>\n"
 | |
| 			"    <data size=\"0x4\">YYYY</data>\n"
 | |
| 			"  </chunk>\n"
 | |
| 			"  <chunk>\n"
 | |
| 			"    <idx>0x3</idx>\n"
 | |
| 			"    <page>0x1</page>\n"
 | |
| 			"    <addr>0x4</addr>\n"
 | |
| 			"    <data size=\"0x2\">YY</data>\n"
 | |
| 			"  </chunk>\n"
 | |
| 			"  <chunk>\n"
 | |
| 			"    <idx>0x4</idx>\n"
 | |
| 			"    <page>0x2</page>\n"
 | |
| 			"    <data size=\"0x4\">ZZZZ</data>\n"
 | |
| 			"  </chunk>\n"
 | |
| 			"  <chunk>\n"
 | |
| 			"    <idx>0x5</idx>\n"
 | |
| 			"    <page>0x2</page>\n"
 | |
| 			"    <addr>0x4</addr>\n"
 | |
| 			"    <data size=\"0x2\">ZZ</data>\n"
 | |
| 			"  </chunk>\n"
 | |
| 			"</chunks>\n");
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_strstrip_func(void)
 | |
| {
 | |
| 	struct {
 | |
| 		const gchar *old;
 | |
| 		const gchar *new;
 | |
| 	} map[] = {{"same", "same"},
 | |
| 		   {" leading", "leading"},
 | |
| 		   {"tailing ", "tailing"},
 | |
| 		   {"  b  ", "b"},
 | |
| 		   {"  ", ""},
 | |
| 		   {NULL, NULL}};
 | |
| 	for (guint i = 0; map[i].old != NULL; i++) {
 | |
| 		g_autofree gchar *tmp = fu_strstrip(map[i].old);
 | |
| 		g_assert_cmpstr(tmp, ==, map[i].new);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_version_semver_func(void)
 | |
| {
 | |
| 	struct {
 | |
| 		const gchar *old;
 | |
| 		const gchar *new;
 | |
| 		FwupdVersionFormat fmt;
 | |
| 	} map[] = {{"1.2.3", "1.2.3", FWUPD_VERSION_FORMAT_TRIPLET},
 | |
| 		   {"1.2.3.4", "1.2.3", FWUPD_VERSION_FORMAT_TRIPLET},
 | |
| 		   {"1.2", "0.1.2", FWUPD_VERSION_FORMAT_TRIPLET},
 | |
| 		   {"1", "0.0.1", FWUPD_VERSION_FORMAT_TRIPLET},
 | |
| 		   {"CBET1.2.3", "1.2.3", FWUPD_VERSION_FORMAT_TRIPLET},
 | |
| 		   {"4.11-1190-g12d8072e6b-dirty", "4.11.1190", FWUPD_VERSION_FORMAT_TRIPLET},
 | |
| 		   {"4.11-1190-g12d8072e6b-dirty", "4.11", FWUPD_VERSION_FORMAT_PAIR},
 | |
| 		   {NULL, NULL}};
 | |
| 	for (guint i = 0; map[i].old != NULL; i++) {
 | |
| 		g_autofree gchar *tmp = fu_version_ensure_semver(map[i].old, map[i].fmt);
 | |
| 		g_assert_cmpstr(tmp, ==, map[i].new);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_strtoull_func(void)
 | |
| {
 | |
| 	gboolean ret;
 | |
| 	guint64 val = 0;
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 
 | |
| 	ret = fu_strtoull("123", &val, 123, 200, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	g_assert_cmpint(val, ==, 123);
 | |
| 
 | |
| 	ret = fu_strtoull("123\n", &val, 0, 200, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	g_assert_cmpint(val, ==, 123);
 | |
| 
 | |
| 	ret = fu_strtoull("0x123", &val, 0, 0x123, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	g_assert_cmpint(val, ==, 0x123);
 | |
| 
 | |
| 	ret = fu_strtoull(NULL, &val, 0, G_MAXUINT32, NULL);
 | |
| 	g_assert_false(ret);
 | |
| 	ret = fu_strtoull("", &val, 120, 123, NULL);
 | |
| 	g_assert_false(ret);
 | |
| 	ret = fu_strtoull("124", &val, 120, 123, NULL);
 | |
| 	g_assert_false(ret);
 | |
| 	ret = fu_strtoull("119", &val, 120, 123, NULL);
 | |
| 	g_assert_false(ret);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_common_version_func(void)
 | |
| {
 | |
| 	guint i;
 | |
| 	struct {
 | |
| 		guint32 val;
 | |
| 		const gchar *ver;
 | |
| 		FwupdVersionFormat flags;
 | |
| 	} version_from_uint32[] = {
 | |
| 	    {0x0, "0.0.0.0", FWUPD_VERSION_FORMAT_QUAD},
 | |
| 	    {0xff, "0.0.0.255", FWUPD_VERSION_FORMAT_QUAD},
 | |
| 	    {0xff01, "0.0.255.1", FWUPD_VERSION_FORMAT_QUAD},
 | |
| 	    {0xff0001, "0.255.0.1", FWUPD_VERSION_FORMAT_QUAD},
 | |
| 	    {0xff000100, "255.0.1.0", FWUPD_VERSION_FORMAT_QUAD},
 | |
| 	    {0x0, "0.0.0", FWUPD_VERSION_FORMAT_TRIPLET},
 | |
| 	    {0xff, "0.0.255", FWUPD_VERSION_FORMAT_TRIPLET},
 | |
| 	    {0xff01, "0.0.65281", FWUPD_VERSION_FORMAT_TRIPLET},
 | |
| 	    {0xff0001, "0.255.1", FWUPD_VERSION_FORMAT_TRIPLET},
 | |
| 	    {0xff000100, "255.0.256", FWUPD_VERSION_FORMAT_TRIPLET},
 | |
| 	    {0x0, "0", FWUPD_VERSION_FORMAT_NUMBER},
 | |
| 	    {0xff000100, "4278190336", FWUPD_VERSION_FORMAT_NUMBER},
 | |
| 	    {0x0, "11.0.0.0", FWUPD_VERSION_FORMAT_INTEL_ME},
 | |
| 	    {0xffffffff, "18.31.255.65535", FWUPD_VERSION_FORMAT_INTEL_ME},
 | |
| 	    {0x0b32057a, "11.11.50.1402", FWUPD_VERSION_FORMAT_INTEL_ME},
 | |
| 	    {0xb8320d84, "11.8.50.3460", FWUPD_VERSION_FORMAT_INTEL_ME2},
 | |
| 	    {0x226a4b00, "137.2706.768", FWUPD_VERSION_FORMAT_SURFACE_LEGACY},
 | |
| 	    {0x6001988, "6.25.136", FWUPD_VERSION_FORMAT_SURFACE},
 | |
| 	    {0x00ff0001, "255.0.1", FWUPD_VERSION_FORMAT_DELL_BIOS},
 | |
| 	    {0xc8, "0x000000c8", FWUPD_VERSION_FORMAT_HEX},
 | |
| 	    {0, NULL}};
 | |
| 	struct {
 | |
| 		guint32 val;
 | |
| 		const gchar *ver;
 | |
| 		FwupdVersionFormat flags;
 | |
| 	} version_from_uint24[] = {{0x0, NULL, FWUPD_VERSION_FORMAT_QUAD},
 | |
| 				   {0x0, "0.0.0", FWUPD_VERSION_FORMAT_TRIPLET},
 | |
| 				   {0xff, "0.0.255", FWUPD_VERSION_FORMAT_TRIPLET},
 | |
| 				   {0x0, "0", FWUPD_VERSION_FORMAT_NUMBER},
 | |
| 				   {0xc8, "0x0000c8", FWUPD_VERSION_FORMAT_HEX},
 | |
| 				   {0, NULL}};
 | |
| 	struct {
 | |
| 		guint64 val;
 | |
| 		const gchar *ver;
 | |
| 		FwupdVersionFormat flags;
 | |
| 	} version_from_uint64[] = {
 | |
| 	    {0x0, "0.0.0.0", FWUPD_VERSION_FORMAT_QUAD},
 | |
| 	    {0xff, "0.0.0.255", FWUPD_VERSION_FORMAT_QUAD},
 | |
| 	    {0xffffffffffffffff, "65535.65535.65535.65535", FWUPD_VERSION_FORMAT_QUAD},
 | |
| 	    {0xff, "0.255", FWUPD_VERSION_FORMAT_PAIR},
 | |
| 	    {0xffffffffffffffff, "4294967295.4294967295", FWUPD_VERSION_FORMAT_PAIR},
 | |
| 	    {0x0, "0", FWUPD_VERSION_FORMAT_NUMBER},
 | |
| 	    {0x11000000c8, "0x00000011000000c8", FWUPD_VERSION_FORMAT_HEX},
 | |
| 	    {0, NULL}};
 | |
| 	struct {
 | |
| 		guint16 val;
 | |
| 		const gchar *ver;
 | |
| 		FwupdVersionFormat flags;
 | |
| 	} version_from_uint16[] = {{0x0, "0.0", FWUPD_VERSION_FORMAT_PAIR},
 | |
| 				   {0xff, "0.255", FWUPD_VERSION_FORMAT_PAIR},
 | |
| 				   {0xff01, "255.1", FWUPD_VERSION_FORMAT_PAIR},
 | |
| 				   {0x0, "0.0", FWUPD_VERSION_FORMAT_BCD},
 | |
| 				   {0x0110, "1.10", FWUPD_VERSION_FORMAT_BCD},
 | |
| 				   {0x9999, "99.99", FWUPD_VERSION_FORMAT_BCD},
 | |
| 				   {0x0, "0", FWUPD_VERSION_FORMAT_NUMBER},
 | |
| 				   {0x1234, "4660", FWUPD_VERSION_FORMAT_NUMBER},
 | |
| 				   {0, NULL}};
 | |
| 	struct {
 | |
| 		const gchar *old;
 | |
| 		const gchar *new;
 | |
| 	} version_parse[] = {{"0", "0"},
 | |
| 			     {"0x1a", "0.0.26"},
 | |
| 			     {"257", "0.0.257"},
 | |
| 			     {"1.2.3", "1.2.3"},
 | |
| 			     {"0xff0001", "0.255.1"},
 | |
| 			     {"16711681", "0.255.1"},
 | |
| 			     {"20150915", "20150915"},
 | |
| 			     {"dave", "dave"},
 | |
| 			     {"0x1x", "0x1x"},
 | |
| 			     {NULL, NULL}};
 | |
| 
 | |
| 	/* check version conversion */
 | |
| 	for (i = 0; version_from_uint64[i].ver != NULL; i++) {
 | |
| 		g_autofree gchar *ver = NULL;
 | |
| 		ver = fu_version_from_uint64(version_from_uint64[i].val,
 | |
| 					     version_from_uint64[i].flags);
 | |
| 		g_assert_cmpstr(ver, ==, version_from_uint64[i].ver);
 | |
| 	}
 | |
| 	for (i = 0; version_from_uint32[i].ver != NULL; i++) {
 | |
| 		g_autofree gchar *ver = NULL;
 | |
| 		ver = fu_version_from_uint32(version_from_uint32[i].val,
 | |
| 					     version_from_uint32[i].flags);
 | |
| 		g_assert_cmpstr(ver, ==, version_from_uint32[i].ver);
 | |
| 	}
 | |
| 	for (i = 0; version_from_uint24[i].ver != NULL; i++) {
 | |
| 		g_autofree gchar *ver = NULL;
 | |
| 		ver = fu_version_from_uint24(version_from_uint24[i].val,
 | |
| 					     version_from_uint24[i].flags);
 | |
| 		g_assert_cmpstr(ver, ==, version_from_uint24[i].ver);
 | |
| 	}
 | |
| 	for (i = 0; version_from_uint16[i].ver != NULL; i++) {
 | |
| 		g_autofree gchar *ver = NULL;
 | |
| 		ver = fu_version_from_uint16(version_from_uint16[i].val,
 | |
| 					     version_from_uint16[i].flags);
 | |
| 		g_assert_cmpstr(ver, ==, version_from_uint16[i].ver);
 | |
| 	}
 | |
| 
 | |
| 	/* check version parsing */
 | |
| 	for (i = 0; version_parse[i].old != NULL; i++) {
 | |
| 		g_autofree gchar *ver = NULL;
 | |
| 		ver = fu_version_parse_from_format(version_parse[i].old,
 | |
| 						   FWUPD_VERSION_FORMAT_TRIPLET);
 | |
| 		g_assert_cmpstr(ver, ==, version_parse[i].new);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_common_vercmp_func(void)
 | |
| {
 | |
| 	/* same */
 | |
| 	g_assert_cmpint(fu_version_compare("1.2.3", "1.2.3", FWUPD_VERSION_FORMAT_UNKNOWN), ==, 0);
 | |
| 	g_assert_cmpint(
 | |
| 	    fu_version_compare("001.002.003", "001.002.003", FWUPD_VERSION_FORMAT_UNKNOWN),
 | |
| 	    ==,
 | |
| 	    0);
 | |
| 	g_assert_cmpint(fu_version_compare("0x00000002", "0x2", FWUPD_VERSION_FORMAT_HEX), ==, 0);
 | |
| 
 | |
| 	/* upgrade and downgrade */
 | |
| 	g_assert_cmpint(fu_version_compare("1.2.3", "1.2.4", FWUPD_VERSION_FORMAT_UNKNOWN), <, 0);
 | |
| 	g_assert_cmpint(
 | |
| 	    fu_version_compare("001.002.000", "001.002.009", FWUPD_VERSION_FORMAT_UNKNOWN),
 | |
| 	    <,
 | |
| 	    0);
 | |
| 	g_assert_cmpint(fu_version_compare("1.2.3", "1.2.2", FWUPD_VERSION_FORMAT_UNKNOWN), >, 0);
 | |
| 	g_assert_cmpint(
 | |
| 	    fu_version_compare("001.002.009", "001.002.000", FWUPD_VERSION_FORMAT_UNKNOWN),
 | |
| 	    >,
 | |
| 	    0);
 | |
| 
 | |
| 	/* unequal depth */
 | |
| 	g_assert_cmpint(fu_version_compare("1.2.3", "1.2.3.1", FWUPD_VERSION_FORMAT_UNKNOWN), <, 0);
 | |
| 	g_assert_cmpint(fu_version_compare("1.2.3.1", "1.2.4", FWUPD_VERSION_FORMAT_UNKNOWN), <, 0);
 | |
| 
 | |
| 	/* mixed-alpha-numeric */
 | |
| 	g_assert_cmpint(fu_version_compare("1.2.3a", "1.2.3a", FWUPD_VERSION_FORMAT_UNKNOWN),
 | |
| 			==,
 | |
| 			0);
 | |
| 	g_assert_cmpint(fu_version_compare("1.2.3a", "1.2.3b", FWUPD_VERSION_FORMAT_UNKNOWN), <, 0);
 | |
| 	g_assert_cmpint(fu_version_compare("1.2.3b", "1.2.3a", FWUPD_VERSION_FORMAT_UNKNOWN), >, 0);
 | |
| 
 | |
| 	/* alpha version append */
 | |
| 	g_assert_cmpint(fu_version_compare("1.2.3", "1.2.3a", FWUPD_VERSION_FORMAT_UNKNOWN), <, 0);
 | |
| 	g_assert_cmpint(fu_version_compare("1.2.3a", "1.2.3", FWUPD_VERSION_FORMAT_UNKNOWN), >, 0);
 | |
| 
 | |
| 	/* alpha only */
 | |
| 	g_assert_cmpint(fu_version_compare("alpha", "alpha", FWUPD_VERSION_FORMAT_UNKNOWN), ==, 0);
 | |
| 	g_assert_cmpint(fu_version_compare("alpha", "beta", FWUPD_VERSION_FORMAT_UNKNOWN), <, 0);
 | |
| 	g_assert_cmpint(fu_version_compare("beta", "alpha", FWUPD_VERSION_FORMAT_UNKNOWN), >, 0);
 | |
| 
 | |
| 	/* alpha-compare */
 | |
| 	g_assert_cmpint(fu_version_compare("1.2a.3", "1.2a.3", FWUPD_VERSION_FORMAT_UNKNOWN),
 | |
| 			==,
 | |
| 			0);
 | |
| 	g_assert_cmpint(fu_version_compare("1.2a.3", "1.2b.3", FWUPD_VERSION_FORMAT_UNKNOWN), <, 0);
 | |
| 	g_assert_cmpint(fu_version_compare("1.2b.3", "1.2a.3", FWUPD_VERSION_FORMAT_UNKNOWN), >, 0);
 | |
| 
 | |
| 	/* tilde is all-powerful */
 | |
| 	g_assert_cmpint(fu_version_compare("1.2.3~rc1", "1.2.3~rc1", FWUPD_VERSION_FORMAT_UNKNOWN),
 | |
| 			==,
 | |
| 			0);
 | |
| 	g_assert_cmpint(fu_version_compare("1.2.3~rc1", "1.2.3", FWUPD_VERSION_FORMAT_UNKNOWN),
 | |
| 			<,
 | |
| 			0);
 | |
| 	g_assert_cmpint(fu_version_compare("1.2.3", "1.2.3~rc1", FWUPD_VERSION_FORMAT_UNKNOWN),
 | |
| 			>,
 | |
| 			0);
 | |
| 	g_assert_cmpint(fu_version_compare("1.2.3~rc2", "1.2.3~rc1", FWUPD_VERSION_FORMAT_UNKNOWN),
 | |
| 			>,
 | |
| 			0);
 | |
| 
 | |
| 	/* invalid */
 | |
| 	g_assert_cmpint(fu_version_compare("1", NULL, FWUPD_VERSION_FORMAT_UNKNOWN), ==, G_MAXINT);
 | |
| 	g_assert_cmpint(fu_version_compare(NULL, "1", FWUPD_VERSION_FORMAT_UNKNOWN), ==, G_MAXINT);
 | |
| 	g_assert_cmpint(fu_version_compare(NULL, NULL, FWUPD_VERSION_FORMAT_UNKNOWN), ==, G_MAXINT);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_firmware_raw_aligned_func(void)
 | |
| {
 | |
| 	gboolean ret;
 | |
| 	g_autoptr(FuFirmware) firmware1 = fu_firmware_new();
 | |
| 	g_autoptr(FuFirmware) firmware2 = fu_firmware_new();
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 	g_autoptr(GBytes) blob = g_bytes_new_static("hello", 5);
 | |
| 
 | |
| 	/* no alignment */
 | |
| 	ret = fu_firmware_parse(firmware1, blob, FWUPD_INSTALL_FLAG_NO_SEARCH, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 
 | |
| 	/* invalid alignment */
 | |
| 	fu_firmware_set_alignment(firmware2, FU_FIRMWARE_ALIGNMENT_4K);
 | |
| 	ret = fu_firmware_parse(firmware2, blob, FWUPD_INSTALL_FLAG_NO_SEARCH, &error);
 | |
| 	g_assert_error(error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE);
 | |
| 	g_assert_false(ret);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_firmware_ihex_func(void)
 | |
| {
 | |
| 	const guint8 *data;
 | |
| 	gboolean ret;
 | |
| 	gsize len;
 | |
| 	g_autofree gchar *filename_hex = NULL;
 | |
| 	g_autofree gchar *filename_ref = NULL;
 | |
| 	g_autofree gchar *str = NULL;
 | |
| 	g_autoptr(FuFirmware) firmware = fu_ihex_firmware_new();
 | |
| 	g_autoptr(GBytes) data_file = NULL;
 | |
| 	g_autoptr(GBytes) data_fw = NULL;
 | |
| 	g_autoptr(GBytes) data_hex = NULL;
 | |
| 	g_autoptr(GBytes) data_ref = NULL;
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 
 | |
| 	/* load a Intel hex32 file */
 | |
| 	filename_hex = g_test_build_filename(G_TEST_DIST, "tests", "firmware.hex", NULL);
 | |
| 	data_file = fu_bytes_get_contents(filename_hex, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(data_file);
 | |
| 	ret = fu_firmware_parse(firmware, data_file, FWUPD_INSTALL_FLAG_NO_SEARCH, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	data_fw = fu_firmware_get_bytes(firmware, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(data_fw);
 | |
| 	g_assert_cmpint(g_bytes_get_size(data_fw), ==, 136);
 | |
| 
 | |
| 	/* did we match the reference file? */
 | |
| 	filename_ref = g_test_build_filename(G_TEST_DIST, "tests", "firmware.bin", NULL);
 | |
| 	data_ref = fu_bytes_get_contents(filename_ref, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(data_ref);
 | |
| 	ret = fu_bytes_compare(data_fw, data_ref, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 
 | |
| 	/* export a ihex file (which will be slightly different due to
 | |
| 	 * non-continuous regions being expanded */
 | |
| 	data_hex = fu_firmware_write(firmware, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(data_hex);
 | |
| 	data = g_bytes_get_data(data_hex, &len);
 | |
| 	str = g_strndup((const gchar *)data, len);
 | |
| 	g_assert_cmpstr(str,
 | |
| 			==,
 | |
| 			":104000003DEF20F000000000FACF01F0FBCF02F0FE\n"
 | |
| 			":10401000E9CF03F0EACF04F0E1CF05F0E2CF06F0FC\n"
 | |
| 			":10402000D9CF07F0DACF08F0F3CF09F0F4CF0AF0D8\n"
 | |
| 			":10403000F6CF0BF0F7CF0CF0F8CF0DF0F5CF0EF078\n"
 | |
| 			":104040000EC0F5FF0DC0F8FF0CC0F7FF0BC0F6FF68\n"
 | |
| 			":104050000AC0F4FF09C0F3FF08C0DAFF07C0D9FFA8\n"
 | |
| 			":1040600006C0E2FF05C0E1FF04C0EAFF03C0E9FFAC\n"
 | |
| 			":1040700002C0FBFF01C0FAFF11003FEF20F000017A\n"
 | |
| 			":0840800042EF20F03DEF20F0BB\n"
 | |
| 			":00000001FF\n");
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_firmware_ihex_signed_func(void)
 | |
| {
 | |
| 	const guint8 *data;
 | |
| 	gboolean ret;
 | |
| 	gsize len;
 | |
| 	g_autofree gchar *filename_shex = NULL;
 | |
| 	g_autoptr(FuFirmware) firmware = fu_ihex_firmware_new();
 | |
| 	g_autoptr(GBytes) data_file = NULL;
 | |
| 	g_autoptr(GBytes) data_fw = NULL;
 | |
| 	g_autoptr(GBytes) data_sig = NULL;
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 
 | |
| 	/* load a signed Intel hex32 file */
 | |
| 	filename_shex = g_test_build_filename(G_TEST_DIST, "tests", "firmware.shex", NULL);
 | |
| 	data_file = fu_bytes_get_contents(filename_shex, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(data_file);
 | |
| 	ret = fu_firmware_parse(firmware, data_file, FWUPD_INSTALL_FLAG_NO_SEARCH, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	data_fw = fu_firmware_get_bytes(firmware, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(data_fw);
 | |
| 	g_assert_cmpint(g_bytes_get_size(data_fw), ==, 136);
 | |
| 
 | |
| 	/* get the signed image */
 | |
| 	data_sig = fu_firmware_get_image_by_id_bytes(firmware, FU_FIRMWARE_ID_SIGNATURE, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(data_sig);
 | |
| 	data = g_bytes_get_data(data_sig, &len);
 | |
| 	g_assert_cmpint(len, ==, 8);
 | |
| 	g_assert_nonnull(data);
 | |
| 	g_assert_cmpint(memcmp(data, "deadbeef", 8), ==, 0);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_firmware_ihex_offset_func(void)
 | |
| {
 | |
| 	const guint8 *data;
 | |
| 	gboolean ret;
 | |
| 	gsize len;
 | |
| 	g_autofree gchar *str = NULL;
 | |
| 	g_autoptr(FuFirmware) firmware = fu_ihex_firmware_new();
 | |
| 	g_autoptr(FuFirmware) firmware_verify = fu_ihex_firmware_new();
 | |
| 	g_autoptr(GBytes) data_bin = NULL;
 | |
| 	g_autoptr(GBytes) data_dummy = NULL;
 | |
| 	g_autoptr(GBytes) data_verify = NULL;
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 
 | |
| 	/* add a 4 byte image in high memory */
 | |
| 	data_dummy = g_bytes_new_static("foo", 4);
 | |
| 	fu_firmware_set_addr(firmware, 0x80000000);
 | |
| 	fu_firmware_set_bytes(firmware, data_dummy);
 | |
| 	data_bin = fu_firmware_write(firmware, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(data_bin);
 | |
| 	data = g_bytes_get_data(data_bin, &len);
 | |
| 	str = g_strndup((const gchar *)data, len);
 | |
| 	g_assert_cmpstr(str,
 | |
| 			==,
 | |
| 			":0200000480007A\n"
 | |
| 			":04000000666F6F00B8\n"
 | |
| 			":00000001FF\n");
 | |
| 
 | |
| 	/* check we can load it too */
 | |
| 	ret = fu_firmware_parse(firmware_verify, data_bin, FWUPD_INSTALL_FLAG_NO_SEARCH, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	g_assert_cmpint(fu_firmware_get_addr(firmware_verify), ==, 0x80000000);
 | |
| 	data_verify = fu_firmware_get_bytes(firmware_verify, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(data_verify);
 | |
| 	g_assert_cmpint(g_bytes_get_size(data_verify), ==, 0x4);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_firmware_srec_func(void)
 | |
| {
 | |
| 	gboolean ret;
 | |
| 	g_autofree gchar *filename_srec = NULL;
 | |
| 	g_autofree gchar *filename_ref = NULL;
 | |
| 	g_autoptr(FuFirmware) firmware = fu_srec_firmware_new();
 | |
| 	g_autoptr(GBytes) data_ref = NULL;
 | |
| 	g_autoptr(GBytes) data_srec = NULL;
 | |
| 	g_autoptr(GBytes) data_bin = NULL;
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 
 | |
| 	filename_srec = g_test_build_filename(G_TEST_DIST, "tests", "firmware.srec", NULL);
 | |
| 	data_srec = fu_bytes_get_contents(filename_srec, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(data_srec);
 | |
| 	ret = fu_firmware_parse(firmware, data_srec, FWUPD_INSTALL_FLAG_NO_SEARCH, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	data_bin = fu_firmware_get_bytes(firmware, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(data_bin);
 | |
| 	g_assert_cmpint(g_bytes_get_size(data_bin), ==, 136);
 | |
| 
 | |
| 	/* did we match the reference file? */
 | |
| 	filename_ref = g_test_build_filename(G_TEST_DIST, "tests", "firmware.bin", NULL);
 | |
| 	data_ref = fu_bytes_get_contents(filename_ref, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(data_ref);
 | |
| 	ret = fu_bytes_compare(data_bin, data_ref, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_firmware_fdt_func(void)
 | |
| {
 | |
| 	gboolean ret;
 | |
| 	guint32 val32 = 0;
 | |
| 	guint64 val64 = 0;
 | |
| 	g_autofree gchar *filename = NULL;
 | |
| 	g_autofree gchar *val = NULL;
 | |
| 	g_autofree gchar *str = NULL;
 | |
| 	g_autoptr(FuFirmware) firmware = fu_fdt_firmware_new();
 | |
| 	g_autoptr(FuFirmware) img1 = NULL;
 | |
| 	g_autoptr(FuFdtImage) img2 = NULL;
 | |
| 	g_autoptr(GBytes) data = NULL;
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 
 | |
| 	filename = g_test_build_filename(G_TEST_DIST, "tests", "fdt.bin", NULL);
 | |
| 	data = fu_bytes_get_contents(filename, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(data);
 | |
| 	ret = fu_firmware_parse(firmware, data, FWUPD_INSTALL_FLAG_NO_SEARCH, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	g_assert_cmpint(fu_fdt_firmware_get_cpuid(FU_FDT_FIRMWARE(firmware)), ==, 0x0);
 | |
| 	str = fu_firmware_to_string(firmware);
 | |
| 	g_debug("%s", str);
 | |
| 
 | |
| 	img1 = fu_firmware_get_image_by_id(firmware, NULL, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(img1);
 | |
| 	ret = fu_fdt_image_get_attr_str(FU_FDT_IMAGE(img1), "key", &val, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	g_assert_cmpstr(val, ==, "hello world");
 | |
| 
 | |
| 	/* get image, and get the uint32 attr */
 | |
| 	img2 = fu_fdt_firmware_get_image_by_path(FU_FDT_FIRMWARE(firmware),
 | |
| 						 "/images/firmware-1",
 | |
| 						 &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(img2);
 | |
| 	ret = fu_fdt_image_get_attr_u32(FU_FDT_IMAGE(img2), "key", &val32, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	g_assert_cmpint(val32, ==, 0x123);
 | |
| 
 | |
| 	/* wrong type */
 | |
| 	ret = fu_fdt_image_get_attr_u64(img2, "key", &val64, &error);
 | |
| 	g_assert_error(error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA);
 | |
| 	g_assert_false(ret);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_firmware_fit_func(void)
 | |
| {
 | |
| 	gboolean ret;
 | |
| 	g_autofree gchar *filename = NULL;
 | |
| 	g_autofree gchar *str = NULL;
 | |
| 	g_auto(GStrv) val = NULL;
 | |
| 	g_autoptr(FuFdtImage) img1 = NULL;
 | |
| 	g_autoptr(FuFirmware) firmware = fu_fit_firmware_new();
 | |
| 	g_autoptr(GBytes) data = NULL;
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 
 | |
| 	filename = g_test_build_filename(G_TEST_DIST, "tests", "fit.bin", NULL);
 | |
| 	data = fu_bytes_get_contents(filename, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(data);
 | |
| 	ret = fu_firmware_parse(firmware, data, FWUPD_INSTALL_FLAG_NO_SEARCH, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	g_assert_cmpint(fu_fit_firmware_get_timestamp(FU_FIT_FIRMWARE(firmware)), ==, 0x629D4ABD);
 | |
| 	str = fu_firmware_to_string(firmware);
 | |
| 	g_debug("%s", str);
 | |
| 
 | |
| 	img1 = fu_fdt_firmware_get_image_by_path(FU_FDT_FIRMWARE(firmware),
 | |
| 						 "/configurations/conf-1",
 | |
| 						 &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(img1);
 | |
| 	ret = fu_fdt_image_get_attr_strlist(FU_FDT_IMAGE(img1),
 | |
| 					    FU_FIT_FIRMWARE_ATTR_COMPATIBLE,
 | |
| 					    &val,
 | |
| 					    &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	g_assert_nonnull(val);
 | |
| 	g_assert_cmpstr(val[0], ==, "alice");
 | |
| 	g_assert_cmpstr(val[1], ==, "bob");
 | |
| 	g_assert_cmpstr(val[2], ==, "clara");
 | |
| 	g_assert_cmpstr(val[3], ==, NULL);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_firmware_srec_tokenization_func(void)
 | |
| {
 | |
| 	FuSrecFirmwareRecord *rcd;
 | |
| 	GPtrArray *records;
 | |
| 	gboolean ret;
 | |
| 	g_autoptr(FuFirmware) firmware = fu_srec_firmware_new();
 | |
| 	g_autoptr(GBytes) data_srec = NULL;
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 	const gchar *buf = "S3060000001400E5\r\n"
 | |
| 			   "S31000000002281102000000007F0304002C\r\n"
 | |
| 			   "S306000000145095\r\n"
 | |
| 			   "S70500000000FA\r\n";
 | |
| 	data_srec = g_bytes_new_static(buf, strlen(buf));
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(data_srec);
 | |
| 	ret = fu_firmware_tokenize(firmware, data_srec, FWUPD_INSTALL_FLAG_NONE, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 
 | |
| 	records = fu_srec_firmware_get_records(FU_SREC_FIRMWARE(firmware));
 | |
| 	g_assert_nonnull(records);
 | |
| 	g_assert_cmpint(records->len, ==, 4);
 | |
| 	rcd = g_ptr_array_index(records, 2);
 | |
| 	g_assert_nonnull(rcd);
 | |
| 	g_assert_cmpint(rcd->ln, ==, 0x3);
 | |
| 	g_assert_cmpint(rcd->kind, ==, 3);
 | |
| 	g_assert_cmpint(rcd->addr, ==, 0x14);
 | |
| 	g_assert_cmpint(rcd->buf->len, ==, 0x1);
 | |
| 	g_assert_cmpint(rcd->buf->data[0], ==, 0x50);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_firmware_build_func(void)
 | |
| {
 | |
| 	gboolean ret;
 | |
| 	g_autofree gchar *str = NULL;
 | |
| 	g_autoptr(FuFirmware) firmware = fu_firmware_new();
 | |
| 	g_autoptr(FuFirmware) img = NULL;
 | |
| 	g_autoptr(GBytes) blob = NULL;
 | |
| 	g_autoptr(GBytes) blob2 = NULL;
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 	g_autoptr(XbBuilder) builder = xb_builder_new();
 | |
| 	g_autoptr(XbBuilderSource) source = xb_builder_source_new();
 | |
| 	g_autoptr(XbNode) n = NULL;
 | |
| 	g_autoptr(XbSilo) silo = NULL;
 | |
| 	const gchar *buf = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
 | |
| 			   "<firmware>\n"
 | |
| 			   "  <version>1.2.3</version>\n"
 | |
| 			   "  <firmware>\n"
 | |
| 			   "    <version>4.5.6</version>\n"
 | |
| 			   "    <id>header</id>\n"
 | |
| 			   "    <idx>456</idx>\n"
 | |
| 			   "    <addr>0x456</addr>\n"
 | |
| 			   "    <data>aGVsbG8=</data>\n"
 | |
| 			   "  </firmware>\n"
 | |
| 			   "  <firmware>\n"
 | |
| 			   "    <version>7.8.9</version>\n"
 | |
| 			   "    <id>header</id>\n"
 | |
| 			   "    <idx>789</idx>\n"
 | |
| 			   "    <addr>0x789</addr>\n"
 | |
| 			   "  </firmware>\n"
 | |
| 			   "</firmware>\n";
 | |
| 	blob = g_bytes_new_static(buf, strlen(buf));
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(blob);
 | |
| 
 | |
| 	/* parse XML */
 | |
| 	ret = xb_builder_source_load_bytes(source, blob, XB_BUILDER_SOURCE_FLAG_NONE, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	xb_builder_import_source(builder, source);
 | |
| 	silo = xb_builder_compile(builder, XB_BUILDER_COMPILE_FLAG_NONE, NULL, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(silo);
 | |
| 	n = xb_silo_query_first(silo, "firmware", &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(n);
 | |
| 
 | |
| 	/* build object */
 | |
| 	ret = fu_firmware_build(firmware, n, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	g_assert_cmpstr(fu_firmware_get_version(firmware), ==, "1.2.3");
 | |
| 
 | |
| 	/* verify image */
 | |
| 	img = fu_firmware_get_image_by_id(firmware, "header", &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(img);
 | |
| 	g_assert_cmpstr(fu_firmware_get_version(img), ==, "4.5.6");
 | |
| 	g_assert_cmpint(fu_firmware_get_idx(img), ==, 456);
 | |
| 	g_assert_cmpint(fu_firmware_get_addr(img), ==, 0x456);
 | |
| 	blob2 = fu_firmware_write(img, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(blob2);
 | |
| 	g_assert_cmpint(g_bytes_get_size(blob2), ==, 5);
 | |
| 	str = g_strndup(g_bytes_get_data(blob2, NULL), g_bytes_get_size(blob2));
 | |
| 	g_assert_cmpstr(str, ==, "hello");
 | |
| }
 | |
| 
 | |
| static gsize
 | |
| fu_firmware_dfuse_image_get_size(FuFirmware *self)
 | |
| {
 | |
| 	g_autoptr(GPtrArray) chunks = fu_firmware_get_chunks(self, NULL);
 | |
| 	gsize length = 0;
 | |
| 	for (guint i = 0; i < chunks->len; i++) {
 | |
| 		FuChunk *chk = g_ptr_array_index(chunks, i);
 | |
| 		length += fu_chunk_get_data_sz(chk);
 | |
| 	}
 | |
| 	return length;
 | |
| }
 | |
| 
 | |
| static gsize
 | |
| fu_firmware_dfuse_get_size(FuFirmware *firmware)
 | |
| {
 | |
| 	gsize length = 0;
 | |
| 	g_autoptr(GPtrArray) images = fu_firmware_get_images(firmware);
 | |
| 	for (guint i = 0; i < images->len; i++) {
 | |
| 		FuFirmware *image = g_ptr_array_index(images, i);
 | |
| 		length += fu_firmware_dfuse_image_get_size(image);
 | |
| 	}
 | |
| 	return length;
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_firmware_dfuse_func(void)
 | |
| {
 | |
| 	gboolean ret;
 | |
| 	g_autofree gchar *filename = NULL;
 | |
| 	g_autoptr(FuFirmware) firmware = fu_dfuse_firmware_new();
 | |
| 	g_autoptr(GBytes) roundtrip_orig = NULL;
 | |
| 	g_autoptr(GBytes) roundtrip = NULL;
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 
 | |
| 	/* load a DfuSe firmware */
 | |
| 	filename = g_test_build_filename(G_TEST_DIST, "tests", "firmware.dfuse", NULL);
 | |
| 	g_assert_nonnull(filename);
 | |
| 	roundtrip_orig = fu_bytes_get_contents(filename, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(roundtrip_orig);
 | |
| 	ret = fu_firmware_parse(firmware, roundtrip_orig, FWUPD_INSTALL_FLAG_NO_SEARCH, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	g_assert_cmpint(fu_dfu_firmware_get_vid(FU_DFU_FIRMWARE(firmware)), ==, 0x1234);
 | |
| 	g_assert_cmpint(fu_dfu_firmware_get_pid(FU_DFU_FIRMWARE(firmware)), ==, 0x5678);
 | |
| 	g_assert_cmpint(fu_dfu_firmware_get_release(FU_DFU_FIRMWARE(firmware)), ==, 0x8642);
 | |
| 	g_assert_cmpint(fu_firmware_dfuse_get_size(firmware), ==, 0x21);
 | |
| 
 | |
| 	/* can we roundtrip without losing data */
 | |
| 	roundtrip = fu_firmware_write(firmware, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(roundtrip);
 | |
| 	ret = fu_bytes_compare(roundtrip, roundtrip_orig, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_firmware_fmap_func(void)
 | |
| {
 | |
| 	gboolean ret;
 | |
| 	g_autofree gchar *filename = NULL;
 | |
| 	g_autofree gchar *img_str = NULL;
 | |
| 	g_autoptr(FuFirmware) firmware = fu_fmap_firmware_new();
 | |
| 	g_autoptr(FuFirmware) img = NULL;
 | |
| 	g_autoptr(GBytes) img_blob = NULL;
 | |
| 	g_autoptr(GBytes) roundtrip = NULL;
 | |
| 	g_autoptr(GBytes) roundtrip_orig = NULL;
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 	g_autoptr(GPtrArray) images = NULL;
 | |
| 
 | |
| #ifndef HAVE_MEMMEM
 | |
| 	g_test_skip("no memmem()");
 | |
| 	return;
 | |
| #endif
 | |
| 
 | |
| 	/* load firmware */
 | |
| 	filename = g_test_build_filename(G_TEST_DIST, "tests", "fmap-offset.bin", NULL);
 | |
| 	g_assert_nonnull(filename);
 | |
| 	roundtrip_orig = fu_bytes_get_contents(filename, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(roundtrip_orig);
 | |
| 	ret = fu_firmware_parse(firmware, roundtrip_orig, FWUPD_INSTALL_FLAG_NONE, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 
 | |
| 	/* check image count */
 | |
| 	images = fu_firmware_get_images(firmware);
 | |
| 	g_assert_cmpint(images->len, ==, 2);
 | |
| 
 | |
| 	/* get a specific image */
 | |
| 	img = fu_firmware_get_image_by_id(firmware, "FMAP", &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(img);
 | |
| 	img_blob = fu_firmware_get_bytes(img, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(img_blob);
 | |
| 	g_assert_cmpint(g_bytes_get_size(img_blob), ==, 0xb);
 | |
| 	img_str = g_strndup(g_bytes_get_data(img_blob, NULL), g_bytes_get_size(img_blob));
 | |
| 	g_assert_cmpstr(img_str, ==, "hello world");
 | |
| 
 | |
| 	/* can we roundtrip without losing data */
 | |
| 	roundtrip = fu_firmware_write(firmware, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(roundtrip);
 | |
| 	ret = fu_bytes_compare(roundtrip, roundtrip_orig, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_firmware_new_from_gtypes_func(void)
 | |
| {
 | |
| 	g_autofree gchar *fn = NULL;
 | |
| 	g_autoptr(FuFirmware) firmware1 = NULL;
 | |
| 	g_autoptr(FuFirmware) firmware2 = NULL;
 | |
| 	g_autoptr(FuFirmware) firmware3 = NULL;
 | |
| 	g_autoptr(GBytes) blob = NULL;
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 
 | |
| 	fn = g_test_build_filename(G_TEST_DIST, "tests", "firmware.dfu", NULL);
 | |
| 	blob = fu_bytes_get_contents(fn, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(blob);
 | |
| 
 | |
| 	/* dfu -> FuDfuFirmware */
 | |
| 	firmware1 = fu_firmware_new_from_gtypes(blob,
 | |
| 						FWUPD_INSTALL_FLAG_NONE,
 | |
| 						&error,
 | |
| 						FU_TYPE_SREC_FIRMWARE,
 | |
| 						FU_TYPE_DFUSE_FIRMWARE,
 | |
| 						FU_TYPE_DFU_FIRMWARE,
 | |
| 						G_TYPE_INVALID);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(firmware1);
 | |
| 	g_assert_cmpstr(G_OBJECT_TYPE_NAME(firmware1), ==, "FuDfuFirmware");
 | |
| 
 | |
| 	/* dfu -> FuFirmware */
 | |
| 	firmware2 = fu_firmware_new_from_gtypes(blob,
 | |
| 						FWUPD_INSTALL_FLAG_NONE,
 | |
| 						&error,
 | |
| 						FU_TYPE_SREC_FIRMWARE,
 | |
| 						FU_TYPE_FIRMWARE,
 | |
| 						G_TYPE_INVALID);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(firmware2);
 | |
| 	g_assert_cmpstr(G_OBJECT_TYPE_NAME(firmware2), ==, "FuFirmware");
 | |
| 
 | |
| 	/* dfu -> error */
 | |
| 	firmware3 = fu_firmware_new_from_gtypes(blob,
 | |
| 						FWUPD_INSTALL_FLAG_NONE,
 | |
| 						&error,
 | |
| 						FU_TYPE_SREC_FIRMWARE,
 | |
| 						G_TYPE_INVALID);
 | |
| 	g_assert_error(error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE);
 | |
| 	g_assert_null(firmware3);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_firmware_archive_func(void)
 | |
| {
 | |
| 	gboolean ret;
 | |
| 	g_autofree gchar *fn = NULL;
 | |
| 	g_autoptr(FuFirmware) firmware = fu_archive_firmware_new();
 | |
| 	g_autoptr(FuFirmware) img_asc = NULL;
 | |
| 	g_autoptr(FuFirmware) img_bin = NULL;
 | |
| 	g_autoptr(FuFirmware) img_both = NULL;
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 	g_autoptr(GFile) file = NULL;
 | |
| 
 | |
| 	fn = g_test_build_filename(G_TEST_BUILT, "tests", "firmware.zip", NULL);
 | |
| 	file = g_file_new_for_path(fn);
 | |
| 	ret = fu_firmware_parse_file(firmware, file, FWUPD_INSTALL_FLAG_NONE, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	g_assert_cmpint(fu_archive_firmware_get_format(FU_ARCHIVE_FIRMWARE(firmware)),
 | |
| 			==,
 | |
| 			FU_ARCHIVE_FORMAT_UNKNOWN);
 | |
| 	g_assert_cmpint(fu_archive_firmware_get_compression(FU_ARCHIVE_FIRMWARE(firmware)),
 | |
| 			==,
 | |
| 			FU_ARCHIVE_COMPRESSION_UNKNOWN);
 | |
| 
 | |
| 	img_bin =
 | |
| 	    fu_archive_firmware_get_image_fnmatch(FU_ARCHIVE_FIRMWARE(firmware), "*.bin", &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(img_bin);
 | |
| 	img_asc = fu_archive_firmware_get_image_fnmatch(FU_ARCHIVE_FIRMWARE(firmware),
 | |
| 							"*.bin.asc",
 | |
| 							&error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(img_asc);
 | |
| 	img_both =
 | |
| 	    fu_archive_firmware_get_image_fnmatch(FU_ARCHIVE_FIRMWARE(firmware), "*.bin*", &error);
 | |
| 	g_assert_error(error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
 | |
| 	g_assert_null(img_both);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_firmware_linear_func(void)
 | |
| {
 | |
| 	gboolean ret;
 | |
| 	g_autoptr(FuFirmware) firmware1 = fu_linear_firmware_new(FU_TYPE_OPROM_FIRMWARE);
 | |
| 	g_autoptr(FuFirmware) firmware2 = fu_linear_firmware_new(FU_TYPE_OPROM_FIRMWARE);
 | |
| 	g_autoptr(GBytes) blob1 = g_bytes_new_static("XXXX", 4);
 | |
| 	g_autoptr(GBytes) blob2 = g_bytes_new_static("HELO", 4);
 | |
| 	g_autoptr(GBytes) blob3 = NULL;
 | |
| 	g_autoptr(FuFirmware) img1 = fu_oprom_firmware_new();
 | |
| 	g_autoptr(FuFirmware) img2 = fu_oprom_firmware_new();
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 	g_autoptr(GPtrArray) imgs = NULL;
 | |
| 	g_autofree gchar *str = NULL;
 | |
| 
 | |
| 	/* add images then parse */
 | |
| 	fu_firmware_set_bytes(img1, blob1);
 | |
| 	fu_firmware_add_image(firmware1, img1);
 | |
| 	fu_firmware_set_bytes(img2, blob2);
 | |
| 	fu_firmware_add_image(firmware1, img2);
 | |
| 	blob3 = fu_firmware_write(firmware1, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(blob3);
 | |
| 	g_assert_cmpint(g_bytes_get_size(blob3), ==, 1024);
 | |
| 
 | |
| 	/* parse them back */
 | |
| 	ret = fu_firmware_parse(firmware2, blob3, FWUPD_INSTALL_FLAG_NO_SEARCH, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	str = fu_firmware_to_string(firmware2);
 | |
| 	g_debug("\n%s", str);
 | |
| 
 | |
| 	/* verify we got both images */
 | |
| 	imgs = fu_firmware_get_images(firmware2);
 | |
| 	g_assert_cmpint(imgs->len, ==, 2);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_firmware_dfu_func(void)
 | |
| {
 | |
| 	gboolean ret;
 | |
| 	g_autofree gchar *filename_dfu = NULL;
 | |
| 	g_autofree gchar *filename_ref = NULL;
 | |
| 	g_autoptr(FuFirmware) firmware = fu_dfu_firmware_new();
 | |
| 	g_autoptr(GBytes) data_ref = NULL;
 | |
| 	g_autoptr(GBytes) data_dfu = NULL;
 | |
| 	g_autoptr(GBytes) data_bin = NULL;
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 
 | |
| 	filename_dfu = g_test_build_filename(G_TEST_DIST, "tests", "firmware.dfu", NULL);
 | |
| 	data_dfu = fu_bytes_get_contents(filename_dfu, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(data_dfu);
 | |
| 	ret = fu_firmware_parse(firmware, data_dfu, FWUPD_INSTALL_FLAG_NO_SEARCH, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	g_assert_cmpint(fu_dfu_firmware_get_vid(FU_DFU_FIRMWARE(firmware)), ==, 0x1234);
 | |
| 	g_assert_cmpint(fu_dfu_firmware_get_pid(FU_DFU_FIRMWARE(firmware)), ==, 0x4321);
 | |
| 	g_assert_cmpint(fu_dfu_firmware_get_release(FU_DFU_FIRMWARE(firmware)), ==, 0xdead);
 | |
| 	data_bin = fu_firmware_get_bytes(firmware, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(data_bin);
 | |
| 	g_assert_cmpint(g_bytes_get_size(data_bin), ==, 136);
 | |
| 
 | |
| 	/* did we match the reference file? */
 | |
| 	filename_ref = g_test_build_filename(G_TEST_DIST, "tests", "firmware.bin", NULL);
 | |
| 	data_ref = fu_bytes_get_contents(filename_ref, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(data_ref);
 | |
| 	ret = fu_bytes_compare(data_bin, data_ref, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_firmware_ifwi_cpd_func(void)
 | |
| {
 | |
| 	gboolean ret;
 | |
| 	g_autofree gchar *filename_ifwi_cpd = NULL;
 | |
| 	g_autoptr(FuFirmware) firmware = fu_ifwi_cpd_firmware_new();
 | |
| 	g_autoptr(FuFirmware) img1 = NULL;
 | |
| 	g_autoptr(FuFirmware) img2 = NULL;
 | |
| 	g_autoptr(GBytes) data_bin = NULL;
 | |
| 	g_autoptr(GBytes) data_ifwi_cpd = NULL;
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 
 | |
| 	filename_ifwi_cpd = g_test_build_filename(G_TEST_DIST, "tests", "ifwi-cpd.bin", NULL);
 | |
| 	data_ifwi_cpd = fu_bytes_get_contents(filename_ifwi_cpd, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(data_ifwi_cpd);
 | |
| 	ret = fu_firmware_parse(firmware, data_ifwi_cpd, FWUPD_INSTALL_FLAG_NO_SEARCH, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	g_assert_cmpint(fu_firmware_get_idx(firmware), ==, 0x1234);
 | |
| 	data_bin = fu_firmware_write(firmware, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(data_bin);
 | |
| 	g_assert_cmpint(g_bytes_get_size(data_bin), ==, 90);
 | |
| 
 | |
| 	img1 = fu_firmware_get_image_by_id(firmware, "one", &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(img1);
 | |
| 	g_assert_cmpint(fu_firmware_get_offset(img1), ==, 68);
 | |
| 	g_assert_cmpint(fu_firmware_get_size(img1), ==, 11);
 | |
| 
 | |
| 	img2 = fu_firmware_get_image_by_id(firmware, "two", &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(img2);
 | |
| 	g_assert_cmpint(fu_firmware_get_offset(img2), ==, 79);
 | |
| 	g_assert_cmpint(fu_firmware_get_size(img2), ==, 11);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_firmware_ifwi_fpt_func(void)
 | |
| {
 | |
| 	gboolean ret;
 | |
| 	g_autofree gchar *filename_ifwi_fpt = NULL;
 | |
| 	g_autoptr(FuFirmware) firmware = fu_ifwi_fpt_firmware_new();
 | |
| 	g_autoptr(FuFirmware) img1 = NULL;
 | |
| 	g_autoptr(FuFirmware) img2 = NULL;
 | |
| 	g_autoptr(GBytes) data_bin = NULL;
 | |
| 	g_autoptr(GBytes) data_ifwi_fpt = NULL;
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 
 | |
| 	filename_ifwi_fpt = g_test_build_filename(G_TEST_DIST, "tests", "ifwi-fpt.bin", NULL);
 | |
| 	data_ifwi_fpt = fu_bytes_get_contents(filename_ifwi_fpt, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(data_ifwi_fpt);
 | |
| 	ret = fu_firmware_parse(firmware, data_ifwi_fpt, FWUPD_INSTALL_FLAG_NO_SEARCH, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	data_bin = fu_firmware_write(firmware, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(data_bin);
 | |
| 	g_assert_cmpint(g_bytes_get_size(data_bin), ==, 118);
 | |
| 
 | |
| 	img1 = fu_firmware_get_image_by_idx(firmware, 0x4f464e49, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(img1);
 | |
| 	g_assert_cmpint(fu_firmware_get_offset(img1), ==, 96);
 | |
| 	g_assert_cmpint(fu_firmware_get_size(img1), ==, 11);
 | |
| 
 | |
| 	img2 = fu_firmware_get_image_by_idx(firmware, 0x4d495746, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(img2);
 | |
| 	g_assert_cmpint(fu_firmware_get_offset(img2), ==, 107);
 | |
| 	g_assert_cmpint(fu_firmware_get_size(img2), ==, 11);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_firmware_oprom_func(void)
 | |
| {
 | |
| 	gboolean ret;
 | |
| 	g_autofree gchar *filename_oprom = NULL;
 | |
| 	g_autoptr(FuFirmware) firmware = fu_oprom_firmware_new();
 | |
| 	g_autoptr(FuFirmware) img1 = NULL;
 | |
| 	g_autoptr(GBytes) data_bin = NULL;
 | |
| 	g_autoptr(GBytes) data_oprom = NULL;
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 
 | |
| 	filename_oprom = g_test_build_filename(G_TEST_DIST, "tests", "oprom.bin", NULL);
 | |
| 	data_oprom = fu_bytes_get_contents(filename_oprom, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(data_oprom);
 | |
| 	ret = fu_firmware_parse(firmware, data_oprom, FWUPD_INSTALL_FLAG_NO_SEARCH, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	g_assert_cmpint(fu_firmware_get_idx(firmware), ==, 0x1);
 | |
| 	data_bin = fu_firmware_write(firmware, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(data_bin);
 | |
| 	g_assert_cmpint(g_bytes_get_size(data_bin), ==, 1024);
 | |
| 
 | |
| 	img1 = fu_firmware_get_image_by_id(firmware, "cpd", &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(img1);
 | |
| 	g_assert_cmpint(fu_firmware_get_offset(img1), ==, 512);
 | |
| 	g_assert_cmpint(fu_firmware_get_size(img1), ==, 512);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_firmware_dfu_patch_func(void)
 | |
| {
 | |
| 	gboolean ret;
 | |
| 	g_autofree gchar *csum = NULL;
 | |
| 	g_autofree gchar *filename_dfu = NULL;
 | |
| 	g_autoptr(FuFirmware) firmware = fu_dfu_firmware_new();
 | |
| 	g_autoptr(GBytes) data_dfu = NULL;
 | |
| 	g_autoptr(GBytes) data_new = NULL;
 | |
| 	g_autoptr(GBytes) data_patch0 = g_bytes_new_static("XXXX", 4);
 | |
| 	g_autoptr(GBytes) data_patch1 = g_bytes_new_static("HELO", 4);
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 
 | |
| 	filename_dfu = g_test_build_filename(G_TEST_DIST, "tests", "firmware.dfu", NULL);
 | |
| 	data_dfu = fu_bytes_get_contents(filename_dfu, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(data_dfu);
 | |
| 	ret = fu_firmware_parse(firmware, data_dfu, FWUPD_INSTALL_FLAG_NO_SEARCH, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 
 | |
| 	/* add a couple of patches */
 | |
| 	fu_firmware_add_patch(firmware, 0x0, data_patch0);
 | |
| 	fu_firmware_add_patch(firmware, 0x0, data_patch1);
 | |
| 	fu_firmware_add_patch(firmware, 136 - 4, data_patch1);
 | |
| 
 | |
| 	data_new = fu_firmware_write(firmware, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(data_new);
 | |
| 	fu_dump_full(G_LOG_DOMAIN,
 | |
| 		     "patch",
 | |
| 		     g_bytes_get_data(data_new, NULL),
 | |
| 		     g_bytes_get_size(data_new),
 | |
| 		     20,
 | |
| 		     FU_DUMP_FLAGS_SHOW_ASCII | FU_DUMP_FLAGS_SHOW_ADDRESSES);
 | |
| 	csum = g_compute_checksum_for_bytes(G_CHECKSUM_SHA1, data_new);
 | |
| 	g_assert_cmpstr(csum, ==, "0722727426092ac564861d1a11697182017be83f");
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_firmware_func(void)
 | |
| {
 | |
| 	gboolean ret;
 | |
| 	g_autoptr(FuFirmware) firmware = fu_firmware_new();
 | |
| 	g_autoptr(FuFirmware) img1 = fu_firmware_new();
 | |
| 	g_autoptr(FuFirmware) img2 = fu_firmware_new();
 | |
| 	g_autoptr(FuFirmware) img_id = NULL;
 | |
| 	g_autoptr(FuFirmware) img_idx = NULL;
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 	g_autoptr(GPtrArray) images = NULL;
 | |
| 	g_autofree gchar *str = NULL;
 | |
| 
 | |
| 	fu_firmware_set_addr(img1, 0x200);
 | |
| 	fu_firmware_set_idx(img1, 13);
 | |
| 	fu_firmware_set_id(img1, "primary");
 | |
| 	fu_firmware_set_filename(img1, "BIOS.bin");
 | |
| 	fu_firmware_add_image(firmware, img1);
 | |
| 	fu_firmware_set_addr(img2, 0x400);
 | |
| 	fu_firmware_set_idx(img2, 23);
 | |
| 	fu_firmware_set_id(img2, "secondary");
 | |
| 	fu_firmware_add_image(firmware, img2);
 | |
| 
 | |
| 	img_id = fu_firmware_get_image_by_id(firmware, "NotGoingToExist", &error);
 | |
| 	g_assert_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND);
 | |
| 	g_assert_null(img_id);
 | |
| 	g_clear_error(&error);
 | |
| 	img_id = fu_firmware_get_image_by_id(firmware, "primary", &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(img_id);
 | |
| 	g_assert_cmpint(fu_firmware_get_addr(img_id), ==, 0x200);
 | |
| 	g_assert_cmpint(fu_firmware_get_idx(img_id), ==, 13);
 | |
| 	g_assert_cmpstr(fu_firmware_get_id(img_id), ==, "primary");
 | |
| 
 | |
| 	img_idx = fu_firmware_get_image_by_idx(firmware, 123456, &error);
 | |
| 	g_assert_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND);
 | |
| 	g_assert_null(img_idx);
 | |
| 	g_clear_error(&error);
 | |
| 	img_idx = fu_firmware_get_image_by_idx(firmware, 23, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(img_idx);
 | |
| 	g_assert_cmpint(fu_firmware_get_addr(img_idx), ==, 0x400);
 | |
| 	g_assert_cmpint(fu_firmware_get_idx(img_idx), ==, 23);
 | |
| 	g_assert_cmpstr(fu_firmware_get_id(img_idx), ==, "secondary");
 | |
| 
 | |
| 	str = fu_firmware_to_string(firmware);
 | |
| 	g_assert_cmpstr(str,
 | |
| 			==,
 | |
| 			"<firmware>\n"
 | |
| 			"  <firmware>\n"
 | |
| 			"    <id>primary</id>\n"
 | |
| 			"    <idx>0xd</idx>\n"
 | |
| 			"    <addr>0x200</addr>\n"
 | |
| 			"    <filename>BIOS.bin</filename>\n"
 | |
| 			"  </firmware>\n"
 | |
| 			"  <firmware>\n"
 | |
| 			"    <id>secondary</id>\n"
 | |
| 			"    <idx>0x17</idx>\n"
 | |
| 			"    <addr>0x400</addr>\n"
 | |
| 			"  </firmware>\n"
 | |
| 			"</firmware>\n");
 | |
| 
 | |
| 	ret = fu_firmware_remove_image_by_idx(firmware, 0xd, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	ret = fu_firmware_remove_image_by_id(firmware, "secondary", &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	images = fu_firmware_get_images(firmware);
 | |
| 	g_assert_nonnull(images);
 | |
| 	g_assert_cmpint(images->len, ==, 0);
 | |
| 	ret = fu_firmware_remove_image_by_id(firmware, "NOTGOINGTOEXIST", &error);
 | |
| 	g_assert_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND);
 | |
| 	g_assert_false(ret);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_firmware_common_func(void)
 | |
| {
 | |
| 	gboolean ret;
 | |
| 	guint8 value = 0;
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 
 | |
| 	ret = fu_firmware_strparse_uint8_safe("ff00XX", 6, 0, &value, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	g_assert_cmpint(value, ==, 0xFF);
 | |
| 
 | |
| 	ret = fu_firmware_strparse_uint8_safe("ff00XX", 6, 2, &value, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	g_assert_cmpint(value, ==, 0x00);
 | |
| 
 | |
| 	ret = fu_firmware_strparse_uint8_safe("ff00XX", 6, 4, &value, &error);
 | |
| 	g_assert_error(error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA);
 | |
| 	g_assert_false(ret);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_firmware_dedupe_func(void)
 | |
| {
 | |
| 	g_autoptr(FuFirmware) firmware = fu_firmware_new();
 | |
| 	g_autoptr(FuFirmware) img1 = fu_firmware_new();
 | |
| 	g_autoptr(FuFirmware) img1_old = fu_firmware_new();
 | |
| 	g_autoptr(FuFirmware) img2 = fu_firmware_new();
 | |
| 	g_autoptr(FuFirmware) img2_old = fu_firmware_new();
 | |
| 	g_autoptr(FuFirmware) img_id = NULL;
 | |
| 	g_autoptr(FuFirmware) img_idx = NULL;
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 
 | |
| 	fu_firmware_add_flag(firmware, FU_FIRMWARE_FLAG_DEDUPE_ID);
 | |
| 	fu_firmware_add_flag(firmware, FU_FIRMWARE_FLAG_DEDUPE_IDX);
 | |
| 
 | |
| 	fu_firmware_set_idx(img1_old, 13);
 | |
| 	fu_firmware_set_id(img1_old, "DAVE");
 | |
| 	fu_firmware_add_image(firmware, img1_old);
 | |
| 	g_assert_true(fu_firmware_get_parent(img1_old) == firmware);
 | |
| 
 | |
| 	fu_firmware_set_idx(img1, 13);
 | |
| 	fu_firmware_set_id(img1, "primary");
 | |
| 	fu_firmware_add_image(firmware, img1);
 | |
| 
 | |
| 	fu_firmware_set_idx(img2_old, 123456);
 | |
| 	fu_firmware_set_id(img2_old, "secondary");
 | |
| 	fu_firmware_add_image(firmware, img2_old);
 | |
| 
 | |
| 	fu_firmware_set_idx(img2, 23);
 | |
| 	fu_firmware_set_id(img2, "secondary");
 | |
| 	fu_firmware_add_image(firmware, img2);
 | |
| 
 | |
| 	img_id = fu_firmware_get_image_by_id(firmware, "primary", &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(img_id);
 | |
| 	g_assert_cmpint(fu_firmware_get_idx(img_id), ==, 13);
 | |
| 	g_assert_cmpstr(fu_firmware_get_id(img_id), ==, "primary");
 | |
| 
 | |
| 	img_idx = fu_firmware_get_image_by_idx(firmware, 23, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(img_idx);
 | |
| 	g_assert_cmpint(fu_firmware_get_idx(img_idx), ==, 23);
 | |
| 	g_assert_cmpstr(fu_firmware_get_id(img_idx), ==, "secondary");
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_efivar_func(void)
 | |
| {
 | |
| 	gboolean ret;
 | |
| 	gsize sz = 0;
 | |
| 	guint32 attr = 0;
 | |
| 	guint64 total;
 | |
| 	g_autofree gchar *sysfsfwdir = NULL;
 | |
| 	g_autofree guint8 *data = NULL;
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 	g_autoptr(GPtrArray) names = NULL;
 | |
| 
 | |
| #ifndef __linux__
 | |
| 	g_test_skip("only works on Linux");
 | |
| 	return;
 | |
| #endif
 | |
| 
 | |
| 	/* these tests will write */
 | |
| 	sysfsfwdir = g_test_build_filename(G_TEST_BUILT, "tests", NULL);
 | |
| 	(void)g_setenv("FWUPD_SYSFSFWDIR", sysfsfwdir, TRUE);
 | |
| 
 | |
| 	/* check supported */
 | |
| 	ret = fu_efivar_supported(&error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 
 | |
| 	/* check we can get the space used */
 | |
| 	total = fu_efivar_space_used(&error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_cmpint(total, >=, 0x2000);
 | |
| 
 | |
| 	/* check existing keys */
 | |
| 	g_assert_false(fu_efivar_exists(FU_EFIVAR_GUID_EFI_GLOBAL, "NotGoingToExist"));
 | |
| 	g_assert_true(fu_efivar_exists(FU_EFIVAR_GUID_EFI_GLOBAL, "SecureBoot"));
 | |
| 
 | |
| 	/* list a few keys */
 | |
| 	names = fu_efivar_get_names(FU_EFIVAR_GUID_EFI_GLOBAL, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_nonnull(names);
 | |
| 	g_assert_cmpint(names->len, ==, 2);
 | |
| 
 | |
| 	/* write and read a key */
 | |
| 	ret = fu_efivar_set_data(FU_EFIVAR_GUID_EFI_GLOBAL,
 | |
| 				 "Test",
 | |
| 				 (guint8 *)"1",
 | |
| 				 1,
 | |
| 				 FU_EFIVAR_ATTR_NON_VOLATILE | FU_EFIVAR_ATTR_RUNTIME_ACCESS,
 | |
| 				 &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	ret = fu_efivar_get_data(FU_EFIVAR_GUID_EFI_GLOBAL, "Test", &data, &sz, &attr, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	g_assert_cmpint(sz, ==, 1);
 | |
| 	g_assert_cmpint(attr, ==, FU_EFIVAR_ATTR_NON_VOLATILE | FU_EFIVAR_ATTR_RUNTIME_ACCESS);
 | |
| 	g_assert_cmpint(data[0], ==, '1');
 | |
| 
 | |
| 	/* delete single key */
 | |
| 	ret = fu_efivar_delete(FU_EFIVAR_GUID_EFI_GLOBAL, "Test", &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	g_assert_false(fu_efivar_exists(FU_EFIVAR_GUID_EFI_GLOBAL, "Test"));
 | |
| 
 | |
| 	/* delete multiple keys */
 | |
| 	ret = fu_efivar_set_data(FU_EFIVAR_GUID_EFI_GLOBAL, "Test1", (guint8 *)"1", 1, 0, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	ret = fu_efivar_set_data(FU_EFIVAR_GUID_EFI_GLOBAL, "Test2", (guint8 *)"1", 1, 0, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	ret = fu_efivar_delete_with_glob(FU_EFIVAR_GUID_EFI_GLOBAL, "Test*", &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	g_assert_false(fu_efivar_exists(FU_EFIVAR_GUID_EFI_GLOBAL, "Test1"));
 | |
| 	g_assert_false(fu_efivar_exists(FU_EFIVAR_GUID_EFI_GLOBAL, "Test2"));
 | |
| 
 | |
| 	/* read a key that doesn't exist */
 | |
| 	ret = fu_efivar_get_data(FU_EFIVAR_GUID_EFI_GLOBAL,
 | |
| 				 "NotGoingToExist",
 | |
| 				 NULL,
 | |
| 				 NULL,
 | |
| 				 NULL,
 | |
| 				 &error);
 | |
| 	g_assert_error(error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
 | |
| 	g_assert_false(ret);
 | |
| }
 | |
| 
 | |
| typedef struct {
 | |
| 	guint cnt_success;
 | |
| 	guint cnt_failed;
 | |
| } FuDeviceRetryHelper;
 | |
| 
 | |
| static gboolean
 | |
| fu_device_retry_success(FuDevice *device, gpointer user_data, GError **error)
 | |
| {
 | |
| 	FuDeviceRetryHelper *helper = (FuDeviceRetryHelper *)user_data;
 | |
| 	helper->cnt_success++;
 | |
| 	return TRUE;
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| fu_device_retry_failed(FuDevice *device, gpointer user_data, GError **error)
 | |
| {
 | |
| 	FuDeviceRetryHelper *helper = (FuDeviceRetryHelper *)user_data;
 | |
| 	helper->cnt_failed++;
 | |
| 	g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "failed");
 | |
| 	return FALSE;
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| fu_device_retry_success_3rd_try(FuDevice *device, gpointer user_data, GError **error)
 | |
| {
 | |
| 	FuDeviceRetryHelper *helper = (FuDeviceRetryHelper *)user_data;
 | |
| 	if (helper->cnt_failed == 2) {
 | |
| 		helper->cnt_success++;
 | |
| 		return TRUE;
 | |
| 	}
 | |
| 	helper->cnt_failed++;
 | |
| 	g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "failed");
 | |
| 	return FALSE;
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_device_retry_success_func(void)
 | |
| {
 | |
| 	gboolean ret;
 | |
| 	g_autoptr(FuDevice) device = fu_device_new(NULL);
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 	FuDeviceRetryHelper helper = {
 | |
| 	    .cnt_success = 0,
 | |
| 	    .cnt_failed = 0,
 | |
| 	};
 | |
| 	fu_device_retry_add_recovery(device,
 | |
| 				     FWUPD_ERROR,
 | |
| 				     FWUPD_ERROR_INTERNAL,
 | |
| 				     fu_device_retry_failed);
 | |
| 	ret = fu_device_retry(device, fu_device_retry_success, 3, &helper, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	g_assert_cmpint(helper.cnt_success, ==, 1);
 | |
| 	g_assert_cmpint(helper.cnt_failed, ==, 0);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_device_retry_failed_func(void)
 | |
| {
 | |
| 	gboolean ret;
 | |
| 	g_autoptr(FuDevice) device = fu_device_new(NULL);
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 	FuDeviceRetryHelper helper = {
 | |
| 	    .cnt_success = 0,
 | |
| 	    .cnt_failed = 0,
 | |
| 	};
 | |
| 	fu_device_retry_add_recovery(device,
 | |
| 				     FWUPD_ERROR,
 | |
| 				     FWUPD_ERROR_INTERNAL,
 | |
| 				     fu_device_retry_success);
 | |
| 	ret = fu_device_retry(device, fu_device_retry_failed, 3, &helper, &error);
 | |
| 	g_assert_error(error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL);
 | |
| 	g_assert_true(!ret);
 | |
| 	g_assert_cmpint(helper.cnt_success, ==, 2); /* do not reset for the last failure */
 | |
| 	g_assert_cmpint(helper.cnt_failed, ==, 3);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_device_retry_hardware_func(void)
 | |
| {
 | |
| 	gboolean ret;
 | |
| 	g_autoptr(FuDevice) device = fu_device_new(NULL);
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 	FuDeviceRetryHelper helper = {
 | |
| 	    .cnt_success = 0,
 | |
| 	    .cnt_failed = 0,
 | |
| 	};
 | |
| 	ret = fu_device_retry(device, fu_device_retry_success_3rd_try, 3, &helper, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	g_assert_cmpint(helper.cnt_success, ==, 1);
 | |
| 	g_assert_cmpint(helper.cnt_failed, ==, 2);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_bios_settings_load_func(void)
 | |
| {
 | |
| 	gboolean ret;
 | |
| 	gint integer;
 | |
| 	const gchar *tmp;
 | |
| 	GPtrArray *values;
 | |
| 	FwupdBiosSetting *setting;
 | |
| 	FwupdBiosSettingKind kind;
 | |
| 	g_autofree gchar *test_dir = NULL;
 | |
| 	g_autoptr(FuContext) ctx = fu_context_new();
 | |
| 	g_autoptr(GError) error = NULL;
 | |
| 	g_autoptr(FuBiosSettings) p620_settings = NULL;
 | |
| 	g_autoptr(FuBiosSettings) p14s_settings = NULL;
 | |
| 	g_autoptr(FuBiosSettings) xp29310_settings = NULL;
 | |
| 	g_autoptr(GPtrArray) p14s_items = NULL;
 | |
| 	g_autoptr(GPtrArray) p620_items = NULL;
 | |
| 	g_autoptr(GPtrArray) xps9310_items = NULL;
 | |
| 
 | |
| 	/* load BIOS settings from a Lenovo P620 (with thinklmi driver problems) */
 | |
| 	test_dir = g_test_build_filename(G_TEST_DIST, "tests", "bios-attrs", "lenovo-p620", NULL);
 | |
| 	(void)g_setenv("FWUPD_SYSFSFWATTRIBDIR", test_dir, TRUE);
 | |
| 
 | |
| 	g_test_expect_message("FuBiosSettings", G_LOG_LEVEL_WARNING, "*BUG*");
 | |
| 	ret = fu_context_reload_bios_settings(ctx, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 	g_test_assert_expected_messages();
 | |
| 
 | |
| 	p620_settings = fu_context_get_bios_settings(ctx);
 | |
| 	p620_items = fu_bios_settings_get_all(p620_settings);
 | |
| 	g_assert_cmpint(p620_items->len, ==, 128);
 | |
| 
 | |
| 	/* make sure nothing pending */
 | |
| 	ret = fu_context_get_bios_setting_pending_reboot(ctx);
 | |
| 	g_assert_false(ret);
 | |
| 
 | |
| 	/* check a BIOS setting reads from kernel as expected by fwupd today */
 | |
| 	setting = fu_context_get_bios_setting(ctx, "com.thinklmi.AMDMemoryGuard");
 | |
| 	g_assert_nonnull(setting);
 | |
| 	tmp = fwupd_bios_setting_get_name(setting);
 | |
| 	g_assert_cmpstr(tmp, ==, "AMDMemoryGuard");
 | |
| 	tmp = fwupd_bios_setting_get_description(setting);
 | |
| 	g_assert_cmpstr(tmp, ==, "AMDMemoryGuard");
 | |
| 	tmp = fwupd_bios_setting_get_current_value(setting);
 | |
| 	g_assert_cmpstr(tmp, ==, "Disable");
 | |
| 	values = fwupd_bios_setting_get_possible_values(setting);
 | |
| 	for (guint i = 0; i < values->len; i++) {
 | |
| 		const gchar *possible = g_ptr_array_index(values, i);
 | |
| 		if (i == 0)
 | |
| 			g_assert_cmpstr(possible, ==, "Disable");
 | |
| 		if (i == 1)
 | |
| 			g_assert_cmpstr(possible, ==, "Enable");
 | |
| 	}
 | |
| 
 | |
| 	/* try to read an BIOS setting known to have ][Status] to make sure we worked
 | |
| 	 * around the thinklmi bug sufficiently
 | |
| 	 */
 | |
| 	setting = fu_context_get_bios_setting(ctx, "com.thinklmi.StartupSequence");
 | |
| 	g_assert_nonnull(setting);
 | |
| 	tmp = fwupd_bios_setting_get_current_value(setting);
 | |
| 	g_assert_cmpstr(tmp, ==, "Primary");
 | |
| 	values = fwupd_bios_setting_get_possible_values(setting);
 | |
| 	for (guint i = 0; i < values->len; i++) {
 | |
| 		const gchar *possible = g_ptr_array_index(values, i);
 | |
| 		if (i == 0)
 | |
| 			g_assert_cmpstr(possible, ==, "Primary");
 | |
| 		if (i == 1)
 | |
| 			g_assert_cmpstr(possible, ==, "Automatic");
 | |
| 	}
 | |
| 
 | |
| 	/* check no BIOS settings have [Status in them */
 | |
| 	for (guint i = 0; i < p620_items->len; i++) {
 | |
| 		setting = g_ptr_array_index(p620_items, i);
 | |
| 		tmp = fwupd_bios_setting_get_current_value(setting);
 | |
| 		g_debug("%s", tmp);
 | |
| 		g_assert_null(g_strrstr(tmp, "[Status"));
 | |
| 	}
 | |
| 
 | |
| 	g_free(test_dir);
 | |
| 
 | |
| 	/* load BIOS settings from a Lenovo P14s Gen1 */
 | |
| 	test_dir =
 | |
| 	    g_test_build_filename(G_TEST_DIST, "tests", "bios-attrs", "lenovo-p14s-gen1", NULL);
 | |
| 	(void)g_setenv("FWUPD_SYSFSFWATTRIBDIR", test_dir, TRUE);
 | |
| 	ret = fu_context_reload_bios_settings(ctx, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 
 | |
| 	p14s_settings = fu_context_get_bios_settings(ctx);
 | |
| 	p14s_items = fu_bios_settings_get_all(p14s_settings);
 | |
| 	g_assert_cmpint(p14s_items->len, ==, 75);
 | |
| 
 | |
| 	/* reboot should be pending on this one */
 | |
| 	ret = fu_context_get_bios_setting_pending_reboot(ctx);
 | |
| 	g_assert_true(ret);
 | |
| 
 | |
| 	/* look for an enumeration BIOS setting with a space */
 | |
| 	setting = fu_context_get_bios_setting(ctx, "com.thinklmi.SleepState");
 | |
| 	g_assert_nonnull(setting);
 | |
| 	tmp = fwupd_bios_setting_get_name(setting);
 | |
| 	g_assert_cmpstr(tmp, ==, "SleepState");
 | |
| 	tmp = fwupd_bios_setting_get_description(setting);
 | |
| 	g_assert_cmpstr(tmp, ==, "SleepState");
 | |
| 	values = fwupd_bios_setting_get_possible_values(setting);
 | |
| 	for (guint i = 0; i < values->len; i++) {
 | |
| 		const gchar *possible = g_ptr_array_index(values, i);
 | |
| 		if (i == 0)
 | |
| 			g_assert_cmpstr(possible, ==, "Linux");
 | |
| 		if (i == 1)
 | |
| 			g_assert_cmpstr(possible, ==, "Windows 10");
 | |
| 	}
 | |
| 
 | |
| 	/* make sure we defaulted UEFI Secure boot to read only if enabled */
 | |
| 	setting = fu_context_get_bios_setting(ctx, "com.thinklmi.SecureBoot");
 | |
| 	g_assert_nonnull(setting);
 | |
| 	ret = fwupd_bios_setting_get_read_only(setting);
 | |
| 	g_assert_true(ret);
 | |
| 
 | |
| 	g_free(test_dir);
 | |
| 
 | |
| 	/* load BIOS settings from a Dell XPS 9310 */
 | |
| 	test_dir =
 | |
| 	    g_test_build_filename(G_TEST_DIST, "tests", "bios-attrs", "dell-xps13-9310", NULL);
 | |
| 	(void)g_setenv("FWUPD_SYSFSFWATTRIBDIR", test_dir, TRUE);
 | |
| 	ret = fu_context_reload_bios_settings(ctx, &error);
 | |
| 	g_assert_no_error(error);
 | |
| 	g_assert_true(ret);
 | |
| 
 | |
| 	xp29310_settings = fu_context_get_bios_settings(ctx);
 | |
| 	xps9310_items = fu_bios_settings_get_all(xp29310_settings);
 | |
| 	g_assert_cmpint(xps9310_items->len, ==, 109);
 | |
| 
 | |
| 	/* make sure that we DIDN'T parse reset_bios setting */
 | |
| 	setting = fu_context_get_bios_setting(ctx, FWUPD_BIOS_SETTING_RESET_BIOS);
 | |
| 	g_assert_null(setting);
 | |
| 
 | |
| 	/* look at a integer BIOS setting */
 | |
| 	setting = fu_context_get_bios_setting(ctx, "com.dell-wmi-sysman.CustomChargeStop");
 | |
| 	g_assert_nonnull(setting);
 | |
| 	kind = fwupd_bios_setting_get_kind(setting);
 | |
| 	g_assert_cmpint(kind, ==, FWUPD_BIOS_SETTING_KIND_INTEGER);
 | |
| 	integer = fwupd_bios_setting_get_lower_bound(setting);
 | |
| 	g_assert_cmpint(integer, ==, 55);
 | |
| 	integer = fwupd_bios_setting_get_upper_bound(setting);
 | |
| 	g_assert_cmpint(integer, ==, 100);
 | |
| 	integer = fwupd_bios_setting_get_scalar_increment(setting);
 | |
| 	g_assert_cmpint(integer, ==, 1);
 | |
| 
 | |
| 	/* look at a string BIOS setting */
 | |
| 	setting = fu_context_get_bios_setting(ctx, "com.dell-wmi-sysman.Asset");
 | |
| 	g_assert_nonnull(setting);
 | |
| 	integer = fwupd_bios_setting_get_lower_bound(setting);
 | |
| 	g_assert_cmpint(integer, ==, 1);
 | |
| 	integer = fwupd_bios_setting_get_upper_bound(setting);
 | |
| 	g_assert_cmpint(integer, ==, 64);
 | |
| 	tmp = fwupd_bios_setting_get_description(setting);
 | |
| 	g_assert_cmpstr(tmp, ==, "Asset Tag");
 | |
| 
 | |
| 	/* look at a enumeration BIOS setting */
 | |
| 	setting = fu_context_get_bios_setting(ctx, "com.dell-wmi-sysman.BiosRcvrFrmHdd");
 | |
| 	g_assert_nonnull(setting);
 | |
| 	kind = fwupd_bios_setting_get_kind(setting);
 | |
| 	g_assert_cmpint(kind, ==, FWUPD_BIOS_SETTING_KIND_ENUMERATION);
 | |
| 	values = fwupd_bios_setting_get_possible_values(setting);
 | |
| 	for (guint i = 0; i < values->len; i++) {
 | |
| 		const gchar *possible = g_ptr_array_index(values, i);
 | |
| 		if (i == 0)
 | |
| 			g_assert_cmpstr(possible, ==, "Disabled");
 | |
| 		if (i == 1)
 | |
| 			g_assert_cmpstr(possible, ==, "Enabled");
 | |
| 	}
 | |
| 
 | |
| 	/* make sure we defaulted UEFI Secure boot to read only if enabled */
 | |
| 	setting = fu_context_get_bios_setting(ctx, "com.dell-wmi-sysman.SecureBoot");
 | |
| 	g_assert_nonnull(setting);
 | |
| 	ret = fwupd_bios_setting_get_read_only(setting);
 | |
| 	g_assert_true(ret);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_security_attrs_hsi_func(void)
 | |
| {
 | |
| 	g_autofree gchar *hsi1 = NULL;
 | |
| 	g_autofree gchar *hsi2 = NULL;
 | |
| 	g_autofree gchar *hsi3 = NULL;
 | |
| 	g_autofree gchar *hsi4 = NULL;
 | |
| 	g_autofree gchar *hsi5 = NULL;
 | |
| 	g_autofree gchar *hsi6 = NULL;
 | |
| 	g_autofree gchar *hsi7 = NULL;
 | |
| 	g_autofree gchar *hsi8 = NULL;
 | |
| 	g_autofree gchar *hsi9 = NULL;
 | |
| 	g_autofree gchar *expected_hsi9 = NULL;
 | |
| 	g_autoptr(FuSecurityAttrs) attrs = NULL;
 | |
| 	g_autoptr(FwupdSecurityAttr) attr = NULL;
 | |
| 
 | |
| 	/* no attrs */
 | |
| 	attrs = fu_security_attrs_new();
 | |
| 	hsi1 = fu_security_attrs_calculate_hsi(attrs, FU_SECURITY_ATTRS_FLAG_NONE);
 | |
| 	g_assert_cmpstr(hsi1, ==, "HSI:0");
 | |
| 
 | |
| 	/* just success from HSI:1 */
 | |
| 	attr = fwupd_security_attr_new(FWUPD_SECURITY_ATTR_ID_SPI_BIOSWE);
 | |
| 	fwupd_security_attr_set_plugin(attr, "test");
 | |
| 	fwupd_security_attr_set_level(attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL);
 | |
| 	fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS);
 | |
| 	fwupd_security_attr_set_url(attr, "http://test");
 | |
| 	fu_security_attrs_append(attrs, attr);
 | |
| 	hsi2 = fu_security_attrs_calculate_hsi(attrs, FU_SECURITY_ATTRS_FLAG_NONE);
 | |
| 	g_assert_cmpstr(hsi2, ==, "HSI:1");
 | |
| 	g_clear_object(&attr);
 | |
| 
 | |
| 	/* add failed from HSI:2, so still HSI:1 */
 | |
| 	attr = fwupd_security_attr_new("org.fwupd.hsi.PRX");
 | |
| 	fwupd_security_attr_set_plugin(attr, "test");
 | |
| 	fwupd_security_attr_set_level(attr, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT);
 | |
| 	fwupd_security_attr_set_url(attr, "http://test");
 | |
| 	fu_security_attrs_append(attrs, attr);
 | |
| 	hsi3 = fu_security_attrs_calculate_hsi(attrs, FU_SECURITY_ATTRS_FLAG_NONE);
 | |
| 	g_assert_cmpstr(hsi3, ==, "HSI:1");
 | |
| 	g_clear_object(&attr);
 | |
| 
 | |
| 	/* add an implicit obsolete via duplication */
 | |
| 	attr = fwupd_security_attr_new("org.fwupd.hsi.PRX");
 | |
| 	fwupd_security_attr_set_plugin(attr, "other-plugin");
 | |
| 	fwupd_security_attr_set_level(attr, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT);
 | |
| 	fwupd_security_attr_set_url(attr, "http://other-plugin");
 | |
| 	fu_security_attrs_append(attrs, attr);
 | |
| 	fu_security_attrs_depsolve(attrs);
 | |
| 	hsi4 = fu_security_attrs_calculate_hsi(attrs, FU_SECURITY_ATTRS_FLAG_NONE);
 | |
| 	g_assert_cmpstr(hsi4, ==, "HSI:1");
 | |
| 	g_assert_true(fwupd_security_attr_has_flag(attr, FWUPD_SECURITY_ATTR_FLAG_OBSOLETED));
 | |
| 	g_clear_object(&attr);
 | |
| 
 | |
| 	/* add attr from HSI:3, obsoleting the failure */
 | |
| 	attr = fwupd_security_attr_new("org.fwupd.hsi.BIOSGuard");
 | |
| 	fwupd_security_attr_set_plugin(attr, "test");
 | |
| 	fwupd_security_attr_set_level(attr, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL);
 | |
| 	fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS);
 | |
| 	fwupd_security_attr_add_obsolete(attr, "org.fwupd.hsi.PRX");
 | |
| 	fwupd_security_attr_set_url(attr, "http://test");
 | |
| 	fu_security_attrs_append(attrs, attr);
 | |
| 	fu_security_attrs_depsolve(attrs);
 | |
| 	hsi5 = fu_security_attrs_calculate_hsi(attrs, FU_SECURITY_ATTRS_FLAG_NONE);
 | |
| 	g_assert_cmpstr(hsi5, ==, "HSI:3");
 | |
| 	g_clear_object(&attr);
 | |
| 
 | |
| 	/* add taint that was fine */
 | |
| 	attr = fwupd_security_attr_new(FWUPD_SECURITY_ATTR_ID_FWUPD_PLUGINS);
 | |
| 	fwupd_security_attr_set_plugin(attr, "test");
 | |
| 	fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS);
 | |
| 	fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE);
 | |
| 	fwupd_security_attr_set_url(attr, "http://test");
 | |
| 	fu_security_attrs_append(attrs, attr);
 | |
| 	hsi6 = fu_security_attrs_calculate_hsi(attrs, FU_SECURITY_ATTRS_FLAG_NONE);
 | |
| 	g_assert_cmpstr(hsi6, ==, "HSI:3");
 | |
| 	g_clear_object(&attr);
 | |
| 
 | |
| 	/* add updates and attestation */
 | |
| 	attr = fwupd_security_attr_new(FWUPD_SECURITY_ATTR_ID_FWUPD_UPDATES);
 | |
| 	fwupd_security_attr_set_plugin(attr, "test");
 | |
| 	fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS);
 | |
| 	fwupd_security_attr_set_url(attr, "http://test");
 | |
| 	fu_security_attrs_append(attrs, attr);
 | |
| 	hsi7 = fu_security_attrs_calculate_hsi(attrs, FU_SECURITY_ATTRS_FLAG_NONE);
 | |
| 	g_assert_cmpstr(hsi7, ==, "HSI:3");
 | |
| 	g_clear_object(&attr);
 | |
| 
 | |
| 	/* add issue that was uncool */
 | |
| 	attr = fwupd_security_attr_new(FWUPD_SECURITY_ATTR_ID_KERNEL_SWAP);
 | |
| 	fwupd_security_attr_set_plugin(attr, "test");
 | |
| 	fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE);
 | |
| 	fwupd_security_attr_set_url(attr, "http://test");
 | |
| 	fu_security_attrs_append(attrs, attr);
 | |
| 	hsi8 = fu_security_attrs_calculate_hsi(attrs, FU_SECURITY_ATTRS_FLAG_NONE);
 | |
| 	g_assert_cmpstr(hsi8, ==, "HSI:3!");
 | |
| 	g_clear_object(&attr);
 | |
| 
 | |
| 	/* show version in the attribute */
 | |
| 	attr = fwupd_security_attr_new(FWUPD_SECURITY_ATTR_ID_KERNEL_SWAP);
 | |
| 	fwupd_security_attr_set_plugin(attr, "test");
 | |
| 	fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE);
 | |
| 	fwupd_security_attr_set_url(attr, "http://test");
 | |
| 	fu_security_attrs_append(attrs, attr);
 | |
| 	hsi9 = fu_security_attrs_calculate_hsi(attrs, FU_SECURITY_ATTRS_FLAG_ADD_VERSION);
 | |
| 	expected_hsi9 = g_strdup_printf("HSI:3! (v%d.%d.%d)",
 | |
| 					FWUPD_MAJOR_VERSION,
 | |
| 					FWUPD_MINOR_VERSION,
 | |
| 					FWUPD_MICRO_VERSION);
 | |
| 	g_assert_cmpstr(hsi9, ==, expected_hsi9);
 | |
| 	g_clear_object(&attr);
 | |
| }
 | |
| static void
 | |
| fu_firmware_builder_round_trip_func(void)
 | |
| {
 | |
| 	struct {
 | |
| 		GType gtype;
 | |
| 		const gchar *xml_fn;
 | |
| 		const gchar *checksum;
 | |
| 	} map[] = {
 | |
| 	    {FU_TYPE_DFUSE_FIRMWARE,
 | |
| 	     "dfuse.builder.xml",
 | |
| 	     "c1ff429f0e381c8fe8e1b2ee41a5a9a79e2f2ff7"},
 | |
| 	    {FU_TYPE_FDT_FIRMWARE, "fdt.builder.xml", "40f7fbaff684a6bcf67c81b3079422c2529741e1"},
 | |
| 	    {FU_TYPE_FIT_FIRMWARE, "fit.builder.xml", "293ce07351bb7d76631c4e2ba47243db1e150f3c"},
 | |
| 	    {FU_TYPE_SREC_FIRMWARE, "srec.builder.xml", "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed"},
 | |
| 	    {FU_TYPE_IHEX_FIRMWARE, "ihex.builder.xml", "a8d74f767f3fc992b413e5ba801cedc80a4cf013"},
 | |
| 	    {FU_TYPE_FMAP_FIRMWARE, "fmap.builder.xml", "a0b9ffc10a586d217edf9e9bae7c1fe7c564ea01"},
 | |
| 	    {FU_TYPE_EFI_FIRMWARE_SECTION,
 | |
| 	     "efi-firmware-section.builder.xml",
 | |
| 	     "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed"},
 | |
| 	    {FU_TYPE_EFI_FIRMWARE_SECTION,
 | |
| 	     "efi-firmware-section.builder.xml",
 | |
| 	     "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed"},
 | |
| 	    {FU_TYPE_EFI_FIRMWARE_FILE,
 | |
| 	     "efi-firmware-file.builder.xml",
 | |
| 	     "1002c14b29a76069f3b7e35c50a55d2b0d197441"},
 | |
| 	    {FU_TYPE_EFI_FIRMWARE_FILESYSTEM,
 | |
| 	     "efi-firmware-filesystem.builder.xml",
 | |
| 	     "d6fbadc1c303a3b4eede9db7fb0ddb353efffc86"},
 | |
| 	    {FU_TYPE_EFI_FIRMWARE_VOLUME,
 | |
| 	     "efi-firmware-volume.builder.xml",
 | |
| 	     "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed"},
 | |
| 	    {FU_TYPE_IFD_FIRMWARE, "ifd.builder.xml", "0805c742e0deec12db2d8f9a86158a7cf610869b"},
 | |
| 	    {FU_TYPE_CFU_OFFER,
 | |
| 	     "cfu-offer.builder.xml",
 | |
| 	     "acc572d03a129081921c36118b527dab34a077ad"},
 | |
| 	    {FU_TYPE_CFU_PAYLOAD,
 | |
| 	     "cfu-payload.builder.xml",
 | |
| 	     "5da829f5fd15a28970aed98ebb26ebf2f88ed6f2"},
 | |
| 	    {FU_TYPE_IFWI_CPD_FIRMWARE,
 | |
| 	     "ifwi-cpd.builder.xml",
 | |
| 	     "91e348d17cb91ef7a528e85beb39d15a0532dca5"},
 | |
| 	    {FU_TYPE_IFWI_FPT_FIRMWARE,
 | |
| 	     "ifwi-fpt.builder.xml",
 | |
| 	     "d1f0fb2c2a7a99441bf4a825d060642315a94d91"},
 | |
| 	    {FU_TYPE_OPROM_FIRMWARE,
 | |
| 	     "oprom.builder.xml",
 | |
| 	     "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed"},
 | |
| 	    {FU_TYPE_INTEL_THUNDERBOLT_NVM,
 | |
| 	     "intel-thunderbolt.builder.xml",
 | |
| 	     "e858000646fecb5223b41df57647c005b495749b"},
 | |
| #ifdef HAVE_CBOR
 | |
| 	    {FU_TYPE_USWID_FIRMWARE,
 | |
| 	     "uswid.builder.xml",
 | |
| 	     "b4631ebb64931da604500b9a7263225708195f54"},
 | |
| #endif
 | |
| 	    {G_TYPE_INVALID, NULL, NULL}};
 | |
| 	g_type_ensure(FU_TYPE_COSWID_FIRMWARE);
 | |
| 	for (guint i = 0; map[i].gtype != G_TYPE_INVALID; i++) {
 | |
| 		gboolean ret;
 | |
| 		g_autofree gchar *csum1 = NULL;
 | |
| 		g_autofree gchar *csum2 = NULL;
 | |
| 		g_autofree gchar *filename = NULL;
 | |
| 		g_autofree gchar *xml1 = NULL;
 | |
| 		g_autofree gchar *xml2 = NULL;
 | |
| 		g_autoptr(FuFirmware) firmware1 = g_object_new(map[i].gtype, NULL);
 | |
| 		g_autoptr(FuFirmware) firmware2 = g_object_new(map[i].gtype, NULL);
 | |
| 		g_autoptr(FuFirmware) firmware3 = g_object_new(map[i].gtype, NULL);
 | |
| 		g_autoptr(GError) error = NULL;
 | |
| 		g_autoptr(GBytes) blob = NULL;
 | |
| 
 | |
| 		/* build and write */
 | |
| 		filename = g_test_build_filename(G_TEST_DIST, "tests", map[i].xml_fn, NULL);
 | |
| 		ret = g_file_get_contents(filename, &xml1, NULL, &error);
 | |
| 		g_assert_no_error(error);
 | |
| 		g_assert_true(ret);
 | |
| 		ret = fu_firmware_build_from_xml(firmware1, xml1, &error);
 | |
| 		g_assert_no_error(error);
 | |
| 		g_assert_true(ret);
 | |
| 		csum1 = fu_firmware_get_checksum(firmware1, G_CHECKSUM_SHA1, &error);
 | |
| 		g_assert_no_error(error);
 | |
| 		g_assert_cmpstr(csum1, ==, map[i].checksum);
 | |
| 
 | |
| 		/* ensure we can write and then parse what we just wrote */
 | |
| 		blob = fu_firmware_write(firmware1, &error);
 | |
| 		g_assert_no_error(error);
 | |
| 		g_assert_nonnull(blob);
 | |
| 		ret = fu_firmware_parse(firmware3, blob, FWUPD_INSTALL_FLAG_NO_SEARCH, &error);
 | |
| 		if (!ret)
 | |
| 			g_prefix_error(&error, "%s: ", map[i].xml_fn);
 | |
| 		g_assert_no_error(error);
 | |
| 		g_assert_true(ret);
 | |
| 
 | |
| 		/* ensure we can round-trip */
 | |
| 		xml2 = fu_firmware_export_to_xml(firmware1, FU_FIRMWARE_EXPORT_FLAG_NONE, &error);
 | |
| 		g_assert_no_error(error);
 | |
| 		ret = fu_firmware_build_from_xml(firmware2, xml2, &error);
 | |
| 		g_assert_no_error(error);
 | |
| 		g_assert_true(ret);
 | |
| 		csum2 = fu_firmware_get_checksum(firmware2, G_CHECKSUM_SHA1, &error);
 | |
| 		g_assert_no_error(error);
 | |
| 		g_assert_cmpstr(csum2, ==, map[i].checksum);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| typedef struct {
 | |
| 	guint last_percentage;
 | |
| 	guint updates;
 | |
| } FuProgressHelper;
 | |
| 
 | |
| static void
 | |
| fu_progress_percentage_changed_cb(FuProgress *progress, guint percentage, gpointer data)
 | |
| {
 | |
| 	FuProgressHelper *helper = (FuProgressHelper *)data;
 | |
| 	helper->last_percentage = percentage;
 | |
| 	helper->updates++;
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_progress_func(void)
 | |
| {
 | |
| 	FuProgressHelper helper = {0};
 | |
| 	g_autoptr(FuProgress) progress = fu_progress_new(G_STRLOC);
 | |
| 	g_autofree gchar *str = NULL;
 | |
| 
 | |
| 	g_signal_connect(FU_PROGRESS(progress),
 | |
| 			 "percentage-changed",
 | |
| 			 G_CALLBACK(fu_progress_percentage_changed_cb),
 | |
| 			 &helper);
 | |
| 
 | |
| 	g_assert_cmpfloat_with_epsilon(fu_progress_get_duration(progress), 0.f, 0.001);
 | |
| 
 | |
| 	fu_progress_set_profile(progress, TRUE);
 | |
| 	fu_progress_set_steps(progress, 5);
 | |
| 	g_assert_cmpint(helper.last_percentage, ==, 0);
 | |
| 
 | |
| 	g_usleep(20 * 1000);
 | |
| 	fu_progress_step_done(progress);
 | |
| 	g_assert_cmpint(helper.updates, ==, 2);
 | |
| 	g_assert_cmpint(helper.last_percentage, ==, 20);
 | |
| 
 | |
| 	for (guint i = 0; i < 4; i++) {
 | |
| 		g_usleep(20 * 1000);
 | |
| 		fu_progress_step_done(progress);
 | |
| 	}
 | |
| 
 | |
| 	g_assert_cmpint(helper.last_percentage, ==, 100);
 | |
| 	g_assert_cmpint(helper.updates, ==, 6);
 | |
| 	g_assert_cmpfloat_with_epsilon(fu_progress_get_duration(progress), 0.1f, 0.05);
 | |
| 	str = fu_progress_traceback(progress);
 | |
| 	g_debug("\n%s", str);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_progress_child_func(void)
 | |
| {
 | |
| 	FuProgressHelper helper = {0};
 | |
| 	FuProgress *child;
 | |
| 	g_autoptr(FuProgress) progress = fu_progress_new(G_STRLOC);
 | |
| 
 | |
| 	/* reset */
 | |
| 	fu_progress_set_profile(progress, TRUE);
 | |
| 	fu_progress_set_steps(progress, 2);
 | |
| 	g_signal_connect(FU_PROGRESS(progress),
 | |
| 			 "percentage-changed",
 | |
| 			 G_CALLBACK(fu_progress_percentage_changed_cb),
 | |
| 			 &helper);
 | |
| 
 | |
| 	/* parent: |-----------------------|-----------------------|
 | |
| 	 * step1:  |-----------------------|
 | |
| 	 * child:                          |-------------|---------|
 | |
| 	 */
 | |
| 
 | |
| 	/* PARENT UPDATE */
 | |
| 	g_debug("parent update #1");
 | |
| 	fu_progress_step_done(progress);
 | |
| 	g_assert_cmpint(helper.updates, ==, 1);
 | |
| 	g_assert_cmpint(helper.last_percentage, ==, 50);
 | |
| 
 | |
| 	/* now test with a child */
 | |
| 	child = fu_progress_get_child(progress);
 | |
| 	fu_progress_set_id(child, G_STRLOC);
 | |
| 	fu_progress_set_steps(child, 2);
 | |
| 
 | |
| 	g_debug("child update #1");
 | |
| 	fu_progress_step_done(child);
 | |
| 	g_assert_cmpint(helper.updates, ==, 2);
 | |
| 	g_assert_cmpint(helper.last_percentage, ==, 75);
 | |
| 
 | |
| 	/* child update */
 | |
| 	g_debug("child update #2");
 | |
| 	fu_progress_step_done(child);
 | |
| 	g_assert_cmpint(helper.updates, ==, 3);
 | |
| 	g_assert_cmpint(helper.last_percentage, ==, 100);
 | |
| 
 | |
| 	/* parent update */
 | |
| 	g_debug("parent update #2");
 | |
| 	fu_progress_step_done(progress);
 | |
| 
 | |
| 	/* ensure we ignored the duplicate */
 | |
| 	g_assert_cmpint(helper.updates, ==, 3);
 | |
| 	g_assert_cmpint(helper.last_percentage, ==, 100);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_progress_parent_one_step_proxy_func(void)
 | |
| {
 | |
| 	FuProgressHelper helper = {0};
 | |
| 	FuProgress *child;
 | |
| 	g_autoptr(FuProgress) progress = fu_progress_new(G_STRLOC);
 | |
| 
 | |
| 	/* one step */
 | |
| 	fu_progress_set_steps(progress, 1);
 | |
| 	g_signal_connect(FU_PROGRESS(progress),
 | |
| 			 "percentage-changed",
 | |
| 			 G_CALLBACK(fu_progress_percentage_changed_cb),
 | |
| 			 &helper);
 | |
| 
 | |
| 	/* now test with a child */
 | |
| 	child = fu_progress_get_child(progress);
 | |
| 	fu_progress_set_id(child, G_STRLOC);
 | |
| 	fu_progress_set_steps(child, 2);
 | |
| 
 | |
| 	/* child set value */
 | |
| 	fu_progress_set_percentage(child, 33);
 | |
| 
 | |
| 	/* ensure 1 updates for progress with one step and ensure using child value as parent */
 | |
| 	g_assert_cmpint(helper.updates, ==, 1);
 | |
| 	g_assert_cmpint(helper.last_percentage, ==, 33);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_progress_non_equal_steps_func(void)
 | |
| {
 | |
| 	g_autoptr(FuProgress) progress = fu_progress_new(G_STRLOC);
 | |
| 	FuProgress *child;
 | |
| 	FuProgress *grandchild;
 | |
| 
 | |
| 	/* test non-equal steps */
 | |
| 	fu_progress_set_id(progress, G_STRLOC);
 | |
| 	fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_ERASE, 20, NULL);
 | |
| 	fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 60, NULL);
 | |
| 	fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_READ, 20, NULL);
 | |
| 	g_assert_cmpint(fu_progress_get_percentage(progress), ==, 0);
 | |
| 	g_assert_cmpint(fu_progress_get_status(progress), ==, FWUPD_STATUS_DEVICE_ERASE);
 | |
| 
 | |
| 	/* child step should increment according to the custom steps */
 | |
| 	child = fu_progress_get_child(progress);
 | |
| 	fu_progress_set_id(child, G_STRLOC);
 | |
| 	fu_progress_set_steps(child, 2);
 | |
| 	fu_progress_set_status(child, FWUPD_STATUS_DEVICE_BUSY);
 | |
| 	g_assert_cmpint(fu_progress_get_status(progress), ==, FWUPD_STATUS_DEVICE_BUSY);
 | |
| 
 | |
| 	/* start child */
 | |
| 	fu_progress_step_done(child);
 | |
| 
 | |
| 	/* verify 10% */
 | |
| 	g_assert_cmpint(fu_progress_get_percentage(progress), ==, 10);
 | |
| 
 | |
| 	/* finish child */
 | |
| 	fu_progress_step_done(child);
 | |
| 
 | |
| 	/* ensure the parent is switched back to the status before the child took over */
 | |
| 	g_assert_cmpint(fu_progress_get_status(progress), ==, FWUPD_STATUS_DEVICE_ERASE);
 | |
| 
 | |
| 	fu_progress_step_done(progress);
 | |
| 	g_assert_cmpint(fu_progress_get_status(progress), ==, FWUPD_STATUS_DEVICE_WRITE);
 | |
| 
 | |
| 	/* verify 20% */
 | |
| 	g_assert_cmpint(fu_progress_get_percentage(progress), ==, 20);
 | |
| 
 | |
| 	/* child step should increment according to the custom steps */
 | |
| 	child = fu_progress_get_child(progress);
 | |
| 	fu_progress_set_id(child, G_STRLOC);
 | |
| 	fu_progress_set_id(child, G_STRLOC);
 | |
| 	fu_progress_add_step(child, FWUPD_STATUS_DEVICE_RESTART, 25, NULL);
 | |
| 	fu_progress_add_step(child, FWUPD_STATUS_DEVICE_WRITE, 75, NULL);
 | |
| 	g_assert_cmpint(fu_progress_get_status(progress), ==, FWUPD_STATUS_DEVICE_RESTART);
 | |
| 
 | |
| 	/* start child */
 | |
| 	fu_progress_step_done(child);
 | |
| 	g_assert_cmpint(fu_progress_get_status(progress), ==, FWUPD_STATUS_DEVICE_WRITE);
 | |
| 
 | |
| 	/* verify bilinear interpolation is working */
 | |
| 	g_assert_cmpint(fu_progress_get_percentage(progress), ==, 35);
 | |
| 
 | |
| 	/*
 | |
| 	 * 0        20                             80         100
 | |
| 	 * |---------||----------------------------||---------|
 | |
| 	 *            |       35                   |
 | |
| 	 *            |-------||-------------------| (25%)
 | |
| 	 *                     |              75.5 |
 | |
| 	 *                     |---------------||--| (90%)
 | |
| 	 */
 | |
| 	grandchild = fu_progress_get_child(child);
 | |
| 	fu_progress_set_id(grandchild, G_STRLOC);
 | |
| 	fu_progress_add_step(grandchild, FWUPD_STATUS_DEVICE_ERASE, 90, NULL);
 | |
| 	fu_progress_add_step(grandchild, FWUPD_STATUS_DEVICE_WRITE, 10, NULL);
 | |
| 
 | |
| 	fu_progress_step_done(grandchild);
 | |
| 
 | |
| 	/* verify bilinear interpolation (twice) is working for subpercentage */
 | |
| 	g_assert_cmpint(fu_progress_get_percentage(progress), ==, 75);
 | |
| 
 | |
| 	fu_progress_step_done(grandchild);
 | |
| 
 | |
| 	/* finish child */
 | |
| 	fu_progress_step_done(child);
 | |
| 
 | |
| 	fu_progress_step_done(progress);
 | |
| 	g_assert_cmpint(fu_progress_get_status(progress), ==, FWUPD_STATUS_DEVICE_READ);
 | |
| 
 | |
| 	/* verify 80% */
 | |
| 	g_assert_cmpint(fu_progress_get_percentage(progress), ==, 80);
 | |
| 
 | |
| 	fu_progress_step_done(progress);
 | |
| 
 | |
| 	/* verify 100% */
 | |
| 	g_assert_cmpint(fu_progress_get_percentage(progress), ==, 100);
 | |
| 	g_assert_cmpint(fu_progress_get_status(progress), ==, FWUPD_STATUS_UNKNOWN);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_progress_finish_func(void)
 | |
| {
 | |
| 	FuProgress *child;
 | |
| 	g_autoptr(FuProgress) progress = fu_progress_new(G_STRLOC);
 | |
| 
 | |
| 	/* check straight finish */
 | |
| 	fu_progress_set_steps(progress, 3);
 | |
| 
 | |
| 	child = fu_progress_get_child(progress);
 | |
| 	fu_progress_set_id(child, G_STRLOC);
 | |
| 	fu_progress_set_steps(child, 3);
 | |
| 	fu_progress_finished(child);
 | |
| 
 | |
| 	/* parent step done after child finish */
 | |
| 	fu_progress_step_done(progress);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fu_progress_child_finished(void)
 | |
| {
 | |
| 	FuProgress *child;
 | |
| 	g_autoptr(FuProgress) progress = fu_progress_new(G_STRLOC);
 | |
| 
 | |
| 	/* check straight finish */
 | |
| 	fu_progress_set_steps(progress, 3);
 | |
| 
 | |
| 	child = fu_progress_get_child(progress);
 | |
| 	fu_progress_set_id(child, G_STRLOC);
 | |
| 	fu_progress_set_steps(child, 3);
 | |
| 	/* some imaginary ignorable error */
 | |
| 
 | |
| 	/* parent step done after child finish */
 | |
| 	fu_progress_add_flag(progress, FU_PROGRESS_FLAG_CHILD_FINISHED);
 | |
| 	fu_progress_step_done(progress);
 | |
| }
 | |
| 
 | |
| int
 | |
| main(int argc, char **argv)
 | |
| {
 | |
| 	g_autofree gchar *testdatadir = NULL;
 | |
| 
 | |
| 	g_test_init(&argc, &argv, NULL);
 | |
| 	g_type_ensure(FU_TYPE_IFD_BIOS);
 | |
| 
 | |
| 	/* only critical and error are fatal */
 | |
| 	g_log_set_fatal_mask(NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);
 | |
| 	(void)g_setenv("G_MESSAGES_DEBUG", "all", TRUE);
 | |
| 
 | |
| 	testdatadir = g_test_build_filename(G_TEST_DIST, "tests", NULL);
 | |
| 	(void)g_setenv("FWUPD_DATADIR", testdatadir, TRUE);
 | |
| 	(void)g_setenv("FWUPD_LIBDIR_PKG", testdatadir, TRUE);
 | |
| 	(void)g_setenv("FWUPD_SYSCONFDIR", testdatadir, TRUE);
 | |
| 	(void)g_setenv("FWUPD_SYSFSFWATTRIBDIR", testdatadir, TRUE);
 | |
| 	(void)g_setenv("FWUPD_SYSFSDMIDIR", testdatadir, TRUE);
 | |
| 	(void)g_setenv("FWUPD_LOCALSTATEDIR", testdatadir, TRUE);
 | |
| 	(void)g_setenv("FWUPD_OFFLINE_TRIGGER", "/tmp/fwupd-self-test/system-update", TRUE);
 | |
| 	(void)g_setenv("FWUPD_LOCALSTATEDIR", "/tmp/fwupd-self-test/var", TRUE);
 | |
| 	(void)g_setenv("FWUPD_PROFILE", "1", TRUE);
 | |
| 
 | |
| 	g_test_add_func("/fwupd/plugin{quirks-append}", fu_plugin_quirks_append_func);
 | |
| 	g_test_add_func("/fwupd/common{strnsplit}", fu_strsplit_func);
 | |
| 	g_test_add_func("/fwupd/common{memmem}", fu_common_memmem_func);
 | |
| 	if (g_test_slow())
 | |
| 		g_test_add_func("/fwupd/progress", fu_progress_func);
 | |
| 	g_test_add_func("/fwupd/progress{child}", fu_progress_child_func);
 | |
| 	g_test_add_func("/fwupd/progress{child-finished}", fu_progress_child_finished);
 | |
| 	g_test_add_func("/fwupd/progress{parent-1-step}", fu_progress_parent_one_step_proxy_func);
 | |
| 	g_test_add_func("/fwupd/progress{no-equal}", fu_progress_non_equal_steps_func);
 | |
| 	g_test_add_func("/fwupd/progress{finish}", fu_progress_finish_func);
 | |
| 	g_test_add_func("/fwupd/bios-attrs{load}", fu_bios_settings_load_func);
 | |
| 	g_test_add_func("/fwupd/security-attrs{hsi}", fu_security_attrs_hsi_func);
 | |
| 	g_test_add_func("/fwupd/plugin{config}", fu_plugin_config_func);
 | |
| 	g_test_add_func("/fwupd/plugin{devices}", fu_plugin_devices_func);
 | |
| 	g_test_add_func("/fwupd/plugin{device-inhibit-children}",
 | |
| 			fu_plugin_device_inhibit_children_func);
 | |
| 	g_test_add_func("/fwupd/plugin{delay}", fu_plugin_delay_func);
 | |
| 	g_test_add_func("/fwupd/plugin{quirks}", fu_plugin_quirks_func);
 | |
| 	g_test_add_func("/fwupd/plugin{fdt}", fu_plugin_fdt_func);
 | |
| 	g_test_add_func("/fwupd/plugin{quirks-performance}", fu_plugin_quirks_performance_func);
 | |
| 	g_test_add_func("/fwupd/plugin{quirks-device}", fu_plugin_quirks_device_func);
 | |
| 	g_test_add_func("/fwupd/backend", fu_backend_func);
 | |
| 	g_test_add_func("/fwupd/chunk", fu_chunk_func);
 | |
| 	g_test_add_func("/fwupd/common{align-up}", fu_common_align_up_func);
 | |
| 	g_test_add_func("/fwupd/volume{gpt-type}", fu_volume_gpt_type_func);
 | |
| 	g_test_add_func("/fwupd/common{byte-array}", fu_common_byte_array_func);
 | |
| 	g_test_add_func("/fwupd/common{crc}", fu_common_crc_func);
 | |
| 	g_test_add_func("/fwupd/common{string-append-kv}", fu_string_append_func);
 | |
| 	g_test_add_func("/fwupd/common{version-guess-format}", fu_version_guess_format_func);
 | |
| 	g_test_add_func("/fwupd/common{strtoull}", fu_strtoull_func);
 | |
| 	g_test_add_func("/fwupd/common{version}", fu_common_version_func);
 | |
| 	g_test_add_func("/fwupd/common{version-semver}", fu_version_semver_func);
 | |
| 	g_test_add_func("/fwupd/common{vercmp}", fu_common_vercmp_func);
 | |
| 	g_test_add_func("/fwupd/common{strstrip}", fu_strstrip_func);
 | |
| 	g_test_add_func("/fwupd/common{endian}", fu_common_endian_func);
 | |
| 	g_test_add_func("/fwupd/common{cabinet}", fu_common_cabinet_func);
 | |
| 	g_test_add_func("/fwupd/common{bytes-get-data}", fu_common_bytes_get_data_func);
 | |
| 	g_test_add_func("/fwupd/common{kernel-lockdown}", fu_common_kernel_lockdown_func);
 | |
| 	g_test_add_func("/fwupd/common{strsafe}", fu_strsafe_func);
 | |
| 	g_test_add_func("/fwupd/efivar", fu_efivar_func);
 | |
| 	g_test_add_func("/fwupd/hwids", fu_hwids_func);
 | |
| 	g_test_add_func("/fwupd/context{flags}", fu_context_flags_func);
 | |
| 	g_test_add_func("/fwupd/context{hwids-dmi}", fu_context_hwids_dmi_func);
 | |
| 	g_test_add_func("/fwupd/smbios", fu_smbios_func);
 | |
| 	g_test_add_func("/fwupd/smbios3", fu_smbios3_func);
 | |
| 	g_test_add_func("/fwupd/firmware", fu_firmware_func);
 | |
| 	g_test_add_func("/fwupd/firmware{common}", fu_firmware_common_func);
 | |
| 	g_test_add_func("/fwupd/firmware{archive}", fu_firmware_archive_func);
 | |
| 	g_test_add_func("/fwupd/firmware{linear}", fu_firmware_linear_func);
 | |
| 	g_test_add_func("/fwupd/firmware{dedupe}", fu_firmware_dedupe_func);
 | |
| 	g_test_add_func("/fwupd/firmware{build}", fu_firmware_build_func);
 | |
| 	g_test_add_func("/fwupd/firmware{raw-aligned}", fu_firmware_raw_aligned_func);
 | |
| 	g_test_add_func("/fwupd/firmware{ihex}", fu_firmware_ihex_func);
 | |
| 	g_test_add_func("/fwupd/firmware{ihex-offset}", fu_firmware_ihex_offset_func);
 | |
| 	g_test_add_func("/fwupd/firmware{ihex-signed}", fu_firmware_ihex_signed_func);
 | |
| 	g_test_add_func("/fwupd/firmware{srec-tokenization}", fu_firmware_srec_tokenization_func);
 | |
| 	g_test_add_func("/fwupd/firmware{srec}", fu_firmware_srec_func);
 | |
| 	g_test_add_func("/fwupd/firmware{fdt}", fu_firmware_fdt_func);
 | |
| 	g_test_add_func("/fwupd/firmware{fit}", fu_firmware_fit_func);
 | |
| 	g_test_add_func("/fwupd/firmware{ifwi-cpd}", fu_firmware_ifwi_cpd_func);
 | |
| 	g_test_add_func("/fwupd/firmware{ifwi-fpt}", fu_firmware_ifwi_fpt_func);
 | |
| 	g_test_add_func("/fwupd/firmware{oprom}", fu_firmware_oprom_func);
 | |
| 	g_test_add_func("/fwupd/firmware{dfu}", fu_firmware_dfu_func);
 | |
| 	g_test_add_func("/fwupd/firmware{dfu-patch}", fu_firmware_dfu_patch_func);
 | |
| 	g_test_add_func("/fwupd/firmware{dfuse}", fu_firmware_dfuse_func);
 | |
| 	g_test_add_func("/fwupd/firmware{builder-round-trip}", fu_firmware_builder_round_trip_func);
 | |
| 	g_test_add_func("/fwupd/firmware{fmap}", fu_firmware_fmap_func);
 | |
| 	g_test_add_func("/fwupd/firmware{gtypes}", fu_firmware_new_from_gtypes_func);
 | |
| 	g_test_add_func("/fwupd/archive{invalid}", fu_archive_invalid_func);
 | |
| 	g_test_add_func("/fwupd/archive{cab}", fu_archive_cab_func);
 | |
| 	g_test_add_func("/fwupd/device", fu_device_func);
 | |
| 	g_test_add_func("/fwupd/device{instance-ids}", fu_device_instance_ids_func);
 | |
| 	g_test_add_func("/fwupd/device{composite-id}", fu_device_composite_id_func);
 | |
| 	g_test_add_func("/fwupd/device{flags}", fu_device_flags_func);
 | |
| 	g_test_add_func("/fwupd/device{custom-flags}", fu_device_private_flags_func);
 | |
| 	g_test_add_func("/fwupd/device{inhibit}", fu_device_inhibit_func);
 | |
| 	g_test_add_func("/fwupd/device{inhibit-updateable}", fu_device_inhibit_updateable_func);
 | |
| 	g_test_add_func("/fwupd/device{parent}", fu_device_parent_func);
 | |
| 	g_test_add_func("/fwupd/device{children}", fu_device_children_func);
 | |
| 	g_test_add_func("/fwupd/device{incorporate}", fu_device_incorporate_func);
 | |
| 	if (g_test_slow())
 | |
| 		g_test_add_func("/fwupd/device{poll}", fu_device_poll_func);
 | |
| 	g_test_add_func("/fwupd/device-locker{success}", fu_device_locker_func);
 | |
| 	g_test_add_func("/fwupd/device-locker{fail}", fu_device_locker_fail_func);
 | |
| 	g_test_add_func("/fwupd/device{name}", fu_device_name_func);
 | |
| 	g_test_add_func("/fwupd/device{metadata}", fu_device_metadata_func);
 | |
| 	g_test_add_func("/fwupd/device{open-refcount}", fu_device_open_refcount_func);
 | |
| 	g_test_add_func("/fwupd/device{version-format}", fu_device_version_format_func);
 | |
| 	g_test_add_func("/fwupd/device{retry-success}", fu_device_retry_success_func);
 | |
| 	g_test_add_func("/fwupd/device{retry-failed}", fu_device_retry_failed_func);
 | |
| 	g_test_add_func("/fwupd/device{retry-hardware}", fu_device_retry_hardware_func);
 | |
| 	g_test_add_func("/fwupd/device{cfi-device}", fu_device_cfi_device_func);
 | |
| 	g_test_add_func("/fwupd/device{progress}", fu_plugin_device_progress_func);
 | |
| 	return g_test_run();
 | |
| }
 |