/* * Copyright (C) 2018 ScyllaDB */ /* * This file is part of Scylla. * * Scylla is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Scylla is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Scylla. If not, see . */ #define BOOST_TEST_MODULE observable_test #include #include #include #include "../utils/observable.hh" using namespace utils; BOOST_AUTO_TEST_CASE(test_basic_functionality) { observable pub; int v1 = 0, v2 = 0; observer sub1 = pub.observe([&] (int x) { v1 = x; }); observer sub2 = pub.observe([&] (int x) { v2 = x; }); pub(7); BOOST_REQUIRE_EQUAL(v1, 7); BOOST_REQUIRE_EQUAL(v2, 7); sub1.disconnect(); pub(3); BOOST_REQUIRE_EQUAL(v1, 7); BOOST_REQUIRE_EQUAL(v2, 3); sub1 = std::move(sub2); pub(4); BOOST_REQUIRE_EQUAL(v1, 7); BOOST_REQUIRE_EQUAL(v2, 4); pub = observable(); pub(5); BOOST_REQUIRE_EQUAL(v1, 7); BOOST_REQUIRE_EQUAL(v2, 4); } BOOST_AUTO_TEST_CASE(test_exceptions) { observable<> pub; bool saw1 = false; observer<> sub1 = pub.observe([&] { saw1 = true; }); observer<> sub2 = pub.observe([&] { throw 2; }); bool saw3 = false; observer<> sub3 = pub.observe([&] { saw3 = true; }); observer<> sub4 = pub.observe([&] { throw 4; }); bool caught = false; try { pub(); } catch (int v) { BOOST_REQUIRE(saw1); BOOST_REQUIRE(saw3); BOOST_REQUIRE(v == 2 || v == 4); caught = true; } BOOST_REQUIRE(caught); } BOOST_AUTO_TEST_CASE(test_disconnect_fully_disconnects) { std::variant, std::array> pub = observable<>(); observer<> sub = std::get>(pub).observe([] {}); sub.disconnect(); auto x = std::array{}; std::iota(x.begin(), x.end(), 'X'); // Once upon a time, disconnect() still remembered the observable's address. // Simulate a the observable being freed and its memory reused for something // else by assigning garbage to the variant that holds its data pub = x; // Would have accessed the overwritten observable before the bug fix. sub.disconnect(); }