/*
 * Copyright 2016 The Android Open Source Project
 *
 * 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.
 */

//#define LOG_NDEBUG 0
#define LOG_TAG "AData_test"

#include <gtest/gtest.h>
#include <utils/RefBase.h>
//#include <utils/StrongPointer.h>

#include <media/stagefright/foundation/AData.h>
#include <media/stagefright/foundation/ABuffer.h>

namespace android {

class ADataTest : public ::testing::Test {
};

// ============ AUnion

struct Events {
    int dtor;
    int ctor_empty;
    int ctor_copy;
};

struct EventCounter : public RefBase {
    EventCounter(int *counter, int magic=1234) : mCounter(counter), mMagic(magic) { }
    virtual ~EventCounter() { ++*mCounter; mMagic = 0; }
    int magic() const { return mMagic; }
private:
    int *mCounter;
    int mMagic;
};

struct DerivedCounter : public EventCounter {
    DerivedCounter(int *counter, int magic=1234) : EventCounter(counter, magic) { }
};

TEST_F(ADataTest, AUnion_Test) {
    AUnion<int, const char *, char> u;
    u.emplace<int>(4);
    u.del<int>();
    EXPECT_EQ(4, u.get<int>()); // verify that del<> is a no-op for trivial types, such as int.
                                // specifically, verify that it does not clear the objet memory

    u.emplace<const char *>("hello");
    EXPECT_STREQ("hello", u.get<const char *>());
    u.del<const char *>();

    // u.del<char *>();
    // u.emplace<const int>(4);
    u.emplace<void>();
    u.del<void>();

    u.emplace<int>(~0);
    u.del<int>();
    EXPECT_EQ(~0, u.get<int>());
    u.emplace<char>(0x15);
    // verify that rest of memory after char is cleared upon construction
    EXPECT_EQ(0, memcmp((char *)(&u) + sizeof(char), "\0\0\0", 3));
    EXPECT_EQ(0x15, u.get<char>());
    u.del<char>();

    AUnion<EventCounter, EventCounter *> d;
    int destructions = 0;

    d.emplace<EventCounter>(&destructions);
    d.del<EventCounter>();
    EXPECT_EQ(1, destructions);

    EventCounter *ctr = new EventCounter(&destructions);
    d.emplace<EventCounter *>(ctr);
    d.del<EventCounter *>();
    EXPECT_EQ(1, destructions);

    delete ctr;
    EXPECT_EQ(2, destructions);

    AUnion<std::shared_ptr<EventCounter>, std::unique_ptr<EventCounter>> md;
    md.emplace<std::shared_ptr<EventCounter>>(new EventCounter(&destructions));
    std::shared_ptr<EventCounter> copy(md.get<std::shared_ptr<EventCounter>>());
    std::weak_ptr<EventCounter> weak(copy);
    EXPECT_EQ(2, destructions);

    copy.reset();
    EXPECT_EQ(2, destructions);
    md.del<std::shared_ptr<EventCounter>>();
    EXPECT_EQ(3, destructions);
    EXPECT_TRUE(weak.expired());

    md.emplace<std::unique_ptr<EventCounter>>(new EventCounter(&destructions));
    EXPECT_EQ(3, destructions);

    std::unique_ptr<EventCounter> unique = std::move(md.get<std::unique_ptr<EventCounter>>());
    EXPECT_EQ(3, destructions);
    EXPECT_FALSE((bool)md.get<std::unique_ptr<EventCounter>>());

    md.del<std::unique_ptr<EventCounter>>();
    EXPECT_EQ(3, destructions);
    md.emplace<std::unique_ptr<EventCounter>>(std::move(unique));
    EXPECT_TRUE((bool)md.get<std::unique_ptr<EventCounter>>());
    EXPECT_EQ(3, destructions);

    md.del<std::unique_ptr<EventCounter>>();
    EXPECT_EQ(4, destructions);
}

TEST_F(ADataTest, AData_StaticTest) {
    using namespace std;

    static_assert(is_copy_assignable<shared_ptr<EventCounter>>::value, "");
    static_assert(is_copy_constructible<shared_ptr<EventCounter>>::value, "");
    static_assert(is_default_constructible<shared_ptr<EventCounter>>::value, "");

    static_assert(is_copy_assignable<weak_ptr<DerivedCounter>>::value, "");
    static_assert(is_copy_constructible<weak_ptr<DerivedCounter>>::value, "");
    static_assert(is_default_constructible<weak_ptr<DerivedCounter>>::value, "");

    static_assert(!is_copy_assignable<unique_ptr<DerivedCounter>>::value, "");
    static_assert(!is_copy_constructible<unique_ptr<DerivedCounter>>::value, "");
    static_assert(is_default_constructible<unique_ptr<DerivedCounter>>::value, "");

    static_assert(is_copy_assignable<sp<EventCounter>>::value, "");
    static_assert(is_copy_constructible<sp<EventCounter>>::value, "");
    static_assert(is_default_constructible<sp<EventCounter>>::value, "");

    static_assert(is_copy_assignable<wp<EventCounter>>::value, "");
    static_assert(is_copy_constructible<wp<EventCounter>>::value, "");
    static_assert(is_default_constructible<wp<EventCounter>>::value, "");

    static_assert(is_convertible<shared_ptr<DerivedCounter>, shared_ptr<EventCounter>>::value, "");
    static_assert(!is_convertible<shared_ptr<EventCounter>, shared_ptr<DerivedCounter>>::value, "");

    static_assert(is_convertible<unique_ptr<DerivedCounter>, unique_ptr<EventCounter>>::value, "");
    static_assert(!is_convertible<unique_ptr<EventCounter>, unique_ptr<DerivedCounter>>::value, "");

    static_assert(is_convertible<unique_ptr<DerivedCounter>, shared_ptr<EventCounter>>::value, "");
    static_assert(!is_convertible<shared_ptr<DerivedCounter>, unique_ptr<EventCounter>>::value, "");

    static_assert(is_convertible<weak_ptr<DerivedCounter>, weak_ptr<EventCounter>>::value, "");
    static_assert(!is_convertible<weak_ptr<EventCounter>, weak_ptr<DerivedCounter>>::value, "");

    static_assert(is_convertible<shared_ptr<DerivedCounter>, weak_ptr<EventCounter>>::value, "");
    static_assert(!is_convertible<weak_ptr<DerivedCounter>, shared_ptr<EventCounter>>::value, "");

    static_assert(is_convertible<sp<EventCounter>, sp<RefBase>>::value, "");
    static_assert(is_convertible<sp<RefBase>, sp<EventCounter>>::value, "YES");

    static_assert(is_convertible<wp<EventCounter>, wp<RefBase>>::value, "");
    static_assert(is_convertible<wp<RefBase>, wp<EventCounter>>::value, "YES");

    static_assert(is_convertible<sp<EventCounter>, wp<RefBase>>::value, "");
    static_assert(!is_convertible<wp<EventCounter>, sp<RefBase>>::value, "");
}

TEST_F(ADataTest, AData_SampleTest) {
    AData<int, float>::Basic data;
    int i = 1;
    float f = 7.0f;

    data.set(5);
    EXPECT_TRUE(data.find(&i));
    EXPECT_FALSE(data.find(&f));
    EXPECT_EQ(i, 5);

    data.set(6.0f);
    EXPECT_FALSE(data.find(&i));
    EXPECT_TRUE(data.find(&f));
    EXPECT_EQ(f, 6.0f);

    AData<int, sp<RefBase>>::RelaxedBasic objdata; // relaxed type support
    sp<ABuffer> buf = new ABuffer(16), buf2;
    sp<RefBase> obj;

    objdata.set(buf);
    EXPECT_TRUE(objdata.find(&buf2));
    EXPECT_EQ(buf, buf2);
    EXPECT_FALSE(objdata.find(&i));
    EXPECT_TRUE(objdata.find(&obj));
    EXPECT_TRUE(obj == buf);

    obj = buf;
    objdata.set(obj); // storing as sp<RefBase>
    EXPECT_FALSE(objdata.find(&buf2));  // not stored as ABuffer(!)
    EXPECT_TRUE(objdata.find(&obj));
}

struct SampleTypeFlagger {
    typedef unsigned type;
    enum Flags : type {
        kEmpty = 100,
        kInt,
        kConstCharPtr,
        kEventCounter,
        kEventCounterPointer,
        kEventCounterSharedPointer,
        kEventCounterUniquePointer,
        kEventCounterWeakPointer,
        kEventCounterSP,
        kEventCounterWP,
    };
    constexpr static type mask = ~Flags(0);
    constexpr static type flagFor(void*) { return kEmpty; }
    constexpr static type flagFor(int*) { return kInt; }
    constexpr static type flagFor(const char**) { return kConstCharPtr; }
    constexpr static type flagFor(EventCounter*) { return kEventCounter; }
    constexpr static type flagFor(EventCounter**) { return kEventCounterPointer; }
    constexpr static
    type flagFor(std::shared_ptr<EventCounter>*) { return kEventCounterSharedPointer; }
    constexpr static
    type flagFor(std::unique_ptr<EventCounter>*) { return kEventCounterUniquePointer; }
    constexpr static type flagFor(std::weak_ptr<EventCounter>*) { return kEventCounterWeakPointer; }
    constexpr static type flagFor(sp<EventCounter>*) { return kEventCounterSP; }
    constexpr static type flagFor(wp<EventCounter>*) { return kEventCounterWP; }
    constexpr static bool canDeleteAs(type object, type del) { return del == object; }
    template <typename T> struct store { typedef T as_type; };
};

TEST_F(ADataTest, AData_SimpleTest) {
    int _int = 0;
    const char *_constCharPtr = NULL;
    AData<int, const char *>::Custom<SampleTypeFlagger> u;
    EXPECT_FALSE(u.used());
    EXPECT_FALSE(u.find<int>(&_int));
    EXPECT_FALSE(u.find<const char *>(&_constCharPtr));

    EXPECT_TRUE(u.set<int>(4));
    EXPECT_TRUE(u.used());
    EXPECT_TRUE(u.find<int>(&_int));
    EXPECT_EQ(4, _int);
    EXPECT_FALSE(u.find<const char *>(&_constCharPtr));
    EXPECT_EQ(NULL, _constCharPtr);

    EXPECT_TRUE(u.clear());
    EXPECT_FALSE(u.used());
    EXPECT_FALSE(u.find<int>(&_int));
    EXPECT_FALSE(u.find<const char *>(&_constCharPtr));

    EXPECT_TRUE(u.set<int>(5));
    EXPECT_TRUE(u.set<int>(6));
    EXPECT_TRUE(u.find<int>(&_int));
    EXPECT_EQ(6, _int);

    EXPECT_TRUE(u.set<const char *>("hello"));
    EXPECT_TRUE(u.used());
    EXPECT_FALSE(u.find<int>(&_int));
    EXPECT_TRUE(u.find<const char *>(&_constCharPtr));
    EXPECT_STREQ("hello", _constCharPtr);

    EXPECT_TRUE(u.clear());
    EXPECT_FALSE(u.used());
    EXPECT_FALSE(u.find<int>(&_int));
    EXPECT_FALSE(u.find<const char *>(&_constCharPtr));

    EXPECT_TRUE(u.set<const char *>("world"));
    EXPECT_TRUE(u.set<const char *>("!!"));
    EXPECT_TRUE(u.used());
    EXPECT_FALSE(u.find<int>(&_int));
    EXPECT_TRUE(u.find<const char *>(&_constCharPtr));
    EXPECT_STREQ("!!", _constCharPtr);

    EXPECT_FALSE(u.find(&_int));
    EXPECT_TRUE(u.find(&_constCharPtr));
}

void set(std::unique_ptr<int> &dst, std::unique_ptr<int> &&src) {
    dst = std::move(src);
}

void set(std::unique_ptr<int> &dst, std::unique_ptr<int> &src) {
    dst = std::move(src);
}

TEST_F(ADataTest, AData_CopyMoveTest) {
    int destructions = 0;
    int _int = 0;
    std::shared_ptr<EventCounter> _shared;
    std::unique_ptr<EventCounter> _unique;
    std::weak_ptr<EventCounter> _weak;
    const std::shared_ptr<EventCounter> _constShared(new EventCounter(&destructions));
    const std::unique_ptr<EventCounter> _constUnique = nullptr;

    AData<int, std::weak_ptr<EventCounter>, std::shared_ptr<EventCounter>,
            std::unique_ptr<EventCounter>>::Basic u;

    // test that data is empty
    EXPECT_FALSE(u.used());
    EXPECT_FALSE(u.find(&_int));
    EXPECT_FALSE(u.find(&_shared));
    EXPECT_FALSE(u.remove(&_unique));
    EXPECT_FALSE(u.find(&_weak));

    // test that integer can be stored and read
    EXPECT_TRUE(u.set<int>(1));
    EXPECT_TRUE(u.used());
    EXPECT_TRUE(u.find(&_int));
    EXPECT_EQ(1, _int);
    EXPECT_FALSE(u.find(&_shared));
    EXPECT_FALSE(u.remove(&_unique));
    EXPECT_FALSE(u.find(&_weak));

    // test that movable type (unique_ptr) can be moved in and read out, and it moves
    _unique = std::unique_ptr<EventCounter>(new EventCounter(&destructions, 123));
    EXPECT_TRUE(u.set(std::move(_unique)));
    EXPECT_FALSE((bool)_unique);
    EXPECT_TRUE(u.used());
    EXPECT_FALSE(u.find(&_int));
    EXPECT_FALSE(u.find(&_shared));
    EXPECT_FALSE(u.find(&_weak));
    EXPECT_TRUE(u.remove(&_unique));
    EXPECT_TRUE((bool)_unique);
    if (_unique) {
        EXPECT_EQ(123, _unique->magic());
    }

    // the unique value should have been removed but still accessible as nullptr
    EXPECT_TRUE(u.remove(&_unique));
    EXPECT_FALSE((bool)_unique);
    EXPECT_EQ(1, destructions);

    // test that movable-only type (unique_ptr) can be stored without moving (and is still
    // moved)
    _unique = std::unique_ptr<EventCounter>(new EventCounter(&destructions, 321));
    EXPECT_TRUE(u.set(std::move(_unique)));
    EXPECT_FALSE((bool)_unique);
    EXPECT_TRUE(u.set(std::unique_ptr<EventCounter>(new EventCounter(&destructions, 1234))));
    EXPECT_EQ(2, destructions);
    EXPECT_TRUE(u.remove(&_unique));
    EXPECT_TRUE((bool)_unique);
    if (_unique) {
        EXPECT_EQ(1234, _unique->magic());
    }
    EXPECT_TRUE(u.set(std::move(_unique)));
    EXPECT_EQ(2, destructions);
    EXPECT_TRUE(u.clear());
    EXPECT_EQ(3, destructions);
    EXPECT_FALSE(u.find(&_int));
    EXPECT_FALSE(u.find(&_shared));
    EXPECT_FALSE(u.remove(&_unique));
    EXPECT_FALSE(u.find(&_weak));

    // u.set(_constUnique);

    // test that copiable & movable type (shared_ptr) is copied unless explicitly moved.
    _shared = std::make_shared<EventCounter>(&destructions, 234);
    EXPECT_EQ(1L, _shared.use_count());
    EXPECT_TRUE(u.set(_shared));
    EXPECT_TRUE((bool)_shared);
    if (_shared) {
        EXPECT_EQ(234, _shared->magic());
    }

    EXPECT_EQ(2L, _shared.use_count());
    EXPECT_FALSE(u.find(&_int));
    EXPECT_FALSE(u.remove(&_unique));
    EXPECT_FALSE(u.find(&_weak));
    EXPECT_TRUE(u.find(&_shared));
    EXPECT_EQ(2L, _shared.use_count());
    EXPECT_TRUE((bool)_shared);
    if (_shared) {
        EXPECT_EQ(234, _shared->magic());
    }

    // explicitly move in shared_ptr
    EXPECT_TRUE(u.set(std::move(_shared)));
    EXPECT_EQ(0, _shared.use_count()); // shared should be nullptr
    EXPECT_FALSE((bool)_shared);
    EXPECT_TRUE(u.find(&_shared));
    EXPECT_EQ(2L, _shared.use_count()); // now both u and _shared contains the object
    EXPECT_TRUE((bool)_shared);
    if (_shared) {
        EXPECT_EQ(234, _shared->magic());
    }
    EXPECT_FALSE(u.find(&_int));
    EXPECT_FALSE(u.remove(&_unique));
    EXPECT_FALSE(u.find(&_weak));
    EXPECT_TRUE(u.find(&_shared));
    EXPECT_EQ(2L, _shared.use_count()); // still both u and _shared contains the object

    EXPECT_TRUE(u.clear());
    EXPECT_TRUE(_shared.unique()); // now only _shared contains the object

    EXPECT_TRUE(u.set(_constShared));
    EXPECT_EQ(2L, _constShared.use_count()); // even though it is const, we can add a use count
    EXPECT_TRUE(u.find(&_shared));
    EXPECT_EQ(3L, _shared.use_count()); // now u, _shared and _constShared contains the const object
    EXPECT_TRUE((bool)_shared);
    if (_shared) {
        EXPECT_EQ(1234, _shared->magic());
    }

    // test that weak pointer can be copied in (support for moving is from C++14 only)
    _weak = _shared;
    EXPECT_EQ(_weak.use_count(), _shared.use_count());
    EXPECT_TRUE(u.set(_weak));

    _weak.reset();
    EXPECT_EQ(_weak.use_count(), 0);

    EXPECT_FALSE(u.find(&_int));
    EXPECT_FALSE(u.remove(&_unique));
    EXPECT_FALSE(u.find(&_shared));
    EXPECT_TRUE(u.find(&_weak));
    EXPECT_EQ(_weak.use_count(), _shared.use_count());
    EXPECT_EQ(_weak.lock(), _shared);

    // we can remove a weak pointer multiple times
    _weak.reset();
    EXPECT_TRUE(u.find(&_weak));
    EXPECT_EQ(_weak.use_count(), _shared.use_count());
    EXPECT_EQ(_weak.lock(), _shared);
    EXPECT_TRUE(u.clear());
    EXPECT_FALSE(u.find(&_int));
    EXPECT_FALSE(u.remove(&_unique));
    EXPECT_FALSE(u.find(&_shared));
    EXPECT_FALSE(u.find(&_weak));
};

TEST_F(ADataTest, AData_RelaxedCopyMoveTest) {
    int destructions = 0;
    int _int = 0;
    std::shared_ptr<DerivedCounter> _shared;
    std::unique_ptr<DerivedCounter> _unique, _unique2;
    std::weak_ptr<DerivedCounter> _weak;
    std::shared_ptr<EventCounter> _shared_base;
    std::unique_ptr<EventCounter> _unique_base;
    std::weak_ptr<EventCounter> _weak_base;
    const std::shared_ptr<DerivedCounter> _constShared(new DerivedCounter(&destructions));
    const std::unique_ptr<DerivedCounter> _constUnique = nullptr;

    AData<int, std::unique_ptr<EventCounter>, std::shared_ptr<EventCounter>,
            std::weak_ptr<EventCounter>>::RelaxedBasic u;

    // test that data is empty
    EXPECT_FALSE(u.used());
    EXPECT_FALSE(u.find(&_int));
    EXPECT_FALSE(u.find(&_shared));
    EXPECT_FALSE(u.remove(&_unique));
    EXPECT_FALSE(u.find(&_weak));
    EXPECT_FALSE(u.find(&_shared_base));
    EXPECT_FALSE(u.remove(&_unique_base));
    EXPECT_FALSE(u.find(&_weak_base));

    // test that integer can be stored and read
    EXPECT_TRUE(u.set<int>(1));
    EXPECT_TRUE(u.used());
    EXPECT_TRUE(u.find(&_int));
    EXPECT_EQ(1, _int);
    EXPECT_FALSE(u.find(&_shared));
    EXPECT_FALSE(u.remove(&_unique));
    EXPECT_FALSE(u.find(&_weak));
    EXPECT_FALSE(u.find(&_shared_base));
    EXPECT_FALSE(u.remove(&_unique_base));
    EXPECT_FALSE(u.find(&_weak_base));

    // test that movable type (unique_ptr) can be moved in and read out, and it moves
    _unique = std::unique_ptr<DerivedCounter>(new DerivedCounter(&destructions, 123));
    EXPECT_TRUE(u.set(std::move(_unique)));
    EXPECT_FALSE((bool)_unique);
    EXPECT_TRUE(u.used());
    EXPECT_FALSE(u.find(&_int));
    EXPECT_FALSE(u.find(&_shared));
    EXPECT_FALSE(u.find(&_weak));
    EXPECT_TRUE(u.remove(&_unique));
    EXPECT_TRUE((bool)_unique);
    if (_unique) {
        EXPECT_EQ(123, _unique->magic());
    }

    // the unique value should have been removed but still accessible as nullptr
    EXPECT_TRUE(u.remove(&_unique));
    EXPECT_FALSE((bool)_unique);
    EXPECT_EQ(1, destructions);

    EXPECT_FALSE(u.find(&_shared_base));
    EXPECT_TRUE(u.remove(&_unique_base));
    EXPECT_FALSE((bool)_unique_base);
    EXPECT_FALSE(u.find(&_weak_base));

    // test that movable-only type (unique_ptr) can be stored without moving (and is still
    // moved)
    _unique = std::unique_ptr<DerivedCounter>(new DerivedCounter(&destructions, 321));
    EXPECT_TRUE(u.set(std::move(_unique)));
    EXPECT_FALSE((bool)_unique);
    EXPECT_TRUE(u.set(std::unique_ptr<DerivedCounter>(new DerivedCounter(&destructions, 1234))));
    EXPECT_EQ(2, destructions);
    EXPECT_TRUE(u.remove(&_unique));
    EXPECT_TRUE((bool)_unique);
    if (_unique) {
        EXPECT_EQ(1234, _unique->magic());
    }
    EXPECT_TRUE(u.set(std::move(_unique)));
    EXPECT_EQ(2, destructions);
    EXPECT_TRUE(u.clear());
    EXPECT_EQ(3, destructions);
    EXPECT_FALSE(u.find(&_int));
    EXPECT_FALSE(u.find(&_shared));
    EXPECT_FALSE(u.remove(&_unique));
    EXPECT_FALSE(u.find(&_weak));
    EXPECT_FALSE(u.find(&_shared_base));
    EXPECT_FALSE(u.remove(&_unique_base));
    EXPECT_FALSE(u.find(&_weak_base));

    // test that unique pointer can be set and removed as base type (but removed as derived only
    // if it was set as derived type)
    _unique = std::unique_ptr<DerivedCounter>(new DerivedCounter(&destructions, 321));
    EXPECT_TRUE(u.set(std::move(_unique)));
    EXPECT_FALSE((bool)_unique);
    EXPECT_TRUE(u.remove(&_unique_base));
    EXPECT_TRUE((bool)_unique_base);
    if (_unique_base) {
        EXPECT_EQ(321, _unique_base->magic());
    }
    EXPECT_TRUE(u.remove(&_unique));
    EXPECT_FALSE((bool)_unique);

    EXPECT_TRUE(u.set(std::move(_unique_base)));
    EXPECT_FALSE((bool)_unique_base);
    EXPECT_FALSE(u.remove(&_unique));
    EXPECT_FALSE((bool)_unique);
    EXPECT_TRUE(u.remove(&_unique_base));
    EXPECT_TRUE((bool)_unique_base);
    if (_unique_base) {
        EXPECT_EQ(321, _unique_base->magic());
    }

    EXPECT_EQ(3, destructions);
    EXPECT_TRUE(u.remove(&_unique_base));
    EXPECT_EQ(4, destructions);
    EXPECT_FALSE((bool)_unique_base);
    EXPECT_FALSE(u.find(&_int));
    EXPECT_FALSE(u.find(&_shared));
    EXPECT_FALSE(u.find(&_shared_base));
    EXPECT_FALSE(u.find(&_weak));
    EXPECT_FALSE(u.find(&_weak_base));

    // u.set(_constUnique);

    // test that copiable & movable type (shared_ptr) is copied unless explicitly moved.
    _shared = std::make_shared<DerivedCounter>(&destructions, 234);
    EXPECT_EQ(1L, _shared.use_count());
    EXPECT_TRUE(u.set(_shared));
    EXPECT_TRUE((bool)_shared);
    if (_shared) {
        EXPECT_EQ(234, _shared->magic());
    }

    EXPECT_EQ(2L, _shared.use_count());
    EXPECT_FALSE(u.find(&_int));
    EXPECT_FALSE(u.remove(&_unique));
    EXPECT_FALSE(u.find(&_weak));
    EXPECT_TRUE(u.find(&_shared));
    EXPECT_FALSE(u.remove(&_unique_base));
    EXPECT_FALSE(u.find(&_weak_base));
    EXPECT_EQ(2L, _shared.use_count());
    EXPECT_TRUE((bool)_shared);
    if (_shared) {
        EXPECT_EQ(234, _shared->magic());
    }

    // explicitly move in shared_ptr
    EXPECT_TRUE(u.set(std::move(_shared)));
    EXPECT_EQ(0, _shared.use_count()); // shared should be nullptr
    EXPECT_FALSE((bool)_shared);
    EXPECT_TRUE(u.find(&_shared));
    EXPECT_EQ(2L, _shared.use_count()); // now both u and _shared contains the object
    EXPECT_TRUE((bool)_shared);
    if (_shared) {
        EXPECT_EQ(234, _shared->magic());
    }
    EXPECT_FALSE(u.find(&_int));
    EXPECT_FALSE(u.remove(&_unique));
    EXPECT_FALSE(u.find(&_weak));
    EXPECT_FALSE(u.remove(&_unique_base));
    EXPECT_FALSE(u.find(&_weak_base));
    EXPECT_TRUE(u.find(&_shared));
    EXPECT_EQ(2L, _shared.use_count()); // still both u and _shared contains the object

    EXPECT_TRUE(u.clear());
    EXPECT_TRUE(_shared.unique()); // now only _shared contains the object

    EXPECT_TRUE(u.set(_constShared));
    EXPECT_EQ(2L, _constShared.use_count()); // even though it is const, we can add a use count
    EXPECT_TRUE(u.find(&_shared));
    EXPECT_EQ(3L, _shared.use_count()); // now u, _shared and _constShared contains the const object
    EXPECT_TRUE((bool)_shared);
    if (_shared) {
        EXPECT_EQ(1234, _shared->magic());
    }

    // test that shared pointer can be set and removed as base type (but removed as derived only
    // if it was set as derived type)
    EXPECT_TRUE(u.find(&_shared_base));
    EXPECT_TRUE((bool)_shared_base);
    if (_shared_base) {
        EXPECT_EQ(1234, _shared_base->magic());
    }
    EXPECT_EQ(4L, _shared.use_count()); // now u, _shared, _constShared and _shared_base contains
                                        // the const object
    _shared.reset();
    EXPECT_EQ(3L, _shared_base.use_count()); // now u, _constShared and _shared_base contains it
    EXPECT_TRUE(u.clear());
    EXPECT_EQ(2L, _shared_base.use_count()); // now _constShared and _shared_base contains it

    EXPECT_TRUE(u.set(_shared_base));        // now u_ also contains it as base class
    EXPECT_EQ(3L, _shared_base.use_count());
    EXPECT_FALSE(u.find(&_shared)); // cannot get it as derived type
    EXPECT_FALSE((bool)_shared);
    _shared_base.reset();
    EXPECT_TRUE(u.find(&_shared_base)); // can still get it as base type
    EXPECT_TRUE((bool)_shared_base);
    if (_shared_base) {
        EXPECT_EQ(1234, _shared_base->magic());
    }
    _shared = std::static_pointer_cast<DerivedCounter>(_shared_base);
    EXPECT_FALSE(u.find(&_int));
    EXPECT_FALSE(u.remove(&_unique));
    EXPECT_FALSE(u.remove(&_unique_base));
    EXPECT_FALSE(u.find(&_weak));
    EXPECT_FALSE(u.find(&_weak_base));

    // test that weak pointer can be copied in (support for moving is from C++14 only)
    _weak = _shared;
    EXPECT_EQ(_weak.use_count(), _shared.use_count());
    EXPECT_TRUE(u.set(_weak));

    _weak.reset();
    EXPECT_EQ(_weak.use_count(), 0);

    EXPECT_FALSE(u.find(&_int));
    EXPECT_FALSE(u.remove(&_unique));
    EXPECT_FALSE(u.find(&_shared));
    EXPECT_FALSE(u.remove(&_unique_base));
    EXPECT_FALSE(u.find(&_shared_base));
    EXPECT_TRUE(u.find(&_weak));
    EXPECT_EQ(_weak.use_count(), _shared.use_count());
    EXPECT_EQ(_weak.lock(), _shared);

    // we can remove a weak pointer multiple times
    _weak.reset();
    EXPECT_TRUE(u.find(&_weak));
    EXPECT_EQ(_weak.use_count(), _shared.use_count());
    EXPECT_EQ(_weak.lock(), _shared);
    EXPECT_TRUE(u.clear());
    EXPECT_FALSE(u.find(&_int));
    EXPECT_FALSE(u.remove(&_unique));
    EXPECT_FALSE(u.find(&_shared));
    EXPECT_FALSE(u.find(&_weak));
    EXPECT_FALSE(u.remove(&_unique_base));
    EXPECT_FALSE(u.find(&_shared_base));
    EXPECT_FALSE(u.find(&_weak_base));

    // test that weak pointer can be set and removed as base type (but removed as derived only
    // if it was set as derived type)
    _weak = _shared;
    EXPECT_TRUE(u.set(_weak));
    EXPECT_TRUE(u.find(&_weak_base));
    EXPECT_FALSE(_weak_base.expired());
    if (!_weak_base.expired()) {
        EXPECT_EQ(1234, _weak_base.lock()->magic());
    }
    // now _shared, _constShared and _shared_base contains the const object
    EXPECT_EQ(3L, _weak.use_count());
    _weak.reset();
    EXPECT_EQ(3L, _weak_base.use_count()); // _weak did not hold a reference
    _shared.reset();
    EXPECT_EQ(2L, _weak_base.use_count()); // now u, _constShared and _shared_base contains it
    EXPECT_TRUE(u.clear());
    EXPECT_FALSE(u.find(&_int));
    EXPECT_FALSE(u.remove(&_unique));
    EXPECT_FALSE(u.find(&_shared));
    EXPECT_FALSE(u.find(&_weak));
    EXPECT_FALSE(u.remove(&_unique_base));
    EXPECT_FALSE(u.find(&_shared_base));
    EXPECT_FALSE(u.find(&_weak_base));

    EXPECT_TRUE(u.set(_weak_base)); // now u_ also contains it as base class
    EXPECT_FALSE(u.find(&_weak));   // cannot get it as derived type
    EXPECT_TRUE(_weak.expired());
    _weak_base.reset();
    EXPECT_TRUE(u.find(&_weak_base)); // can still get it as base type
    EXPECT_FALSE(_weak_base.expired());
    if (!_weak_base.expired()) {
        EXPECT_EQ(1234, _weak_base.lock()->magic());
    }
};

TEST_F(ADataTest, AData_AndroidSpTest) {
    int destructions = 0;
    int _int = 0;
    sp<EventCounter> _shared;
    wp<EventCounter> _weak;
    const sp<EventCounter> _constShared(new EventCounter(&destructions));

    AData<int, sp<EventCounter>, wp<EventCounter>>::Strict<uint8_t> u;

    // test that data is empty
    EXPECT_FALSE(u.used());
    EXPECT_FALSE(u.find(&_int));
    EXPECT_FALSE(u.find(&_shared));
    EXPECT_FALSE(u.find(&_weak));

    // test that integer can be stored and read
    EXPECT_TRUE(u.set<int>(1));
    EXPECT_TRUE(u.used());
    EXPECT_TRUE(u.find(&_int));
    EXPECT_EQ(1, _int);
    EXPECT_FALSE(u.find(&_shared));
    EXPECT_FALSE(u.find(&_weak));

    // test that copiable & movable type (shared_ptr) is copied unless explicitly moved.
    _shared = new EventCounter(&destructions, 234);
    _weak = _shared; // used for tracking #234

    EXPECT_TRUE(u.set(_shared));
    EXPECT_TRUE((bool)_shared.get());
    if (_shared.get()) {
        EXPECT_EQ(234, _shared->magic());
    }

    _shared.clear();
    EXPECT_EQ(NULL, _shared.get());
    EXPECT_NE(nullptr, _weak.promote().get()); // u still holds object

    EXPECT_FALSE(u.find(&_int));
    EXPECT_FALSE(u.find(&_weak));
    EXPECT_TRUE(u.find(&_shared)); // now u and _shared both hold object
    EXPECT_TRUE((bool)_shared.get());
    if (_shared.get()) {
        EXPECT_EQ(234, _shared->magic());
    }
    // verify the find did not move out object
    _shared.clear();
    EXPECT_EQ(NULL, _shared.get());
    EXPECT_NE(nullptr, _weak.promote().get()); // u still holds object
    EXPECT_TRUE(u.find(&_shared)); // now u and _shared both hold object
    if (_shared.get()) {
        EXPECT_EQ(234, _shared->magic());
    }

    // verify that we can set object multiple times
    EXPECT_TRUE(u.set(_shared));

    // explicitly move in sp
    EXPECT_TRUE(u.set(std::move(_shared)));
    EXPECT_FALSE((bool)_shared.get()); // android also clears sp<> on move...
    EXPECT_TRUE(u.find(&_shared)); // still can get it back
    EXPECT_TRUE((bool)_shared.get());
    if (_shared.get()) {
        EXPECT_EQ(234, _shared->magic());
    }
    EXPECT_FALSE(u.find(&_int));
    EXPECT_FALSE(u.find(&_weak));

    EXPECT_TRUE(u.used());
    EXPECT_TRUE(u.clear()); // now only _shared contains the object
    EXPECT_FALSE(u.used());

    // we still hold a copy
    EXPECT_TRUE((bool)_shared.get());
    EXPECT_FALSE(u.find(&_int));
    EXPECT_FALSE(u.find(&_shared)); // _shared still contains the object

    EXPECT_TRUE(u.set(_constShared));
    EXPECT_TRUE(u.find(&_shared)); // now _shared contains _constShared
    EXPECT_EQ(NULL, _weak.promote().get()); // original _shared is now lost

    EXPECT_TRUE((bool)_shared.get());
    if (_shared.get()) {
        EXPECT_EQ(1234, _shared->magic());
    }
    EXPECT_TRUE(u.clear());

    // test that wp can be copied in
    _weak = _shared;
    EXPECT_TRUE(u.set(_weak));

    _weak.clear();

    EXPECT_FALSE(u.find(&_int));
    EXPECT_FALSE(u.find(&_shared));
    EXPECT_TRUE(u.find(&_weak));
    EXPECT_EQ(_weak.promote(), _shared);

    // we can remove a weak pointer multiple times
    _weak.clear();
    EXPECT_TRUE(u.find(&_weak));
    EXPECT_EQ(_weak.promote(), _shared);
    EXPECT_TRUE(u.clear());
    EXPECT_FALSE(u.find(&_int));
    EXPECT_FALSE(u.find(&_shared));
    EXPECT_FALSE(u.find(&_weak));
};

TEST_F(ADataTest, AData_RelaxedAndroidSpTest) {
    int destructions = 0;
    int _int = 0;
    sp<EventCounter> _shared;
    wp<EventCounter> _weak;
    sp<RefBase> _shared_base;
    wp<RefBase> _weak_base;
    const sp<EventCounter> _constShared(new EventCounter(&destructions));

    AData<int, sp<RefBase>, wp<RefBase>>::Relaxed<uint16_t> u;

    // test that data is empty
    EXPECT_FALSE(u.used());
    EXPECT_FALSE(u.find(&_int));
    EXPECT_FALSE(u.find(&_shared));
    EXPECT_FALSE(u.find(&_weak));
    EXPECT_FALSE(u.find(&_shared_base));
    EXPECT_FALSE(u.find(&_weak_base));

    // test that integer can be stored and read
    EXPECT_TRUE(u.set<int>(1));
    EXPECT_TRUE(u.used());
    EXPECT_TRUE(u.find(&_int));
    EXPECT_EQ(1, _int);
    EXPECT_FALSE(u.find(&_shared));
    EXPECT_FALSE(u.find(&_weak));
    EXPECT_FALSE(u.find(&_shared_base));
    EXPECT_FALSE(u.find(&_weak_base));

    // test that copiable & movable type (shared_ptr) is copied unless explicitly moved.
    _shared = new EventCounter(&destructions, 234);
    _weak = _shared; // used for tracking #234

    EXPECT_TRUE(u.set(_shared));
    EXPECT_TRUE((bool)_shared.get());
    if (_shared.get()) {
        EXPECT_EQ(234, _shared->magic());
    }

    _shared.clear();
    EXPECT_EQ(NULL, _shared.get());
    EXPECT_NE(nullptr, _weak.promote().get()); // u still holds object

    EXPECT_FALSE(u.find(&_int));
    EXPECT_TRUE(u.find(&_shared)); // now u and _shared both hold object
    EXPECT_TRUE((bool)_shared.get());
    if (_shared.get()) {
        EXPECT_EQ(234, _shared->magic());
    }
    // verify the find did not move out object
    _shared.clear();
    EXPECT_EQ(NULL, _shared.get());
    EXPECT_NE(nullptr, _weak.promote().get()); // u still holds object
    EXPECT_TRUE(u.find(&_shared)); // now u and _shared both hold object
    if (_shared.get()) {
        EXPECT_EQ(234, _shared->magic());
    }

    // verify that we can set object multiple times
    EXPECT_TRUE(u.set(_shared));

    // explicitly move in sp
    EXPECT_TRUE(u.set(std::move(_shared)));
    EXPECT_FALSE((bool)_shared.get()); // android also clears sp<> on move...
    EXPECT_TRUE(u.find(&_shared)); // still can get it back
    EXPECT_TRUE((bool)_shared.get());
    if (_shared.get()) {
        EXPECT_EQ(234, _shared->magic());
    }
    EXPECT_FALSE(u.find(&_int));
    EXPECT_FALSE(u.find(&_weak));
    EXPECT_FALSE(u.find(&_weak_base));

    EXPECT_TRUE(u.used());
    EXPECT_TRUE(u.clear()); // now only _shared contains the object
    EXPECT_FALSE(u.used());

    // we still hold a copy
    EXPECT_TRUE((bool)_shared.get());
    EXPECT_FALSE(u.find(&_int));
    EXPECT_FALSE(u.find(&_shared)); // _shared still contains the object

    EXPECT_TRUE(u.set(_constShared));
    EXPECT_TRUE(u.find(&_shared)); // now _shared contains _constShared
    EXPECT_EQ(NULL, _weak.promote().get()); // original _shared is now lost

    EXPECT_TRUE((bool)_shared.get());
    if (_shared.get()) {
        EXPECT_EQ(1234, _shared->magic());
    }
    EXPECT_TRUE(u.clear());

    // test that shared pointer can be set and removed as base type (but removed as derived only
    // if it was set as derived type)
    EXPECT_TRUE(u.set(_constShared));
    EXPECT_TRUE(u.find(&_shared_base));
    EXPECT_TRUE((bool)_shared_base.get());
    if (_shared_base.get()) {
        EXPECT_EQ(1234, static_cast<EventCounter*>(_shared_base.get())->magic());
    }
    _shared.clear();
    EXPECT_TRUE(u.clear());
    EXPECT_TRUE((bool)_shared_base.get());
    if (_shared_base.get()) {
        EXPECT_EQ(1234, static_cast<EventCounter*>(_shared_base.get())->magic());
    }

    EXPECT_TRUE(u.set(_shared_base)); // now u contains it as base class
    EXPECT_TRUE((bool)_shared_base.get());
    EXPECT_FALSE(u.find(&_shared)); // cannot get it as derived type
    EXPECT_FALSE((bool)_shared.get());
    _shared_base.clear();
    EXPECT_TRUE(u.find(&_shared_base)); // can still get it as base type
    EXPECT_TRUE((bool)_shared_base.get());
    if (_shared_base.get()) {
        EXPECT_EQ(1234, static_cast<EventCounter*>(_shared_base.get())->magic());
    }
    _shared = static_cast<DerivedCounter*>(_shared_base.get());
    EXPECT_FALSE(u.find(&_int));
    EXPECT_FALSE(u.find(&_weak));
    EXPECT_FALSE(u.find(&_weak_base));

    // test that wp can be copied in
    _weak = _shared;
    EXPECT_TRUE(u.set(_weak));

    _weak.clear();

    EXPECT_FALSE(u.find(&_int));
    EXPECT_FALSE(u.find(&_shared));
    EXPECT_FALSE(u.find(&_shared_base));
    EXPECT_TRUE(u.find(&_weak));
    EXPECT_EQ(_weak.promote(), _shared);

    // we can remove a weak pointer multiple times
    _weak.clear();
    EXPECT_TRUE(u.find(&_weak));
    EXPECT_EQ(_weak.promote(), _shared);
    EXPECT_TRUE(u.clear());
    EXPECT_FALSE(u.find(&_int));
    EXPECT_FALSE(u.find(&_shared));
    EXPECT_FALSE(u.find(&_weak));
    EXPECT_FALSE(u.find(&_shared_base));
    EXPECT_FALSE(u.find(&_weak_base));

    // test that weak pointer can be set and removed as base type (but removed as derived only
    // if it was set as derived type)
    _weak = _shared;
    EXPECT_TRUE(u.set(_weak));
    EXPECT_TRUE(u.find(&_weak_base));
    EXPECT_TRUE(_weak_base.promote().get() == _shared.get());

    _weak.clear();
    _shared.clear();
    EXPECT_TRUE(u.clear());
    EXPECT_FALSE(u.find(&_int));
    EXPECT_FALSE(u.find(&_shared));
    EXPECT_FALSE(u.find(&_weak));
    EXPECT_FALSE(u.find(&_shared_base));
    EXPECT_FALSE(u.find(&_weak_base));

    EXPECT_TRUE(u.set(_weak_base)); // now u_ also contains it as base class
    EXPECT_FALSE(u.find(&_weak));   // cannot get it as derived type
    EXPECT_FALSE(_weak.promote().get());
    _weak_base.clear();
    EXPECT_TRUE(u.find(&_weak_base)); // can still get it as base type
    EXPECT_TRUE(_weak_base.promote().get());
    if (_weak_base.promote().get()) {
        EXPECT_EQ(1234, static_cast<EventCounter*>(_weak_base.promote().get())->magic());
    }
};

} // namespace android
