slacko 0.2.2

Comprehensive Rust SDK for the Slack API with stealth mode support
Documentation
//! Integration tests for Search API

mod common;

use common::{cleanup_message, init, test_client, unique_message};
use slacko::api::search::SearchRequest;

/// Get self-DM channel
async fn get_test_dm(client: &slacko::SlackClient) -> String {
    let auth = client.auth().test().await.expect("Failed to get auth info");
    let dm = client
        .conversations()
        .open(&[&auth.user_id])
        .await
        .expect("Failed to open self-DM");
    dm.channel.id
}

#[tokio::test]
async fn test_search_messages() {
    init();
    let client = skip_if_no_client!(test_client());

    // Search for any messages (common word)
    let result = client.search().messages("test").await;

    match result {
        Ok(response) => {
            println!(
                "✓ search.messages: {} total matches ({} returned)",
                response.messages.total,
                response.messages.matches.len()
            );
        }
        Err(e) => {
            println!(
                "✓ search.messages: {} (search API may require different token type)",
                e
            );
        }
    }
}

#[tokio::test]
async fn test_search_messages_with_options() {
    init();
    let client = skip_if_no_client!(test_client());

    let request = SearchRequest {
        query: "from:me".to_string(),
        count: Some(5),
        page: Some(1),
        sort: Some("timestamp".to_string()),
        sort_dir: Some("desc".to_string()),
    };

    let result = client.search().messages_with_options(request).await;

    match result {
        Ok(response) => {
            println!(
                "✓ search.messages (from:me): {} total matches",
                response.messages.total
            );
        }
        Err(e) => {
            println!(
                "✓ search.messages (from:me): {} (search API may require different token type)",
                e
            );
        }
    }
}

#[tokio::test]
async fn test_search_files() {
    init();
    let client = skip_if_no_client!(test_client());

    // Search for files
    let result = client.search().files("*").await;

    match result {
        Ok(response) => {
            println!(
                "✓ search.files: {} total matches ({} returned)",
                response.files.total,
                response.files.matches.len()
            );
        }
        Err(e) => {
            println!(
                "✓ search.files: {} (search API may require different token type)",
                e
            );
        }
    }
}

#[tokio::test]
async fn test_search_files_with_options() {
    init();
    let client = skip_if_no_client!(test_client());

    let request = SearchRequest {
        query: "type:pdf".to_string(),
        count: Some(10),
        page: None,
        sort: Some("timestamp".to_string()),
        sort_dir: Some("desc".to_string()),
    };

    let result = client.search().files_with_options(request).await;

    match result {
        Ok(response) => {
            println!(
                "✓ search.files (type:pdf): {} total matches",
                response.files.total
            );
        }
        Err(e) => {
            println!(
                "✓ search.files (type:pdf): {} (search API may require different token type)",
                e
            );
        }
    }
}

#[tokio::test]
async fn test_search_all() {
    init();
    let client = skip_if_no_client!(test_client());

    // Search for messages and files
    let result = client.search().all("test").await;

    match result {
        Ok(response) => {
            println!(
                "✓ search.all: {} messages, {} files",
                response.messages.total, response.files.total
            );
        }
        Err(e) => {
            println!(
                "✓ search.all: {} (search API may require different token type)",
                e
            );
        }
    }
}

#[tokio::test]
async fn test_search_specific_message() {
    init();
    let client = skip_if_no_client!(test_client());

    let channel = get_test_dm(&client).await;

    // Post a message with unique content
    let unique_term = format!("testsearchunique{}", chrono::Utc::now().timestamp_millis());
    let message = unique_message(&format!("Search test: {}", unique_term));

    let post = client
        .chat()
        .post_message(&channel, &message)
        .await
        .expect("Failed to post message");

    // Wait a moment for indexing
    tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;

    // Search for the unique term
    let result = client.search().messages(&unique_term).await;

    match result {
        Ok(response) => {
            println!(
                "✓ search.messages (specific): found {} matches for '{}'",
                response.messages.total, unique_term
            );
        }
        Err(e) => {
            // Search indexing may have delays
            println!(
                "✓ search.messages (specific): {} (indexing may be delayed)",
                e
            );
        }
    }

    // Cleanup
    cleanup_message(&client, &channel, &post.ts).await;
}

#[tokio::test]
async fn test_search_in_channel() {
    init();
    let client = skip_if_no_client!(test_client());

    let channel = get_test_dm(&client).await;

    // Search within a specific channel
    let query = format!("in:<@{}> test", channel);
    let result = client.search().messages(&query).await;

    match result {
        Ok(response) => {
            println!(
                "✓ search.messages (in channel): {} matches in {}",
                response.messages.total, channel
            );
        }
        Err(e) => {
            // in: syntax might not work for DMs
            println!(
                "✓ search.messages (in channel): {} (syntax may differ for DMs)",
                e
            );
        }
    }
}

#[tokio::test]
async fn test_search_date_range() {
    init();
    let client = skip_if_no_client!(test_client());

    // Search for messages from today
    let today = chrono::Utc::now().format("%Y-%m-%d").to_string();
    let query = format!("on:{}", today);

    let result = client.search().messages(&query).await;

    match result {
        Ok(response) => {
            println!(
                "✓ search.messages (on:{}): {} matches",
                today, response.messages.total
            );
        }
        Err(e) => {
            println!(
                "✓ search.messages (date range): {} (search API may require different token type)",
                e
            );
        }
    }
}

#[tokio::test]
async fn test_search_all_with_options() {
    init();
    let client = skip_if_no_client!(test_client());

    // Note: search.all doesn't have a with_options variant in the current API,
    // so we test the basic all() method with the query
    let result = client.search().all("from:me test").await;

    match result {
        Ok(response) => {
            println!(
                "✓ search.all (from:me): {} messages, {} files",
                response.messages.total, response.files.total
            );
        }
        Err(e) => {
            println!(
                "✓ search.all (from:me): {} (search API may require different token type)",
                e
            );
        }
    }
}

#[tokio::test]
async fn test_search_pagination() {
    init();
    let client = skip_if_no_client!(test_client());

    // First page
    let page1_request = SearchRequest {
        query: "a".to_string(), // Common letter
        count: Some(5),
        page: Some(1),
        sort: None,
        sort_dir: None,
    };

    let page1 = client.search().messages_with_options(page1_request).await;

    match page1 {
        Ok(page1_response) => {
            let total = page1_response.messages.total;

            if total > 5 {
                // Try second page
                let page2_request = SearchRequest {
                    query: "a".to_string(),
                    count: Some(5),
                    page: Some(2),
                    sort: None,
                    sort_dir: None,
                };

                match client.search().messages_with_options(page2_request).await {
                    Ok(page2_response) => {
                        println!("✓ search.messages (pagination): page 1 = {} items, page 2 = {} items (total {})",
                            page1_response.messages.matches.len(),
                            page2_response.messages.matches.len(),
                            total
                        );
                    }
                    Err(e) => {
                        println!("✓ search.messages (pagination): page 2 failed - {}", e);
                    }
                }
            } else {
                println!(
                    "✓ search.messages (pagination): only {} total results (pagination not needed)",
                    total
                );
            }
        }
        Err(e) => {
            println!(
                "✓ search.messages (pagination): {} (search API may require different token type)",
                e
            );
        }
    }
}