summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Withnall <withnall@endlessm.com>2019-10-02 12:47:02 +0100
committerRichard Hughes <richard@hughsie.com>2019-10-02 13:58:24 +0100
commitaa07925a826978b1a03c39cab6b94cd1f289271f (patch)
treea1b021fccf237bdca0b631200eefb73e2950553e
parentb871fa2ad473f765cc40771613a19aa6f821915a (diff)
downloadappstream-glib-aa07925a826978b1a03c39cab6b94cd1f289271f.tar.gz
as-content-rating: Make default values match OARS semantics
If an OARS key is missing from a `<content_rating/>` element, the default value should be `none`, not `unknown`. Change the implementation of `as_content_rating_get_value()` to do that, and add some tests. See the OARS specification: https://github.com/hughsie/oars/blob/master/specification/oars-1.1.md Signed-off-by: Philip Withnall <withnall@endlessm.com>
-rw-r--r--libappstream-glib/as-content-rating.c88
-rw-r--r--libappstream-glib/as-self-test.c48
2 files changed, 106 insertions, 30 deletions
diff --git a/libappstream-glib/as-content-rating.c b/libappstream-glib/as-content-rating.c
index 6d6ae76..11bc20d 100644
--- a/libappstream-glib/as-content-rating.c
+++ b/libappstream-glib/as-content-rating.c
@@ -38,6 +38,14 @@ G_DEFINE_TYPE_WITH_PRIVATE (AsContentRating, as_content_rating, G_TYPE_OBJECT)
#define GET_PRIVATE(o) (as_content_rating_get_instance_private (o))
+typedef enum
+{
+ OARS_1_0,
+ OARS_1_1,
+} OarsVersion;
+
+static gboolean is_oars_key (const gchar *id, OarsVersion version);
+
static void
as_content_rating_finalize (GObject *object)
{
@@ -139,7 +147,18 @@ as_content_rating_get_value (AsContentRating *content_rating, const gchar *id)
if (g_strcmp0 (key->id, id) == 0)
return key->value;
}
- return AS_CONTENT_RATING_VALUE_UNKNOWN;
+
+ /* According to the
+ * [OARS specification](https://github.com/hughsie/oars/blob/master/specification/oars-1.1.md),
+ * return %AS_CONTENT_RATING_VALUE_NONE if the #AsContentRating exists
+ * overall. Only return %AS_CONTENT_RATING_VALUE_UNKNOWN if the
+ * #AsContentRating doesn’t exist at all (or for other types of content
+ * rating). */
+ if ((g_strcmp0 (priv->kind, "oars-1.0") == 0 && is_oars_key (id, OARS_1_0)) ||
+ (g_strcmp0 (priv->kind, "oars-1.1") == 0 && is_oars_key (id, OARS_1_1)))
+ return AS_CONTENT_RATING_VALUE_NONE;
+ else
+ return AS_CONTENT_RATING_VALUE_UNKNOWN;
}
/**
@@ -196,6 +215,7 @@ G_STATIC_ASSERT (AS_CONTENT_RATING_VALUE_LAST == AS_CONTENT_RATING_VALUE_INTENSE
static const struct {
const gchar *id;
+ OarsVersion oars_version; /* when the key was first added */
guint csm_age_none; /* for %AS_CONTENT_RATING_VALUE_NONE */
guint csm_age_mild; /* for %AS_CONTENT_RATING_VALUE_MILD */
guint csm_age_moderate; /* for %AS_CONTENT_RATING_VALUE_MODERATE */
@@ -204,37 +224,47 @@ static const struct {
/* Each @id must only appear once. The set of @csm_age_* values for a
* given @id must be complete and non-decreasing. */
/* v1.0 */
- { "violence-cartoon", 0, 3, 4, 6 },
- { "violence-fantasy", 0, 3, 7, 8 },
- { "violence-realistic", 0, 4, 9, 14 },
- { "violence-bloodshed", 0, 9, 11, 18 },
- { "violence-sexual", 0, 18, 18, 18 },
- { "drugs-alcohol", 0, 11, 13, 16 },
- { "drugs-narcotics", 0, 12, 14, 17 },
- { "drugs-tobacco", 0, 10, 13, 13 },
- { "sex-nudity", 0, 12, 14, 14 },
- { "sex-themes", 0, 13, 14, 15 },
- { "language-profanity", 0, 8, 11, 14 },
- { "language-humor", 0, 3, 8, 14 },
- { "language-discrimination", 0, 9, 10, 11 },
- { "money-advertising", 0, 7, 8, 10 },
- { "money-gambling", 0, 7, 10, 18 },
- { "money-purchasing", 0, 12, 14, 15 },
- { "social-chat", 0, 4, 10, 13 },
- { "social-audio", 0, 15, 15, 15 },
- { "social-contacts", 0, 12, 12, 12 },
- { "social-info", 0, 0, 13, 13 },
- { "social-location", 0, 13, 13, 13 },
+ { "violence-cartoon", OARS_1_0, 0, 3, 4, 6 },
+ { "violence-fantasy", OARS_1_0, 0, 3, 7, 8 },
+ { "violence-realistic", OARS_1_0, 0, 4, 9, 14 },
+ { "violence-bloodshed", OARS_1_0, 0, 9, 11, 18 },
+ { "violence-sexual", OARS_1_0, 0, 18, 18, 18 },
+ { "drugs-alcohol", OARS_1_0, 0, 11, 13, 16 },
+ { "drugs-narcotics", OARS_1_0, 0, 12, 14, 17 },
+ { "drugs-tobacco", OARS_1_0, 0, 10, 13, 13 },
+ { "sex-nudity", OARS_1_0, 0, 12, 14, 14 },
+ { "sex-themes", OARS_1_0, 0, 13, 14, 15 },
+ { "language-profanity", OARS_1_0, 0, 8, 11, 14 },
+ { "language-humor", OARS_1_0, 0, 3, 8, 14 },
+ { "language-discrimination", OARS_1_0, 0, 9, 10, 11 },
+ { "money-advertising", OARS_1_0, 0, 7, 8, 10 },
+ { "money-gambling", OARS_1_0, 0, 7, 10, 18 },
+ { "money-purchasing", OARS_1_0, 0, 12, 14, 15 },
+ { "social-chat", OARS_1_0, 0, 4, 10, 13 },
+ { "social-audio", OARS_1_0, 0, 15, 15, 15 },
+ { "social-contacts", OARS_1_0, 0, 12, 12, 12 },
+ { "social-info", OARS_1_0, 0, 0, 13, 13 },
+ { "social-location", OARS_1_0, 0, 13, 13, 13 },
/* v1.1 additions */
- { "sex-homosexuality", 0, 10, 13, 18 },
- { "sex-prostitution", 0, 12, 14, 18 },
- { "sex-adultery", 0, 8, 10, 18 },
- { "sex-appearance", 0, 10, 10, 15 },
- { "violence-worship", 0, 13, 15, 18 },
- { "violence-desecration", 0, 13, 15, 18 },
- { "violence-slavery", 0, 13, 15, 18 },
+ { "sex-homosexuality", OARS_1_1, 0, 10, 13, 18 },
+ { "sex-prostitution", OARS_1_1, 0, 12, 14, 18 },
+ { "sex-adultery", OARS_1_1, 0, 8, 10, 18 },
+ { "sex-appearance", OARS_1_1, 0, 10, 10, 15 },
+ { "violence-worship", OARS_1_1, 0, 13, 15, 18 },
+ { "violence-desecration", OARS_1_1, 0, 13, 15, 18 },
+ { "violence-slavery", OARS_1_1, 0, 13, 15, 18 },
};
+static gboolean
+is_oars_key (const gchar *id, OarsVersion version)
+{
+ for (gsize i = 0; i < G_N_ELEMENTS (oars_to_csm_mappings); i++) {
+ if (g_str_equal (id, oars_to_csm_mappings[i].id))
+ return (oars_to_csm_mappings[i].oars_version <= version);
+ }
+ return FALSE;
+}
+
/**
* as_content_rating_attribute_to_csm_age:
* @id: the subsection ID e.g. `violence-cartoon`
diff --git a/libappstream-glib/as-self-test.c b/libappstream-glib/as-self-test.c
index 1de3d3d..7100f69 100644
--- a/libappstream-glib/as-self-test.c
+++ b/libappstream-glib/as-self-test.c
@@ -1743,7 +1743,7 @@ as_test_content_rating_func (void)
g_assert_cmpint (as_content_rating_get_value (content_rating, "violence-cartoon"), ==,
AS_CONTENT_RATING_VALUE_MILD);
g_assert_cmpint (as_content_rating_get_value (content_rating, "violence-bloodshed"), ==,
- AS_CONTENT_RATING_VALUE_UNKNOWN);
+ AS_CONTENT_RATING_VALUE_NONE);
rating_ids = as_content_rating_get_rating_ids (content_rating);
g_assert_nonnull (rating_ids);
@@ -1770,6 +1770,51 @@ as_test_content_rating_func (void)
as_node_unref (root);
}
+/* Test that parsing an empty content rating correctly returns `none` as the
+ * value for all the ratings defined by that particular kind of content rating,
+ * and `unknown` for everything else. */
+static void
+as_test_content_rating_empty (void)
+{
+ GError *error = NULL;
+ AsNode *n;
+ AsNode *root;
+ const gchar *src =
+ "<content_rating type=\"oars-1.0\">\n"
+ "</content_rating>\n";
+ gboolean ret;
+ g_autoptr(AsNodeContext) ctx = NULL;
+ g_autoptr(AsContentRating) content_rating = NULL;
+
+ content_rating = as_content_rating_new ();
+
+ /* to object */
+ root = as_node_from_xml (src, 0, &error);
+ g_assert_no_error (error);
+ g_assert_nonnull (root);
+ n = as_node_find (root, "content_rating");
+ g_assert_nonnull (n);
+ ctx = as_node_context_new ();
+ ret = as_content_rating_node_parse (content_rating, n, ctx, &error);
+ g_assert_no_error (error);
+ g_assert_true (ret);
+
+ /* verify */
+ g_assert_cmpstr (as_content_rating_get_kind (content_rating), ==, "oars-1.0");
+ g_assert_cmpint (as_content_rating_get_value (content_rating, "drugs-alcohol"), ==,
+ AS_CONTENT_RATING_VALUE_NONE);
+ g_assert_cmpint (as_content_rating_get_value (content_rating, "violence-cartoon"), ==,
+ AS_CONTENT_RATING_VALUE_NONE);
+ g_assert_cmpint (as_content_rating_get_value (content_rating, "violence-bloodshed"), ==,
+ AS_CONTENT_RATING_VALUE_NONE);
+
+ /* This one was only added in OARS-1.1, so it shouldn’t have a value of `none`. */
+ g_assert_cmpint (as_content_rating_get_value (content_rating, "sex-adultery"), ==,
+ AS_CONTENT_RATING_VALUE_UNKNOWN);
+
+ as_node_unref (root);
+}
+
/* Test that the OARS → CSM mapping table in as_content_rating_attribute_to_csm_age()
* is complete (contains mappings for all known IDs), and that the ages it
* returns are non-decreasing for increasing values of #AsContentRatingValue in
@@ -5625,6 +5670,7 @@ main (int argc, char **argv)
g_test_add_func ("/AppStream/require", as_test_require_func);
g_test_add_func ("/AppStream/checksum", as_test_checksum_func);
g_test_add_func ("/AppStream/content_rating", as_test_content_rating_func);
+ g_test_add_func ("/AppStream/content_rating/empty", as_test_content_rating_empty);
g_test_add_func ("/AppStream/content_rating/mappings", as_test_content_rating_mappings);
g_test_add_func ("/AppStream/release", as_test_release_func);
g_test_add_func ("/AppStream/release{date}", as_test_release_date_func);