//
// Created by pgess on 26/03/2020.
//

#include "xreatemanager.h"
#include "pass/compilepass.h"
#include "llvmlayer.h"
#include "supplemental/basics.h"

#include "gtest/gtest.h"

using namespace xreate;

TEST(Problems, MinMax1){
  struct Pair {intmax_t x; intmax_t y;};
  typedef Pair (*FnPair)();

  FILE* code = fopen("scripts/containers/minmax.xreate", "r");
  assert(code != nullptr);

  auto man = details::tier1::XreateManager::prepare(code);
  LLVMLayer* llvm = man->llvm;
  man->analyse();

  std::unique_ptr<CompilePass> compiler(new compilation::CompilePassCustomDecorators<>(man));
  compiler->prepare();
  llvm::Function* fnMinMax1Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax1"))->compile();
  llvm::Function* fnMinMax2Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax2"))->compile();
  llvm::Function* fnMinMax3Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax3"))->compile();
  llvm::Function* fnMinMax4Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax4"))->compile();
  llvm::Function* fnMinMax5Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax5"))->compile();
  llvm::Function* fnMinMax6Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax6"))->compile();
  llvm::Function* fnMinMax7Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax7"))->compile();
  llvm::Function* fnMinMax8Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax8"))->compile();
  llvm::Function* fnMinMax9Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax9"))->compile();
  llvm::Function* fnMinMax10Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax10"))->compile();
  llvm::Function* fnMinMax11Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax11"))->compile();
  llvm::Function* fnMinMax12Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax12"))->compile();
  llvm::Function* fnMinMax13Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax13"))->compile();
  llvm::Function* fnMinMax14Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax14"))->compile();
  llvm->print();

  llvm->initJit();
  {
    FnPair fnMinxMax1 = (FnPair) llvm->getFunctionPointer(fnMinMax1Raw);
    Pair resultMinMax1 = fnMinxMax1();
    ASSERT_EQ(3, resultMinMax1.x);
    ASSERT_EQ(37, resultMinMax1.y);
  }

  {
    FnNoArgs fnMinMax2 = (FnNoArgs) llvm->getFunctionPointer(fnMinMax2Raw);
    intmax_t resultMinMax2 = fnMinMax2();
    ASSERT_EQ(10, resultMinMax2);
  }

  {
    FnNoArgs fnMinMax3 = (FnNoArgs) llvm->getFunctionPointer(fnMinMax3Raw);
    intmax_t resultMinMax3 = fnMinMax3();
    ASSERT_EQ(146, resultMinMax3);
  }

  {
    FnNoArgs fnMinMax4 = (FnNoArgs) llvm->getFunctionPointer(fnMinMax4Raw);
    intmax_t resultMinMax4 = fnMinMax4();
    ASSERT_EQ(6, resultMinMax4);
  }

  {
    FnPair fnMinMax5 = (FnPair) llvm->getFunctionPointer(fnMinMax5Raw);
    Pair resultMinMax5 = fnMinMax5();
    ASSERT_EQ(4, resultMinMax5.x);
    ASSERT_EQ(11, resultMinMax5.y);
  }

  {
    FnPair fnMinMax6 = (FnPair) llvm->getFunctionPointer(fnMinMax6Raw);
    Pair resultMinMax6 = fnMinMax6();
    ASSERT_EQ(2, resultMinMax6.x);
    ASSERT_EQ(8, resultMinMax6.y);
  }

  {
    FnPair fnMinMax7 = (FnPair) llvm->getFunctionPointer(fnMinMax7Raw);
    Pair resultMinMax7 = fnMinMax7();
    ASSERT_EQ(1, resultMinMax7.x);
    ASSERT_EQ(3, resultMinMax7.y);
  }

  {
    FnPair fnMinMax8 = (FnPair) llvm->getFunctionPointer(fnMinMax8Raw);
    Pair resultMinMax8 = fnMinMax8();
    ASSERT_EQ(2, resultMinMax8.x);
    ASSERT_EQ(3, resultMinMax8.y);
  }

  {
    FnPair fnMinMax9 = (FnPair) llvm->getFunctionPointer(fnMinMax9Raw);
    Pair resultMinMax9 = fnMinMax9();
    ASSERT_EQ(1, resultMinMax9.x);
    ASSERT_EQ(8, resultMinMax9.y);
  }

  {
    FnNoArgs fnMinMax10 = (FnNoArgs ) llvm->getFunctionPointer(fnMinMax10Raw);
    intmax_t resultMinMax10 = fnMinMax10();
    ASSERT_EQ(1, resultMinMax10);
  }

  {
    FnNoArgs fnMinMax11 = (FnNoArgs ) llvm->getFunctionPointer(fnMinMax11Raw);
    intmax_t resultMinMax11 = fnMinMax11();
    ASSERT_EQ(8, resultMinMax11);
  }

  {
    FnNoArgs fnMinMax12 = (FnNoArgs ) llvm->getFunctionPointer(fnMinMax12Raw);
    intmax_t resultMinMax12 = fnMinMax12();
    ASSERT_EQ(2, resultMinMax12);
  }

  {
    FnNoArgs fnMinMax13 = (FnNoArgs ) llvm->getFunctionPointer(fnMinMax13Raw);
    intmax_t resultMinMax13 = fnMinMax13();
    ASSERT_EQ(3, resultMinMax13);
  }

  {
    FnPair fnMinMax14 = (FnPair) llvm->getFunctionPointer(fnMinMax14Raw);
    Pair resultMinMax14 = fnMinMax14();
    ASSERT_EQ(2, resultMinMax14.x);
    ASSERT_EQ(3, resultMinMax14.y);
  }
}