diff options
-rw-r--r-- | libappstream-glib/as-content-rating.c | 88 | ||||
-rw-r--r-- | libappstream-glib/as-self-test.c | 48 |
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); |