Skip to content

Commit 4e79a1a

Browse files
committed
Q CLI Automation for basic chat and context
1 parent 827f050 commit 4e79a1a

13 files changed

+739
-0
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
use q_cli_e2e_tests::q_chat_helper::QChatSession;
2+
3+
#[test]
4+
#[cfg(feature = "context")]
5+
fn test_add_file_context() -> Result<(), Box<dyn std::error::Error>> {
6+
println!("🔍 Testing /context add <filename> command...");
7+
8+
let test_file_path = "/tmp/test_context_file.py";
9+
10+
// Create a test file
11+
std::fs::write(test_file_path, "# Test file for context\nprint('Hello from test file')")?;
12+
println!("✅ Created test file at {}", test_file_path);
13+
14+
let mut chat = QChatSession::new()?;
15+
println!("✅ Q Chat session started");
16+
17+
// Add file to context
18+
let add_response = chat.execute_command(&format!("/context add {}", test_file_path))?;
19+
20+
println!("📝 Context add response: {} bytes", add_response.len());
21+
println!("📝 ADD RESPONSE:");
22+
println!("{}", add_response);
23+
println!("📝 END ADD RESPONSE");
24+
25+
// Verify file was added successfully
26+
assert!(add_response.contains("Added 1 path(s) to context"), "Missing success message for adding file");
27+
println!("✅ File added to context successfully");
28+
29+
// Execute /context show to confirm file is present
30+
let show_response = chat.execute_command("/context show")?;
31+
32+
println!("📝 Context show response: {} bytes", show_response.len());
33+
println!("📝 SHOW RESPONSE:");
34+
println!("{}", show_response);
35+
println!("📝 END SHOW RESPONSE");
36+
37+
// Verify file is present in context
38+
assert!(show_response.contains(test_file_path), "File not found in context show output");
39+
assert!(show_response.contains("💬 Session (temporary):"), "Missing Session section");
40+
println!("✅ File confirmed present in context");
41+
42+
chat.quit()?;
43+
44+
// Clean up test file
45+
let _ = std::fs::remove_file(test_file_path);
46+
println!("✅ Cleaned up test file");
47+
48+
println!("✅ Test completed successfully");
49+
50+
Ok(())
51+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
use q_cli_e2e_tests::q_chat_helper::QChatSession;
2+
3+
#[test]
4+
#[cfg(feature = "context")]
5+
fn test_add_glob_pattern_file_context() -> Result<(), Box<dyn std::error::Error>> {
6+
println!("🔍 Testing /context add *.py glob pattern command...");
7+
8+
let test_file1_path = "/tmp/test_context_file1.py";
9+
let test_file2_path = "/tmp/test_context_file2.py";
10+
let test_file3_path = "/tmp/test_context_file.js"; // Non-matching file
11+
let glob_pattern = "/tmp/*.py";
12+
13+
// Create test files
14+
std::fs::write(test_file1_path, "# Test Python file 1 for context\nprint('Hello from Python file 1')")?;
15+
std::fs::write(test_file2_path, "# Test Python file 2 for context\nprint('Hello from Python file 2')")?;
16+
std::fs::write(test_file3_path, "// Test JavaScript file\nconsole.log('Hello from JS file');")?;
17+
println!("✅ Created test files at {}, {}, {}", test_file1_path, test_file2_path, test_file3_path);
18+
19+
let mut chat = QChatSession::new()?;
20+
println!("✅ Q Chat session started");
21+
22+
// Add glob pattern to context
23+
let add_response = chat.execute_command(&format!("/context add {}", glob_pattern))?;
24+
25+
println!("📝 Context add response: {} bytes", add_response.len());
26+
println!("📝 ADD RESPONSE:");
27+
println!("{}", add_response);
28+
println!("📝 END ADD RESPONSE");
29+
30+
// Verify glob pattern was added successfully
31+
assert!(add_response.contains("Added 1 path(s) to context"), "Missing success message for adding glob pattern");
32+
println!("✅ Glob pattern added to context successfully");
33+
34+
// Execute /context show to confirm pattern matches files
35+
let show_response = chat.execute_command("/context show")?;
36+
37+
println!("📝 Context show response: {} bytes", show_response.len());
38+
println!("📝 SHOW RESPONSE:");
39+
println!("{}", show_response);
40+
println!("📝 END SHOW RESPONSE");
41+
42+
// Verify glob pattern is present and matches files
43+
assert!(show_response.contains(glob_pattern), "Glob pattern not found in context show output");
44+
assert!(show_response.contains("match"), "Missing match indicator for glob pattern");
45+
assert!(show_response.contains("💬 Session (temporary):"), "Missing Session section");
46+
println!("✅ Glob pattern confirmed present in context with matches");
47+
48+
chat.quit()?;
49+
50+
// Clean up test files
51+
let _ = std::fs::remove_file(test_file1_path);
52+
let _ = std::fs::remove_file(test_file2_path);
53+
let _ = std::fs::remove_file(test_file3_path);
54+
println!("✅ Cleaned up test files");
55+
56+
println!("✅ Test completed successfully");
57+
58+
Ok(())
59+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
use q_cli_e2e_tests::q_chat_helper::QChatSession;
2+
3+
#[test]
4+
#[cfg(feature = "context")]
5+
fn test_add_multiple_file_context() -> Result<(), Box<dyn std::error::Error>> {
6+
println!("🔍 Testing /context add <filename1> <filename2> <filename3> command...");
7+
8+
let test_file1_path = "/tmp/test_context_file1.py";
9+
let test_file2_path = "/tmp/test_context_file2.js";
10+
let test_file3_path = "/tmp/test_context_file3.txt";
11+
12+
// Create multiple test files
13+
std::fs::write(test_file1_path, "# Test Python file for context\nprint('Hello from Python file')")?;
14+
std::fs::write(test_file2_path, "// Test JavaScript file for context\nconsole.log('Hello from JS file');")?;
15+
std::fs::write(test_file3_path, "Test text file for context\nHello from text file")?;
16+
println!("✅ Created test files at {}, {}, {}", test_file1_path, test_file2_path, test_file3_path);
17+
18+
let mut chat = QChatSession::new()?;
19+
println!("✅ Q Chat session started");
20+
21+
// Add multiple files to context in one command
22+
let add_response = chat.execute_command(&format!("/context add {} {} {}", test_file1_path, test_file2_path, test_file3_path))?;
23+
24+
println!("📝 Context add response: {} bytes", add_response.len());
25+
println!("📝 ADD RESPONSE:");
26+
println!("{}", add_response);
27+
println!("📝 END ADD RESPONSE");
28+
29+
// Verify files were added successfully
30+
assert!(add_response.contains("Added 3 path(s) to context"), "Missing success message for adding multiple files");
31+
println!("✅ Multiple files added to context successfully");
32+
33+
// Execute /context show to confirm files are present
34+
let show_response = chat.execute_command("/context show")?;
35+
36+
println!("📝 Context show response: {} bytes", show_response.len());
37+
println!("📝 SHOW RESPONSE:");
38+
println!("{}", show_response);
39+
println!("📝 END SHOW RESPONSE");
40+
41+
// Verify all files are present in context
42+
assert!(show_response.contains(test_file1_path), "Python file not found in context show output");
43+
assert!(show_response.contains(test_file2_path), "JavaScript file not found in context show output");
44+
assert!(show_response.contains(test_file3_path), "Text file not found in context show output");
45+
assert!(show_response.contains("💬 Session (temporary):"), "Missing Session section");
46+
println!("✅ All files confirmed present in context");
47+
48+
chat.quit()?;
49+
50+
// Clean up test files
51+
let _ = std::fs::remove_file(test_file1_path);
52+
let _ = std::fs::remove_file(test_file2_path);
53+
let _ = std::fs::remove_file(test_file3_path);
54+
println!("✅ Cleaned up test files");
55+
56+
println!("✅ Test completed successfully");
57+
58+
Ok(())
59+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
use q_cli_e2e_tests::q_chat_helper::QChatSession;
2+
3+
#[test]
4+
#[cfg(feature = "context")]
5+
fn test_add_non_existing_file_context() -> Result<(), Box<dyn std::error::Error>> {
6+
println!("🔍 Testing /context add non-existing file command...");
7+
8+
let non_existing_file_path = "/tmp/non_existing_file.py";
9+
10+
let mut chat = QChatSession::new()?;
11+
println!("✅ Q Chat session started");
12+
13+
// Try to add non-existing file to context
14+
let add_response = chat.execute_command(&format!("/context add {}", non_existing_file_path))?;
15+
16+
println!("📝 Context add response: {} bytes", add_response.len());
17+
println!("📝 ADD RESPONSE:");
18+
println!("{}", add_response);
19+
println!("📝 END ADD RESPONSE");
20+
21+
// Verify error message for non-existing file
22+
assert!(add_response.contains("Error:") && add_response.contains("Invalid path") && add_response.contains("does not exist"), "Missing error message for non-existing file");
23+
assert!(add_response.contains("Use --force to add anyway"), "Missing --force suggestion in error message");
24+
println!("✅ Found expected error message for non-existing file with --force suggestion");
25+
26+
chat.quit()?;
27+
28+
println!("✅ Test completed successfully");
29+
30+
Ok(())
31+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
use q_cli_e2e_tests::q_chat_helper::QChatSession;
2+
3+
#[test]
4+
#[cfg(feature = "context")]
5+
fn test_clear_context_command() -> Result<(), Box<dyn std::error::Error>> {
6+
println!("🔍 Testing /context clear command...");
7+
8+
let test_file1_path = "/tmp/test_context_file1.py";
9+
let test_file2_path = "/tmp/test_context_file2.js";
10+
11+
// Create multiple test files
12+
std::fs::write(test_file1_path, "# Test Python file for context\nprint('Hello from Python file')")?;
13+
std::fs::write(test_file2_path, "// Test JavaScript file for context\nconsole.log('Hello from JS file');")?;
14+
println!("✅ Created test files at {}, {}", test_file1_path, test_file2_path);
15+
16+
let mut chat = QChatSession::new()?;
17+
println!("✅ Q Chat session started");
18+
19+
// Add multiple files to context
20+
let add_response = chat.execute_command(&format!("/context add {} {}", test_file1_path, test_file2_path))?;
21+
22+
println!("📝 Context add response: {} bytes", add_response.len());
23+
println!("📝 ADD RESPONSE:");
24+
println!("{}", add_response);
25+
println!("📝 END ADD RESPONSE");
26+
27+
// Verify files were added successfully
28+
assert!(add_response.contains("Added 2 path(s) to context"), "Missing success message for adding files");
29+
println!("✅ Files added to context successfully");
30+
31+
// Execute /context show to confirm files are present
32+
let show_response = chat.execute_command("/context show")?;
33+
34+
println!("📝 Context show response: {} bytes", show_response.len());
35+
println!("📝 SHOW RESPONSE:");
36+
println!("{}", show_response);
37+
println!("📝 END SHOW RESPONSE");
38+
39+
// Verify files are present in context
40+
assert!(show_response.contains(test_file1_path), "Python file not found in context show output");
41+
assert!(show_response.contains(test_file2_path), "JavaScript file not found in context show output");
42+
println!("✅ Files confirmed present in context");
43+
44+
// Execute /context clear to remove all files
45+
let clear_response = chat.execute_command("/context clear")?;
46+
47+
println!("📝 Context clear response: {} bytes", clear_response.len());
48+
println!("📝 CLEAR RESPONSE:");
49+
println!("{}", clear_response);
50+
println!("📝 END CLEAR RESPONSE");
51+
52+
// Verify context was cleared successfully
53+
assert!(clear_response.contains("Cleared context"), "Missing success message for clearing context");
54+
println!("✅ Context cleared successfully");
55+
56+
// Execute /context show to confirm no files remain
57+
let final_show_response = chat.execute_command("/context show")?;
58+
59+
println!("📝 Final context show response: {} bytes", final_show_response.len());
60+
println!("📝 FINAL SHOW RESPONSE:");
61+
println!("{}", final_show_response);
62+
println!("📝 END FINAL SHOW RESPONSE");
63+
64+
// Verify no files remain in context
65+
assert!(!final_show_response.contains(test_file1_path), "Python file still found in context after clear");
66+
assert!(!final_show_response.contains(test_file2_path), "JavaScript file still found in context after clear");
67+
assert!(final_show_response.contains("👤 Agent (q_cli_default):"), "Missing Agent section");
68+
assert!(final_show_response.contains("💬 Session (temporary):"), "Missing Session section");
69+
assert!(final_show_response.contains("<none>"), "Missing <none> indicator for cleared context");
70+
println!("✅ All files confirmed removed from context and <none> sections present");
71+
72+
chat.quit()?;
73+
74+
// Clean up test files
75+
let _ = std::fs::remove_file(test_file1_path);
76+
let _ = std::fs::remove_file(test_file2_path);
77+
println!("✅ Cleaned up test files");
78+
79+
println!("✅ Test completed successfully");
80+
81+
Ok(())
82+
}

e2etests/tests/test_load_command.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
use q_cli_e2e_tests::q_chat_helper::QChatSession;
2+
3+
struct FileCleanup<'a> {
4+
path: &'a str,
5+
}
6+
7+
impl<'a> Drop for FileCleanup<'a> {
8+
fn drop(&mut self) {
9+
if std::path::Path::new(self.path).exists() {
10+
let _ = std::fs::remove_file(self.path);
11+
println!("✅ Cleaned up test file");
12+
}
13+
}
14+
}
15+
16+
#[test]
17+
#[cfg(feature = "save_load")]
18+
fn test_load_command() -> Result<(), Box<dyn std::error::Error>> {
19+
println!("🔍 Testing /load command...");
20+
21+
let save_path = "/tmp/qcli_test_load.json";
22+
let _cleanup = FileCleanup { path: save_path };
23+
24+
let mut chat = QChatSession::new()?;
25+
println!("✅ Q Chat session started");
26+
27+
// Create actual conversation content
28+
let _help_response = chat.execute_command("/help")?;
29+
let _tools_response = chat.execute_command("/tools")?;
30+
println!("✅ Created conversation content with /help and /tools commands");
31+
32+
// Execute /save command to create a file to load
33+
let save_response = chat.execute_command(&format!("/save {}", save_path))?;
34+
35+
println!("📝 Save response: {} bytes", save_response.len());
36+
println!("📝 SAVE OUTPUT:");
37+
println!("{}", save_response);
38+
println!("📝 END SAVE OUTPUT");
39+
40+
// Verify save was successful
41+
assert!(save_response.contains("Exported conversation state to") && save_response.contains(save_path), "Missing export confirmation message");
42+
println!("✅ Save completed successfully");
43+
44+
// Verify file was created
45+
assert!(std::path::Path::new(save_path).exists(), "Save file was not created");
46+
println!("✅ Save file created at {}", save_path);
47+
48+
// Execute /load command to load the saved conversation
49+
let load_response = chat.execute_command(&format!("/load {}", save_path))?;
50+
51+
println!("📝 Load response: {} bytes", load_response.len());
52+
println!("📝 LOAD OUTPUT:");
53+
println!("{}", load_response);
54+
println!("📝 END LOAD OUTPUT");
55+
56+
// Verify load was successful
57+
assert!(!load_response.is_empty(), "Load command should return non-empty response");
58+
assert!(load_response.contains("Imported conversation state from") && load_response.contains(save_path), "Missing import confirmation message");
59+
println!("✅ Load command executed successfully and imported conversation state");
60+
61+
chat.quit()?;
62+
println!("✅ Test completed successfully");
63+
64+
Ok(())
65+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
use q_cli_e2e_tests::q_chat_helper::QChatSession;
2+
3+
#[test]
4+
#[cfg(feature = "save_load")]
5+
fn test_load_command_argument_validation() -> Result<(), Box<dyn std::error::Error>> {
6+
println!("🔍 Testing /load command...");
7+
8+
let mut chat = QChatSession::new()?;
9+
println!("✅ Q Chat session started");
10+
11+
let response = chat.execute_command("/load")?;
12+
13+
println!("📝 Help response: {} bytes", response.len());
14+
println!("📝 FULL OUTPUT:");
15+
println!("{}", response);
16+
println!("📝 END OUTPUT");
17+
18+
// Verify load error message
19+
assert!(response.contains("error:") && response.contains("the following required arguments were not provided:"), "Missing load error message");
20+
println!("✅ Found load error message");
21+
22+
assert!(response.contains("Usage:"), "Missing Usage section");
23+
assert!(response.contains("/load"), "Missing /load command in usage");
24+
println!("✅ Found Usage section with /load command");
25+
26+
assert!(response.contains("Arguments:"), "Missing Arguments section");
27+
assert!(response.contains("<PATH>"), "Missing PATH argument");
28+
println!("✅ Found Arguments section with PATH parameter");
29+
30+
assert!(response.contains("Options:"), "Missing Options section");
31+
assert!(response.contains("-h"), "Missing -h flag");
32+
assert!(response.contains("--help") || response.contains("—help"), "Missing --help flag");
33+
println!("✅ Found Options section with -h, --help flags");
34+
35+
assert!(response.contains("Print help"), "Missing help description");
36+
println!("✅ Found help flag description");
37+
38+
println!("✅ All help content verified!");
39+
40+
chat.quit()?;
41+
println!("✅ Test completed successfully");
42+
43+
Ok(())
44+
}

0 commit comments

Comments
 (0)