* This file is part of the MindStudio project.
* Copyright (c) 2025 Huawei Technologies Co.,Ltd.
*
* MindStudio is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
* -------------------------------------------------------------------------
*/
#include <gtest/gtest.h>
#include <gtest/internal/gtest-port.h>
#include "utility/cpython.h"
using namespace Utility;
class PythonGlobalInit {
public:
PythonGlobalInit()
{
Py_Initialize();
}
~PythonGlobalInit()
{
Py_Finalize();
}
};
static PythonGlobalInit GlobalPythonInit;
TEST(TestCpython, BeforeInit)
{
Py_Finalize();
EXPECT_FALSE(IsPyInterpRepeInited());
std::string stack;
PythonCallstack(20, stack);
EXPECT_EQ(stack, "\"NA\"");
PythonObject obj;
EXPECT_TRUE(obj.IsBad());
PythonObject obj2 = obj.NewRef();
EXPECT_TRUE(obj2.IsBad());
Py_Initialize();
}
TEST(TestCpython, PythonObjectFromTo)
{
int32_t inputInt = -42;
PythonObject objInt(inputInt);
EXPECT_FALSE(objInt.IsBad());
EXPECT_EQ(objInt.Type(), "int");
EXPECT_EQ(objInt.Cast<int32_t>(), inputInt);
uint32_t inputUint = 56;
PythonObject objUint(inputUint);
EXPECT_FALSE(objUint.IsBad());
EXPECT_EQ(objUint.Type(), "int");
EXPECT_EQ(objUint.Cast<uint32_t>(), inputUint);
double inputDouble = 3.14;
PythonObject objDouble(inputDouble);
EXPECT_FALSE(objDouble.IsBad());
EXPECT_EQ(objDouble.Type(), "float");
EXPECT_DOUBLE_EQ(objDouble.Cast<double>(), inputDouble);
std::string inputStr = "hello";
PythonObject objStr(inputStr);
EXPECT_FALSE(objStr.IsBad());
EXPECT_EQ(objStr.Type(), "str");
EXPECT_EQ(objStr.Cast<std::string>(), inputStr);
const char* inputChar = "world";
PythonObject objStr1(inputChar);
EXPECT_FALSE(objStr1.IsBad());
EXPECT_EQ(objStr1.Type(), "str");
EXPECT_EQ(objStr1.Cast<std::string>(), std::string(inputChar));
bool inputBool = true;
PythonObject objBool(inputBool);
EXPECT_FALSE(objBool.IsBad());
EXPECT_EQ(objBool.Type(), "bool");
EXPECT_TRUE(objBool.Cast<bool>());
std::vector<std::string> inputVectorStr = {"a", "bb", "ccc", "dddd"};
PythonObject listStrObj(inputVectorStr);
EXPECT_FALSE(listStrObj.IsBad());
EXPECT_EQ(listStrObj.Type(), "list");
std::vector<int32_t> inputVectorInt = {1, 2, 11, 123};
PythonObject listIntObj(inputVectorInt);
EXPECT_FALSE(listIntObj.IsBad());
EXPECT_EQ(listIntObj.Type(), "list");
std::map<int32_t, std::string> inputMapIntStr = {{1, "x"}, {2, "y"}, {3, "z"}};
PythonObject dictIntStrObj(inputMapIntStr);
EXPECT_FALSE(dictIntStrObj.IsBad());
EXPECT_EQ(dictIntStrObj.Type(), "dict");
PythonObject obj1(0);
PythonObject obj2 = obj1;
EXPECT_EQ(obj2.Cast<int32_t>(), 0);
}
TEST(TestCpython, PythonObjectImport)
{
PythonObject sys = PythonObject::Import("sys");
EXPECT_FALSE(sys.IsBad());
EXPECT_EQ(sys.Type(), "module");
EXPECT_EQ(static_cast<PyObject*>(sys), PyImport_ImportModule("sys"));
PythonObject sys2 = PythonObject::Import("sys", true);
EXPECT_EQ(static_cast<PyObject*>(sys), PyImport_ImportModule("sys"));
PythonObject name = PythonObject::GetGlobal("__name__");
EXPECT_TRUE(name.IsBad());
PythonObject invalid = PythonObject::Import("invalid", false, false);
EXPECT_TRUE(invalid.IsBad());
}
TEST(TestCpython, PythonObjectGetAttr)
{
PythonObject sys = PythonObject::Import("sys");
PythonObject sysPath = sys.Get("path");
EXPECT_EQ(sysPath.Type(), "list");
EXPECT_EQ(sysPath[PythonObject(0)].Type(), "str");
PythonObject fexit = sys.Get("exit");
EXPECT_EQ(fexit.Type(), "builtin_function_or_method");
PythonObject invalid = sys.Get("invalid");
EXPECT_TRUE(invalid.IsBad());
EXPECT_TRUE(invalid.Get("attr").IsBad());
EXPECT_TRUE(invalid.GetItem(PythonObject(0)).IsBad());
EXPECT_TRUE(sysPath.GetItem(invalid).IsBad());
std::vector<int> inputVector = {1, 2, 3, 100};
PythonObject listObj(inputVector);
PythonObject append = listObj.Get("append");
EXPECT_EQ(append.Type(), "builtin_function_or_method");
EXPECT_TRUE(invalid.Get("invalid", false).IsBad());
}
TEST(TestCpython, PythonObjectType)
{
PythonObject none(Py_None);
EXPECT_EQ(none.Type(), "NoneType");
EXPECT_FALSE(none.IsCallable());
PythonObject pytrue(Py_True);
EXPECT_EQ(pytrue.Type(), "bool");
PythonObject builtins(PyImport_ImportModule("builtins"));
EXPECT_EQ(builtins.Type(), "module");
}
TEST(TestCpython, PythonObjectCall)
{
PythonObject intClass = PythonObject::Import("builtins").Get("int");
EXPECT_TRUE(intClass.IsCallable());
PythonObject intObj = intClass.Call();
EXPECT_EQ(intObj.Type(), "int");
EXPECT_EQ(intObj.Cast<int32_t>(), 0);
PythonObject intObj1(1);
PythonTupleObject args(std::vector<PyObject*>({intObj1}));
args.Size();
PythonObject intObj2 = intClass.Call(args);
EXPECT_EQ(intObj2.Type(), "int");
EXPECT_EQ(intObj2.Cast<int32_t>(), 1);
PythonDictObject kws(std::map<std::string, int32_t>({{"base", 10}}));
PythonObject intObj3 = intClass.Call(args, kws);
EXPECT_EQ(intObj2.Type(), "int");
EXPECT_EQ(intObj2.Cast<int32_t>(), 1);
PythonObject ret = PythonObject::Import("builtins").Call();
EXPECT_TRUE(ret.IsBad());
PythonObject invalid;
EXPECT_TRUE(invalid.Call().IsBad());
EXPECT_TRUE(invalid.Call(args).IsBad());
EXPECT_TRUE(invalid.Call(args, kws).IsBad());
EXPECT_TRUE(intObj1.Call().IsBad());
EXPECT_TRUE(intObj1.Call(args).IsBad());
EXPECT_TRUE(intObj1.Call(args, kws).IsBad());
PythonTupleObject args2(std::vector<PyObject*>({intClass}));
EXPECT_TRUE(intClass(args2).IsBad());
EXPECT_TRUE(intClass(args2, kws).IsBad());
}
TEST(TestCpython, PythonNumberObject)
{
PythonNumberObject o1;
PythonNumberObject o2(PyLong_FromLong(123));
PythonNumberObject o3(321);
PythonNumberObject o4(2.33);
PythonNumberObject o5(PythonObject("1111").Cast<PyObject*>());
EXPECT_FALSE(o1.IsBad());
EXPECT_EQ(o1.Cast<int32_t>(), 0);
EXPECT_EQ(o2.Cast<int32_t>(), 123);
EXPECT_EQ(o2.Type(), "int");
EXPECT_EQ(o3.Type(), "int");
EXPECT_EQ(o4.Type(), "float");
EXPECT_TRUE(o5.IsBad());
EXPECT_TRUE(PythonNumberObject(static_cast<PyObject*>(nullptr)).IsBad());
}
TEST(TestCpython, PythonStringObject)
{
PythonStringObject o1;
PythonStringObject o2(PyUnicode_FromString("hello"));
PythonStringObject o3("OK");
PythonStringObject o4(std::string("banana"));
PythonStringObject o5(PythonObject(1));
EXPECT_EQ(o1.Cast<std::string>(), "");
EXPECT_EQ(o2.Cast<std::string>(), "hello");
EXPECT_EQ(o3.Cast<std::string>(), "OK");
EXPECT_EQ(o4.Cast<std::string>(), "banana");
EXPECT_TRUE(o5.IsBad());
EXPECT_TRUE(PythonStringObject(static_cast<PyObject*>(nullptr)).IsBad());
}
TEST(TestCpython, PythonBoolObject)
{
PythonBoolObject o1;
PythonBoolObject o2(Py_True);
PythonBoolObject o3(Py_False);
PythonBoolObject o4(true);
EXPECT_EQ(o1.Cast<bool>(), false);
EXPECT_EQ(o2.Cast<bool>(), true);
EXPECT_EQ(o3.Cast<bool>(), false);
EXPECT_EQ(o4.Cast<bool>(), true);
}
TEST(TestCpython, PythonListObject)
{
PythonListObject empty_list(5);
PythonListObject sys_path(static_cast<PyObject*>(PythonObject::Import("sys").Get("path")));
PythonListObject list1(std::vector<int32_t>({1, 3, 5, 7}));
PythonListObject list2(std::vector<std::vector<int32_t>>({{1, 3, 5, 7}, {2, 4, 6}}));
PythonListObject list3;
EXPECT_EQ(empty_list.Size(), 5);
EXPECT_FALSE(sys_path.IsBad());
EXPECT_TRUE(sys_path.Size() > 0);
EXPECT_EQ(sys_path.GetItem<PythonObject>(0).Type(), "str");
EXPECT_EQ(list1.Size(), 4);
EXPECT_EQ(list1.GetItem<int32_t>(1), 3);
EXPECT_EQ(list1.GetItem<std::string>(3), "7");
EXPECT_EQ(list2.Size(), 2);
EXPECT_EQ(list2.GetItem<PythonObject>(0).Type(), "list");
EXPECT_EQ(list2.GetItem<std::string>(1), "[2, 4, 6]");
EXPECT_EQ(list3.Size(), 0);
list3.Append(1);
EXPECT_EQ(list3.Size(), 1);
list3.Append("2").Append(true);
EXPECT_EQ(list3.Size(), 3);
EXPECT_EQ(list3.GetItem<std::string>(1), "2");
list3.SetItem(1, empty_list);
EXPECT_EQ(list3.Size(), 3);
EXPECT_EQ(list3.GetItem<PyObject*>(1), static_cast<PyObject*>(empty_list));
list3.Insert(0, sys_path);
EXPECT_EQ(list3.Size(), 4);
EXPECT_EQ(list3.GetItem<PyObject*>(0), static_cast<PyObject*>(sys_path));
PythonTupleObject tuple = list3.ToTuple();
EXPECT_FALSE(tuple.IsBad());
}
TEST(TestCpython, TestGetPyFuncInfoInputNullFrame)
{
std::string info = "original_info";
std::string hash = "original_hash";
GetPyFuncInfo(nullptr, info, hash);
EXPECT_EQ(info, "original_info");
EXPECT_EQ(hash, "original_hash");
}
TEST(TestCpython, NotIgnoreCFunc)
{
EXPECT_FALSE(IsIgnoreCFunc("anyfile.py:some_function"));
EXPECT_FALSE(IsIgnoreCFunc("contextlib.py:__init__"));
EXPECT_FALSE(IsIgnoreCFunc("otherfile.py:__exit__"));
EXPECT_FALSE(IsIgnoreCFunc("/path/to/otherfile.py:__exit__"));
}
TEST(TestCpython, TrueMatch)
{
EXPECT_TRUE(IsIgnoreCFunc("contextlib.py:__exit__"));
EXPECT_TRUE(IsIgnoreCFunc("dir/contextlib.py:__exit__"));
EXPECT_TRUE(IsIgnoreCFunc("/full/path/to/contextlib.py:__exit__"));
}
TEST(TestCpython, PyProfileFnNullptrTest)
{
PyFrameObject* frame = nullptr;
int ret = pyProfileFn(nullptr, frame, PyTrace_CALL, nullptr);
ASSERT_EQ(ret, 0);
}
TEST(TestCpython, GetTraceCallStackTest)
{
std::string type = "test";
uint64_t time = 123456;
GetTraceCallStack(type, time);
}