text: //===- JITEventListenerTestCommon.h - Helper for JITEventListener tests ------------===//
  //
  //                     The LLVM Compiler Infrastructure
  //
  // This file is distributed under the University of Illinois Open Source
  // License. See LICENSE.TXT for details.
  //
  //===-------------------------------------------------------------------------------===//
  
  #ifndef JIT_EVENT_LISTENER_TEST_COMMON_H
  #define JIT_EVENT_LISTENER_TEST_COMMON_H
  
  #include "llvm/CodeGen/MachineCodeInfo.h"
  #include "llvm/Config/config.h"
  #include "llvm/DIBuilder.h"
  #include "llvm/DebugInfo.h"
  #include "llvm/ExecutionEngine/JIT.h"
  #include "llvm/ExecutionEngine/JITEventListener.h"
  #include "llvm/IR/IRBuilder.h"
  #include "llvm/IR/Instructions.h"
  #include "llvm/IR/Module.h"
  #include "llvm/IR/TypeBuilder.h"
  #include "llvm/Support/Dwarf.h"
  #include "llvm/Support/TargetSelect.h"
  #include "gtest/gtest.h"
  #include <string>
  #include <utility>
  #include <vector>
  
  typedef std::vector<std::pair<std::string, unsigned int> > SourceLocations;
  typedef std::map<uint64_t, SourceLocations> NativeCodeMap;
  
  class JITEnvironment : public testing::Environment {
    virtual void SetUp() {
      // Required to create a JIT.
      llvm::InitializeNativeTarget();
    }
  };
  
  inline unsigned int getLine() {
    return 12;
  }
  
  inline unsigned int getCol() {
    return 0;
  }
  
  inline const char* getFilename() {
    return "mock_source_file.cpp";
  }
  
  // Test fixture shared by tests for listener implementations
  template<typename WrapperT>
  class JITEventListenerTestBase : public testing::Test {
  protected:
    llvm::OwningPtr<WrapperT> MockWrapper;
    llvm::OwningPtr<llvm::JITEventListener> Listener;
  
  public:
    llvm::Module* M;
    llvm::MDNode* Scope;
    llvm::ExecutionEngine* EE;
    llvm::DIBuilder* DebugBuilder;
    llvm::IRBuilder<> Builder;
  
    JITEventListenerTestBase(WrapperT* w)
    : MockWrapper(w)
    , M(new llvm::Module("module", llvm::getGlobalContext()))
    , EE(llvm::EngineBuilder(M)
      .setEngineKind(llvm::EngineKind::JIT)
      .setOptLevel(llvm::CodeGenOpt::None)
      .create())
    , DebugBuilder(new llvm::DIBuilder(*M))
    , Builder(llvm::getGlobalContext())
    {
      DebugBuilder->createCompileUnit(llvm::dwarf::DW_LANG_C_plus_plus,
                                      "JIT",
                                      "JIT",
                                      "JIT",
                                      true,
                                      "",
                                      1);
  
      Scope = DebugBuilder->createFile(getFilename(), ".");
    }
  
    llvm::Function *buildFunction(const SourceLocations& DebugLocations) {
      using namespace llvm;
  
      LLVMContext& GlobalContext = getGlobalContext();
  
      SourceLocations::const_iterator CurrentDebugLocation
        = DebugLocations.begin();
  
      if (CurrentDebugLocation != DebugLocations.end()) {
        DebugLoc DebugLocation = DebugLoc::get(getLine(), getCol(),
            DebugBuilder->createFile(CurrentDebugLocation->first, "."));
        Builder.SetCurrentDebugLocation(DebugLocation);
        CurrentDebugLocation++;
      }
  
      Function *Result = Function::Create(
          TypeBuilder<int32_t(int32_t), false>::get(GlobalContext),
          GlobalValue::ExternalLinkage, "id", M);
      Value *Arg = Result->arg_begin();
      BasicBlock *BB = BasicBlock::Create(M->getContext(), "entry", Result);
      Builder.SetInsertPoint(BB);
      Value* one = ConstantInt::get(GlobalContext, APInt(32, 1));
      for(; CurrentDebugLocation != DebugLocations.end();
          ++CurrentDebugLocation) {
        Arg = Builder.CreateMul(Arg, Builder.CreateAdd(Arg, one));
        Builder.SetCurrentDebugLocation(
          DebugLoc::get(CurrentDebugLocation->second, 0,
                        DebugBuilder->createFile(CurrentDebugLocation->first, ".")));
      }
      Builder.CreateRet(Arg);
      return Result;
    }
  
    void TestNoDebugInfo(NativeCodeMap& ReportedDebugFuncs) {
      SourceLocations DebugLocations;
      llvm::Function* f = buildFunction(DebugLocations);
      EXPECT_TRUE(0 != f);
  
      //Cause JITting and callbacks to our listener
      EXPECT_TRUE(0 != EE->getPointerToFunction(f));
      EXPECT_TRUE(1 == ReportedDebugFuncs.size());
  
      EE->freeMachineCodeForFunction(f);
      EXPECT_TRUE(ReportedDebugFuncs.size() == 0);
    }
  
    void TestSingleLine(NativeCodeMap& ReportedDebugFuncs) {
      SourceLocations DebugLocations;
      DebugLocations.push_back(std::make_pair(std::string(getFilename()),
                                              getLine()));
      llvm::Function* f = buildFunction(DebugLocations);
      EXPECT_TRUE(0 != f);
  
      EXPECT_TRUE(0 != EE->getPointerToFunction(f));
      EXPECT_TRUE(1 == ReportedDebugFuncs.size());
      EXPECT_STREQ(ReportedDebugFuncs.begin()->second.begin()->first.c_str(),
                   getFilename());
      EXPECT_EQ(ReportedDebugFuncs.begin()->second.begin()->second, getLine());
  
      EE->freeMachineCodeForFunction(f);
      EXPECT_TRUE(ReportedDebugFuncs.size() == 0);
    }
  
    void TestMultipleLines(NativeCodeMap& ReportedDebugFuncs) {
      using namespace std;
  
      SourceLocations DebugLocations;
      unsigned int c = 5;
      for(unsigned int i = 0; i < c; ++i) {
        DebugLocations.push_back(make_pair(string(getFilename()), getLine() + i));
      }
  
      llvm::Function* f = buildFunction(DebugLocations);
      EXPECT_TRUE(0 != f);
  
      EXPECT_TRUE(0 != EE->getPointerToFunction(f));
      EXPECT_TRUE(1 == ReportedDebugFuncs.size());
      SourceLocations& FunctionInfo = ReportedDebugFuncs.begin()->second;
      EXPECT_EQ(c, FunctionInfo.size());
  
      int VerifyCount = 0;
      for(SourceLocations::iterator i = FunctionInfo.begin();
          i != FunctionInfo.end();
          ++i) {
        EXPECT_STREQ(i->first.c_str(), getFilename());
        EXPECT_EQ(i->second, getLine() + VerifyCount);
        VerifyCount++;
      }
  
      EE->freeMachineCodeForFunction(f);
      EXPECT_TRUE(ReportedDebugFuncs.size() == 0);
    }
  
    void TestMultipleFiles(NativeCodeMap& ReportedDebugFuncs) {
  
      std::string secondFilename("another_file.cpp");
  
      SourceLocations DebugLocations;
      DebugLocations.push_back(std::make_pair(std::string(getFilename()),
                                              getLine()));
      DebugLocations.push_back(std::make_pair(secondFilename, getLine()));
      llvm::Function* f = buildFunction(DebugLocations);
      EXPECT_TRUE(0 != f);
  
      EXPECT_TRUE(0 != EE->getPointerToFunction(f));
      EXPECT_TRUE(1 == ReportedDebugFuncs.size());
      SourceLocations& FunctionInfo = ReportedDebugFuncs.begin()->second;
      EXPECT_TRUE(2 == FunctionInfo.size());
  
      EXPECT_STREQ(FunctionInfo.at(0).first.c_str(), getFilename());
      EXPECT_STREQ(FunctionInfo.at(1).first.c_str(), secondFilename.c_str());
  
      EXPECT_EQ(FunctionInfo.at(0).second, getLine());
      EXPECT_EQ(FunctionInfo.at(1).second, getLine());
  
      EE->freeMachineCodeForFunction(f);
      EXPECT_TRUE(ReportedDebugFuncs.size() == 0);
    }
  };
  
  #endif //JIT_EVENT_LISTENER_TEST_COMMON_H
  