//===-- tsan_clock_test.cc ------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of ThreadSanitizer (TSan), a race detector.
//
//===----------------------------------------------------------------------===//
#include "tsan_clock.h"
#include "tsan_rtl.h"
#include "gtest/gtest.h"

namespace __tsan {

TEST(Clock, VectorBasic) {
  ScopedInRtl in_rtl;
  ThreadClock clk;
  CHECK_EQ(clk.size(), 0);
  clk.tick(0);
  CHECK_EQ(clk.size(), 1);
  CHECK_EQ(clk.get(0), 1);
  clk.tick(3);
  CHECK_EQ(clk.size(), 4);
  CHECK_EQ(clk.get(0), 1);
  CHECK_EQ(clk.get(1), 0);
  CHECK_EQ(clk.get(2), 0);
  CHECK_EQ(clk.get(3), 1);
  clk.tick(3);
  CHECK_EQ(clk.get(3), 2);
}

TEST(Clock, ChunkedBasic) {
  ScopedInRtl in_rtl;
  ThreadClock vector;
  SyncClock chunked;
  CHECK_EQ(vector.size(), 0);
  CHECK_EQ(chunked.size(), 0);
  vector.acquire(&chunked);
  CHECK_EQ(vector.size(), 0);
  CHECK_EQ(chunked.size(), 0);
  vector.release(&chunked);
  CHECK_EQ(vector.size(), 0);
  CHECK_EQ(chunked.size(), 0);
  vector.acq_rel(&chunked);
  CHECK_EQ(vector.size(), 0);
  CHECK_EQ(chunked.size(), 0);
}

TEST(Clock, AcquireRelease) {
  ScopedInRtl in_rtl;
  ThreadClock vector1;
  vector1.tick(100);
  SyncClock chunked;
  vector1.release(&chunked);
  CHECK_EQ(chunked.size(), 101);
  ThreadClock vector2;
  vector2.acquire(&chunked);
  CHECK_EQ(vector2.size(), 101);
  CHECK_EQ(vector2.get(0), 0);
  CHECK_EQ(vector2.get(1), 0);
  CHECK_EQ(vector2.get(99), 0);
  CHECK_EQ(vector2.get(100), 1);
}

TEST(Clock, ManyThreads) {
  ScopedInRtl in_rtl;
  SyncClock chunked;
  for (int i = 0; i < 100; i++) {
    ThreadClock vector;
    vector.tick(i);
    vector.release(&chunked);
    CHECK_EQ(chunked.size(), i + 1);
    vector.acquire(&chunked);
    CHECK_EQ(vector.size(), i + 1);
  }
  ThreadClock vector;
  vector.acquire(&chunked);
  CHECK_EQ(vector.size(), 100);
  for (int i = 0; i < 100; i++)
    CHECK_EQ(vector.get(i), 1);
}

TEST(Clock, DifferentSizes) {
  ScopedInRtl in_rtl;
  {
    ThreadClock vector1;
    vector1.tick(10);
    ThreadClock vector2;
    vector2.tick(20);
    {
      SyncClock chunked;
      vector1.release(&chunked);
      CHECK_EQ(chunked.size(), 11);
      vector2.release(&chunked);
      CHECK_EQ(chunked.size(), 21);
    }
    {
      SyncClock chunked;
      vector2.release(&chunked);
      CHECK_EQ(chunked.size(), 21);
      vector1.release(&chunked);
      CHECK_EQ(chunked.size(), 21);
    }
    {
      SyncClock chunked;
      vector1.release(&chunked);
      vector2.acquire(&chunked);
      CHECK_EQ(vector2.size(), 21);
    }
    {
      SyncClock chunked;
      vector2.release(&chunked);
      vector1.acquire(&chunked);
      CHECK_EQ(vector1.size(), 21);
    }
  }
}

}  // namespace __tsan
