cheatah
Source

stdlib/tests/os_test.cpp

1// Copyright (c) 2026 BigBrain LLC. MIT-licensed (see LICENSE).
2// Original work; see ACKNOWLEDGMENTS.md for the open-source ideas we build upon.
3#include "os.hpp"
5#include <fstream>
6#include <stdexcept>
7#include <string>
8#include <string_view>
9#include <utility>
10#include <vector>
12#include <gtest/gtest.h>
14namespace os = cheatah::os;
16// The os.path.join concept must accept string-constructible types and reject the
17// rest, without narrowing today's accepted set.
18static_assert(os::StringLike<const char*>);
19static_assert(os::StringLike<std::string>);
20static_assert(os::StringLike<std::string_view>);
21static_assert(!os::StringLike<int>);
23TEST(CheatahOs, PathJoin) {
24 EXPECT_EQ(os::path::join("a", "b", "c"), "a/b/c");
25 EXPECT_EQ(os::path::join("only"), "only");
28TEST(CheatahOs, PathSplitext) {
29 const auto [root, ext] = os::path::splitext("dir/file.purr");
30 EXPECT_EQ(root, "dir/file");
31 EXPECT_EQ(ext, ".purr");
32 const auto [root2, ext2] = os::path::splitext("noext");
33 EXPECT_EQ(root2, "noext");
34 EXPECT_EQ(ext2, "");
37TEST(CheatahOs, PathBasenameDirname) {
38 EXPECT_EQ(os::path::basename("a/b/c.txt"), "c.txt");
39 EXPECT_EQ(os::path::dirname("a/b/c.txt"), "a/b");
42TEST(CheatahOs, CwdAndCpuCount) {
43 EXPECT_FALSE(os::getcwd().empty());
44 EXPECT_GT(os::cpu_count(), 0u);
47TEST(CheatahOs, GetenvFallback) {
48 EXPECT_EQ(os::getenv("CHEATAH_NONEXISTENT_VAR_xyz", "fallback"), "fallback");
51TEST(CheatahOs, SetenvThenGetenv) {
52 os::setenv("CHEATAH_PURR_TEST_VAR", "meow");
53 EXPECT_EQ(os::getenv("CHEATAH_PURR_TEST_VAR"), "meow");
56TEST(CheatahOs, MakeDirExistsThenRemove) {
57 const std::string dir = "purr_os_tmpdir";
58 os::remove(dir); // start clean
59 os::mkdir(dir);
60 EXPECT_TRUE(os::path::exists(dir));
61 EXPECT_TRUE(os::path::isdir(dir));
62 os::rmdir(dir);
63 EXPECT_FALSE(os::path::exists(dir));
66TEST(CheatahOs, FileQueriesIsfileAndGetsize) {
67 const std::string f = "purr_os_file.txt";
68 { std::ofstream o(f); o << "12345"; }
69 EXPECT_TRUE(os::path::exists(f));
70 EXPECT_TRUE(os::path::isfile(f));
71 EXPECT_FALSE(os::path::isdir(f));
72 EXPECT_EQ(os::path::getsize(f), 5u);
73 EXPECT_TRUE(os::remove(f));
74 EXPECT_FALSE(os::path::exists(f));
77TEST(CheatahOs, AbspathAndNormpath) {
78 EXPECT_EQ(os::path::normpath("a/./b/../c"), "a/c");
79 const std::string ap = os::path::abspath("x");
80 ASSERT_FALSE(ap.empty());
81 EXPECT_EQ(ap.front(), '/'); // absolute path
84TEST(CheatahOs, MakedirsAndChdir) {
85 const std::string nested = "purr_os_a/b/c";
86 os::makedirs(nested);
87 EXPECT_TRUE(os::path::isdir(nested));
88 const std::string cwd = os::getcwd();
89 os::chdir("purr_os_a");
90 EXPECT_NE(os::getcwd(), cwd);
91 os::chdir(cwd); // restore
92 EXPECT_EQ(os::getcwd(), cwd);
93 os::rmdir("purr_os_a/b/c");
94 os::rmdir("purr_os_a/b");
95 os::rmdir("purr_os_a");
96 EXPECT_FALSE(os::path::exists("purr_os_a"));
99TEST(CheatahOs, ListdirAndRename) {
100 const std::string dir = "purr_os_list";
101 os::remove(dir);
102 os::mkdir(dir);
103 { std::ofstream o(dir + "/one.txt"); o << "x"; }
104 const std::vector<std::string> entries = os::listdir(dir);
105 ASSERT_EQ(entries.size(), 1u);
106 EXPECT_EQ(entries[0], "one.txt"); // listdir returns basenames
107 os::rename(dir + "/one.txt", dir + "/two.txt");
108 EXPECT_TRUE(os::path::isfile(dir + "/two.txt"));
109 EXPECT_FALSE(os::path::isfile(dir + "/one.txt"));
110 os::remove(dir + "/two.txt");
111 os::rmdir(dir);
114TEST(CheatahOs, PidAndSystem) {
115 EXPECT_GT(os::getpid(), 0);
116 EXPECT_EQ(os::system("true"), 0);
117 EXPECT_NE(os::system("false"), 0);
120TEST(CheatahOs, Urandom) {
121 EXPECT_EQ(os::urandom(0).size(), 0u);
122 EXPECT_EQ(os::urandom(32).size(), 32u);
123 // A request larger than one getentropy() chunk (256 bytes) must still be filled.
124 EXPECT_EQ(os::urandom(300).size(), 300u);
125 // Two draws of real entropy are astronomically unlikely to collide.
126 EXPECT_NE(os::urandom(32), os::urandom(32));
127 EXPECT_THROW(os::urandom(-1), std::invalid_argument);
130TEST(CheatahOs, ModuleExt) {
131 // Exactly the platform's loadable-module extension, leading dot included.
132 const std::string ext = os::module_ext();
133#if defined(_WIN32)
134 EXPECT_EQ(ext, ".dll");
135#elif defined(__APPLE__)
136 EXPECT_EQ(ext, ".dylib");
137#else
138 EXPECT_EQ(ext, ".so");
139#endif