26382a7ac6
CI / Clippy (push) Failing after 15m13s
CI / Test (ubuntu-latest) (push) Failing after 16m1s
CI / Test (macos-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Build (no embeddings / no ORT) (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / Cookbook (Node) (push) Has been cancelled
CI / Pi Extension (Node) (push) Has been cancelled
CI / Rust SDK (lean-ctx-client) (push) Has been cancelled
CI / Embed SDK (lean-ctx-sdk) (push) Has been cancelled
CI / Python SDK (leanctx) (push) Has been cancelled
CI / Hermes Plugin (Python) (push) Has been cancelled
CI / SDK Conformance Matrix (push) Has been cancelled
CI / Coverage (push) Has been cancelled
CI / cargo-deny (push) Has been cancelled
CI / Adversarial Safety (push) Has been cancelled
CI / Benchmarks (push) Has been cancelled
CI / Output-Quality Gate (eval A/B) (push) Has been cancelled
CI / Documentation (push) Has been cancelled
CI / CI Green (push) Has been cancelled
JetBrains Plugin / Actionlint (push) Has been cancelled
CodeQL / Analyze (actions) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
CodeQL / Analyze (rust) (push) Has been cancelled
JetBrains Plugin / Validation (push) Has been cancelled
JetBrains Plugin / Build (push) Has been cancelled
JetBrains Plugin / Test (push) Has been cancelled
Security Check / Security Scan (push) Has been cancelled
102 lines
3.6 KiB
Rust
102 lines
3.6 KiB
Rust
use std::sync::Mutex;
|
|
|
|
use lean_ctx::core::cache::SessionCache;
|
|
use lean_ctx::tools::CrpMode;
|
|
use lean_ctx::tools::ctx_multi_read;
|
|
|
|
/// `LCTX_MAX_MULTI_READ_BYTES` is process-global, so tests that mutate it must
|
|
/// not run concurrently or they clobber each other's value. Serialize them.
|
|
static ENV_GUARD: Mutex<()> = Mutex::new(());
|
|
|
|
fn setup_test_files(count: usize, size_per_file: usize) -> (tempfile::TempDir, Vec<String>) {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
let mut paths = Vec::new();
|
|
for i in 0..count {
|
|
let path = dir.path().join(format!("file_{i}.txt"));
|
|
let content = format!("// File {i}\n{}", "x".repeat(size_per_file));
|
|
std::fs::write(&path, &content).unwrap();
|
|
paths.push(path.to_string_lossy().to_string());
|
|
}
|
|
(dir, paths)
|
|
}
|
|
|
|
#[test]
|
|
fn multi_read_respects_output_cap() {
|
|
let _guard = ENV_GUARD
|
|
.lock()
|
|
.unwrap_or_else(std::sync::PoisonError::into_inner);
|
|
// TODO: Audit that the environment access only happens in single-threaded code.
|
|
unsafe { std::env::set_var("LCTX_MAX_MULTI_READ_BYTES", "10000") };
|
|
let (_dir, paths) = setup_test_files(20, 5000);
|
|
|
|
let mut cache = SessionCache::new();
|
|
let output = ctx_multi_read::handle(&mut cache, &paths, "full", CrpMode::Off);
|
|
|
|
assert!(
|
|
output.contains("Output capped"),
|
|
"output must contain cap warning when exceeding limit:\n{}",
|
|
&output[output.len().saturating_sub(300)..]
|
|
);
|
|
assert!(
|
|
output.contains("file(s) skipped"),
|
|
"must report skipped files"
|
|
);
|
|
// TODO: Audit that the environment access only happens in single-threaded code.
|
|
unsafe { std::env::remove_var("LCTX_MAX_MULTI_READ_BYTES") };
|
|
}
|
|
|
|
#[test]
|
|
fn multi_read_no_cap_when_under_limit() {
|
|
let _guard = ENV_GUARD
|
|
.lock()
|
|
.unwrap_or_else(std::sync::PoisonError::into_inner);
|
|
// TODO: Audit that the environment access only happens in single-threaded code.
|
|
unsafe { std::env::set_var("LCTX_MAX_MULTI_READ_BYTES", "1000000") };
|
|
let (_dir, paths) = setup_test_files(3, 100);
|
|
|
|
let mut cache = SessionCache::new();
|
|
let output = ctx_multi_read::handle(&mut cache, &paths, "full", CrpMode::Off);
|
|
|
|
assert!(
|
|
!output.contains("Output capped"),
|
|
"should not cap when under limit"
|
|
);
|
|
assert!(output.contains("Read 3 files"), "should read all files");
|
|
// TODO: Audit that the environment access only happens in single-threaded code.
|
|
unsafe { std::env::remove_var("LCTX_MAX_MULTI_READ_BYTES") };
|
|
}
|
|
|
|
#[test]
|
|
fn multi_read_empty_paths() {
|
|
let _guard = ENV_GUARD
|
|
.lock()
|
|
.unwrap_or_else(std::sync::PoisonError::into_inner);
|
|
let mut cache = SessionCache::new();
|
|
let output = ctx_multi_read::handle(&mut cache, &[], "full", CrpMode::Off);
|
|
assert!(output.contains("Read 0 files"));
|
|
}
|
|
|
|
#[test]
|
|
fn multi_read_single_large_file_passes() {
|
|
let _guard = ENV_GUARD
|
|
.lock()
|
|
.unwrap_or_else(std::sync::PoisonError::into_inner);
|
|
// TODO: Audit that the environment access only happens in single-threaded code.
|
|
unsafe { std::env::set_var("LCTX_MAX_MULTI_READ_BYTES", "100000") };
|
|
let (_dir, paths) = setup_test_files(1, 50000);
|
|
|
|
let mut cache = SessionCache::new();
|
|
let output = ctx_multi_read::handle(&mut cache, &paths, "full", CrpMode::Off);
|
|
|
|
assert!(
|
|
output.contains("Read 1 files"),
|
|
"single file should always be included even if large"
|
|
);
|
|
assert!(
|
|
!output.contains("Output capped"),
|
|
"single file should not trigger cap"
|
|
);
|
|
// TODO: Audit that the environment access only happens in single-threaded code.
|
|
unsafe { std::env::remove_var("LCTX_MAX_MULTI_READ_BYTES") };
|
|
}
|