Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion core/base/src/TPluginManager.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,8 @@ void TPluginManager::LoadHandlersFromPluginDirs(const char *base)
}
if (!skip) {
if (sbase != "") {
const char *p = gSystem->PrependPathName(d, sbase);
TString temp = sbase;
const char *p = gSystem->PrependPathName(d, temp);
LoadHandlerMacros(p);
} else {
void *dirp = gSystem->OpenDirectory(d);
Expand Down
1 change: 0 additions & 1 deletion core/base/src/TSystem.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -2619,7 +2619,6 @@ static void R__WriteDependencyFile(const TString & build_loc, const TString &dep
} else {
needToUnlinkTempFile = true;
devnullfile = depfilename + ".stderr.tmp";
gSystem->PrependPathName(build_loc, devnullfile);
}
}
#endif
Expand Down
2 changes: 2 additions & 0 deletions core/base/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,5 @@ configure_file(Foo.C Foo.C COPYONLY)
ROOT_ADD_GTEST(IncludePathTest IncludePathTest.cxx LIBRARIES Core)

ROOT_ADD_GTEST(UUIDTest UUIDTest.cxx LIBRARIES Core)

ROOT_ADD_GTEST(CorePluginManagerTests TPluginManagerTests.cxx LIBRARIES Core)
41 changes: 40 additions & 1 deletion core/base/test/IncludePathTest.cxx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "gtest/gtest.h"
#include "TSystem.h"
#include "TUUID.h"

#include <string>

Expand All @@ -14,15 +15,53 @@ TEST(TSystem, IncludePath)
"-I \"C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\MSVC\\14.38.33130\\include\"");
#endif

#ifdef WIN32
struct ComspecGuard {
TString fOriginal;
TString fAlias;

~ComspecGuard()
{
gSystem->Setenv("COMSPEC", fOriginal);
gSystem->Unlink(fAlias);
}
};

const char *comspec = gSystem->Getenv("COMSPEC");
ASSERT_NE(comspec, nullptr);
TString cmdPath = comspec;
if (cmdPath.BeginsWith("\"") && cmdPath.EndsWith("\"")) {
cmdPath.Remove(0, 1);
cmdPath.Chop();
}
TString normalizedCmdPath = cmdPath;
normalizedCmdPath.ToLower();
ASSERT_TRUE(normalizedCmdPath.EndsWith("cmd.exe")) << "This regression test needs cmd.exe as the process shell";

TUUID uuid;
TString alias = TString::Format("root_test_shell_%s.exe", uuid.AsString());
gSystem->PrependPathName(gSystem->TempDirectory(), alias);
ComspecGuard comspecGuard{comspec, alias};
ASSERT_EQ(0, gSystem->CopyFile(cmdPath, alias));

// Use a copied cmd.exe under a different name to exercise the temporary
// stderr-file path without changing the shell used to execute commands.
gSystem->Setenv("COMSPEC", alias);
ASSERT_EQ(0, gSystem->Exec("exit 0"));
#endif

testing::internal::CaptureStderr();
gSystem->CompileMacro("Foo.C", "f");
const auto compileResult = gSystem->CompileMacro("Foo.C", "f");
std::cerr.flush();
std::string errors = testing::internal::GetCapturedStderr();

EXPECT_TRUE(compileResult);
gSystem->Unload("Foo_C");
gSystem->CleanCompiledMacros();
#ifdef WIN32
EXPECT_TRUE((errors.find("cl : Command line warning D9002 : ignoring unknown option ") == std::string::npos));
// This will need to be updated once we no longer rely on rmkdepend.
EXPECT_EQ(errors.find("Failed to run rmkdepend"), std::string::npos);
gSystem->Exec("del Foo_C*");
#else
EXPECT_TRUE((errors.find("c++: error: unrecognized command line option ") == std::string::npos));
Expand Down
98 changes: 98 additions & 0 deletions core/base/test/TPluginManagerTests.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#include "gtest/gtest.h"

#include "TEnv.h"
#include "TPluginManager.h"
#include "TROOT.h"
#include "TString.h"
#include "TSystem.h"
#include "TUUID.h"

#include <fstream>
#include <vector>

