/*
 * Copyright (C) 2015 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.
 */

#include "variant_map.h"
#include "gtest/gtest.h"

#define EXPECT_NULL(expected) EXPECT_EQ(reinterpret_cast<const void*>(expected), \
                                        reinterpret_cast<void*>(NULL));

namespace art {

namespace {
  template <typename TValue>
  struct FruitMapKey : VariantMapKey<TValue> {
    FruitMapKey() {}
  };

  struct FruitMap : VariantMap<FruitMap, FruitMapKey> {
    // This 'using' line is necessary to inherit the variadic constructor.
    using VariantMap<FruitMap, FruitMapKey>::VariantMap;

    // Make the next '4' usages of Key slightly shorter to type.
    template <typename TValue>
    using Key = FruitMapKey<TValue>;

    static const Key<int> Apple;
    static const Key<double> Orange;
    static const Key<std::string> Label;
  };

  const FruitMap::Key<int> FruitMap::Apple;
  const FruitMap::Key<double> FruitMap::Orange;
  const FruitMap::Key<std::string> FruitMap::Label;
}  // namespace

TEST(VariantMaps, BasicReadWrite) {
  FruitMap fm;

  EXPECT_NULL(fm.Get(FruitMap::Apple));
  EXPECT_FALSE(fm.Exists(FruitMap::Apple));
  EXPECT_NULL(fm.Get(FruitMap::Orange));
  EXPECT_FALSE(fm.Exists(FruitMap::Orange));

  fm.Set(FruitMap::Apple, 1);
  EXPECT_NULL(fm.Get(FruitMap::Orange));
  EXPECT_EQ(1, *fm.Get(FruitMap::Apple));
  EXPECT_TRUE(fm.Exists(FruitMap::Apple));

  fm.Set(FruitMap::Apple, 5);
  EXPECT_NULL(fm.Get(FruitMap::Orange));
  EXPECT_EQ(5, *fm.Get(FruitMap::Apple));
  EXPECT_TRUE(fm.Exists(FruitMap::Apple));

  fm.Set(FruitMap::Orange, 555.0);
  EXPECT_EQ(5, *fm.Get(FruitMap::Apple));
  EXPECT_DOUBLE_EQ(555.0, *fm.Get(FruitMap::Orange));
  EXPECT_EQ(size_t(2), fm.Size());

  // Simple remove
  fm.Remove(FruitMap::Apple);
  EXPECT_FALSE(fm.Exists(FruitMap::Apple));

  fm.Clear();
  EXPECT_EQ(size_t(0), fm.Size());
  EXPECT_FALSE(fm.Exists(FruitMap::Orange));
}

TEST(VariantMaps, SetPreviousValue) {
  FruitMap fm;

  // Indirect remove by setting yourself again
  fm.Set(FruitMap::Label, std::string("hello_world"));
  auto* ptr = fm.Get(FruitMap::Label);
  ASSERT_TRUE(ptr != nullptr);
  *ptr = "foobar";

  // Set the value to the same exact pointer which we got out of the map.
  // This should cleanly 'just work' and not try to delete the value too early.
  fm.Set(FruitMap::Label, *ptr);

  auto* new_ptr = fm.Get(FruitMap::Label);
  ASSERT_TRUE(ptr != nullptr);
  EXPECT_EQ(std::string("foobar"), *new_ptr);
}

TEST(VariantMaps, RuleOfFive) {
  // Test empty constructor
  FruitMap fmEmpty;
  EXPECT_EQ(size_t(0), fmEmpty.Size());

  // Test empty constructor
  FruitMap fmFilled;
  fmFilled.Set(FruitMap::Apple, 1);
  fmFilled.Set(FruitMap::Orange, 555.0);
  EXPECT_EQ(size_t(2), fmFilled.Size());

  // Test copy constructor
  FruitMap fmEmptyCopy(fmEmpty);
  EXPECT_EQ(size_t(0), fmEmptyCopy.Size());

  // Test copy constructor
  FruitMap fmFilledCopy(fmFilled);
  EXPECT_EQ(size_t(2), fmFilledCopy.Size());
  EXPECT_EQ(*fmFilled.Get(FruitMap::Apple), *fmFilledCopy.Get(FruitMap::Apple));
  EXPECT_DOUBLE_EQ(*fmFilled.Get(FruitMap::Orange), *fmFilledCopy.Get(FruitMap::Orange));

  // Test operator=
  FruitMap fmFilledCopy2;
  fmFilledCopy2 = fmFilled;
  EXPECT_EQ(size_t(2), fmFilledCopy2.Size());
  EXPECT_EQ(*fmFilled.Get(FruitMap::Apple), *fmFilledCopy2.Get(FruitMap::Apple));
  EXPECT_DOUBLE_EQ(*fmFilled.Get(FruitMap::Orange), *fmFilledCopy2.Get(FruitMap::Orange));

  // Test move constructor
  FruitMap fmMoved(std::move(fmFilledCopy));
  EXPECT_EQ(size_t(0), fmFilledCopy.Size());
  EXPECT_EQ(size_t(2), fmMoved.Size());
  EXPECT_EQ(*fmFilled.Get(FruitMap::Apple), *fmMoved.Get(FruitMap::Apple));
  EXPECT_DOUBLE_EQ(*fmFilled.Get(FruitMap::Orange), *fmMoved.Get(FruitMap::Orange));

  // Test operator= move
  FruitMap fmMoved2;
  fmMoved2.Set(FruitMap::Apple, 12345);  // This value will be clobbered after the move

  fmMoved2 = std::move(fmFilledCopy2);
  EXPECT_EQ(size_t(0), fmFilledCopy2.Size());
  EXPECT_EQ(size_t(2), fmMoved2.Size());
  EXPECT_EQ(*fmFilled.Get(FruitMap::Apple), *fmMoved2.Get(FruitMap::Apple));
  EXPECT_DOUBLE_EQ(*fmFilled.Get(FruitMap::Orange), *fmMoved2.Get(FruitMap::Orange));
}

TEST(VariantMaps, VariadicConstructors) {
  // Variadic constructor, 1 kv/pair
  FruitMap fmApple(FruitMap::Apple, 12345);
  EXPECT_EQ(size_t(1), fmApple.Size());
  EXPECT_EQ(12345, *fmApple.Get(FruitMap::Apple));

  // Variadic constructor, 2 kv/pair
  FruitMap fmAppleAndOrange(FruitMap::Apple,   12345,
                            FruitMap::Orange,  100.0);
  EXPECT_EQ(size_t(2), fmAppleAndOrange.Size());
  EXPECT_EQ(12345, *fmAppleAndOrange.Get(FruitMap::Apple));
  EXPECT_DOUBLE_EQ(100.0, *fmAppleAndOrange.Get(FruitMap::Orange));
}

TEST(VariantMaps, ReleaseOrDefault) {
  FruitMap fmAppleAndOrange(FruitMap::Apple,   12345,
                            FruitMap::Orange,  100.0);

  int apple = fmAppleAndOrange.ReleaseOrDefault(FruitMap::Apple);
  EXPECT_EQ(12345, apple);

  // Releasing will also remove the Apple key.
  EXPECT_EQ(size_t(1), fmAppleAndOrange.Size());

  // Releasing again yields a default value.
  int apple2 = fmAppleAndOrange.ReleaseOrDefault(FruitMap::Apple);
  EXPECT_EQ(0, apple2);
}

TEST(VariantMaps, GetOrDefault) {
  FruitMap fm(FruitMap::Apple,   12345);

  // Apple gives the expected value we set.
  int apple = fm.GetOrDefault(FruitMap::Apple);
  EXPECT_EQ(12345, apple);

  // Map is still 1.
  EXPECT_EQ(size_t(1), fm.Size());

  // Orange gives back a default value, since it's not in the map.
  double orange = fm.GetOrDefault(FruitMap::Orange);
  EXPECT_DOUBLE_EQ(0.0, orange);
}

}  // namespace art
