#include "catch.hpp"
#include "language_packages.h"
#if BUILD_PYTHON_LANGUAGE_PACKAGE
# include <memory>
# include <fstream>
# include "FileSystem.h"
# include "IndexerCommandCustom.h"
# include "PersistentStorage.h"
# include "ResourcePaths.h"
# include "SqliteIndexStorage.h"
# include "TaskExecuteCustomCommands.h"
# include "TestStorage.h"
# include "utilityApp.h"
namespace
{
void deleteAllContents(const FilePath& tempPath)
{
if (tempPath.recheckExists())
{
for (const FilePath& path: FileSystem::getFilePathsFromDirectory(tempPath))
{
FileSystem::remove(path);
}
}
}
std::shared_ptr<TestStorage> parseCode(std::string code)
{
const FilePath rootPath = FilePath(L"data/PythonIndexerTestSuite/temp/").makeAbsolute();
if (!rootPath.exists())
{
FileSystem::createDirectory(rootPath);
}
deleteAllContents(rootPath);
const FilePath sourceFilePath = rootPath.getConcatenated(L"test.py");
const FilePath tempDbPath = rootPath.getConcatenated(L"temp.srctrldb");
{
std::ofstream codeFile;
codeFile.open(sourceFilePath.str());
codeFile << code;
codeFile.close();
}
{
const std::set<FilePath> indexedPaths = {rootPath};
const std::set<FilePathFilter> excludeFilters;
const std::set<FilePathFilter> includeFilters;
const FilePath workingDirectory(L".");
std::vector<std::wstring> args;
args.push_back(L"index");
args.push_back(L"--source-file-path");
args.push_back(L"%{SOURCE_FILE_PATH}");
args.push_back(L"--database-file-path");
args.push_back(L"%{DATABASE_FILE_PATH}");
args.push_back(L"--shallow");
std::shared_ptr<IndexerCommandCustom> indexerCommand = std::make_shared<IndexerCommandCustom>(
INDEXER_COMMAND_PYTHON,
FilePath("../app")
.getConcatenated(ResourcePaths::getPythonIndexerFilePath())
.makeAbsolute()
.makeCanonical()
.wstr(),
args,
rootPath,
tempDbPath,
std::to_wstring(SqliteIndexStorage::getStorageVersion()),
sourceFilePath,
true);
const utility::ProcessOutput out = utility::executeProcess(
indexerCommand->getCommand(), indexerCommand->getArguments(), rootPath, false, -1, true);
if (!out.error.empty())
{
FAIL(
"Error occurred while running the indexer: \"" + utility::encodeToUtf8(out.error) +
"\". Process output was: \"" + utility::encodeToUtf8(out.output) + "\"");
}
REQUIRE(out.exitCode == 0);
}
std::shared_ptr<TestStorage> testStorage;
{
std::shared_ptr<PersistentStorage> persistentStorage = std::make_shared<PersistentStorage>(
tempDbPath, FilePath());
persistentStorage->setup();
persistentStorage->buildCaches();
TaskExecuteCustomCommands::runPythonPostProcessing(*(persistentStorage.get()));
testStorage = TestStorage::create(persistentStorage);
}
deleteAllContents(rootPath);
return testStorage;
}
}
TEST_CASE("python post processing regards class name in call context when adding ambiguous edges")
{
std::shared_ptr<TestStorage> storage = parseCode(
"class A:\n"
" def __init__(self):\n"
" pass\n"
"\n"
"class A1(A):\n"
" def __init__(self):\n"
" A.__init__()\n"
"\n"
"class B:\n"
" def __init__(self):\n"
" pass\n");
REQUIRE(storage->calls.size() == 1);
REQUIRE(utility::containsElement<std::wstring>(
storage->calls, L"test.A1.__init__ -> test.A.__init__"));
REQUIRE(!utility::containsElement<std::wstring>(
storage->calls, L"test.A1.__init__ -> test.A1.__init__"));
REQUIRE(!utility::containsElement<std::wstring>(
storage->calls, L"test.A1.__init__ -> test.B.__init__"));
}
TEST_CASE("python post processing regards super() in call context when adding ambiguous edges")
{
std::shared_ptr<TestStorage> storage = parseCode(
"class A:\n"
" def __init__(self):\n"
" pass\n"
"\n"
"class A1(A):\n"
" def __init__(self):\n"
" super().__init__()\n"
"\n"
"class B:\n"
" def __init__(self):\n"
" pass\n");
REQUIRE(storage->calls.size() == 2);
REQUIRE(utility::containsElement<std::wstring>(
storage->calls, L"test.A1.__init__ -> test.A.__init__"));
REQUIRE(!utility::containsElement<std::wstring>(
storage->calls, L"test.A1.__init__ -> test.A1.__init__"));
REQUIRE(!utility::containsElement<std::wstring>(
storage->calls, L"test.A1.__init__ -> test.B.__init__"));
}
#endif