File 0001-Add-explicit-UTF8-tests-to-check-for-libfyaml-s-unic.patch of Package AppStream
From 21073ec9ae2b89fee42bab8a15e5f21d7fa2adbd Mon Sep 17 00:00:00 2001
From: Matthias Klumpp <matthias@tenstral.net>
Date: Tue, 23 Sep 2025 20:11:07 +0200
Subject: [PATCH] Add explicit UTF8 tests to check for libfyaml's unicode
handling
libfyaml <= 0.8 had a bug which made it corrupt UTF-8 data. Check for
that, so it (hopefully) will never happen again.
This will likely fail CI and we will have to upgrade libfyaml on a few
tested distributions.
---
src/as-metadata.c | 7 +--
src/as-release.c | 2 +-
src/as-yaml.c | 42 +++++++++++++++
src/as-yaml.h | 4 ++
tests/test-basics.c | 4 ++
tests/test-compose.c | 4 ++
tests/test-misc.c | 4 ++
tests/test-performance.c | 2 +
tests/test-pool.c | 1 +
tests/test-validate.c | 4 ++
tests/test-xmldata.c | 3 ++
tests/test-yamldata.c | 114 +++++++++++++++++++++++++++------------
12 files changed, 154 insertions(+), 37 deletions(-)
diff --git a/src/as-metadata.c b/src/as-metadata.c
index b5cdbb13..060e7f67 100644
--- a/src/as-metadata.c
+++ b/src/as-metadata.c
@@ -1320,9 +1320,10 @@ as_yamldata_write_header (AsContext *context, struct fy_emitter *emitter, gboole
as_yaml_mapping_start (emitter);
as_yaml_emit_entry (emitter, "File", "DEP-11");
- as_yaml_emit_entry (emitter,
- "Version",
- as_format_version_to_string (as_context_get_format_version (context)));
+ as_yaml_emit_entry_str (
+ emitter,
+ "Version",
+ as_format_version_to_string (as_context_get_format_version (context)));
as_yaml_emit_entry (emitter, "Origin", as_context_get_origin (context));
if (as_context_has_media_baseurl (context))
as_yaml_emit_entry (emitter,
diff --git a/src/as-release.c b/src/as-release.c
index 37948f00..b503bd29 100644
--- a/src/as-release.c
+++ b/src/as-release.c
@@ -1200,7 +1200,7 @@ as_release_emit_yaml (AsRelease *release, AsContext *ctx, struct fy_emitter *emi
as_yaml_mapping_start (emitter);
/* version */
- as_yaml_emit_entry (emitter, "version", priv->version);
+ as_yaml_emit_entry_str (emitter, "version", priv->version);
/* type */
as_yaml_emit_entry (emitter, "type", as_release_kind_to_string (priv->kind));
diff --git a/src/as-yaml.c b/src/as-yaml.c
index 7e4dea9d..123a7796 100644
--- a/src/as-yaml.c
+++ b/src/as-yaml.c
@@ -396,6 +396,30 @@ as_yaml_emit_scalar (struct fy_emitter *emitter, const gchar *value)
fy_emit_event (emitter, fye);
}
+/**
+ * as_yaml_emit_scalar_str:
+ * @emitter: the YAML emitter.
+ * @value: the string value to emit.
+ *
+ * Emit a string scalar and ensure it is always quoted.
+ */
+void
+as_yaml_emit_scalar_str (struct fy_emitter *emitter, const gchar *value)
+{
+ struct fy_event *fye;
+ g_return_if_fail (value != NULL);
+
+ fye = fy_emit_event_create (emitter,
+ FYET_SCALAR,
+ FYSS_SINGLE_QUOTED,
+ value,
+ FY_NT,
+ NULL,
+ NULL);
+ if (fye != NULL)
+ fy_emit_event (emitter, fye);
+}
+
/**
* as_yaml_emit_scalar_raw:
*/
@@ -461,6 +485,24 @@ as_yaml_emit_entry (struct fy_emitter *emitter, const gchar *key, const gchar *v
as_yaml_emit_scalar (emitter, value);
}
+/**
+ * as_yaml_emit_entry_str:
+ * @emitter: the YAML emitter.
+ * @key: the key to emit.
+ * @value: the string value to emit.
+ *
+ * Emit a kv pair, and ensure the string value is always quoted.
+ */
+void
+as_yaml_emit_entry_str (struct fy_emitter *emitter, const gchar *key, const gchar *value)
+{
+ if (value == NULL)
+ return;
+
+ as_yaml_emit_scalar_key (emitter, key);
+ as_yaml_emit_scalar_str (emitter, value);
+}
+
/**
* as_yaml_emit_entry_uint64:
*/
diff --git a/src/as-yaml.h b/src/as-yaml.h
index 29659477..af2341be 100644
--- a/src/as-yaml.h
+++ b/src/as-yaml.h
@@ -105,13 +105,17 @@ void as_yaml_emit_long_entry_literal (struct fy_emitter *emitter,
const gchar *value);
void as_yaml_emit_scalar_raw (struct fy_emitter *emitter, const gchar *value);
void as_yaml_emit_scalar (struct fy_emitter *emitter, const gchar *value);
+void as_yaml_emit_scalar_str (struct fy_emitter *emitter, const gchar *value);
void as_yaml_emit_scalar_uint64 (struct fy_emitter *emitter, guint64 value);
void as_yaml_emit_scalar_key (struct fy_emitter *emitter, const gchar *key);
+
void as_yaml_emit_entry (struct fy_emitter *emitter, const gchar *key, const gchar *value);
+void as_yaml_emit_entry_str (struct fy_emitter *emitter, const gchar *key, const gchar *value);
void as_yaml_emit_entry_uint64 (struct fy_emitter *emitter, const gchar *key, guint64 value);
void as_yaml_emit_entry_timestamp (struct fy_emitter *emitter, const gchar *key, guint64 unixtime);
void as_yaml_emit_long_entry (struct fy_emitter *emitter, const gchar *key, const gchar *value);
void as_yaml_emit_sequence (struct fy_emitter *emitter, const gchar *key, GPtrArray *list);
+
#pragma GCC visibility pop
void as_yaml_emit_sequence_from_str_array (struct fy_emitter *emitter,
const gchar *key,
diff --git a/tests/test-basics.c b/tests/test-basics.c
index be371755..1f7ac0e9 100644
--- a/tests/test-basics.c
+++ b/tests/test-basics.c
@@ -20,6 +20,8 @@
#include <config.h>
#include <glib.h>
+#include <locale.h>
+
#include "appstream.h"
#include "as-component-private.h"
#include "as-component-box-private.h"
@@ -1244,6 +1246,8 @@ main (int argc, char **argv)
{
int ret;
+ setlocale (LC_ALL, "");
+
if (argc == 0) {
g_error ("No test directory specified!");
return 1;
diff --git a/tests/test-compose.c b/tests/test-compose.c
index 83c8ea74..a7382561 100644
--- a/tests/test-compose.c
+++ b/tests/test-compose.c
@@ -19,6 +19,8 @@
*/
#include <glib.h>
+#include <locale.h>
+
#include "appstream-compose.h"
#include "asc-font-private.h"
#include "asc-utils-metainfo.h"
@@ -1079,6 +1081,8 @@ main (int argc, char **argv)
{
int ret;
+ setlocale (LC_ALL, "");
+
if (argc == 0) {
g_error ("No test directory specified!");
return 1;
diff --git a/tests/test-misc.c b/tests/test-misc.c
index ba3d4dbd..ae4ed4c7 100644
--- a/tests/test-misc.c
+++ b/tests/test-misc.c
@@ -19,6 +19,8 @@
*/
#include <glib.h>
+#include <locale.h>
+
#include "appstream.h"
#include "as-news-convert.h"
#include "as-utils-private.h"
@@ -463,6 +465,8 @@ main (int argc, char **argv)
{
int ret;
+ setlocale (LC_ALL, "");
+
if (argc == 0) {
g_error ("No test directory specified!");
return 1;
diff --git a/tests/test-performance.c b/tests/test-performance.c
index 3bee90ba..a39ee248 100644
--- a/tests/test-performance.c
+++ b/tests/test-performance.c
@@ -21,6 +21,7 @@
#include <glib.h>
#include <glib/gprintf.h>
#include <glib/gstdio.h>
+#include <locale.h>
#include "appstream.h"
#include "as-utils-private.h"
@@ -184,6 +185,7 @@ main (int argc, char **argv)
{
int ret;
+ setlocale (LC_ALL, "");
g_test_init (&argc, &argv, NULL);
if (argc == 0) {
diff --git a/tests/test-pool.c b/tests/test-pool.c
index 3691404f..a2c3c7b6 100644
--- a/tests/test-pool.c
+++ b/tests/test-pool.c
@@ -1058,6 +1058,7 @@ main (int argc, char **argv)
}
/* ensure locale is reset, to avoid interference when stemming is enabled & tested */
+ setlocale (LC_ALL, "");
if (setlocale (LC_ALL, "C.UTF-8") == NULL)
g_warning ("Failed to set locale to C.UTF-8");
diff --git a/tests/test-validate.c b/tests/test-validate.c
index 22774e9e..307ebac7 100644
--- a/tests/test-validate.c
+++ b/tests/test-validate.c
@@ -19,6 +19,8 @@
*/
#include <glib.h>
+#include <locale.h>
+
#include "appstream.h"
#include "as-component-private.h"
#include "as-validator-issue-tag.h"
@@ -415,6 +417,8 @@ main (int argc, char **argv)
{
int ret;
+ setlocale (LC_ALL, "");
+
if (argc == 0) {
g_error ("No test directory specified!");
return 1;
diff --git a/tests/test-xmldata.c b/tests/test-xmldata.c
index a2d45276..d5feddeb 100644
--- a/tests/test-xmldata.c
+++ b/tests/test-xmldata.c
@@ -20,6 +20,7 @@
#include <glib.h>
#include <glib/gprintf.h>
+#include <locale.h>
#include "appstream.h"
#include "as-component-private.h"
@@ -2444,6 +2445,8 @@ main (int argc, char **argv)
{
int ret;
+ setlocale (LC_ALL, "");
+
if (argc == 0) {
g_error ("No test directory specified!");
return 1;
diff --git a/tests/test-yamldata.c b/tests/test-yamldata.c
index 066cf24f..89e06e1e 100644
--- a/tests/test-yamldata.c
+++ b/tests/test-yamldata.c
@@ -20,6 +20,7 @@
#include <glib.h>
#include <glib/gprintf.h>
+#include <locale.h>
#include "appstream.h"
#include "as-screenshot-private.h"
@@ -1874,22 +1875,22 @@ test_yaml_rw_tags (void)
static void
test_yaml_rw_branding (void)
{
- static const gchar *yamldata_tags = "Type: generic\n"
- "ID: org.example.BrandingTest\n"
- "Branding:\n"
- " colors:\n"
- " - type: primary\n"
- " scheme-preference: light\n"
- " value: \"#ff00ff\"\n"
- " - type: primary\n"
- " scheme-preference: dark\n"
- " value: \"#993d3d\"\n";
+ static const gchar *yamldata = "Type: generic\n"
+ "ID: org.example.BrandingTest\n"
+ "Branding:\n"
+ " colors:\n"
+ " - type: primary\n"
+ " scheme-preference: light\n"
+ " value: \"#ff00ff\"\n"
+ " - type: primary\n"
+ " scheme-preference: dark\n"
+ " value: \"#993d3d\"\n";
g_autoptr(AsComponent) cpt = NULL;
g_autofree gchar *res = NULL;
AsBranding *branding;
/* read */
- cpt = as_yaml_test_read_data (yamldata_tags, NULL);
+ cpt = as_yaml_test_read_data (yamldata, NULL);
g_assert_cmpstr (as_component_get_id (cpt), ==, "org.example.BrandingTest");
/* validate */
@@ -1907,7 +1908,7 @@ test_yaml_rw_branding (void)
/* write */
res = as_yaml_test_serialize (cpt);
- g_assert_true (as_yaml_test_compare_yaml (res, yamldata_tags));
+ g_assert_true (as_yaml_test_compare_yaml (res, yamldata));
}
/**
@@ -1916,18 +1917,18 @@ test_yaml_rw_branding (void)
static void
test_yaml_rw_developer (void)
{
- static const gchar *yamldata_tags = "Type: generic\n"
- "ID: org.example.DeveloperTest\n"
- "Developer:\n"
- " id: freedesktop.org\n"
- " name:\n"
- " C: FreeDesktop.org Project\n";
+ static const gchar *yamldata = "Type: generic\n"
+ "ID: org.example.DeveloperTest\n"
+ "Developer:\n"
+ " id: freedesktop.org\n"
+ " name:\n"
+ " C: FreeDesktop.org Project\n";
g_autoptr(AsComponent) cpt = NULL;
g_autofree gchar *res = NULL;
AsDeveloper *devp;
/* read */
- cpt = as_yaml_test_read_data (yamldata_tags, NULL);
+ cpt = as_yaml_test_read_data (yamldata, NULL);
g_assert_cmpstr (as_component_get_id (cpt), ==, "org.example.DeveloperTest");
/* validate */
@@ -1939,32 +1940,32 @@ test_yaml_rw_developer (void)
/* write */
res = as_yaml_test_serialize (cpt);
- g_assert_true (as_yaml_test_compare_yaml (res, yamldata_tags));
+ g_assert_true (as_yaml_test_compare_yaml (res, yamldata));
}
/**
- * test_yaml_rw_developer:
+ * test_yaml_rw_references:
*/
static void
test_yaml_rw_references (void)
{
- static const gchar *yamldata_tags = "Type: generic\n"
- "ID: org.example.ReferencesTest\n"
- "References:\n"
- "- type: doi\n"
- " value: 10.1000/182\n"
- "- type: citation_cff\n"
- " value: https://example.org/CITATION.cff\n"
- "- type: registry\n"
- " value: SCR_000000\n"
- " registry: SciCrunch\n";
+ static const gchar *yamldata = "Type: generic\n"
+ "ID: org.example.ReferencesTest\n"
+ "References:\n"
+ "- type: doi\n"
+ " value: 10.1000/182\n"
+ "- type: citation_cff\n"
+ " value: https://example.org/CITATION.cff\n"
+ "- type: registry\n"
+ " value: SCR_000000\n"
+ " registry: SciCrunch\n";
g_autoptr(AsComponent) cpt = NULL;
g_autofree gchar *res = NULL;
GPtrArray *refs;
AsReference *ref;
/* read */
- cpt = as_yaml_test_read_data (yamldata_tags, NULL);
+ cpt = as_yaml_test_read_data (yamldata, NULL);
g_assert_cmpstr (as_component_get_id (cpt), ==, "org.example.ReferencesTest");
/* validate */
@@ -1987,7 +1988,51 @@ test_yaml_rw_references (void)
/* write */
res = as_yaml_test_serialize (cpt);
- g_assert_true (as_yaml_test_compare_yaml (res, yamldata_tags));
+ g_assert_true (as_yaml_test_compare_yaml (res, yamldata));
+}
+
+/**
+ * test_yaml_rw_utf8:
+ */
+static void
+test_yaml_rw_utf8 (void)
+{
+ static const gchar *yamldata =
+ "Type: generic\n"
+ "ID: org.example.Utf8Test\n"
+ "Name:\n"
+ " C: Test\n"
+ " uk: Тест\n"
+ "Description:\n"
+ " C: >-\n"
+ " <p>JFtp is a graphical Java network and file transfer client. It supports FTP "
+ "using its own FTP API and various other protocols like SMB,\n"
+ " SFTP, NFS, HTTP, and file I/O using third party APIs. It includes many advanced "
+ "features such as recursive directory up/download, browsing\n"
+ " FTP servers while transferring files, FTP resuming and queueing, browsing the LAN "
+ "for Windows shares, and more. Multiple connections can\n"
+ " open at a time in a Mozilla-style tabbed browsing environment.</p>\n"
+ " uk: >-\n"
+ " <p>Jftp — це графічний клієнт передачі даних мережею. Підтримка FTP реалізована "
+ "за допомогою внутрішнього інтерфейсу, а підтримку протоколів\n"
+ " SMB, SFTP, NFS, HTTP та роботу з файлами — за допомогою зовнішніх інтерфейсів. "
+ "Він має багато гарних можливостей, наприклад, рекурсивне\n"
+ " відправлення/завантаження, роботу з FTP-сервером під час передачі файлів, "
+ "продовження та створення черг завантажень з FTP, перегляд локальної\n"
+ " мережі в пошуках спільних тек Windows, тощо. Може створювати по декілька "
+ "з'єднань одразу за допомогою подібного до Mozilla інтерфейсу\n"
+ " з вкладками.</p>\n";
+
+ g_autoptr(AsComponent) cpt = NULL;
+ g_autofree gchar *res = NULL;
+
+ /* read */
+ cpt = as_yaml_test_read_data (yamldata, NULL);
+ g_assert_cmpstr (as_component_get_id (cpt), ==, "org.example.Utf8Test");
+
+ /* write */
+ res = as_yaml_test_serialize (cpt);
+ g_assert_true (as_yaml_test_compare_yaml (res, yamldata));
}
/**
@@ -1998,6 +2043,8 @@ main (int argc, char **argv)
{
int ret;
+ setlocale (LC_ALL, "");
+
if (argc == 0) {
g_error ("No test directory specified!");
return 1;
@@ -2056,6 +2103,7 @@ main (int argc, char **argv)
g_test_add_func ("/YAML/ReadWrite/Branding", test_yaml_rw_branding);
g_test_add_func ("/YAML/ReadWrite/Developer", test_yaml_rw_developer);
g_test_add_func ("/YAML/ReadWrite/References", test_yaml_rw_references);
+ g_test_add_func ("/YAML/ReadWrite/Utf8", test_yaml_rw_utf8);
ret = g_test_run ();
g_free (datadir);
--
2.51.0