/*
 * Copyright (C) 2012 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 "space_bitmap.h"

#include "common_test.h"
#include "globals.h"
#include "space_bitmap-inl.h"
#include "UniquePtr.h"

#include <stdint.h>

namespace art {
namespace gc {
namespace accounting {

class SpaceBitmapTest : public CommonTest {
 public:
};

TEST_F(SpaceBitmapTest, Init) {
  byte* heap_begin = reinterpret_cast<byte*>(0x10000000);
  size_t heap_capacity = 16 * MB;
  UniquePtr<SpaceBitmap> space_bitmap(SpaceBitmap::Create("test bitmap",
                                                          heap_begin, heap_capacity));
  EXPECT_TRUE(space_bitmap.get() != NULL);
}

class BitmapVerify {
 public:
  BitmapVerify(SpaceBitmap* bitmap, const mirror::Object* begin, const mirror::Object* end)
    : bitmap_(bitmap),
      begin_(begin),
      end_(end) {}

  void operator()(const mirror::Object* obj) {
    EXPECT_TRUE(obj >= begin_);
    EXPECT_TRUE(obj <= end_);
    EXPECT_TRUE(bitmap_->Test(obj) == ((reinterpret_cast<uintptr_t>(obj) & 0xF) != 0));
  }

  SpaceBitmap* bitmap_;
  const mirror::Object* begin_;
  const mirror::Object* end_;
};

TEST_F(SpaceBitmapTest, ScanRange) {
  byte* heap_begin = reinterpret_cast<byte*>(0x10000000);
  size_t heap_capacity = 16 * MB;

  UniquePtr<SpaceBitmap> space_bitmap(SpaceBitmap::Create("test bitmap",
                                                          heap_begin, heap_capacity));
  EXPECT_TRUE(space_bitmap.get() != NULL);

  // Set all the odd bits in the first BitsPerWord * 3 to one.
  for (size_t j = 0;j < kBitsPerWord * 3; ++j) {
    const mirror::Object* obj =
        reinterpret_cast<mirror::Object*>(heap_begin + j * SpaceBitmap::kAlignment);
    if (reinterpret_cast<uintptr_t>(obj) & 0xF) {
      space_bitmap->Set(obj);
    }
  }
  // Try every possible starting bit in the first word. Then for each starting bit, try each
  // possible length up to a maximum of kBitsPerWord * 2 - 1 bits.
  // This handles all the cases, having runs which start and end on the same word, and different
  // words.
  for (size_t i = 0; i < static_cast<size_t>(kBitsPerWord); ++i) {
    mirror::Object* start =
        reinterpret_cast<mirror::Object*>(heap_begin + i * SpaceBitmap::kAlignment);
    for (size_t j = 0; j < static_cast<size_t>(kBitsPerWord * 2); ++j) {
      mirror::Object* end =
          reinterpret_cast<mirror::Object*>(heap_begin + (i + j) * SpaceBitmap::kAlignment);
      BitmapVerify(space_bitmap.get(), start, end);
    }
  }
}

}  // namespace accounting
}  // namespace gc
}  // namespace art
