Skip to content

Commit 895f45b

Browse files
author
DhanashreePetare
committed
volk: prefer XDG config paths, ensure directories on write; add VolkPaths tests; address reviewer suggestions (refs #792 #810)
1 parent d7c6b77 commit 895f45b

File tree

3 files changed

+185
-6
lines changed

3 files changed

+185
-6
lines changed

lib/volk_prefs.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,19 @@ void volk_get_config_path(char* path, bool read)
5555
if (xdg) {
5656
snprintf(tmp, sizeof(tmp), "%s/volk/volk_config", xdg);
5757
if (!read) {
58+
char parent[512];
5859
char dir[512];
60+
/* ensure XDG_CONFIG_HOME exists, then create XDG/volk */
61+
snprintf(parent, sizeof(parent), "%s", xdg);
5962
snprintf(dir, sizeof(dir), "%s/volk", xdg);
6063
#if defined(_MSC_VER)
64+
_mkdir(parent);
6165
_mkdir(dir);
6266
#else
6367
struct stat st = { 0 };
68+
if (stat(parent, &st) == -1) {
69+
mkdir(parent, 0755);
70+
}
6471
if (stat(dir, &st) == -1) {
6572
mkdir(dir, 0755);
6673
}
@@ -77,12 +84,19 @@ void volk_get_config_path(char* path, bool read)
7784
if (home) {
7885
snprintf(tmp, sizeof(tmp), "%s/.config/volk/volk_config", home);
7986
if (!read) {
87+
char parent[512];
8088
char dir[512];
89+
/* ensure HOME/.config exists, then create HOME/.config/volk */
90+
snprintf(parent, sizeof(parent), "%s/.config", home);
8191
snprintf(dir, sizeof(dir), "%s/.config/volk", home);
8292
#if defined(_MSC_VER)
93+
_mkdir(parent);
8394
_mkdir(dir);
8495
#else
8596
struct stat st = { 0 };
97+
if (stat(parent, &st) == -1) {
98+
mkdir(parent, 0755);
99+
}
86100
if (stat(dir, &st) == -1) {
87101
mkdir(dir, 0755);
88102
}

tests/CMakeLists.txt

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,36 @@ endif(NOT ENABLE_TESTING)
1212

1313
include(FetchContent)
1414

15+
# Prefer system fmt if available, otherwise fetch a pinned version.
1516
find_package(fmt QUIET)
16-
find_package(fmt QUIET)
17-
find_package(GTest QUIET)
17+
if(NOT fmt_FOUND)
18+
message(STATUS "fmt not found: fetching fmt via FetchContent")
19+
FetchContent_Declare(
20+
fmt
1821
GIT_REPOSITORY https://github.com/fmtlib/fmt.git
1922
GIT_TAG 10.2.1
20-
GIT_SHALLOW TRUE)
23+
GIT_SHALLOW TRUE
24+
)
2125
FetchContent_MakeAvailable(fmt)
2226
endif()
2327

28+
# Prefer system GTest if available, otherwise fetch googletest.
29+
find_package(GTest QUIET)
2430
if(NOT GTest_FOUND)
2531
message(STATUS "GTest not found: fetching googletest via FetchContent")
32+
set(BUILD_GMOCK OFF CACHE BOOL "Disable gmock" FORCE)
33+
set(INSTALL_GTEST OFF CACHE BOOL "Disable gtest install" FORCE)
2634
FetchContent_Declare(
2735
googletest
2836
GIT_REPOSITORY https://github.com/google/googletest.git
2937
GIT_TAG release-1.12.1
30-
GIT_SHALLOW TRUE)
31-
FetchContent_MakeAvailable(googletest)
32-
find_package(GTest REQUIRED)
38+
GIT_SHALLOW TRUE
39+
)
40+
FetchContent_GetProperties(googletest)
41+
if(NOT googletest_POPULATED)
42+
FetchContent_Populate(googletest)
43+
add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR} EXCLUDE_FROM_ALL)
44+
endif()
3345
endif()
3446

3547
file(GLOB volk_test_files "test_*.cc")

tests/test_volk_paths.cc

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
// Tests for volk config path resolution (XDG preference, legacy fallback)
2+
#include <gtest/gtest.h>
3+
#include <volk/volk_prefs.h>
4+
5+
#include <filesystem>
6+
#include <fstream>
7+
#include <string>
8+
#include <string_view>
9+
#include <cstdlib>
10+
#include <random>
11+
#include <sstream>
12+
13+
#if defined(_WIN32)
14+
static void set_env(std::string_view name, const char* value)
15+
{
16+
std::string n(name);
17+
if (value)
18+
_putenv_s(n.c_str(), value);
19+
else
20+
_putenv_s(n.c_str(), "");
21+
}
22+
#else
23+
static void set_env(std::string_view name, const char* value)
24+
{
25+
std::string n(name);
26+
if (value)
27+
setenv(n.c_str(), value, 1);
28+
else
29+
unsetenv(n.c_str());
30+
}
31+
#endif
32+
33+
static std::string volk_config_path_read()
34+
{
35+
char buf[512] = {0};
36+
volk_get_config_path(buf, true);
37+
return std::string(buf);
38+
}
39+
40+
static std::string volk_config_path_write()
41+
{
42+
char buf[512] = {0};
43+
volk_get_config_path(buf, false);
44+
return std::string(buf);
45+
}
46+
47+
// Helper to generate unique temp directory names
48+
static std::filesystem::path unique_temp_path(const char* prefix)
49+
{
50+
std::random_device rd;
51+
std::mt19937 gen(rd());
52+
std::uniform_int_distribution<> distrib(100000, 999999);
53+
std::ostringstream oss;
54+
oss << prefix << "_" << distrib(gen);
55+
return std::filesystem::temp_directory_path() / oss.str();
56+
}
57+
58+
TEST(VolkPaths, OverrideEnv)
59+
{
60+
namespace fs = std::filesystem;
61+
fs::path tmp = unique_temp_path("volk_test_override");
62+
fs::create_directories(tmp / "volk");
63+
std::ofstream(tmp / "volk" / "volk_config") << "test";
64+
65+
set_env("VOLK_CONFIGPATH", tmp.string().c_str());
66+
67+
std::string expect = (tmp / "volk" / "volk_config").generic_string();
68+
std::string got = volk_config_path_read();
69+
EXPECT_EQ(expect, got);
70+
71+
// cleanup
72+
set_env("VOLK_CONFIGPATH", nullptr);
73+
fs::remove_all(tmp);
74+
}
75+
76+
TEST(VolkPaths, XDGPreference)
77+
{
78+
namespace fs = std::filesystem;
79+
fs::path tmp = unique_temp_path("volk_test_xdg");
80+
fs::create_directories(tmp / "volk");
81+
std::ofstream(tmp / "volk" / "volk_config") << "test";
82+
83+
set_env("VOLK_CONFIGPATH", nullptr);
84+
set_env("XDG_CONFIG_HOME", tmp.string().c_str());
85+
86+
std::string expect = (tmp / "volk" / "volk_config").generic_string();
87+
std::string got = volk_config_path_read();
88+
EXPECT_EQ(expect, got);
89+
90+
set_env("XDG_CONFIG_HOME", nullptr);
91+
fs::remove_all(tmp);
92+
}
93+
94+
TEST(VolkPaths, HomeDotConfigFallback)
95+
{
96+
namespace fs = std::filesystem;
97+
fs::path tmp = unique_temp_path("volk_test_homecfg");
98+
fs::create_directories(tmp / ".config" / "volk");
99+
std::ofstream(tmp / ".config" / "volk" / "volk_config") << "test";
100+
101+
set_env("VOLK_CONFIGPATH", nullptr);
102+
set_env("XDG_CONFIG_HOME", nullptr);
103+
set_env("HOME", tmp.string().c_str());
104+
105+
std::string expect = (tmp / ".config" / "volk" / "volk_config").generic_string();
106+
std::string got = volk_config_path_read();
107+
EXPECT_EQ(expect, got);
108+
109+
set_env("HOME", nullptr);
110+
fs::remove_all(tmp);
111+
}
112+
113+
TEST(VolkPaths, LegacyFallback)
114+
{
115+
namespace fs = std::filesystem;
116+
fs::path tmp = unique_temp_path("volk_test_legacy");
117+
fs::create_directories(tmp / ".volk");
118+
std::ofstream(tmp / ".volk" / "volk_config") << "test";
119+
120+
set_env("VOLK_CONFIGPATH", nullptr);
121+
set_env("XDG_CONFIG_HOME", nullptr);
122+
set_env("HOME", tmp.string().c_str());
123+
124+
// Ensure .config/volk does not exist to force legacy path selection
125+
fs::remove_all(tmp / ".config");
126+
127+
std::string expect = (tmp / ".volk" / "volk_config").generic_string();
128+
std::string got = volk_config_path_read();
129+
EXPECT_EQ(expect, got);
130+
131+
set_env("HOME", nullptr);
132+
fs::remove_all(tmp);
133+
}
134+
135+
TEST(VolkPaths, WriteCreatesXDGDir)
136+
{
137+
namespace fs = std::filesystem;
138+
fs::path tmp = unique_temp_path("volk_test_write");
139+
140+
set_env("VOLK_CONFIGPATH", nullptr);
141+
set_env("XDG_CONFIG_HOME", tmp.string().c_str());
142+
143+
// Ensure directory does not exist yet
144+
fs::remove_all(tmp);
145+
EXPECT_FALSE(fs::exists(tmp / "volk"));
146+
147+
// Call write-mode; this should create the XDG/volk directory
148+
volk_config_path_write();
149+
EXPECT_TRUE(fs::exists(tmp / "volk"));
150+
151+
set_env("XDG_CONFIG_HOME", nullptr);
152+
fs::remove_all(tmp);
153+
}

0 commit comments

Comments
 (0)