-
Notifications
You must be signed in to change notification settings - Fork 1
[Linux] Add AutoStart implementation and tests #40
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,9 @@ | ||
| add_executable(url_opener_test url_opener_test.cpp) | ||
| target_link_libraries(url_opener_test PRIVATE nativeapi) | ||
| add_test(NAME url_opener_test COMMAND url_opener_test) | ||
|
|
||
| if(CMAKE_SYSTEM_NAME STREQUAL "Linux") | ||
| add_executable(autostart_test autostart_test.cpp) | ||
| target_link_libraries(autostart_test PRIVATE nativeapi) | ||
| add_test(NAME autostart_test COMMAND autostart_test) | ||
| endif() |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,350 @@ | ||||||||||||||||||||||||||||||||||||
| #include <sys/stat.h> | ||||||||||||||||||||||||||||||||||||
| #include <unistd.h> | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| #include <cstdlib> | ||||||||||||||||||||||||||||||||||||
| #include <fstream> | ||||||||||||||||||||||||||||||||||||
| #include <iostream> | ||||||||||||||||||||||||||||||||||||
| #include <sstream> | ||||||||||||||||||||||||||||||||||||
| #include <string> | ||||||||||||||||||||||||||||||||||||
| #include <vector> | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| #include "../src/autostart.h" | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| namespace { | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // Return a temporary XDG_CONFIG_HOME directory unique to this test run | ||||||||||||||||||||||||||||||||||||
| static std::string MakeTempConfigDir() { | ||||||||||||||||||||||||||||||||||||
| const char* tmpbase = std::getenv("TMPDIR"); | ||||||||||||||||||||||||||||||||||||
| if (!tmpbase || !*tmpbase) | ||||||||||||||||||||||||||||||||||||
| tmpbase = "/tmp"; | ||||||||||||||||||||||||||||||||||||
| std::string tmpl = std::string(tmpbase) + "/autostart_test_XXXXXX"; | ||||||||||||||||||||||||||||||||||||
| const char* dir = mkdtemp(tmpl.data()); | ||||||||||||||||||||||||||||||||||||
| if (!dir) { | ||||||||||||||||||||||||||||||||||||
| std::cerr << "mkdtemp failed" << std::endl; | ||||||||||||||||||||||||||||||||||||
| return std::string(); | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
| return std::string(dir); | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // Remove a directory tree (non-recursively safe: only removes known files). | ||||||||||||||||||||||||||||||||||||
| // Failures are intentionally ignored since this is test cleanup only. | ||||||||||||||||||||||||||||||||||||
| static void RemoveDesktopFile(const std::string& config_dir, const std::string& id) { | ||||||||||||||||||||||||||||||||||||
| std::string path = config_dir + "/autostart/" + id + ".desktop"; | ||||||||||||||||||||||||||||||||||||
| unlink(path.c_str()); | ||||||||||||||||||||||||||||||||||||
| rmdir((config_dir + "/autostart").c_str()); | ||||||||||||||||||||||||||||||||||||
| rmdir(config_dir.c_str()); | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // Read file contents into a string | ||||||||||||||||||||||||||||||||||||
| static std::string ReadFile(const std::string& path) { | ||||||||||||||||||||||||||||||||||||
| std::ifstream ifs(path); | ||||||||||||||||||||||||||||||||||||
| if (!ifs.is_open()) | ||||||||||||||||||||||||||||||||||||
| return std::string(); | ||||||||||||||||||||||||||||||||||||
| std::ostringstream oss; | ||||||||||||||||||||||||||||||||||||
| oss << ifs.rdbuf(); | ||||||||||||||||||||||||||||||||||||
| return oss.str(); | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // Scoped XDG_CONFIG_HOME override to isolate tests | ||||||||||||||||||||||||||||||||||||
| struct ScopedConfigHome { | ||||||||||||||||||||||||||||||||||||
| std::string dir; | ||||||||||||||||||||||||||||||||||||
| std::string prev; | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| explicit ScopedConfigHome(const std::string& d) : dir(d) { | ||||||||||||||||||||||||||||||||||||
| const char* p = std::getenv("XDG_CONFIG_HOME"); | ||||||||||||||||||||||||||||||||||||
| prev = p ? std::string(p) : std::string(); | ||||||||||||||||||||||||||||||||||||
| setenv("XDG_CONFIG_HOME", dir.c_str(), 1); | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| ~ScopedConfigHome() { | ||||||||||||||||||||||||||||||||||||
| if (prev.empty()) { | ||||||||||||||||||||||||||||||||||||
| unsetenv("XDG_CONFIG_HOME"); | ||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||
| setenv("XDG_CONFIG_HOME", prev.c_str(), 1); | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| int RunTests() { | ||||||||||||||||||||||||||||||||||||
| using namespace nativeapi; | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // IsSupported returns true on Linux | ||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||
| if (!AutoStart::IsSupported()) { | ||||||||||||||||||||||||||||||||||||
| std::cerr << "AutoStart::IsSupported() should return true on Linux." << std::endl; | ||||||||||||||||||||||||||||||||||||
| return 1; | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // Constructors and getters | ||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||
| const std::string tmpDir = MakeTempConfigDir(); | ||||||||||||||||||||||||||||||||||||
| if (tmpDir.empty()) | ||||||||||||||||||||||||||||||||||||
| return 1; | ||||||||||||||||||||||||||||||||||||
| ScopedConfigHome scope(tmpDir); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| AutoStart as("com.example.testapp", "TestApp"); | ||||||||||||||||||||||||||||||||||||
| if (as.GetId() != "com.example.testapp") { | ||||||||||||||||||||||||||||||||||||
| std::cerr << "GetId() should return 'com.example.testapp', got '" << as.GetId() << "'" | ||||||||||||||||||||||||||||||||||||
| << std::endl; | ||||||||||||||||||||||||||||||||||||
| rmdir(tmpDir.c_str()); | ||||||||||||||||||||||||||||||||||||
| return 1; | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
| if (as.GetDisplayName() != "TestApp") { | ||||||||||||||||||||||||||||||||||||
| std::cerr << "GetDisplayName() should return 'TestApp', got '" << as.GetDisplayName() << "'" | ||||||||||||||||||||||||||||||||||||
| << std::endl; | ||||||||||||||||||||||||||||||||||||
| rmdir(tmpDir.c_str()); | ||||||||||||||||||||||||||||||||||||
| return 1; | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
| rmdir(tmpDir.c_str()); | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // SetDisplayName | ||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||
| const std::string tmpDir = MakeTempConfigDir(); | ||||||||||||||||||||||||||||||||||||
| if (tmpDir.empty()) | ||||||||||||||||||||||||||||||||||||
| return 1; | ||||||||||||||||||||||||||||||||||||
| ScopedConfigHome scope(tmpDir); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| AutoStart as("com.example.testapp", "OriginalName"); | ||||||||||||||||||||||||||||||||||||
| if (!as.SetDisplayName("NewName")) { | ||||||||||||||||||||||||||||||||||||
| std::cerr << "SetDisplayName() should return true." << std::endl; | ||||||||||||||||||||||||||||||||||||
| rmdir(tmpDir.c_str()); | ||||||||||||||||||||||||||||||||||||
| return 1; | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
| if (as.GetDisplayName() != "NewName") { | ||||||||||||||||||||||||||||||||||||
| std::cerr << "GetDisplayName() after SetDisplayName() should return 'NewName', got '" | ||||||||||||||||||||||||||||||||||||
| << as.GetDisplayName() << "'" << std::endl; | ||||||||||||||||||||||||||||||||||||
| rmdir(tmpDir.c_str()); | ||||||||||||||||||||||||||||||||||||
| return 1; | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
| rmdir(tmpDir.c_str()); | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // SetProgram / GetExecutablePath / GetArguments | ||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||
| const std::string tmpDir = MakeTempConfigDir(); | ||||||||||||||||||||||||||||||||||||
| if (tmpDir.empty()) | ||||||||||||||||||||||||||||||||||||
| return 1; | ||||||||||||||||||||||||||||||||||||
| ScopedConfigHome scope(tmpDir); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| AutoStart as("com.example.testapp", "TestApp"); | ||||||||||||||||||||||||||||||||||||
| std::vector<std::string> args = {"--minimized", "--tray"}; | ||||||||||||||||||||||||||||||||||||
| if (!as.SetProgram("/usr/bin/testapp", args)) { | ||||||||||||||||||||||||||||||||||||
| std::cerr << "SetProgram() should return true." << std::endl; | ||||||||||||||||||||||||||||||||||||
| rmdir(tmpDir.c_str()); | ||||||||||||||||||||||||||||||||||||
| return 1; | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
| if (as.GetExecutablePath() != "/usr/bin/testapp") { | ||||||||||||||||||||||||||||||||||||
| std::cerr << "GetExecutablePath() should return '/usr/bin/testapp', got '" | ||||||||||||||||||||||||||||||||||||
| << as.GetExecutablePath() << "'" << std::endl; | ||||||||||||||||||||||||||||||||||||
| rmdir(tmpDir.c_str()); | ||||||||||||||||||||||||||||||||||||
| return 1; | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
| auto gotArgs = as.GetArguments(); | ||||||||||||||||||||||||||||||||||||
| if (gotArgs != args) { | ||||||||||||||||||||||||||||||||||||
| std::cerr << "GetArguments() returned unexpected values." << std::endl; | ||||||||||||||||||||||||||||||||||||
| rmdir(tmpDir.c_str()); | ||||||||||||||||||||||||||||||||||||
| return 1; | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
| rmdir(tmpDir.c_str()); | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // Enable creates .desktop file and IsEnabled returns true | ||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||
| const std::string tmpDir = MakeTempConfigDir(); | ||||||||||||||||||||||||||||||||||||
| if (tmpDir.empty()) | ||||||||||||||||||||||||||||||||||||
| return 1; | ||||||||||||||||||||||||||||||||||||
| ScopedConfigHome scope(tmpDir); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| const std::string testId = "com.example.autostarttest"; | ||||||||||||||||||||||||||||||||||||
| AutoStart as(testId, "AutoStartTest"); | ||||||||||||||||||||||||||||||||||||
| as.SetProgram("/usr/bin/testapp", {}); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| if (!as.Enable()) { | ||||||||||||||||||||||||||||||||||||
| std::cerr << "Enable() should return true." << std::endl; | ||||||||||||||||||||||||||||||||||||
| RemoveDesktopFile(tmpDir, testId); | ||||||||||||||||||||||||||||||||||||
| return 1; | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| if (!as.IsEnabled()) { | ||||||||||||||||||||||||||||||||||||
| std::cerr << "IsEnabled() should return true after Enable()." << std::endl; | ||||||||||||||||||||||||||||||||||||
| RemoveDesktopFile(tmpDir, testId); | ||||||||||||||||||||||||||||||||||||
| return 1; | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| RemoveDesktopFile(tmpDir, testId); | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // Disable removes .desktop file and IsEnabled returns false | ||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||
| const std::string tmpDir = MakeTempConfigDir(); | ||||||||||||||||||||||||||||||||||||
| if (tmpDir.empty()) | ||||||||||||||||||||||||||||||||||||
| return 1; | ||||||||||||||||||||||||||||||||||||
| ScopedConfigHome scope(tmpDir); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| const std::string testId = "com.example.autostarttest"; | ||||||||||||||||||||||||||||||||||||
| AutoStart as(testId, "AutoStartTest"); | ||||||||||||||||||||||||||||||||||||
| as.SetProgram("/usr/bin/testapp", {}); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| if (!as.Enable()) { | ||||||||||||||||||||||||||||||||||||
| std::cerr << "Enable() should return true (precondition for Disable test)." << std::endl; | ||||||||||||||||||||||||||||||||||||
| RemoveDesktopFile(tmpDir, testId); | ||||||||||||||||||||||||||||||||||||
| return 1; | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| if (!as.Disable()) { | ||||||||||||||||||||||||||||||||||||
| std::cerr << "Disable() should return true." << std::endl; | ||||||||||||||||||||||||||||||||||||
| RemoveDesktopFile(tmpDir, testId); | ||||||||||||||||||||||||||||||||||||
| return 1; | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| if (as.IsEnabled()) { | ||||||||||||||||||||||||||||||||||||
| std::cerr << "IsEnabled() should return false after Disable()." << std::endl; | ||||||||||||||||||||||||||||||||||||
| RemoveDesktopFile(tmpDir, testId); | ||||||||||||||||||||||||||||||||||||
| return 1; | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| RemoveDesktopFile(tmpDir, testId); | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // Disable is idempotent (no error when file does not exist) | ||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||
| const std::string tmpDir = MakeTempConfigDir(); | ||||||||||||||||||||||||||||||||||||
| if (tmpDir.empty()) | ||||||||||||||||||||||||||||||||||||
| return 1; | ||||||||||||||||||||||||||||||||||||
| ScopedConfigHome scope(tmpDir); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| AutoStart as("com.example.autostarttest", "AutoStartTest"); | ||||||||||||||||||||||||||||||||||||
| if (!as.Disable()) { | ||||||||||||||||||||||||||||||||||||
| std::cerr << "Disable() on non-existent entry should return true (idempotent)." << std::endl; | ||||||||||||||||||||||||||||||||||||
| rmdir(tmpDir.c_str()); | ||||||||||||||||||||||||||||||||||||
| return 1; | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
| rmdir(tmpDir.c_str()); | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // IsEnabled returns false before Enable() is called | ||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||
| const std::string tmpDir = MakeTempConfigDir(); | ||||||||||||||||||||||||||||||||||||
| if (tmpDir.empty()) | ||||||||||||||||||||||||||||||||||||
| return 1; | ||||||||||||||||||||||||||||||||||||
| ScopedConfigHome scope(tmpDir); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| AutoStart as("com.example.autostarttest", "AutoStartTest"); | ||||||||||||||||||||||||||||||||||||
| if (as.IsEnabled()) { | ||||||||||||||||||||||||||||||||||||
| std::cerr << "IsEnabled() should return false before Enable() is called." << std::endl; | ||||||||||||||||||||||||||||||||||||
| rmdir(tmpDir.c_str()); | ||||||||||||||||||||||||||||||||||||
| return 1; | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
| rmdir(tmpDir.c_str()); | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // Enable() writes valid .desktop content | ||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||
| const std::string tmpDir = MakeTempConfigDir(); | ||||||||||||||||||||||||||||||||||||
| if (tmpDir.empty()) | ||||||||||||||||||||||||||||||||||||
| return 1; | ||||||||||||||||||||||||||||||||||||
| ScopedConfigHome scope(tmpDir); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| const std::string testId = "com.example.contenttest"; | ||||||||||||||||||||||||||||||||||||
| AutoStart as(testId, "ContentTestApp"); | ||||||||||||||||||||||||||||||||||||
| as.SetProgram("/usr/local/bin/myapp", {"--flag", "value with space"}); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| if (!as.Enable()) { | ||||||||||||||||||||||||||||||||||||
| std::cerr << "Enable() should return true." << std::endl; | ||||||||||||||||||||||||||||||||||||
| RemoveDesktopFile(tmpDir, testId); | ||||||||||||||||||||||||||||||||||||
| return 1; | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| std::string desktopPath = tmpDir + "/autostart/" + testId + ".desktop"; | ||||||||||||||||||||||||||||||||||||
| std::string content = ReadFile(desktopPath); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| if (content.find("[Desktop Entry]") == std::string::npos) { | ||||||||||||||||||||||||||||||||||||
| std::cerr << "Desktop file missing [Desktop Entry] section." << std::endl; | ||||||||||||||||||||||||||||||||||||
| RemoveDesktopFile(tmpDir, testId); | ||||||||||||||||||||||||||||||||||||
| return 1; | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
| if (content.find("Type=Application") == std::string::npos) { | ||||||||||||||||||||||||||||||||||||
| std::cerr << "Desktop file missing 'Type=Application'." << std::endl; | ||||||||||||||||||||||||||||||||||||
| RemoveDesktopFile(tmpDir, testId); | ||||||||||||||||||||||||||||||||||||
| return 1; | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
| if (content.find("Name=ContentTestApp") == std::string::npos) { | ||||||||||||||||||||||||||||||||||||
| std::cerr << "Desktop file missing 'Name=ContentTestApp'." << std::endl; | ||||||||||||||||||||||||||||||||||||
| RemoveDesktopFile(tmpDir, testId); | ||||||||||||||||||||||||||||||||||||
| return 1; | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
| if (content.find("Exec=") == std::string::npos) { | ||||||||||||||||||||||||||||||||||||
| std::cerr << "Desktop file missing 'Exec=' line." << std::endl; | ||||||||||||||||||||||||||||||||||||
| RemoveDesktopFile(tmpDir, testId); | ||||||||||||||||||||||||||||||||||||
| return 1; | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
| if (content.find("/usr/local/bin/myapp") == std::string::npos) { | ||||||||||||||||||||||||||||||||||||
| std::cerr << "Desktop file Exec line missing executable path." << std::endl; | ||||||||||||||||||||||||||||||||||||
| RemoveDesktopFile(tmpDir, testId); | ||||||||||||||||||||||||||||||||||||
| return 1; | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
| } | |
| } | |
| // Verify that the Exec line preserves the spaced argument as a single argument | |
| std::size_t execPos = content.find("Exec="); | |
| if (execPos != std::string::npos) { | |
| std::size_t endOfLine = content.find('\n', execPos); | |
| std::string execLine = | |
| content.substr(execPos, endOfLine == std::string::npos ? std::string::npos | |
| : endOfLine - execPos); | |
| if (execLine.find("\"value with space\"") == std::string::npos && | |
| execLine.find("value\\ with\\ space") == std::string::npos) { | |
| std::cerr << "Exec line does not preserve spaced argument correctly: " | |
| << execLine << std::endl; | |
| RemoveDesktopFile(tmpDir, testId); | |
| return 1; | |
| } | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<sys/stat.h> is included but not used anywhere in this test file. Removing unused headers keeps build times and dependencies minimal.