Source
tests/purrc/io_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 (whole-module) test for the `io` stdlib module: ONE cohesive .purr4
// program that exercises EVERY public purr-callable entry point in stdlib/io/io.hpp5
// in a single run, compiles it with purrc, runs it under the cheatah runtime, and6
// asserts the exact stdout byte-for-byte. Complements the per-function compile-run7
// tests (tests/purrc/io_cr_test.cpp) and the in-process unit tests8
// (stdlib/tests/io_test.cpp).9
//10
// Coverage (every documented purr-callable symbol in io.hpp):11
// io.str (generic Streamable overload) -> io.str(3), io.str(os.remove(...))12
// io.str (bool overload) -> io.str(1 == 1) / io.str(1 == 2) -> True/False13
// io.str (std::string identity) -> io.str(name)14
// io.repr (std::string overload) -> io.repr(name), io.repr(first), io.repr(rest)15
// io.repr (const char* overload) -> io.repr("raw")16
// io.print -> used throughout17
// io.format -> summary + the file body18
// io.open (free function) -> let f/g/h = io.open(path, mode)19
// File.write -> f.write(...)20
// File.is_open -> f.is_open() before/after close21
// File.close -> f.close()22
// File.read -> g.read()23
// File.readline -> g.readline()24
// File.readlines -> h.readlines()25
// io.read_file -> io.read_file(path)26
//27
// io.input is intentionally NOT covered: it reads from stdin, which the e2e harness28
// does not feed (covered instead by the in-process test CheatahIo.InputReadsALine).29
//30
// The program builds strings with str/repr/format, writes a temp file under /tmp via31
// the File object, reads it back three ways (readline+read, readlines, read_file),32
// prints a deterministic summary, then deletes the temp file (os.remove) and confirms33
// it is gone (os.path.exists). os is imported only for path joining and cleanup.34
#include "e2e_harness.hpp"36
TEST(StdlibE2E, Io) {37
e2e::expect_e2e("io_sys", R"PURR(import io38
import os40
let path = os.path.join("/tmp", "io_sys_data.txt")42
let name = "lines"43
let header = io.str(1 == 1)44
let count = io.str(3)45
let kind = io.str(name)46
let label = io.repr(name)47
let lit = io.repr("raw")48
let summary = io.format("{} {} {} ({} total)", header, label, lit, count)50
let f = io.open(path, "w")51
f.write(io.format("alpha={}\n", 1))52
f.write(io.format("beta={}\n", io.str(1 == 2)))53
f.write("gamma=3\n")54
io.print("writing open:", io.str(f.is_open()))55
f.close()56
io.print("writing closed:", io.str(f.is_open()))58
let g = io.open(path, "r")59
let first = g.readline()60
let rest = g.read()61
g.close()63
let h = io.open(path, "r")64
let all_lines = h.readlines()65
h.close()67
let whole = io.read_file(path)69
io.print("kind:", kind)70
io.print("summary:", summary)71
io.print("first:", io.repr(first))72
io.print("rest:", io.repr(rest))73
io.print("line count:", io.str(3))74
for line in all_lines { io.print(" line:", line) }75
io.print("first line again:", all_lines[0])76
io.print("read_file whole:")77
io.print(whole)79
io.print("removed:", io.str(os.remove(path)))80
io.print("still exists:", io.str(os.path.exists(path)))81
)PURR",82
"writing open: True\n"83
"writing closed: False\n"84
"kind: lines\n"85
"summary: True 'lines' 'raw' (3 total)\n"86
"first: 'alpha=1'\n"87
"rest: 'beta=False\ngamma=3\n'\n"88
"line count: 3\n"89
" line: alpha=1\n"90
" line: beta=False\n"91
" line: gamma=3\n"92
"first line again: alpha=1\n"93
"read_file whole:\n"94
"alpha=1\nbeta=False\ngamma=3\n\n"95
"removed: True\n"96
"still exists: False\n");97
}