rename app-code crate to repo-code
This commit is contained in:
Generated
+18
-18
@@ -1886,23 +1886,6 @@ dependencies = [
|
|||||||
"walkdir",
|
"walkdir",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "signal-gateway-app-code"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"async-trait",
|
|
||||||
"flate2",
|
|
||||||
"globset",
|
|
||||||
"regex",
|
|
||||||
"reqwest",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"signal-gateway-assistant",
|
|
||||||
"tar",
|
|
||||||
"tokio",
|
|
||||||
"tracing",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signal-gateway-assistant"
|
name = "signal-gateway-assistant"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -1951,9 +1934,9 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"signal-gateway",
|
"signal-gateway",
|
||||||
"signal-gateway-app-code",
|
|
||||||
"signal-gateway-assistant-claude",
|
"signal-gateway-assistant-claude",
|
||||||
"signal-gateway-log-ingest",
|
"signal-gateway-log-ingest",
|
||||||
|
"signal-gateway-repo-code",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
"toml",
|
"toml",
|
||||||
@@ -1977,6 +1960,23 @@ dependencies = [
|
|||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "signal-gateway-repo-code"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"async-trait",
|
||||||
|
"flate2",
|
||||||
|
"globset",
|
||||||
|
"regex",
|
||||||
|
"reqwest",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"signal-gateway-assistant",
|
||||||
|
"tar",
|
||||||
|
"tokio",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signal-hook-registry"
|
name = "signal-hook-registry"
|
||||||
version = "1.4.7"
|
version = "1.4.7"
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@ resolver = "2"
|
|||||||
members = [
|
members = [
|
||||||
"prometheus-http-client",
|
"prometheus-http-client",
|
||||||
"signal-gateway",
|
"signal-gateway",
|
||||||
"signal-gateway-app-code",
|
"signal-gateway-repo-code",
|
||||||
"signal-gateway-assistant",
|
"signal-gateway-assistant",
|
||||||
"signal-gateway-assistant/claude",
|
"signal-gateway-assistant/claude",
|
||||||
"signal-gateway-bin",
|
"signal-gateway-bin",
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ rustls-tls = ["signal-gateway/rustls-tls"]
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
signal-gateway = { workspace = true }
|
signal-gateway = { workspace = true }
|
||||||
signal-gateway-assistant-claude = { workspace = true }
|
signal-gateway-assistant-claude = { workspace = true }
|
||||||
signal-gateway-app-code = { path = "../signal-gateway-app-code" }
|
signal-gateway-repo-code = { path = "../signal-gateway-repo-code" }
|
||||||
signal-gateway-log-ingest = { path = "../signal-gateway-log-ingest" }
|
signal-gateway-log-ingest = { path = "../signal-gateway-log-ingest" }
|
||||||
|
|
||||||
async-trait = { workspace = true }
|
async-trait = { workspace = true }
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
use conf::Conf;
|
use conf::Conf;
|
||||||
use metrics_exporter_prometheus::PrometheusBuilder;
|
use metrics_exporter_prometheus::PrometheusBuilder;
|
||||||
use signal_gateway::{CommandRouter, Gateway, GatewayConfig, Handling};
|
use signal_gateway::{CommandRouter, Gateway, GatewayConfig, Handling};
|
||||||
use signal_gateway_app_code::AppCodeTools;
|
|
||||||
use signal_gateway_assistant_claude::{ClaudeAssistant, ClaudeConfig};
|
use signal_gateway_assistant_claude::{ClaudeAssistant, ClaudeConfig};
|
||||||
|
use signal_gateway_repo_code::RepoCodeTools;
|
||||||
use std::{env, fs, net::SocketAddr, path::PathBuf, sync::Arc};
|
use std::{env, fs, net::SocketAddr, path::PathBuf, sync::Arc};
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
use tokio_util::sync::CancellationToken;
|
use tokio_util::sync::CancellationToken;
|
||||||
@@ -16,8 +16,8 @@ use tracing_subscriber::EnvFilter;
|
|||||||
mod admin_http;
|
mod admin_http;
|
||||||
use admin_http::AdminHttpConfig;
|
use admin_http::AdminHttpConfig;
|
||||||
|
|
||||||
mod app_code;
|
mod repo_code;
|
||||||
use app_code::AppCodeConfigExt;
|
use repo_code::RepoCodeConfigExt;
|
||||||
|
|
||||||
mod listen_http;
|
mod listen_http;
|
||||||
use listen_http::start_http_task;
|
use listen_http::start_http_task;
|
||||||
@@ -51,7 +51,7 @@ pub struct Config {
|
|||||||
admin_http: Option<AdminHttpConfig>,
|
admin_http: Option<AdminHttpConfig>,
|
||||||
/// Application source code configurations for Claude tools.
|
/// Application source code configurations for Claude tools.
|
||||||
#[conf(long, env, value_parser = serde_json::from_str, default, default_help_str = "[]")]
|
#[conf(long, env, value_parser = serde_json::from_str, default, default_help_str = "[]")]
|
||||||
app_code: Vec<AppCodeConfigExt>,
|
app_code: Vec<RepoCodeConfigExt>,
|
||||||
/// Claude API configuration for AI-powered responses.
|
/// Claude API configuration for AI-powered responses.
|
||||||
#[conf(flatten, prefix)]
|
#[conf(flatten, prefix)]
|
||||||
claude: Option<ClaudeConfig>,
|
claude: Option<ClaudeConfig>,
|
||||||
@@ -150,7 +150,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
router_builder.build()
|
router_builder.build()
|
||||||
};
|
};
|
||||||
|
|
||||||
// Build AppCode tools if configured
|
// Build RepoCode tools if configured
|
||||||
let app_code_tools = if !config.app_code.is_empty() {
|
let app_code_tools = if !config.app_code.is_empty() {
|
||||||
let mut apps = Vec::new();
|
let mut apps = Vec::new();
|
||||||
for app_config in config.app_code {
|
for app_config in config.app_code {
|
||||||
@@ -163,7 +163,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(Arc::new(AppCodeTools::new(apps)))
|
Some(Arc::new(RepoCodeTools::new(apps)))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,24 +1,24 @@
|
|||||||
//! Extended configuration for application source code browsing.
|
//! Extended configuration for application source code browsing.
|
||||||
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use signal_gateway_app_code::{AppCode, AppCodeConfig, ShaCallback};
|
use signal_gateway_repo_code::{RepoCode, RepoCodeConfig, ShaCallback};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tracing::warn;
|
use tracing::warn;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
/// Extended configuration for AppCode with HTTP-based SHA fetching.
|
/// Extended configuration for RepoCode with HTTP-based SHA fetching.
|
||||||
#[derive(Clone, Debug, Deserialize)]
|
#[derive(Clone, Debug, Deserialize)]
|
||||||
pub struct AppCodeConfigExt {
|
pub struct RepoCodeConfigExt {
|
||||||
/// The base AppCode configuration.
|
/// The base RepoCode configuration.
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub config: AppCodeConfig,
|
pub config: RepoCodeConfig,
|
||||||
/// URL to GET the current deployed version SHA.
|
/// URL to GET the current deployed version SHA.
|
||||||
pub version_sha_http_get: Url,
|
pub version_sha_http_get: Url,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppCodeConfigExt {
|
impl RepoCodeConfigExt {
|
||||||
/// Convert to an AppCode instance with HTTP-based SHA callback.
|
/// Convert to an RepoCode instance with HTTP-based SHA callback.
|
||||||
pub fn into_app_code(self) -> Result<AppCode, std::io::Error> {
|
pub fn into_app_code(self) -> Result<RepoCode, std::io::Error> {
|
||||||
let url = self.version_sha_http_get.clone();
|
let url = self.version_sha_http_get.clone();
|
||||||
let client = reqwest::Client::new();
|
let client = reqwest::Client::new();
|
||||||
|
|
||||||
@@ -66,6 +66,6 @@ impl AppCodeConfigExt {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
AppCode::new(self.config, sha_callback)
|
RepoCode::new(self.config, sha_callback)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "signal-gateway-app-code"
|
name = "signal-gateway-repo-code"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
|
|
||||||
@@ -55,7 +55,7 @@ impl TryFrom<String> for GitHubRepo {
|
|||||||
|
|
||||||
/// Configuration for an application's source code access.
|
/// Configuration for an application's source code access.
|
||||||
#[derive(Clone, Debug, Deserialize)]
|
#[derive(Clone, Debug, Deserialize)]
|
||||||
pub struct AppCodeConfig {
|
pub struct RepoCodeConfig {
|
||||||
/// Name of the application (used to identify it in tool calls).
|
/// Name of the application (used to identify it in tool calls).
|
||||||
pub name: String,
|
pub name: String,
|
||||||
/// GitHub repository in "owner/repo" format.
|
/// GitHub repository in "owner/repo" format.
|
||||||
@@ -101,8 +101,8 @@ pub type ShaCallback = Arc<
|
|||||||
/// Application source code browser.
|
/// Application source code browser.
|
||||||
///
|
///
|
||||||
/// Downloads and caches GitHub tarballs for browsing application source code.
|
/// Downloads and caches GitHub tarballs for browsing application source code.
|
||||||
pub struct AppCode {
|
pub struct RepoCode {
|
||||||
config: AppCodeConfig,
|
config: RepoCodeConfig,
|
||||||
token: Option<String>,
|
token: Option<String>,
|
||||||
glob_filter: Option<GlobSet>,
|
glob_filter: Option<GlobSet>,
|
||||||
get_sha: ShaCallback,
|
get_sha: ShaCallback,
|
||||||
@@ -110,12 +110,12 @@ pub struct AppCode {
|
|||||||
cache: Mutex<Option<CachedTarball>>,
|
cache: Mutex<Option<CachedTarball>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppCode {
|
impl RepoCode {
|
||||||
/// Create a new AppCode instance from configuration.
|
/// Create a new RepoCode instance from configuration.
|
||||||
///
|
///
|
||||||
/// The `get_sha` callback is called to determine which git SHA to download.
|
/// The `get_sha` callback is called to determine which git SHA to download.
|
||||||
/// It should return `None` if the SHA is not yet known.
|
/// It should return `None` if the SHA is not yet known.
|
||||||
pub fn new(config: AppCodeConfig, get_sha: ShaCallback) -> Result<Self, std::io::Error> {
|
pub fn new(config: RepoCodeConfig, get_sha: ShaCallback) -> Result<Self, std::io::Error> {
|
||||||
let token = config
|
let token = config
|
||||||
.token_file
|
.token_file
|
||||||
.as_ref()
|
.as_ref()
|
||||||
@@ -123,20 +123,21 @@ impl AppCode {
|
|||||||
.transpose()?;
|
.transpose()?;
|
||||||
|
|
||||||
// Compile glob patterns if any are specified
|
// Compile glob patterns if any are specified
|
||||||
let glob_filter = if config.glob.is_empty() {
|
let glob_filter =
|
||||||
None
|
if config.glob.is_empty() {
|
||||||
} else {
|
None
|
||||||
let mut builder = GlobSetBuilder::new();
|
} else {
|
||||||
for pattern in &config.glob {
|
let mut builder = GlobSetBuilder::new();
|
||||||
let glob = Glob::new(pattern).map_err(|e| {
|
for pattern in &config.glob {
|
||||||
std::io::Error::other(format!("invalid glob pattern '{}': {}", pattern, e))
|
let glob = Glob::new(pattern).map_err(|e| {
|
||||||
})?;
|
std::io::Error::other(format!("invalid glob pattern '{}': {}", pattern, e))
|
||||||
builder.add(glob);
|
})?;
|
||||||
}
|
builder.add(glob);
|
||||||
Some(builder.build().map_err(|e| {
|
}
|
||||||
std::io::Error::other(format!("failed to build glob set: {}", e))
|
Some(builder.build().map_err(|e| {
|
||||||
})?)
|
std::io::Error::other(format!("failed to build glob set: {}", e))
|
||||||
};
|
})?)
|
||||||
|
};
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
config,
|
config,
|
||||||
@@ -589,18 +590,18 @@ fn looks_binary(content: &str) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Tool executor for multiple application source code browsers.
|
/// Tool executor for multiple application source code browsers.
|
||||||
pub struct AppCodeTools {
|
pub struct RepoCodeTools {
|
||||||
apps: Vec<AppCode>,
|
apps: Vec<RepoCode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppCodeTools {
|
impl RepoCodeTools {
|
||||||
/// Create a new AppCodeTools instance.
|
/// Create a new RepoCodeTools instance.
|
||||||
pub fn new(apps: Vec<AppCode>) -> Self {
|
pub fn new(apps: Vec<RepoCode>) -> Self {
|
||||||
Self { apps }
|
Self { apps }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Find an app by name.
|
/// Find an app by name.
|
||||||
fn find_app(&self, name: &str) -> Option<&AppCode> {
|
fn find_app(&self, name: &str) -> Option<&RepoCode> {
|
||||||
self.apps.iter().find(|app| app.name() == name)
|
self.apps.iter().find(|app| app.name() == name)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -644,7 +645,7 @@ struct SearchInput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl ToolExecutor for AppCodeTools {
|
impl ToolExecutor for RepoCodeTools {
|
||||||
fn tools(&self) -> Vec<Tool> {
|
fn tools(&self) -> Vec<Tool> {
|
||||||
vec![
|
vec![
|
||||||
Tool {
|
Tool {
|
||||||
+83
-29
@@ -1,9 +1,9 @@
|
|||||||
//! Integration tests for signal-gateway-app-code.
|
//! Integration tests for signal-gateway-repo-code.
|
||||||
//!
|
//!
|
||||||
//! These tests exercise the GitHub tarball download and file browsing functionality
|
//! These tests exercise the GitHub tarball download and file browsing functionality
|
||||||
//! against a real public repository at a pinned commit.
|
//! against a real public repository at a pinned commit.
|
||||||
|
|
||||||
use signal_gateway_app_code::{AppCode, AppCodeConfig, GitHubRepo, ShaCallback};
|
use signal_gateway_repo_code::{GitHubRepo, RepoCode, RepoCodeConfig, ShaCallback};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Test against cbeck88/ver-stub-rs at a known commit.
|
/// Test against cbeck88/ver-stub-rs at a known commit.
|
||||||
@@ -12,12 +12,12 @@ const TEST_OWNER: &str = "cbeck88";
|
|||||||
const TEST_REPO: &str = "ver-stub-rs";
|
const TEST_REPO: &str = "ver-stub-rs";
|
||||||
const TEST_SHA: &str = "79b98e25f27ae4f5dd73a5a3d8f37dad655a57e8";
|
const TEST_SHA: &str = "79b98e25f27ae4f5dd73a5a3d8f37dad655a57e8";
|
||||||
|
|
||||||
fn create_test_app_code() -> AppCode {
|
fn create_test_app_code() -> RepoCode {
|
||||||
create_test_app_code_with_glob(vec![])
|
create_test_app_code_with_glob(vec![])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_test_app_code_with_glob(glob: Vec<String>) -> AppCode {
|
fn create_test_app_code_with_glob(glob: Vec<String>) -> RepoCode {
|
||||||
let config = AppCodeConfig {
|
let config = RepoCodeConfig {
|
||||||
name: "test-app".to_string(),
|
name: "test-app".to_string(),
|
||||||
github: GitHubRepo {
|
github: GitHubRepo {
|
||||||
owner: TEST_OWNER.to_string(),
|
owner: TEST_OWNER.to_string(),
|
||||||
@@ -34,7 +34,7 @@ fn create_test_app_code_with_glob(glob: Vec<String>) -> AppCode {
|
|||||||
Box::pin(async move { Ok(sha) })
|
Box::pin(async move { Ok(sha) })
|
||||||
});
|
});
|
||||||
|
|
||||||
AppCode::new(config, sha_callback).expect("Failed to create AppCode")
|
RepoCode::new(config, sha_callback).expect("Failed to create RepoCode")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -46,8 +46,14 @@ async fn test_ls_root() {
|
|||||||
// Verify expected top-level entries exist
|
// Verify expected top-level entries exist
|
||||||
assert!(result.contains("Cargo.toml"), "Should contain Cargo.toml");
|
assert!(result.contains("Cargo.toml"), "Should contain Cargo.toml");
|
||||||
assert!(result.contains("README.md"), "Should contain README.md");
|
assert!(result.contains("README.md"), "Should contain README.md");
|
||||||
assert!(result.contains("ver-stub/"), "Should contain ver-stub/ directory");
|
assert!(
|
||||||
assert!(result.contains("ver-stub-build/"), "Should contain ver-stub-build/ directory");
|
result.contains("ver-stub/"),
|
||||||
|
"Should contain ver-stub/ directory"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
result.contains("ver-stub-build/"),
|
||||||
|
"Should contain ver-stub-build/ directory"
|
||||||
|
);
|
||||||
assert!(result.contains("tests.sh"), "Should contain tests.sh");
|
assert!(result.contains("tests.sh"), "Should contain tests.sh");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,30 +75,48 @@ async fn test_find_rust_files() {
|
|||||||
let result = app.find(Some("*.rs")).await.expect("find failed");
|
let result = app.find(Some("*.rs")).await.expect("find failed");
|
||||||
|
|
||||||
// Should find Rust source files
|
// Should find Rust source files
|
||||||
assert!(result.contains("ver-stub/src/lib.rs"), "Should find ver-stub/src/lib.rs");
|
assert!(
|
||||||
assert!(result.contains("ver-stub-build/src/lib.rs"), "Should find ver-stub-build/src/lib.rs");
|
result.contains("ver-stub/src/lib.rs"),
|
||||||
|
"Should find ver-stub/src/lib.rs"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
result.contains("ver-stub-build/src/lib.rs"),
|
||||||
|
"Should find ver-stub-build/src/lib.rs"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_find_with_path_pattern() {
|
async fn test_find_with_path_pattern() {
|
||||||
let app = create_test_app_code();
|
let app = create_test_app_code();
|
||||||
|
|
||||||
let result = app.find(Some("ver-stub-build/src/*.rs")).await.expect("find failed");
|
let result = app
|
||||||
|
.find(Some("ver-stub-build/src/*.rs"))
|
||||||
|
.await
|
||||||
|
.expect("find failed");
|
||||||
|
|
||||||
// Should find files in ver-stub-build/src/
|
// Should find files in ver-stub-build/src/
|
||||||
assert!(result.contains("ver-stub-build/src/lib.rs"), "Should find lib.rs");
|
assert!(
|
||||||
|
result.contains("ver-stub-build/src/lib.rs"),
|
||||||
|
"Should find lib.rs"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_read_cargo_toml() {
|
async fn test_read_cargo_toml() {
|
||||||
let app = create_test_app_code();
|
let app = create_test_app_code();
|
||||||
|
|
||||||
let result = app.read("Cargo.toml", None, None).await.expect("read failed");
|
let result = app
|
||||||
|
.read("Cargo.toml", None, None)
|
||||||
|
.await
|
||||||
|
.expect("read failed");
|
||||||
|
|
||||||
// Verify content matches what we know is in the file
|
// Verify content matches what we know is in the file
|
||||||
assert!(result.contains("[workspace]"), "Should contain [workspace]");
|
assert!(result.contains("[workspace]"), "Should contain [workspace]");
|
||||||
assert!(result.contains("ver-stub"), "Should contain ver-stub");
|
assert!(result.contains("ver-stub"), "Should contain ver-stub");
|
||||||
assert!(result.contains("ver-stub-build"), "Should contain ver-stub-build");
|
assert!(
|
||||||
|
result.contains("ver-stub-build"),
|
||||||
|
"Should contain ver-stub-build"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -100,14 +124,20 @@ async fn test_read_with_line_range() {
|
|||||||
let app = create_test_app_code();
|
let app = create_test_app_code();
|
||||||
|
|
||||||
// Read just the first 5 lines
|
// Read just the first 5 lines
|
||||||
let result = app.read("Cargo.toml", Some(1), Some(5)).await.expect("read failed");
|
let result = app
|
||||||
|
.read("Cargo.toml", Some(1), Some(5))
|
||||||
|
.await
|
||||||
|
.expect("read failed");
|
||||||
|
|
||||||
// Should only have 5 lines
|
// Should only have 5 lines
|
||||||
let line_count = result.lines().count();
|
let line_count = result.lines().count();
|
||||||
assert_eq!(line_count, 5, "Should have exactly 5 lines");
|
assert_eq!(line_count, 5, "Should have exactly 5 lines");
|
||||||
|
|
||||||
// First line should be [workspace]
|
// First line should be [workspace]
|
||||||
assert!(result.contains("[workspace]"), "First lines should contain [workspace]");
|
assert!(
|
||||||
|
result.contains("[workspace]"),
|
||||||
|
"First lines should contain [workspace]"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -127,22 +157,37 @@ async fn test_read_nonexistent_file() {
|
|||||||
async fn test_search_simple() {
|
async fn test_search_simple() {
|
||||||
let app = create_test_app_code();
|
let app = create_test_app_code();
|
||||||
|
|
||||||
let result = app.search("workspace", 0, None).await.expect("search failed");
|
let result = app
|
||||||
|
.search("workspace", 0, None)
|
||||||
|
.await
|
||||||
|
.expect("search failed");
|
||||||
|
|
||||||
// Should find "workspace" in Cargo.toml
|
// Should find "workspace" in Cargo.toml
|
||||||
assert!(result.contains("Cargo.toml"), "Should find match in Cargo.toml");
|
assert!(
|
||||||
|
result.contains("Cargo.toml"),
|
||||||
|
"Should find match in Cargo.toml"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_search_with_context() {
|
async fn test_search_with_context() {
|
||||||
let app = create_test_app_code();
|
let app = create_test_app_code();
|
||||||
|
|
||||||
let result = app.search("resolver", 2, None).await.expect("search failed");
|
let result = app
|
||||||
|
.search("resolver", 2, None)
|
||||||
|
.await
|
||||||
|
.expect("search failed");
|
||||||
|
|
||||||
// Should have context lines around the match
|
// Should have context lines around the match
|
||||||
assert!(result.contains("Cargo.toml"), "Should find match in Cargo.toml");
|
assert!(
|
||||||
|
result.contains("Cargo.toml"),
|
||||||
|
"Should find match in Cargo.toml"
|
||||||
|
);
|
||||||
// With context, should see surrounding lines
|
// With context, should see surrounding lines
|
||||||
assert!(result.contains("[workspace]"), "Should show context including [workspace]");
|
assert!(
|
||||||
|
result.contains("[workspace]"),
|
||||||
|
"Should show context including [workspace]"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -191,8 +236,14 @@ async fn test_glob_filter_rust_files_only() {
|
|||||||
assert!(result.contains(".rs"), "Should contain .rs files");
|
assert!(result.contains(".rs"), "Should contain .rs files");
|
||||||
|
|
||||||
// Should NOT find non-Rust files
|
// Should NOT find non-Rust files
|
||||||
assert!(!result.contains("Cargo.toml"), "Should not contain Cargo.toml");
|
assert!(
|
||||||
assert!(!result.contains("README.md"), "Should not contain README.md");
|
!result.contains("Cargo.toml"),
|
||||||
|
"Should not contain Cargo.toml"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
!result.contains("README.md"),
|
||||||
|
"Should not contain README.md"
|
||||||
|
);
|
||||||
assert!(!result.contains("tests.sh"), "Should not contain tests.sh");
|
assert!(!result.contains("tests.sh"), "Should not contain tests.sh");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,16 +265,16 @@ async fn test_glob_filter_specific_directory() {
|
|||||||
!result.contains("ver-stub-build/"),
|
!result.contains("ver-stub-build/"),
|
||||||
"Should not contain ver-stub-build files"
|
"Should not contain ver-stub-build files"
|
||||||
);
|
);
|
||||||
assert!(!result.contains("Cargo.toml"), "Should not contain root Cargo.toml");
|
assert!(
|
||||||
|
!result.contains("Cargo.toml"),
|
||||||
|
"Should not contain root Cargo.toml"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_glob_filter_multiple_patterns() {
|
async fn test_glob_filter_multiple_patterns() {
|
||||||
// Include both Cargo.toml files and shell scripts
|
// Include both Cargo.toml files and shell scripts
|
||||||
let app = create_test_app_code_with_glob(vec![
|
let app = create_test_app_code_with_glob(vec!["**/Cargo.toml".to_string(), "*.sh".to_string()]);
|
||||||
"**/Cargo.toml".to_string(),
|
|
||||||
"*.sh".to_string(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
let result = app.find(Some("*")).await.expect("find failed");
|
let result = app.find(Some("*")).await.expect("find failed");
|
||||||
|
|
||||||
@@ -234,7 +285,10 @@ async fn test_glob_filter_multiple_patterns() {
|
|||||||
assert!(result.contains("tests.sh"), "Should contain tests.sh");
|
assert!(result.contains("tests.sh"), "Should contain tests.sh");
|
||||||
|
|
||||||
// Should NOT find other files
|
// Should NOT find other files
|
||||||
assert!(!result.contains("README.md"), "Should not contain README.md");
|
assert!(
|
||||||
|
!result.contains("README.md"),
|
||||||
|
"Should not contain README.md"
|
||||||
|
);
|
||||||
assert!(!result.contains(".rs"), "Should not contain .rs files");
|
assert!(!result.contains(".rs"), "Should not contain .rs files");
|
||||||
}
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user