blob: a5361636909780cb75b086f4d04c00561714116c [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/attribution_reporting/attribution_scopes_set.h"
#include <stdint.h>
#include "base/test/gmock_expected_support.h"
#include "base/test/values_test_util.h"
#include "base/types/expected.h"
#include "base/values.h"
#include "components/attribution_reporting/source_registration_error.mojom.h"
#include "components/attribution_reporting/test_utils.h"
#include "components/attribution_reporting/trigger_registration_error.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace attribution_reporting {
namespace {
using ::attribution_reporting::mojom::SourceRegistrationError;
using ::attribution_reporting::mojom::TriggerRegistrationError;
using ::base::test::ErrorIs;
using ::base::test::ValueIs;
using ::testing::IsEmpty;
using ::testing::Property;
using ::testing::UnorderedElementsAre;
TEST(AttributionScopesSetTest, ParseSource) {
const struct {
const char* desc;
const char* json;
::testing::Matcher<
base::expected<AttributionScopesSet, SourceRegistrationError>>
matches;
uint32_t scope_limit = 20u;
} kTestCases[] = {
{
"empty",
R"json({})json",
ErrorIs(SourceRegistrationError::kAttributionScopesListInvalid),
},
{
"scopes_list_wrong_type",
R"json({"values": 0})json",
ErrorIs(SourceRegistrationError::kAttributionScopesListInvalid),
},
{
"basic_scopes",
R"json({"values": ["1"]})json",
ValueIs(Property(&AttributionScopesSet::scopes,
UnorderedElementsAre("1"))),
},
{
"scopes_list_empty",
R"json({"values": []})json",
ErrorIs(SourceRegistrationError::kAttributionScopesListInvalid),
},
{
"scope_in_list_wrong_type",
R"json({"values": [1]})json",
ErrorIs(SourceRegistrationError::kAttributionScopesListValueInvalid),
},
{
"multiple_scopes",
R"json({"values": ["1", "2", "3"]})json",
ValueIs(Property(&AttributionScopesSet::scopes,
UnorderedElementsAre("1", "2", "3"))),
},
{
"too_many_scopes",
R"json({
"values": [
"1", "2", "3", "4", "5"
]
})json",
ErrorIs(SourceRegistrationError::kAttributionScopesListInvalid),
/*scope_limit=*/4,
},
{
"too_many_scopes_default_limit",
R"json({
"values": [
"01", "02", "03", "04", "05",
"06", "07", "08", "09", "10",
"11", "12", "13", "14", "15",
"16", "17", "18", "19", "20", "21"
]
})json",
ErrorIs(SourceRegistrationError::kAttributionScopesListInvalid),
/*scope_limit=*/25,
},
{
"duplicate_scopes_condensed",
R"json({"values": ["1", "1"]})json",
ValueIs(Property(&AttributionScopesSet::scopes,
UnorderedElementsAre("1"))),
},
{
"scopes_value_length_too_long",
R"json({"values": [
"This string exceeds 50 characters to pass the limit"
]})json",
ErrorIs(SourceRegistrationError::kAttributionScopesListValueInvalid),
},
};
for (const auto& test_case : kTestCases) {
SCOPED_TRACE(test_case.desc);
base::Value::Dict value = base::test::ParseJsonDict(test_case.json);
EXPECT_THAT(AttributionScopesSet::FromJSON(value, test_case.scope_limit),
test_case.matches);
}
}
TEST(AttributionScopesSetTest, ParseTrigger) {
const struct {
const char* desc;
const char* json;
::testing::Matcher<
base::expected<AttributionScopesSet, TriggerRegistrationError>>
matches;
} kTestCases[] = {
{
"empty",
R"json({})json",
ValueIs(AttributionScopesSet()),
},
{
"scopes_list_wrong_type",
R"json({"attribution_scopes": 0})json",
ErrorIs(TriggerRegistrationError::kAttributionScopesInvalid),
},
{
"basic_scopes",
R"json({"attribution_scopes": ["1"]})json",
ValueIs(Property(&AttributionScopesSet::scopes,
UnorderedElementsAre("1"))),
},
{
"scopes_list_empty",
R"json({"attribution_scopes": []})json",
ValueIs(AttributionScopesSet()),
},
{
"scope_in_list_wrong_type",
R"json({"attribution_scopes": [1]})json",
ErrorIs(TriggerRegistrationError::kAttributionScopesValueInvalid),
},
{
"multiple_scopes",
R"json({"attribution_scopes": ["1", "2", "3"]})json",
ValueIs(Property(&AttributionScopesSet::scopes,
UnorderedElementsAre("1", "2", "3"))),
},
{
"more_than_20_scopes",
R"json({
"attribution_scopes": [
"01", "02", "03", "04", "05",
"06", "07", "08", "09", "10",
"11", "12", "13", "14", "15",
"16", "17", "18", "19", "20", "21"
]
})json",
ValueIs(Property(
&AttributionScopesSet::scopes,
UnorderedElementsAre("01", "02", "03", "04", "05", "06", "07",
"08", "09", "10", "11", "12", "13", "14",
"15", "16", "17", "18", "19", "20", "21"))),
},
{
"duplicate_scopes_condensed",
R"json({"attribution_scopes": ["1", "1"]})json",
ValueIs(Property(&AttributionScopesSet::scopes,
UnorderedElementsAre("1"))),
},
{
"scope_more_than_50_characters",
R"json({"attribution_scopes": [
"This string exceeds 50 characters to pass the limit"
]})json",
ValueIs(Property(
&AttributionScopesSet::scopes,
UnorderedElementsAre(
"This string exceeds 50 characters to pass the limit"))),
},
};
for (const auto& test_case : kTestCases) {
SCOPED_TRACE(test_case.desc);
base::Value::Dict value = base::test::ParseJsonDict(test_case.json);
EXPECT_THAT(AttributionScopesSet::FromJSON(value), test_case.matches);
}
}
TEST(AttributionScopesSetTest, ToJsonSource) {
const struct {
AttributionScopesSet input;
const char* expected_json;
} kTestCases[] = {
{
AttributionScopesSet(),
R"json({})json",
},
{
AttributionScopesSet({"foo", "bar"}),
R"json({"values": ["bar", "foo"]})json",
},
};
for (const auto& test_case : kTestCases) {
base::Value::Dict actual;
test_case.input.SerializeForSource(actual);
EXPECT_THAT(actual, base::test::IsJson(test_case.expected_json));
}
}
TEST(AttributionScopesSetTest, ToJsonTrigger) {
const struct {
AttributionScopesSet input;
const char* expected_json;
} kTestCases[] = {
{
AttributionScopesSet(),
R"json({})json",
},
{
AttributionScopesSet({"foo", "bar"}),
R"json({"attribution_scopes": ["bar", "foo"]})json",
},
};
for (const auto& test_case : kTestCases) {
base::Value::Dict actual;
test_case.input.SerializeForTrigger(actual);
EXPECT_THAT(actual, base::test::IsJson(test_case.expected_json));
}
}
TEST(AttributionScopesSetTest, HasIntersection) {
const struct {
AttributionScopesSet set_1;
AttributionScopesSet set_2;
bool expected;
} kTestCases[] = {
{AttributionScopesSet(), AttributionScopesSet(), false},
{AttributionScopesSet({"a"}), AttributionScopesSet(), false},
{AttributionScopesSet({"a"}), AttributionScopesSet({"a"}), true},
{AttributionScopesSet({"a", "c"}), AttributionScopesSet({"b", "c"}),
true},
{AttributionScopesSet({"a"}), AttributionScopesSet({"b"}), false}};
for (const auto& test_case : kTestCases) {
EXPECT_THAT(test_case.set_1.HasIntersection(test_case.set_2),
test_case.expected);
EXPECT_THAT(test_case.set_2.HasIntersection(test_case.set_1),
test_case.expected);
}
}
} // namespace
} // namespace attribution_reporting