#![cfg(test)]
use std::fs;
use tempfile::TempDir;
#[test]
fn test_files_with_syntax_errors() {
let temp_dir = TempDir::new().unwrap();
let src_dir = temp_dir.path().join("src");
fs::create_dir_all(&src_dir).unwrap();
fs::write(
src_dir.join("broken.rs"),
r#"
// Missing closing brace
fn broken_function() {
println!("This function never closes");
use some::module; // use statement in wrong place
"#,
)
.unwrap();
fs::write(
src_dir.join("incomplete.rs"),
r#"
mod utils;
use utils::{helper,}; // trailing comma
fn main() {
helper(; // syntax error
}
"#,
)
.unwrap();
let output = std::process::Command::new(env!("CARGO_BIN_EXE_context-creator"))
.arg(&src_dir)
.arg("--trace-imports")
.arg("--include-callers")
.output()
.expect("Failed to execute context-creator");
assert!(
output.status.success(),
"Should handle syntax errors gracefully"
);
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(stdout.contains("broken.rs"));
assert!(stdout.contains("incomplete.rs"));
}
#[test]
fn test_comment_only_files() {
let temp_dir = TempDir::new().unwrap();
let src_dir = temp_dir.path().join("src");
fs::create_dir_all(&src_dir).unwrap();
fs::write(
src_dir.join("comments.rs"),
r#"
// This file contains only comments
// No actual code here
/*
Multi-line comment
Still no code
*/
/// Documentation comment
/// But no actual items
// The end
"#,
)
.unwrap();
fs::write(
src_dir.join("todo.rs"),
r#"
// TODO: Implement this module
// FIXME: Add proper error handling
// NOTE: This is a placeholder file
"#,
)
.unwrap();
let output = std::process::Command::new(env!("CARGO_BIN_EXE_context-creator"))
.arg(&src_dir)
.arg("--trace-imports")
.output()
.expect("Failed to execute context-creator");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(output.status.success());
assert!(stdout.contains("comments.rs"));
assert!(stdout.contains("todo.rs"));
let comments_section = stdout
.split("## comments.rs")
.nth(1)
.unwrap_or("")
.split("##")
.next()
.unwrap_or("");
assert!(!comments_section.contains("Imports:"));
assert!(!comments_section.contains("Function calls:"));
}
#[test]
fn test_macro_heavy_code() {
let temp_dir = TempDir::new().unwrap();
let src_dir = temp_dir.path().join("src");
fs::create_dir_all(&src_dir).unwrap();
fs::write(
src_dir.join("macros.rs"),
r#"
macro_rules! create_functions {
($($name:ident),*) => {
$(
pub fn $name() {
println!(stringify!($name));
}
)*
};
}
create_functions!(foo, bar, baz);
#[derive(Debug, Clone)]
pub struct Generated;
// Procedural macro usage
#[cfg(feature = "serde")]
#[derive(Serialize, Deserialize)]
pub struct Config {
value: String,
}
fn main() {
foo(); // This is generated by macro
println!("Hello"); // Regular macro call
vec![1, 2, 3]; // Another macro
}
"#,
)
.unwrap();
let output = std::process::Command::new(env!("CARGO_BIN_EXE_context-creator"))
.arg(&src_dir)
.arg("--trace-imports")
.arg("--include-callers")
.output()
.expect("Failed to execute context-creator");
assert!(output.status.success());
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(stdout.contains("macros.rs"));
}
#[test]
fn test_very_long_lines() {
let temp_dir = TempDir::new().unwrap();
let src_dir = temp_dir.path().join("src");
fs::create_dir_all(&src_dir).unwrap();
let long_import_list = (0..100)
.map(|i| format!("item_{i}"))
.collect::<Vec<_>>()
.join(", ");
fs::write(
src_dir.join("long_lines.rs"),
format!(
r#"
use some::module::{{{}}};
fn function_with_many_params({}) {{
println!("Many parameters");
}}
const VERY_LONG_STRING: &str = "{}";
"#,
long_import_list,
(0..50)
.map(|i| format!("param_{i}: i32"))
.collect::<Vec<_>>()
.join(", "),
"A".repeat(1000)
),
)
.unwrap();
let output = std::process::Command::new(env!("CARGO_BIN_EXE_context-creator"))
.arg(&src_dir)
.arg("--trace-imports")
.output()
.expect("Failed to execute context-creator");
assert!(output.status.success());
}
#[test]
fn test_unicode_content() {
let temp_dir = TempDir::new().unwrap();
let src_dir = temp_dir.path().join("src");
fs::create_dir_all(&src_dir).unwrap();
fs::write(
src_dir.join("unicode.rs"),
r#"
// Unicode identifiers (allowed in Rust)
pub fn 你好() {
println!("Hello in Chinese");
}
pub fn здравствуйте() {
println!("Hello in Russian");
}
fn main() {
let π = 3.14159;
let 文字列 = "Japanese string";
你好();
здравствуйте();
// Emoji in strings
println!("🦀 Rust is awesome! 🎉");
// Unicode in comments
// → ← ↑ ↓ ⇒ ⇐ ⇑ ⇓
}
"#,
)
.unwrap();
let output = std::process::Command::new(env!("CARGO_BIN_EXE_context-creator"))
.arg(&src_dir)
.arg("--trace-imports")
.arg("--include-callers")
.output()
.expect("Failed to execute context-creator");
assert!(output.status.success());
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(stdout.contains("unicode.rs"));
if stdout.contains("Function calls:") {
assert!(stdout.contains("你好()") || stdout.contains("здравствуйте()"));
}
}
#[test]
fn test_conditional_compilation() {
let temp_dir = TempDir::new().unwrap();
let src_dir = temp_dir.path().join("src");
fs::create_dir_all(&src_dir).unwrap();
fs::write(
src_dir.join("conditional.rs"),
r#"
#[cfg(target_os = "windows")]
mod windows_specific;
#[cfg(target_os = "linux")]
mod linux_specific;
#[cfg(target_os = "macos")]
mod macos_specific;
#[cfg(feature = "advanced")]
use advanced::features::{Feature1, Feature2};
#[cfg(not(feature = "minimal"))]
pub fn full_version() {
#[cfg(debug_assertions)]
println!("Debug mode");
#[cfg(not(debug_assertions))]
println!("Release mode");
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_something() {
// Test code
}
}
"#,
)
.unwrap();
let output = std::process::Command::new(env!("CARGO_BIN_EXE_context-creator"))
.arg(&src_dir)
.arg("--trace-imports")
.output()
.expect("Failed to execute context-creator");
assert!(output.status.success());
}
#[test]
fn test_async_await_code() {
let temp_dir = TempDir::new().unwrap();
let src_dir = temp_dir.path().join("src");
fs::create_dir_all(&src_dir).unwrap();
fs::write(
src_dir.join("async_code.rs"),
r#"
use std::future::Future;
mod utils;
use utils::async_helper;
pub async fn async_function() -> Result<(), Box<dyn std::error::Error>> {
async_helper().await?;
// Async block
let result = async {
println!("In async block");
42
}.await;
Ok(())
}
async fn another_async() {
async_function().await.unwrap();
}
// Async trait (with async-trait crate syntax)
#[async_trait]
trait AsyncTrait {
async fn method(&self) -> i32;
}
"#,
)
.unwrap();
fs::write(
src_dir.join("utils.rs"),
r#"
pub async fn async_helper() -> Result<(), Box<dyn std::error::Error>> {
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
Ok(())
}
"#,
)
.unwrap();
let output = std::process::Command::new(env!("CARGO_BIN_EXE_context-creator"))
.arg(&src_dir)
.arg("--trace-imports")
.arg("--include-callers")
.output()
.expect("Failed to execute context-creator");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(output.status.success());
assert!(stdout.contains("async_code.rs"));
assert!(stdout.contains("Imports: utils"));
assert!(stdout.contains("utils.rs") && stdout.contains("Imported by: async_code.rs"));
}
#[test]
fn test_complex_generics() {
let temp_dir = TempDir::new().unwrap();
let src_dir = temp_dir.path().join("src");
fs::create_dir_all(&src_dir).unwrap();
fs::write(
src_dir.join("generics.rs"),
r#"
use std::fmt::{Debug, Display};
use std::marker::PhantomData;
mod traits;
use traits::{CustomTrait, AnotherTrait};
pub struct Complex<T, U, V>
where
T: Debug + Display + Send + Sync,
U: CustomTrait<Item = T> + 'static,
V: AnotherTrait<T, U>,
{
t: T,
u: U,
v: V,
_phantom: PhantomData<fn(T) -> U>,
}
impl<T, U, V> Complex<T, U, V>
where
T: Debug + Display + Send + Sync,
U: CustomTrait<Item = T> + 'static,
V: AnotherTrait<T, U>,
{
pub fn new(t: T, u: U, v: V) -> Self {
Self {
t,
u,
v,
_phantom: PhantomData,
}
}
}
// Higher-ranked trait bounds
fn higher_ranked<F>(f: F)
where
F: for<'a> Fn(&'a str) -> &'a str,
{
let result = f("test");
println!("{}", result);
}
"#,
)
.unwrap();
fs::write(
src_dir.join("traits.rs"),
r#"
pub trait CustomTrait {
type Item;
fn process(&self) -> Self::Item;
}
pub trait AnotherTrait<T, U> {
fn combine(&self, t: T, u: U);
}
"#,
)
.unwrap();
let output = std::process::Command::new(env!("CARGO_BIN_EXE_context-creator"))
.arg(&src_dir)
.arg("--trace-imports")
.arg("--include-types")
.output()
.expect("Failed to execute context-creator");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(output.status.success());
assert!(stdout.contains("generics.rs"));
assert!(stdout.contains("Imports: traits"));
}
#[test]
fn test_inline_modules() {
let temp_dir = TempDir::new().unwrap();
let src_dir = temp_dir.path().join("src");
fs::create_dir_all(&src_dir).unwrap();
fs::write(
src_dir.join("inline_mods.rs"),
r#"
// Inline module definition
mod inner {
pub fn inner_function() {
println!("Inner");
}
pub mod deeper {
pub fn deeper_function() {
super::inner_function();
}
}
}
mod another {
use super::inner::{self, deeper};
pub fn use_inner() {
inner::inner_function();
deeper::deeper_function();
}
}
fn main() {
inner::inner_function();
inner::deeper::deeper_function();
another::use_inner();
}
"#,
)
.unwrap();
let output = std::process::Command::new(env!("CARGO_BIN_EXE_context-creator"))
.arg(&src_dir)
.arg("--trace-imports")
.arg("--include-callers")
.output()
.expect("Failed to execute context-creator");
assert!(output.status.success());
}
#[test]
fn test_reexports_and_glob_imports() {
let temp_dir = TempDir::new().unwrap();
let src_dir = temp_dir.path().join("src");
fs::create_dir_all(&src_dir).unwrap();
fs::write(
src_dir.join("lib.rs"),
r#"
mod internal;
mod types;
// Re-export everything from internal
pub use internal::*;
// Selective re-exports
pub use types::{Type1, Type2 as RenamedType};
// Glob import in the module
use std::collections::*;
pub fn use_hashmap() -> HashMap<String, i32> {
let mut map = HashMap::new();
map.insert("key".to_string(), 42);
map
}
"#,
)
.unwrap();
fs::write(
src_dir.join("internal.rs"),
r#"
pub fn exported_function() {
println!("This is re-exported");
}
pub struct ExportedStruct {
pub field: i32,
}
"#,
)
.unwrap();
fs::write(
src_dir.join("types.rs"),
r#"
pub struct Type1;
pub struct Type2;
pub struct Type3; // Not re-exported
"#,
)
.unwrap();
let output = std::process::Command::new(env!("CARGO_BIN_EXE_context-creator"))
.arg(&src_dir)
.arg("--trace-imports")
.output()
.expect("Failed to execute context-creator");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(output.status.success());
assert!(stdout.contains("lib.rs"));
assert!(stdout.contains("Imports: internal, types"));
}
#[test]
fn test_empty_modules() {
let temp_dir = TempDir::new().unwrap();
let src_dir = temp_dir.path().join("src");
fs::create_dir_all(&src_dir).unwrap();
fs::write(src_dir.join("empty.rs"), "").unwrap();
fs::write(src_dir.join("just_mod.rs"), "mod empty;\n").unwrap();
let output = std::process::Command::new(env!("CARGO_BIN_EXE_context-creator"))
.arg(&src_dir)
.arg("--trace-imports")
.output()
.expect("Failed to execute context-creator");
assert!(output.status.success());
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(stdout.contains("empty.rs"));
assert!(stdout.contains("just_mod.rs"));
}