cheatah
Source

tests/purrc/app_eventlog_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 "application" test: a small event-log pipeline that only passes
4// if datetime + time + os + io + string all cooperate end to end.
5//
6// Unlike the per-module system tests in stdlib_e2e_test.cpp (which exercise one
7// module each), this is a realistic multi-module program:
8//
9// 1. datetime.format() turns FIXED epochs (deterministic under TZ=UTC) into
10// timestamps, which io.format() + string.upper() compose into log lines;
11// 2. io.open()/File.write() persist the lines to a temp file whose path is
12// built and normalized with os.path.join()/os.path.normpath(), then
13// os.path.isfile() confirms the write landed;
14// 3. io.read_file() reads it back, string.splitlines()/len()/string.count()
15// derive a DETERMINISTIC summary (line count, first/last line, error tally);
16// 4. time.perf_counter() across a tiny sleep yields a monotonic PROPERTY check
17// printed as a boolean (raw clock values are never printed);
18// 5. os.remove() cleans up and os.path.exists() confirms the teardown.
19//
20// The 4th arg pins TZ=UTC so datetime.format() is deterministic. The expected
21// stdout was captured byte-for-byte by compiling+running the program under
22// TZ=UTC before being hardcoded here.
24#include "e2e_harness.hpp"
27TEST(SystemApps, EventLog) {
28 e2e::expect_e2e("app_eventlog", R"PURR(import io
29import os
30import string
31import datetime
32import time
34# Fixed epochs (seconds) -> deterministic timestamps under TZ=UTC.
35let epochs = [0.0, 3661.0, 90061.0]
36let levels = ["INFO", "WARN", "ERROR"]
37let msgs = ["service start", "cache miss", "disk full"]
39# Build one normalized temp path with os.path.
40let path = os.path.normpath(os.path.join("/tmp", "cheatah_eventlog", "..", "cheatah_eventlog.log"))
42# Format each event into "TS [LEVEL] msg" via datetime + io.format + string.
43let n = len(epochs)
44let f = io.open(path, "w")
45let i = 0
46while i < n {
47 let ts = datetime.format(epochs[i], "%Y-%m-%d %H:%M:%S")
48 let line = io.format("{} [{}] {}", ts, string.upper(levels[i]), msgs[i])
49 f.write(line)
50 f.write("\n")
51 i = i + 1
53f.close()
55# os confirms the file the pipeline just produced exists.
56let wrote_ok = os.path.isfile(path)
58# Read it back with io, split into lines with string.
59let blob = io.read_file(path)
60let lines = string.splitlines(blob)
61let count = len(lines)
62let first = lines[0]
63let last = lines[count - 1]
65# time: deterministic monotonic PROPERTY across a tiny sleep (never print raw).
66let t0 = time.perf_counter()
67time.sleep(0.005)
68let t1 = time.perf_counter()
69let monotonic_ok = t1 >= t0
71# Deterministic summary.
72io.print("file:", os.path.basename(path))
73io.print("exists:", wrote_ok)
74io.print("lines:", count)
75io.print("first:", first)
76io.print("last:", last)
77io.print("errors:", string.count(blob, "[ERROR]"))
78io.print("monotonic:", monotonic_ok)
80# Clean up the temp file.
81os.remove(path)
82io.print("cleaned:", not os.path.exists(path))
83)PURR",
84 "file: cheatah_eventlog.log\n"
85 "exists: True\n"
86 "lines: 3\n"
87 "first: 1970-01-01 00:00:00 [INFO] service start\n"
88 "last: 1970-01-02 01:01:01 [ERROR] disk full\n"
89 "errors: 1\n"
90 "monotonic: True\n"
91 "cleaned: True\n",
92 "TZ=UTC ");