1
0
mirror of https://github.com/wqking/eventpp.git synced 2024-12-27 16:41:11 +08:00
eventpp/tests/unittest/test_no_extra_copy_move.cpp
2020-12-27 21:05:21 +08:00

355 lines
9.4 KiB
C++

// eventpp library
// Copyright (C) 2018 Wang Qi (wqking)
// Github: https://github.com/wqking/eventpp
// 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 "test.h"
#include "eventpp/callbacklist.h"
#include "eventpp/eventdispatcher.h"
#include <memory>
class CopyMoveCounter
{
public:
struct Counter
{
int copied;
int moved;
int called;
};
public:
CopyMoveCounter()
: counter(std::make_shared<Counter>()) {
}
CopyMoveCounter(const CopyMoveCounter & other)
: counter(other.counter) {
++counter->copied;
}
CopyMoveCounter(CopyMoveCounter && other)
: counter(std::move(other.counter)) {
++counter->moved;
}
const Counter & getCounter() const {
return *counter;
}
void called() const {
// This is to test the callback is added to callbacklist properly and be invoked.
++counter->called;
}
int getCalledAndReset() const {
const int result = counter->called;
counter->called = 0;
return result;
}
private:
std::shared_ptr<Counter> counter;
};
TEST_CASE("CopyMoveCounter")
{
CopyMoveCounter obj1;
REQUIRE(obj1.getCounter().copied == 0);
REQUIRE(obj1.getCounter().moved == 0);
CopyMoveCounter copy1(obj1);
REQUIRE(obj1.getCounter().copied == 1);
REQUIRE(obj1.getCounter().moved == 0);
CopyMoveCounter copy2(copy1);
REQUIRE(obj1.getCounter().copied == 2);
REQUIRE(obj1.getCounter().moved == 0);
CopyMoveCounter move1(std::move(obj1));
REQUIRE(move1.getCounter().copied == 2); // can't use obj1 any more
REQUIRE(move1.getCounter().moved == 1);
CopyMoveCounter move2(std::move(move1));
REQUIRE(move2.getCounter().copied == 2);
REQUIRE(move2.getCounter().moved == 2);
}
TEST_CASE("copymove, CallbackList<void(const &)>, callback(const &)")
{
using CL = eventpp::CallbackList<void(const CopyMoveCounter &, int)>;
CL callbackList;
auto func = [](const CopyMoveCounter & obj, const int expected) {
REQUIRE(obj.getCounter().copied == expected);
obj.called();
};
SECTION("Raw function: temporary object") {
func(CopyMoveCounter(), 0);
}
SECTION("Raw function: object variable") {
CopyMoveCounter obj1;
REQUIRE(obj1.getCalledAndReset() == 0);
func(obj1, 0);
REQUIRE(obj1.getCalledAndReset() > 0);
}
SECTION("CallbackList: temporary object") {
callbackList.append(func);
callbackList(CopyMoveCounter(), 0);
}
SECTION("CallbackList: object variable") {
callbackList.append(func);
CopyMoveCounter obj1;
REQUIRE(obj1.getCalledAndReset() == 0);
callbackList(obj1, 0);
REQUIRE(obj1.getCalledAndReset() > 0);
}
}
TEST_CASE("copymove, CallbackList<void(value)>, callback(value)")
{
using CL = eventpp::CallbackList<void(CopyMoveCounter, int)>;
CL callbackList;
auto func = [](CopyMoveCounter obj, const int expected) {
REQUIRE(obj.getCounter().copied == expected);
obj.called();
};
SECTION("Raw function: temporary object") {
func(CopyMoveCounter(), 0);
}
SECTION("Raw function: object variable") {
CopyMoveCounter obj1;
REQUIRE(obj1.getCalledAndReset() == 0);
func(obj1, 1);
REQUIRE(obj1.getCalledAndReset() > 0);
}
// For the reason in the comment in CallbackList::operator(), i.e, can't use std::forward,
// the copied count in the CallbackList version is larger by 1 than the raw function version.
SECTION("CallbackList: temporary object") {
callbackList.append(func);
callbackList(CopyMoveCounter(), 1);
}
SECTION("CallbackList: object variable") {
callbackList.append(func);
CopyMoveCounter obj1;
REQUIRE(obj1.getCalledAndReset() == 0);
callbackList(obj1, 2);
REQUIRE(obj1.getCalledAndReset() > 0);
}
}
TEST_CASE("copymove, CallbackList<void(value)>, callback(const &)")
{
using CL = eventpp::CallbackList<void(CopyMoveCounter, int)>;
CL callbackList;
auto func = [](const CopyMoveCounter & obj, const int expected) {
REQUIRE(obj.getCounter().copied == expected);
obj.called();
};
SECTION("Raw function: temporary object") {
func(CopyMoveCounter(), 0);
}
SECTION("Raw function: object variable") {
CopyMoveCounter obj1;
REQUIRE(obj1.getCalledAndReset() == 0);
func(obj1, 0);
REQUIRE(obj1.getCalledAndReset() > 0);
}
SECTION("CallbackList: temporary object") {
callbackList.append(func);
callbackList(CopyMoveCounter(), 1);
}
SECTION("CallbackList: object variable") {
callbackList.append(func);
CopyMoveCounter obj1;
REQUIRE(obj1.getCalledAndReset() == 0);
callbackList(obj1, 2);
REQUIRE(obj1.getCalledAndReset() > 0);
}
}
TEST_CASE("copymove, CallbackList<void(const &)>, callback(value)")
{
using CL = eventpp::CallbackList<void(const CopyMoveCounter &, int)>;
CL callbackList;
auto func = [](CopyMoveCounter obj, const int expected) {
REQUIRE(obj.getCounter().copied == expected);
obj.called();
};
SECTION("Raw function: temporary object") {
func(CopyMoveCounter(), 0);
}
SECTION("Raw function: object variable") {
CopyMoveCounter obj1;
const CopyMoveCounter & ref1 = obj1;
REQUIRE(ref1.getCalledAndReset() == 0);
func(ref1, 1);
REQUIRE(ref1.getCalledAndReset() > 0);
}
SECTION("CallbackList: temporary object") {
callbackList.append(func);
callbackList(CopyMoveCounter(), 1);
}
SECTION("CallbackList: object variable") {
callbackList.append(func);
CopyMoveCounter obj1;
const CopyMoveCounter & ref1 = obj1;
REQUIRE(ref1.getCalledAndReset() == 0);
callbackList(ref1, 1);
REQUIRE(ref1.getCalledAndReset() > 0);
}
}
TEST_CASE("copymove, EventDispatcher<void(const &)>, callback(const &)")
{
using ED = eventpp::EventDispatcher<int, void(const CopyMoveCounter &, int)>;
ED eventDispatcher;
auto func = [](const CopyMoveCounter & obj, const int expected) {
REQUIRE(obj.getCounter().copied == expected);
obj.called();
};
SECTION("Raw function: temporary object") {
func(CopyMoveCounter(), 0);
}
SECTION("Raw function: object variable") {
CopyMoveCounter obj1;
REQUIRE(obj1.getCalledAndReset() == 0);
func(obj1, 0);
REQUIRE(obj1.getCalledAndReset() > 0);
}
SECTION("EventDispatcher: temporary object") {
eventDispatcher.appendListener(1, func);
eventDispatcher.dispatch(1, CopyMoveCounter(), 0);
}
SECTION("eventDispatcher: object variable") {
eventDispatcher.appendListener(1, func);
CopyMoveCounter obj1;
REQUIRE(obj1.getCalledAndReset() == 0);
eventDispatcher.dispatch(1, obj1, 0);
REQUIRE(obj1.getCalledAndReset() > 0);
}
}
TEST_CASE("copymove, EventDispatcher<void(value)>, callback(value)")
{
using ED = eventpp::EventDispatcher<int, void(CopyMoveCounter, int)>;
ED eventDispatcher;
auto func = [](CopyMoveCounter obj, const int expected) {
REQUIRE(obj.getCounter().copied == expected);
obj.called();
};
SECTION("Raw function: temporary object") {
func(CopyMoveCounter(), 0);
}
SECTION("Raw function: object variable") {
CopyMoveCounter obj1;
REQUIRE(obj1.getCalledAndReset() == 0);
func(obj1, 1);
REQUIRE(obj1.getCalledAndReset() > 0);
}
SECTION("EventDispatcher: temporary object") {
eventDispatcher.appendListener(1, func);
eventDispatcher.dispatch(1, CopyMoveCounter(), 1);
}
SECTION("eventDispatcher: object variable") {
eventDispatcher.appendListener(1, func);
CopyMoveCounter obj1;
REQUIRE(obj1.getCalledAndReset() == 0);
eventDispatcher.dispatch(1, obj1, 2);
REQUIRE(obj1.getCalledAndReset() > 0);
}
}
TEST_CASE("copymove, EventDispatcher<void(value)>, callback(const &)")
{
using ED = eventpp::EventDispatcher<int, void(CopyMoveCounter, int)>;
ED eventDispatcher;
auto func = [](CopyMoveCounter obj, const int expected) {
REQUIRE(obj.getCounter().copied == expected);
obj.called();
};
SECTION("Raw function: temporary object") {
func(CopyMoveCounter(), 0);
}
SECTION("Raw function: object variable") {
CopyMoveCounter obj1;
REQUIRE(obj1.getCalledAndReset() == 0);
func(obj1, 1);
REQUIRE(obj1.getCalledAndReset() > 0);
}
SECTION("EventDispatcher: temporary object") {
eventDispatcher.appendListener(1, func);
eventDispatcher.dispatch(1, CopyMoveCounter(), 1);
}
SECTION("eventDispatcher: object variable") {
eventDispatcher.appendListener(1, func);
CopyMoveCounter obj1;
REQUIRE(obj1.getCalledAndReset() == 0);
eventDispatcher.dispatch(1, obj1, 2);
REQUIRE(obj1.getCalledAndReset() > 0);
}
}
TEST_CASE("copymove, EventDispatcher<void(const &)>, callback(value)")
{
using ED = eventpp::EventDispatcher<int, void(const CopyMoveCounter &, int)>;
ED eventDispatcher;
auto func = [](CopyMoveCounter obj, const int expected) {
REQUIRE(obj.getCounter().copied == expected);
obj.called();
};
SECTION("Raw function: temporary object") {
func(CopyMoveCounter(), 0);
}
SECTION("Raw function: object variable") {
CopyMoveCounter obj1;
REQUIRE(obj1.getCalledAndReset() == 0);
func(obj1, 1);
REQUIRE(obj1.getCalledAndReset() > 0);
}
SECTION("EventDispatcher: temporary object") {
eventDispatcher.appendListener(1, func);
eventDispatcher.dispatch(1, CopyMoveCounter(), 1);
}
SECTION("eventDispatcher: object variable") {
eventDispatcher.appendListener(1, func);
CopyMoveCounter obj1;
REQUIRE(obj1.getCalledAndReset() == 0);
eventDispatcher.dispatch(1, obj1, 1);
REQUIRE(obj1.getCalledAndReset() > 0);
}
}