use std::io::Write;
use std::path::PathBuf;
use tempfile::NamedTempFile;
fn create_temp_go_file(content: &str) -> NamedTempFile {
let mut temp_file = NamedTempFile::with_suffix(".go").expect("Failed to create temp file");
write!(temp_file, "{}", content).expect("Failed to write to temp file");
temp_file
}
#[test]
fn red_test_unified_go_analyzer_can_be_created() {
use crate::services::unified_go_analyzer::UnifiedGoAnalyzer;
let path = PathBuf::from("test.go");
let analyzer = UnifiedGoAnalyzer::new(path.clone());
assert_eq!(analyzer.file_path(), &path);
}
#[tokio::test]
async fn red_test_unified_go_parses_only_once() {
use crate::services::unified_go_analyzer::UnifiedGoAnalyzer;
let temp_file = create_temp_go_file(
r#"
package main
func add(a, b int) int {
return a + b
}
"#,
);
let analyzer = UnifiedGoAnalyzer::new(temp_file.path().to_path_buf());
let result = analyzer.analyze().await;
assert!(result.is_ok(), "Should parse successfully");
#[cfg(test)]
{
assert_eq!(analyzer.parse_count(), 1, "Must parse exactly once!");
}
}
#[tokio::test]
async fn red_test_unified_go_returns_both_ast_and_complexity() {
use crate::services::unified_go_analyzer::UnifiedGoAnalyzer;
let temp_file = create_temp_go_file(
r#"
package main
import "fmt"
func greet(name string) {
fmt.Printf("Hello %s\n", name)
}
"#,
);
let analyzer = UnifiedGoAnalyzer::new(temp_file.path().to_path_buf());
let result = analyzer.analyze().await.expect("Should parse successfully");
assert!(!result.ast_items.is_empty(), "Must extract AST items");
assert!(
!result.ast_items.is_empty(),
"Should find at least 1 function"
);
assert!(
!result.file_metrics.functions.is_empty(),
"Must extract complexity"
);
}
#[tokio::test]
async fn red_test_unified_go_ast_extraction() {
use crate::services::unified_go_analyzer::UnifiedGoAnalyzer;
let temp_file = create_temp_go_file(
r#"
package main
func multiply(x, y int) int {
return x * y
}
type Point struct {
X int
Y int
}
func (p *Point) Distance() float64 {
return math.Sqrt(float64(p.X*p.X + p.Y*p.Y))
}
"#,
);
let analyzer = UnifiedGoAnalyzer::new(temp_file.path().to_path_buf());
let result = analyzer.analyze().await.unwrap();
assert!(
result.ast_items.len() >= 3,
"Should find at least 3 items (function + struct + method)"
);
}
#[tokio::test]
async fn red_test_unified_go_handles_invalid_syntax() {
use crate::services::unified_go_analyzer::UnifiedGoAnalyzer;
let temp_file = create_temp_go_file(
r#"
broken syntax here {{{ !!!
"#,
);
let analyzer = UnifiedGoAnalyzer::new(temp_file.path().to_path_buf());
let result = analyzer.analyze().await;
assert!(
result.is_ok(),
"Go analyzer handles invalid syntax gracefully"
);
let _analysis = result.unwrap();
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod property_tests {
use super::*;
use proptest::prelude::*;
proptest! {
#[test]
fn red_property_unified_go_handles_any_valid_code(
function_count in 1usize..20,
) {
use crate::services::unified_go_analyzer::UnifiedGoAnalyzer;
let mut source = String::from("package main\n\n");
for i in 0..function_count {
source.push_str(&format!(
"func func_{}() {{\n\tfmt.Println(\"test\")\n}}\n\n",
i
));
}
let temp_file = create_temp_go_file(&source);
let analyzer = UnifiedGoAnalyzer::new(temp_file.path().to_path_buf());
let runtime = tokio::runtime::Runtime::new().unwrap();
let result = runtime.block_on(analyzer.analyze());
prop_assert!(result.is_ok(), "Must handle any valid Go");
let analysis = result.unwrap();
prop_assert!(!analysis.ast_items.is_empty(), "Should find at least some items");
}
}
}
#[tokio::test]
async fn red_test_unified_go_on_real_file() {
use crate::services::unified_go_analyzer::UnifiedGoAnalyzer;
let real_file = PathBuf::from("/home/noah/src/agentic-ai/go-actors/simple.go");
if !real_file.exists() {
return;
}
let analyzer = UnifiedGoAnalyzer::new(real_file);
let result = analyzer.analyze().await;
assert!(result.is_ok(), "Must handle real-world Go files");
let analysis = result.unwrap();
assert!(analysis.ast_items.len() > 1, "simple.go has multiple items");
}
#[tokio::test]
async fn red_test_unified_go_handles_multiple_constructs() {
use crate::services::unified_go_analyzer::UnifiedGoAnalyzer;
let temp_file = create_temp_go_file(
r#"
package main
// Function
func regularFunc() {}
// Struct
type MyStruct struct {
Field1 string
Field2 int
}
// Method
func (m *MyStruct) Method() {}
// Interface
type MyInterface interface {
DoSomething()
}
// Goroutine function
func asyncFunc() {
go func() {
fmt.Println("goroutine")
}()
}
"#,
);
let analyzer = UnifiedGoAnalyzer::new(temp_file.path().to_path_buf());
let result = analyzer.analyze().await.expect("Should parse successfully");
assert!(result.ast_items.len() >= 4, "Should find at least 4 items");
}
#[tokio::test]
async fn red_test_unified_go_handles_empty_file() {
use crate::services::unified_go_analyzer::UnifiedGoAnalyzer;
let temp_file = create_temp_go_file("package main\n");
let analyzer = UnifiedGoAnalyzer::new(temp_file.path().to_path_buf());
let result = analyzer.analyze().await;
assert!(result.is_ok(), "Empty file should parse successfully");
let analysis = result.unwrap();
assert_eq!(
analysis.ast_items.len(),
0,
"Empty file should have 0 items"
);
assert_eq!(
analysis.file_metrics.functions.len(),
0,
"Empty file should have 0 functions"
);
}
#[tokio::test]
async fn red_test_unified_go_handles_comment_only_file() {
use crate::services::unified_go_analyzer::UnifiedGoAnalyzer;
let temp_file = create_temp_go_file(
r#"
package main
// This is just a comment
/* And a block comment */
"#,
);
let analyzer = UnifiedGoAnalyzer::new(temp_file.path().to_path_buf());
let result = analyzer.analyze().await;
assert!(
result.is_ok(),
"Comment-only file should parse successfully"
);
let analysis = result.unwrap();
assert_eq!(
analysis.ast_items.len(),
0,
"Comment-only file should have 0 items"
);
}