// Copyright 2015 The Crashpad Authors. All rights reserved.
//
// 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 "snapshot/win/process_reader_win.h"

#include <windows.h>
#include <string.h>

#include "base/stl_util.h"
#include "gtest/gtest.h"
#include "test/win/win_multiprocess.h"
#include "util/misc/from_pointer_cast.h"
#include "util/synchronization/semaphore.h"
#include "util/thread/thread.h"
#include "util/win/context_wrappers.h"
#include "util/win/scoped_process_suspend.h"

namespace crashpad {
namespace test {
namespace {

TEST(ProcessReaderWin, SelfBasic) {
  ProcessReaderWin process_reader;
  ASSERT_TRUE(process_reader.Initialize(GetCurrentProcess(),
                                        ProcessSuspensionState::kRunning));

#if !defined(ARCH_CPU_64_BITS)
  EXPECT_FALSE(process_reader.Is64Bit());
#else
  EXPECT_TRUE(process_reader.Is64Bit());
#endif

  EXPECT_EQ(process_reader.GetProcessInfo().ProcessID(), GetCurrentProcessId());

  static constexpr char kTestMemory[] = "Some test memory";
  char buffer[base::size(kTestMemory)];
  ASSERT_TRUE(process_reader.Memory()->Read(
      reinterpret_cast<uintptr_t>(kTestMemory), sizeof(kTestMemory), &buffer));
  EXPECT_STREQ(kTestMemory, buffer);
}

constexpr char kTestMemory[] = "Read me from another process";

class ProcessReaderChild final : public WinMultiprocess {
 public:
  ProcessReaderChild() : WinMultiprocess() {}
  ~ProcessReaderChild() {}

 private:
  void WinMultiprocessParent() override {
    ProcessReaderWin process_reader;
    ASSERT_TRUE(process_reader.Initialize(ChildProcess(),
                                          ProcessSuspensionState::kRunning));

#if !defined(ARCH_CPU_64_BITS)
    EXPECT_FALSE(process_reader.Is64Bit());
#else
    EXPECT_TRUE(process_reader.Is64Bit());
#endif

    WinVMAddress address;
    CheckedReadFileExactly(ReadPipeHandle(), &address, sizeof(address));

    char buffer[sizeof(kTestMemory)];
    ASSERT_TRUE(
        process_reader.Memory()->Read(address, sizeof(kTestMemory), &buffer));
    EXPECT_EQ(strcmp(kTestMemory, buffer), 0);
  }

  void WinMultiprocessChild() override {
    WinVMAddress address = FromPointerCast<WinVMAddress>(kTestMemory);
    CheckedWriteFile(WritePipeHandle(), &address, sizeof(address));

    // Wait for the parent to signal that it's OK to exit by closing its end of
    // the pipe.
    CheckedReadFileAtEOF(ReadPipeHandle());
  }

  DISALLOW_COPY_AND_ASSIGN(ProcessReaderChild);
};

TEST(ProcessReaderWin, ChildBasic) {
  WinMultiprocess::Run<ProcessReaderChild>();
}

TEST(ProcessReaderWin, SelfOneThread) {
  ProcessReaderWin process_reader;
  ASSERT_TRUE(process_reader.Initialize(GetCurrentProcess(),
                                        ProcessSuspensionState::kRunning));

  const std::vector<ProcessReaderWin::Thread>& threads =
      process_reader.Threads();

  // If other tests ran in this process previously, threads may have been
  // created and may still be running. This check must look for at least one
  // thread, not exactly one thread.
  ASSERT_GE(threads.size(), 1u);

  EXPECT_EQ(threads[0].id, GetCurrentThreadId());
  EXPECT_NE(ProgramCounterFromCONTEXT(&threads[0].context.native), nullptr);
  EXPECT_EQ(threads[0].suspend_count, 0u);
}

class ProcessReaderChildThreadSuspendCount final : public WinMultiprocess {
 public:
  ProcessReaderChildThreadSuspendCount() : WinMultiprocess() {}
  ~ProcessReaderChildThreadSuspendCount() {}

 private:
  enum : unsigned int { kCreatedThreads = 3 };

  class SleepingThread : public Thread {
   public:
    SleepingThread() : done_(nullptr) {}

    void SetHandle(Semaphore* done) {
      done_= done;
    }

    void ThreadMain() override {
      done_->Wait();
    }

   private:
    Semaphore* done_;
  };

  void WinMultiprocessParent() override {
    char c;
    CheckedReadFileExactly(ReadPipeHandle(), &c, sizeof(c));
    ASSERT_EQ(c, ' ');

    {
      ProcessReaderWin process_reader;
      ASSERT_TRUE(process_reader.Initialize(ChildProcess(),
                                            ProcessSuspensionState::kRunning));

      const auto& threads = process_reader.Threads();
      ASSERT_GE(threads.size(), kCreatedThreads + 1);
      for (const auto& thread : threads)
        EXPECT_EQ(thread.suspend_count, 0u);
    }

    {
      ScopedProcessSuspend suspend(ChildProcess());

      ProcessReaderWin process_reader;
      ASSERT_TRUE(process_reader.Initialize(
          ChildProcess(), ProcessSuspensionState::kSuspended));

      // Confirm that thread counts are adjusted correctly for the process being
      // suspended.
      const auto& threads = process_reader.Threads();
      ASSERT_GE(threads.size(), kCreatedThreads + 1);
      for (const auto& thread : threads)
        EXPECT_EQ(thread.suspend_count, 0u);
    }
  }

  void WinMultiprocessChild() override {
    // Create three dummy threads so we can confirm we read successfully read
    // more than just the main thread.
    SleepingThread threads[kCreatedThreads];
    Semaphore done(0);
    for (auto& thread : threads)
      thread.SetHandle(&done);
    for (auto& thread : threads)
      thread.Start();

    char c = ' ';
    CheckedWriteFile(WritePipeHandle(), &c, sizeof(c));

    // Wait for the parent to signal that it's OK to exit by closing its end of
    // the pipe.
    CheckedReadFileAtEOF(ReadPipeHandle());

    for (size_t i = 0; i < base::size(threads); ++i)
      done.Signal();
    for (auto& thread : threads)
      thread.Join();
  }

  DISALLOW_COPY_AND_ASSIGN(ProcessReaderChildThreadSuspendCount);
};

TEST(ProcessReaderWin, ChildThreadSuspendCounts) {
  WinMultiprocess::Run<ProcessReaderChildThreadSuspendCount>();
}

}  // namespace
}  // namespace test
}  // namespace crashpad
