blob: 27080df2b0eed1d37f5e169bd742fe06572232d4 [file] [log] [blame]
//
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "algorithms/algorithm.h"
#include <forward_list>
#include <list>
#include <vector>
#include "base/testing/status_matchers.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "base/statusor.h"
namespace differential_privacy {
namespace {
using ::testing::DoubleNear;
const double kTestPrecision = 1e-5;
template <typename T>
class TestAlgorithm : public Algorithm<T> {
public:
TestAlgorithm() : Algorithm<T>(1.0) {}
void AddEntry(const T& t) override {}
Summary Serialize() override { return Summary(); }
absl::Status Merge(const Summary& summary) override {
return absl::OkStatus();
}
int64_t MemoryUsed() override { return sizeof(TestAlgorithm<T>); }
protected:
base::StatusOr<Output> GenerateResult(double privacy_budget,
double noise_interval_level) override {
Output output;
output.mutable_error_report()
->mutable_noise_confidence_interval()
->set_confidence_level(noise_interval_level);
return output;
}
void ResetState() override {}
};
TEST(IncrementalAlgorithmTest, StartsWithFullBudget) {
TestAlgorithm<double> alg;
EXPECT_THAT(alg.RemainingPrivacyBudget(), DoubleNear(1.0, kTestPrecision));
}
TEST(IncrementalAlgorithmTest, PartialResultConsumesBudget) {
TestAlgorithm<double> alg;
ASSERT_OK(alg.PartialResult());
EXPECT_THAT(alg.RemainingPrivacyBudget(), DoubleNear(0.0, kTestPrecision));
}
TEST(IncrementalAlgorithmTest, PartialResultConsumesPartialBudget) {
TestAlgorithm<double> alg;
ASSERT_OK(alg.PartialResult(0.5));
EXPECT_THAT(alg.RemainingPrivacyBudget(), DoubleNear(0.5, kTestPrecision));
}
TEST(IncrementalAlgorithmTest, PartialResultConsumesPartialBudgetMultiRound) {
TestAlgorithm<double> alg;
ASSERT_OK(alg.PartialResult(0.5));
alg.ConsumePrivacyBudget(0.5);
EXPECT_THAT(alg.RemainingPrivacyBudget(), DoubleNear(0.0, kTestPrecision));
}
TEST(IncrementalAlgorithmTest, PartialResultPassesConfidenceLevel) {
TestAlgorithm<double> alg;
const double level = .9;
base::StatusOr<Output> result = alg.PartialResult(1, level);
ASSERT_OK(result);
EXPECT_EQ(
result->error_report().noise_confidence_interval().confidence_level(),
level);
}
TEST(IncrementalAlgorithmTest, Reset) {
TestAlgorithm<double> alg;
ASSERT_OK(alg.PartialResult(0.5));
alg.ConsumePrivacyBudget(0.5);
alg.Reset();
EXPECT_THAT(alg.RemainingPrivacyBudget(), DoubleNear(1.0, kTestPrecision));
}
TEST(IncrementalAlgorithmTest, MergedPartialResultConsumesBudget) {
// Serialize and merge alg_1 into alg_2.
TestAlgorithm<double> alg_1;
TestAlgorithm<double> alg_2;
Summary summary_1 = alg_1.Serialize();
EXPECT_OK(alg_2.Merge(summary_1));
ASSERT_OK(alg_2.PartialResult());
EXPECT_THAT(alg_2.RemainingPrivacyBudget(), DoubleNear(0.0, kTestPrecision));
}
TEST(IncrementalAlgorithmDeathTest, BudgetTooHigh) {
TestAlgorithm<double> alg;
ASSERT_OK(alg.PartialResult(0.5));
EXPECT_DEATH(alg.ConsumePrivacyBudget(0.6), "Requested budget.*");
}
} // namespace
} // namespace differential_privacy