namespace {

class TPluginManagerTest : public testing::Test {
protected:
TEnv fEnv;
TPluginManager fPluginManager;
TEnv *fSavedEnv = nullptr;
TPluginManager *fSavedPluginManager = nullptr;
std::vector<TString> fPaths;
TString fBase;

void SetUp() override
{
// Initialize ROOT before replacing the globals used by interpreted plugin macros.
(void)gROOT->GetPluginManager();
fSavedEnv = gEnv;
fSavedPluginManager = gPluginMgr;
gEnv = &fEnv;
gPluginMgr = &fPluginManager;

TUUID uuid;
TString id = uuid.AsString();
id.ReplaceAll("-", "_");
fBase = "TestPluginBase_" + id;
TString rootDir = "test_plugins_" + id;
gSystem->PrependPathName(gSystem->TempDirectory(), rootDir);
ASSERT_EQ(0, gSystem->mkdir(rootDir));
fPaths.push_back(rootDir);

TString pluginPath;
for (int i = 0; i < 3; ++i) {
TString dir = TString::Format("dir%d", i);
gSystem->PrependPathName(rootDir, dir);
ASSERT_EQ(0, gSystem->mkdir(dir));
fPaths.push_back(dir);

TString baseDir = fBase;
gSystem->PrependPathName(dir, baseDir);
ASSERT_EQ(0, gSystem->mkdir(baseDir));
fPaths.push_back(baseDir);

TString macroName = TString::Format("P010_TestPlugin%d_", i) + id;
TString macroFile = macroName + ".C";
gSystem->PrependPathName(baseDir, macroFile);
fPaths.push_back(macroFile);
std::ofstream macro(macroFile.Data());
ASSERT_TRUE(macro.is_open());
macro << "#include \"TPluginManager.h\"\n"
<< "void " << macroName << "()\n{\n"
<< " gPluginMgr->AddHandler(\"" << fBase << "\", \"^test" << i << ":\", \"TestPlugin" << i
<< "\", \"TestPluginLib\", \"TestPlugin" << i << "()\");\n}\n";
macro.close();
ASSERT_TRUE(macro.good());

if (i != 0) {
#ifdef R__WIN32
pluginPath += ";";
#else
pluginPath += ":";
#endif
}
pluginPath += dir;
}
fEnv.SetValue("Root.PluginPath", pluginPath);
}

void TearDown() override
{
gPluginMgr = fSavedPluginManager;
gEnv = fSavedEnv;
for (auto it = fPaths.rbegin(); it != fPaths.rend(); ++it)
EXPECT_EQ(0, gSystem->Unlink(*it)) << *it;
}
};

// Regression test for https://github.com/root-project/root/issues/23536.
TEST_F(TPluginManagerTest, MultiDirectoryPluginPath)
{
for (int i = 0; i < 3; ++i) {
auto *handler = fPluginManager.FindHandler(fBase, TString::Format("test%d:example", i));
ASSERT_NE(handler, nullptr) << "Plugin directory " << i;
EXPECT_STREQ(handler->GetClass(), TString::Format("TestPlugin%d", i).Data());
}
}

} // namespace
6 changes: 5 additions & 1 deletion core/metacling/src/TCling.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -778,8 +778,12 @@ int TCling_GenerateDictionary(const std::vector<std::string> &classes,
while (dirbase.Length() && dirbase != "."
&& dirbase != "include" && dirbase != "inc"
&& dirbase != "prec_stl") {
TString parent = gSystem->GetDirName(dir);
if (parent == dir)
break;
gSystem->PrependPathName(dirbase, header);
dir = gSystem->GetDirName(dir);
dir = parent;
dirbase = gSystem->BaseName(dir);
}
fileContent += TString("#include \"") + header + "\"\n";
}
Expand Down
19 changes: 19 additions & 0 deletions core/metacling/test/TClingTests.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "TInterpreter.h"
#include "TROOT.h"
#include "TSystem.h"
#include "TString.h"

#include "gmock/gmock.h"

Expand Down Expand Up @@ -63,6 +64,24 @@ TEST_F(TClingTests, GenerateDictionaryRegression)
EXPECT_TRUE(gInterpreter->GenerateDictionary("std::set<int>", ""));
EXPECT_TRUE(gInterpreter->GenerateDictionary("std::set<int>", "set"));

auto *sequentialExecutor = TClass::GetClass("ROOT::TSequentialExecutor");
ASSERT_NE(sequentialExecutor, nullptr);
TString headerDir = gSystem->GetDirName(sequentialExecutor->GetDeclFileName());
ASSERT_STREQ(gSystem->BaseName(headerDir), "ROOT");

ASSERT_TRUE(gInterpreter->Declare(
"#include <string>\n"
"#include <vector>\n"
"int TCling_GenerateDictionary(const std::vector<std::string>&, const std::vector<std::string>&,\n"
" const std::vector<std::string>&, const std::vector<std::string>&);"));
TString includePath = gSystem->GetIncludePath();
const auto result =
gInterpreter->ProcessLine("std::vector<std::string> classes{\"std::list<ROOT::TSequentialExecutor*>\"};"
"std::vector<std::string> emptyvector, unknown{\"ROOT::TSequentialExecutor\"};"
"return TCling_GenerateDictionary(classes, emptyvector, emptyvector, unknown);");
gSystem->SetIncludePath(includePath);
EXPECT_EQ(result, 0);

// FIXME: This makes the linkdef parser go in an infinite loop.
//EXPECT_TRUE(gInterpreter->GenerateDictionary("std::vector<std::array<int, 5>>", ""));
}
Expand Down
Loading