Source
tests/purrc/os_sys_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
// System-level test for the cheatah `os` standard-library module.4
//5
// Unlike os_cr_test.cpp (one tiny program per function), this is a SINGLE6
// cohesive filesystem workflow that exercises EVERY public function in7
// stdlib/os/os.hpp in one program: it builds a nested directory tree, creates8
// and renames and removes files (writing content via os.system), queries them9
// (exists/isfile/isdir/getsize/listdir), changes directory, applies the10
// purely-lexical os.path helpers, round-trips an environment variable, and11
// reports the process/system facts. Everything happens under a unique /tmp12
// workspace that is torn down at the end.13
//14
// Output is DETERMINISTIC: filesystem state is fully controlled, and the15
// non-deterministic facts (getpid, getcwd, cpu_count, the exit status of16
// `false`) are asserted as PROPERTIES (pid > 0, cpu_count >= 1, cwd basename,17
// false != 0) rather than printed raw.18
//19
// Coverage (all 24 public functions):20
// os.* getcwd chdir listdir mkdir makedirs rmdir remove rename21
// getenv setenv cpu_count system getpid urandom22
// os.path.* join exists isfile isdir basename dirname abspath getsize23
// splitext normpath24
//25
// splitext returns a std::pair (not io.print-Streamable); it is read via the26
// pair's .first / .second members, matching os_cr_test.cpp.27
#include "e2e_harness.hpp"29
TEST(StdlibE2E, Os) {30
e2e::expect_e2e("os_sys", R"PURR(import io31
import os33
# --- Setup: a unique workspace under /tmp -----------------------------------34
let root = "/tmp/cheatah_os_sys_ws"35
os.system("rm -rf /tmp/cheatah_os_sys_ws")36
os.mkdir(root)38
# Remember where we started so we can restore it.39
let start = os.getcwd()41
# --- makedirs: create a nested tree -----------------------------------------42
let nested = os.path.join(root, "a", "b", "c")43
os.makedirs(nested)44
io.print("isdir nested:", os.path.isdir(nested))46
# --- mkdir: create a sibling leaf directory ---------------------------------47
let data = os.path.join(root, "data")48
os.mkdir(data)49
io.print("isdir data:", os.path.isdir(data))51
# --- create files via os.system, then query them ----------------------------52
let f1 = os.path.join(data, "hello.txt")53
os.system("printf 'hello' > " + f1)54
io.print("exists f1:", os.path.exists(f1))55
io.print("isfile f1:", os.path.isfile(f1))56
io.print("isdir f1:", os.path.isdir(f1))57
io.print("getsize f1:", os.path.getsize(f1))59
# --- rename a file ----------------------------------------------------------60
let f2 = os.path.join(data, "renamed.txt")61
os.rename(f1, f2)62
io.print("isfile f2:", os.path.isfile(f2))63
io.print("isfile f1 gone:", os.path.isfile(f1))65
# --- listdir -----------------------------------------------------------------66
let entries = os.listdir(data)67
io.print("listdir len:", len(entries))68
io.print("listdir[0]:", entries[0])70
# --- chdir + getcwd: cd into data, confirm basename -------------------------71
os.chdir(data)72
io.print("cwd basename:", os.path.basename(os.getcwd()))73
os.chdir(start)75
# --- lexical path helpers ----------------------------------------------------76
io.print("join:", os.path.join("x", "y", "z.txt"))77
io.print("basename:", os.path.basename("/p/q/r.dat"))78
io.print("dirname:", os.path.dirname("/p/q/r.dat"))79
io.print("normpath:", os.path.normpath("/p/./q/../r"))80
io.print("abspath:", os.path.abspath("/already/abs"))81
let se = os.path.splitext("archive.tar.gz")82
io.print("splitext:", se.first, se.second)84
# --- environment round-trip --------------------------------------------------85
os.setenv("CHEATAH_OS_SYS_VAR", "purr")86
io.print("getenv set:", os.getenv("CHEATAH_OS_SYS_VAR"))87
io.print("getenv fallback:", os.getenv("CHEATAH_OS_SYS_MISSING_zzz", "none"))89
# --- process / system facts (asserted as properties) ------------------------90
io.print("pid positive:", os.getpid() > 0)91
io.print("cpu>=1:", os.cpu_count() >= 1)92
io.print("system true:", os.system("true"))93
io.print("system false nonzero:", os.system("false") != 0)94
io.print("urandom len:", len(os.urandom(32)))95
io.print("urandom varies:", os.urandom(16) != os.urandom(16))97
# --- teardown: remove files and dirs ----------------------------------------98
io.print("remove f2:", os.remove(f2))99
os.rmdir(data)100
os.rmdir(nested)101
os.rmdir(os.path.join(root, "a", "b"))102
os.rmdir(os.path.join(root, "a"))103
os.rmdir(root)104
io.print("root gone:", os.path.exists(root))105
)PURR",106
"isdir nested: True\n"107
"isdir data: True\n"108
"exists f1: True\n"109
"isfile f1: True\n"110
"isdir f1: False\n"111
"getsize f1: 5\n"112
"isfile f2: True\n"113
"isfile f1 gone: False\n"114
"listdir len: 1\n"115
"listdir[0]: renamed.txt\n"116
"cwd basename: data\n"117
"join: x/y/z.txt\n"118
"basename: r.dat\n"119
"dirname: /p/q\n"120
"normpath: /p/r\n"121
"abspath: /already/abs\n"122
"splitext: archive.tar .gz\n"123
"getenv set: purr\n"124
"getenv fallback: none\n"125
"pid positive: True\n"126
"cpu>=1: True\n"127
"system true: 0\n"128
"system false nonzero: True\n"129
"urandom len: 32\n"130
"urandom varies: True\n"131
"remove f2: True\n"132
"root gone: False\n");133
}