//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      Tests/Unit/PyBinding/PyInfo.cpp
//!
//! @homepage  http://www.bornagainproject.org
//! @license   GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2018
//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
//
//  ************************************************************************************************

#include "BABuild.h"
#include "BAVersion.h"
#include "Base/Py/PyCore.h"
#include "Base/Py/PyUtil.h"
#include "Tests/GTestWrapper/google_test.h"
#include <iostream>

//! Accessing to the information about Python used during the build, content of path.sys variable.

TEST(PyInfo, SysPath)
{
    // Python build info
    std::cout << "pythonExecutable(): " << BABuild::pythonExecutable() << std::endl;
    std::cout << "pythonInterpreterID(): " << BABuild::pythonInterpreterID() << std::endl;
    std::cout << "pythonVersionString(): " << BABuild::pythonVersionString() << std::endl;
    std::cout << "pythonLibraries(): " << BABuild::pythonLibraries() << std::endl;
    std::cout << "pythonIncludeDirs(): " << BABuild::pythonIncludeDirs() << std::endl;
    std::cout << "pythonSiteLib(): " << BABuild::pythonSiteLib() << std::endl;
    std::cout << "numpyIncludeDir(): " << BABuild::numpyIncludeDir() << std::endl;
    std::cout << "numpyVersionString(): " << BABuild::numpyVersionString() << std::endl;

    // BornAgain build
    std::cout << "buildLibDir(): " << BABuild::buildLibDir() << std::endl;

    // Runtime info
    auto content = Base::Python::pythonRuntimeInfo();

    EXPECT_TRUE(!content.empty());
}

//! Comparing results of GetVersionNumber() function obtained in "embedded" and "native C++" ways.

TEST(PyInfo, FunctionCall)
{
    PyObject* pmod = Base::Python::import_bornagain({BABuild::buildLibDir()});
    EXPECT_TRUE(pmod);

    PyObject* pfun = PyObject_GetAttrString(pmod, "GetVersionNumber");
    Py_DecRef(pmod);
    if (!pfun)
        throw std::runtime_error("Cannot get a function");

    PyObject* pargs = Py_BuildValue("()");
    if (!pargs)
        throw std::runtime_error("Cannot build arguments list");

    PyObject* result = PyObject_Call(pfun, pargs, nullptr);
    Py_DecRef(pfun);
    Py_DecRef(pargs);
    if (!result)
        throw std::runtime_error("Error while calling function");

    auto str = Base::Python::toString(result);
    Py_DecRef(result);

    Py_Finalize();

    std::cout << "BornAgain version via Python: '" << str << "'\n";
    std::cout << "BornAgain version from Core:  '" << BornAgain::GetVersionNumber() << "'\n";
    if (str != BornAgain::GetVersionNumber()) {
        std::cout << "Version numbers disagree, test will fail.\n"
                  << "Possible reasons:\n"
                  << "- Python bindings not regenerated\n"
                  << "- Python module load from wrong location\n";
        EXPECT_TRUE(false);
    }
    EXPECT_TRUE(true);
}
