blob: 1ffa92d45088cd6d2db04d74189f00d79c89a872 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/public/test/attribution_simulator.h"
#include <sstream>
#include <string>
#include <utility>
#include <vector>
#include "base/files/file_enumerator.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/path_service.h"
#include "base/test/values_test_util.h"
#include "base/values.h"
#include "content/public/browser/attribution_reporting.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
namespace {
base::Value ReadJsonFromFile(const base::FilePath& path) {
std::string contents;
EXPECT_TRUE(base::ReadFileToString(path, &contents));
return base::test::ParseJson(contents);
}
// Removes `.input.json` from the path.
base::FilePath RemoveInputPathExtension(const base::FilePath& path) {
EXPECT_EQ(FILE_PATH_LITERAL(".json"), path.FinalExtension());
EXPECT_EQ(FILE_PATH_LITERAL(".input"),
path.RemoveFinalExtension().FinalExtension());
return path.RemoveFinalExtension().RemoveFinalExtension();
}
std::vector<base::FilePath> GetInputPaths() {
base::FilePath input_dir;
base::PathService::Get(base::DIR_SOURCE_ROOT, &input_dir);
input_dir = input_dir.AppendASCII(
"content/test/data/attribution_reporting/simulator");
std::vector<base::FilePath> input_paths;
base::FileEnumerator e(input_dir, /*recursive=*/false,
base::FileEnumerator::FILES,
FILE_PATH_LITERAL("*.input.json"));
for (base::FilePath name = e.Next(); !name.empty(); name = e.Next()) {
input_paths.push_back(std::move(name));
}
return input_paths;
}
base::FilePath OutputPath(const base::FilePath& input_path) {
return RemoveInputPathExtension(input_path).AddExtensionASCII("output.json");
}
base::FilePath OptionsPath(const base::FilePath& input_path) {
return RemoveInputPathExtension(input_path).AddExtensionASCII("options.json");
}
void ParseOptions(const base::Value& dict,
AttributionSimulationOptions& options) {
if (const std::string* delay_mode = dict.FindStringKey("delay_mode")) {
if (*delay_mode == "none") {
options.delay_mode = AttributionDelayMode::kNone;
} else {
ASSERT_EQ(*delay_mode, "default")
<< "unknown delay mode: " << *delay_mode;
options.delay_mode = AttributionDelayMode::kDefault;
}
}
if (const std::string* noise_mode = dict.FindStringKey("noise_mode")) {
if (*noise_mode == "none") {
options.noise_mode = AttributionNoiseMode::kNone;
} else {
ASSERT_EQ(*noise_mode, "default")
<< "unknown noise mode: " << *noise_mode;
options.noise_mode = AttributionNoiseMode::kDefault;
}
}
}
class AttributionSimulatorImplTest
: public ::testing::TestWithParam<base::FilePath> {};
TEST_P(AttributionSimulatorImplTest, HasExpectedOutput) {
const base::FilePath input_path = GetParam();
base::Value input = ReadJsonFromFile(input_path);
// Tests are nondeterministic if noise is used or report IDs are present.
AttributionSimulationOptions options{
.noise_mode = AttributionNoiseMode::kNone,
.delay_mode = AttributionDelayMode::kDefault,
.output_options =
AttributionSimulationOutputOptions{
.remove_report_ids = true,
.remove_assembled_report = true,
.remove_actual_report_times = true,
},
};
const base::FilePath options_path = OptionsPath(input_path);
if (base::PathExists(options_path))
ParseOptions(ReadJsonFromFile(options_path), options);
const base::Value expected_output = ReadJsonFromFile(OutputPath(input_path));
std::ostringstream error_stream;
EXPECT_THAT(RunAttributionSimulation(std::move(input), options, error_stream),
base::test::IsJson(expected_output));
EXPECT_EQ(error_stream.str(), "");
}
INSTANTIATE_TEST_SUITE_P(
AttributionSimulatorInputs,
AttributionSimulatorImplTest,
::testing::ValuesIn(GetInputPaths()),
/*name_generator=*/
[](const ::testing::TestParamInfo<base::FilePath>& info) {
return RemoveInputPathExtension(info.param).BaseName().MaybeAsASCII();
});
} // namespace
} // namespace content