Some checks failed
Test Suite / unit-tests (3.11) (push) Has been cancelled
Test Suite / unit-tests (3.12) (push) Has been cancelled
Test Suite / integration-tests (push) Has been cancelled
Test Suite / e2e-tests (push) Has been cancelled
Test Suite / performance-tests (push) Has been cancelled
Test Suite / code-quality (push) Has been cancelled
Test Suite / security-scan (push) Has been cancelled
Test Suite / test-summary (push) Has been cancelled
Separate capability-specific tests from core system tests to establish clear test organization and separation of concerns. ## Test Reorganization: - **markitect-content tests**: Moved 6 tests to capabilities/markitect-content/tests/ - **markitect-finance tests**: Moved 7 tests to markitect/finance/tests/ - **markitect-query tests**: Moved 1 test to markitect/query_paradigms/tests/ - **markitect-graphql tests**: Moved 2 tests to markitect/graphql/tests/ - **markitect-plugins tests**: Moved 2 tests to markitect/plugins/tests/ ## Makefile Updates: - **make test**: Excludes capability tests, runs only core system tests - **make test-capabilities**: Runs all capability tests - **make test-capability-***: Individual capability test targets - Updated all test targets (test-red, test-green, test-ultra-fast, test-perf) - Added capability test targets to help documentation ## Benefits: - Clear separation between core system tests and capability-specific tests - Faster core test execution (capability tests not run by default) - Individual capability testing for focused development - Supports future capability extraction workflow - Maintains capability test independence Test verification: - Core tests: 1291 tests (capability tests excluded) - Finance capability: 143 tests working independently - Content capability: 79 tests working independently 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
627 lines
22 KiB
Python
627 lines
22 KiB
Python
"""
|
|
Tests for Issue #83: Full text search functionality.
|
|
|
|
Tests the FTS5-based full text search plugin including indexing,
|
|
querying, and CLI integration.
|
|
"""
|
|
|
|
import pytest
|
|
import tempfile
|
|
import sqlite3
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
from unittest.mock import patch, MagicMock
|
|
|
|
from markitect.plugins.builtin.search import FTSSearchPlugin, SearchIndexer, QueryParser
|
|
from markitect.database import DatabaseManager
|
|
|
|
|
|
class TestSearchIndexer:
|
|
"""Test the search indexing functionality."""
|
|
|
|
@pytest.fixture
|
|
def temp_db_path(self):
|
|
"""Create a temporary database for testing."""
|
|
with tempfile.NamedTemporaryFile(suffix='.db', delete=False) as f:
|
|
db_path = f.name
|
|
|
|
# Initialize database with test data
|
|
db_manager = DatabaseManager(db_path)
|
|
db_manager.initialize_database()
|
|
|
|
# Add test markdown files
|
|
db_manager.store_markdown_file("test1.md", "# Test Document\n\nThis is a test document about API development.")
|
|
db_manager.store_markdown_file("test2.md", "# Another Document\n\nGraphQL interface documentation.")
|
|
db_manager.store_markdown_file("test3.md", "---\ntitle: Blog Post\n---\n# My Blog\n\nContent about technology.")
|
|
|
|
# Add test schemas
|
|
schema1 = {"type": "object", "title": "User Schema", "description": "Schema for user objects"}
|
|
schema2 = {"type": "object", "title": "Product Schema", "description": "E-commerce product definition"}
|
|
db_manager.store_schema_file("user.json", json.dumps(schema1))
|
|
db_manager.store_schema_file("product.json", json.dumps(schema2))
|
|
|
|
yield db_path
|
|
|
|
# Cleanup
|
|
os.unlink(db_path)
|
|
|
|
def test_check_fts_availability(self, temp_db_path):
|
|
"""Test checking FTS5 availability."""
|
|
indexer = SearchIndexer()
|
|
available = indexer.check_fts_availability(temp_db_path)
|
|
|
|
# FTS5 should be available in most modern SQLite installations
|
|
assert isinstance(available, bool)
|
|
|
|
def test_initialize_fts_tables(self, temp_db_path):
|
|
"""Test FTS5 table initialization."""
|
|
indexer = SearchIndexer()
|
|
indexer.initialize_fts_tables(temp_db_path)
|
|
|
|
# Check that FTS tables were created
|
|
conn = sqlite3.connect(temp_db_path)
|
|
cursor = conn.cursor()
|
|
|
|
cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'fts_%'")
|
|
fts_tables = [row[0] for row in cursor.fetchall()]
|
|
|
|
if indexer.check_fts_availability(temp_db_path):
|
|
assert 'fts_files' in fts_tables
|
|
assert 'fts_schemas' in fts_tables
|
|
else:
|
|
# If FTS5 not available, should have status table
|
|
cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='fts_status'")
|
|
assert cursor.fetchone() is not None
|
|
|
|
conn.close()
|
|
|
|
def test_rebuild_index(self, temp_db_path):
|
|
"""Test rebuilding search indexes."""
|
|
indexer = SearchIndexer()
|
|
indexer.initialize_fts_tables(temp_db_path)
|
|
|
|
stats = indexer.rebuild_index(temp_db_path)
|
|
|
|
assert 'files_indexed' in stats
|
|
assert 'schemas_indexed' in stats
|
|
|
|
if indexer.check_fts_availability(temp_db_path):
|
|
# If FTS5 is available, should index successfully
|
|
assert stats['files_indexed'] >= 0
|
|
assert stats['schemas_indexed'] >= 0
|
|
else:
|
|
# If FTS5 not available, might have error
|
|
pass # Just check stats exist
|
|
|
|
def test_get_index_info(self, temp_db_path):
|
|
"""Test getting index information."""
|
|
indexer = SearchIndexer()
|
|
indexer.initialize_fts_tables(temp_db_path)
|
|
indexer.rebuild_index(temp_db_path)
|
|
|
|
info = indexer.get_index_info(temp_db_path)
|
|
|
|
assert 'fts_enabled' in info
|
|
if info['fts_enabled']:
|
|
assert 'fts_tables' in info
|
|
assert 'fts_files_count' in info
|
|
assert 'fts_schemas_count' in info
|
|
|
|
|
|
class TestQueryParser:
|
|
"""Test query parsing functionality."""
|
|
|
|
def test_parse_simple_query(self):
|
|
"""Test parsing simple queries."""
|
|
parser = QueryParser()
|
|
|
|
# Simple word
|
|
result = parser.parse_query("test")
|
|
assert "test*" in result
|
|
|
|
# Multiple words
|
|
result = parser.parse_query("test document")
|
|
assert "test*" in result
|
|
assert "document*" in result
|
|
assert "AND" in result
|
|
|
|
def test_parse_phrase_query(self):
|
|
"""Test parsing phrase queries."""
|
|
parser = QueryParser()
|
|
|
|
result = parser.parse_query('"exact phrase"')
|
|
assert '"exact phrase"' in result
|
|
|
|
def test_parse_boolean_operators(self):
|
|
"""Test parsing boolean operators."""
|
|
parser = QueryParser()
|
|
|
|
# AND operator - if already FTS5, should be preserved
|
|
result = parser.parse_query("test AND document")
|
|
assert "test" in result
|
|
assert "AND" in result
|
|
assert "document" in result
|
|
|
|
# OR operator - if already FTS5, should be preserved
|
|
result = parser.parse_query("test OR document")
|
|
assert "test" in result
|
|
assert "OR" in result
|
|
assert "document" in result
|
|
|
|
# NOT operator - if already FTS5, should be preserved
|
|
result = parser.parse_query("test NOT document")
|
|
assert "test" in result
|
|
assert "NOT" in result
|
|
|
|
def test_validate_query(self):
|
|
"""Test query validation."""
|
|
parser = QueryParser()
|
|
|
|
# Valid queries
|
|
valid, error = parser.validate_query("test")
|
|
assert valid
|
|
assert error is None
|
|
|
|
valid, error = parser.validate_query('"exact phrase"')
|
|
assert valid
|
|
assert error is None
|
|
|
|
# Invalid queries
|
|
valid, error = parser.validate_query('unmatched "quote')
|
|
assert not valid
|
|
assert "quotes" in error
|
|
|
|
valid, error = parser.validate_query("test (unmatched")
|
|
assert not valid
|
|
assert "parentheses" in error
|
|
|
|
def test_get_query_terms(self):
|
|
"""Test extracting terms from queries."""
|
|
parser = QueryParser()
|
|
|
|
terms = parser.get_query_terms("test document AND api")
|
|
assert "test" in terms
|
|
assert "document" in terms
|
|
assert "api" in terms
|
|
assert "AND" not in terms # Operators should be excluded
|
|
|
|
def test_build_column_query(self):
|
|
"""Test building column-specific queries."""
|
|
parser = QueryParser()
|
|
|
|
result = parser.build_column_query("test", ["title", "content"])
|
|
assert "title:" in result
|
|
assert "content:" in result
|
|
assert "OR" in result
|
|
|
|
|
|
class TestFTSSearchPlugin:
|
|
"""Test the main FTS search plugin."""
|
|
|
|
@pytest.fixture
|
|
def temp_db_path(self):
|
|
"""Create a temporary database with test data."""
|
|
with tempfile.NamedTemporaryFile(suffix='.db', delete=False) as f:
|
|
db_path = f.name
|
|
|
|
# Initialize database with test data
|
|
db_manager = DatabaseManager(db_path)
|
|
db_manager.initialize_database()
|
|
|
|
# Add test markdown files
|
|
db_manager.store_markdown_file("api-guide.md", "# API Guide\n\nComprehensive API development guide with examples.")
|
|
db_manager.store_markdown_file("tutorial.md", "# GraphQL Tutorial\n\nLearn GraphQL basics and advanced concepts.")
|
|
db_manager.store_markdown_file("readme.md", "---\ntitle: Project README\ntags: [documentation, guide]\n---\n# Project\n\nProject documentation and setup guide.")
|
|
|
|
# Add test schemas
|
|
schema1 = {"type": "object", "title": "API Schema", "description": "REST API response schema", "properties": {"data": {"type": "object"}}}
|
|
schema2 = {"type": "object", "title": "User Schema", "description": "User profile schema", "properties": {"name": {"type": "string"}}}
|
|
db_manager.store_schema_file("api-schema.json", json.dumps(schema1))
|
|
db_manager.store_schema_file("user-schema.json", json.dumps(schema2))
|
|
|
|
yield db_path
|
|
|
|
# Cleanup
|
|
os.unlink(db_path)
|
|
|
|
def test_plugin_metadata(self):
|
|
"""Test plugin metadata."""
|
|
plugin = FTSSearchPlugin()
|
|
metadata = plugin.metadata
|
|
|
|
assert metadata.name == "fts_search"
|
|
assert metadata.version == "1.0.0"
|
|
assert "full text search" in metadata.description.lower()
|
|
|
|
def test_initialize_plugin(self, temp_db_path):
|
|
"""Test plugin initialization."""
|
|
plugin = FTSSearchPlugin()
|
|
plugin.initialize(temp_db_path)
|
|
|
|
# Check that FTS tables exist (if FTS5 is available)
|
|
stats = plugin.get_search_stats(temp_db_path)
|
|
assert 'fts_enabled' in stats
|
|
|
|
def test_search_files_only(self, temp_db_path):
|
|
"""Test searching only in files."""
|
|
plugin = FTSSearchPlugin()
|
|
plugin.initialize(temp_db_path)
|
|
plugin.rebuild_index(temp_db_path)
|
|
|
|
results = plugin.search(temp_db_path, "API", content_type="files", limit=10)
|
|
|
|
# Should find files containing "API"
|
|
assert isinstance(results, list)
|
|
for result in results:
|
|
assert result['type'] == 'file'
|
|
assert 'file' in result
|
|
assert 'score' in result
|
|
|
|
def test_search_schemas_only(self, temp_db_path):
|
|
"""Test searching only in schemas."""
|
|
plugin = FTSSearchPlugin()
|
|
plugin.initialize(temp_db_path)
|
|
plugin.rebuild_index(temp_db_path)
|
|
|
|
results = plugin.search(temp_db_path, "schema", content_type="schemas", limit=10)
|
|
|
|
# Should find schemas
|
|
assert isinstance(results, list)
|
|
for result in results:
|
|
assert result['type'] == 'schema'
|
|
assert 'schema' in result
|
|
assert 'score' in result
|
|
|
|
def test_search_all_content(self, temp_db_path):
|
|
"""Test searching all content types."""
|
|
plugin = FTSSearchPlugin()
|
|
plugin.initialize(temp_db_path)
|
|
plugin.rebuild_index(temp_db_path)
|
|
|
|
results = plugin.search(temp_db_path, "guide", content_type="all", limit=10)
|
|
|
|
# Should find both files and schemas (or empty list if FTS5 unavailable)
|
|
assert isinstance(results, list)
|
|
|
|
# If results found, should be properly formatted and sorted
|
|
if results:
|
|
# Results should be sorted by score
|
|
scores = [result.get('score', 0) for result in results]
|
|
assert scores == sorted(scores, reverse=True)
|
|
|
|
# Check result structure
|
|
for result in results:
|
|
assert 'type' in result
|
|
assert 'score' in result
|
|
|
|
def test_search_with_pagination(self, temp_db_path):
|
|
"""Test search with pagination."""
|
|
plugin = FTSSearchPlugin()
|
|
plugin.initialize(temp_db_path)
|
|
plugin.rebuild_index(temp_db_path)
|
|
|
|
# Get first page
|
|
results1 = plugin.search(temp_db_path, "guide", limit=1, offset=0)
|
|
|
|
# Get second page
|
|
results2 = plugin.search(temp_db_path, "guide", limit=1, offset=1)
|
|
|
|
# Results should be different (if there are enough results)
|
|
if len(results1) > 0 and len(results2) > 0:
|
|
assert results1[0] != results2[0]
|
|
|
|
def test_fallback_search(self, temp_db_path):
|
|
"""Test fallback search when FTS5 fails."""
|
|
plugin = FTSSearchPlugin()
|
|
plugin.initialize(temp_db_path)
|
|
|
|
# Force fallback by using invalid FTS5 query syntax with mock
|
|
with patch.object(plugin, '_search_files', side_effect=Exception("FTS5 error")):
|
|
with patch.object(plugin, '_search_schemas', side_effect=Exception("FTS5 error")):
|
|
results = plugin.search(temp_db_path, "API", content_type="all", limit=10)
|
|
|
|
# Should still return results via fallback
|
|
assert isinstance(results, list)
|
|
|
|
def test_get_search_stats(self, temp_db_path):
|
|
"""Test getting search statistics."""
|
|
plugin = FTSSearchPlugin()
|
|
plugin.initialize(temp_db_path)
|
|
|
|
stats = plugin.get_search_stats(temp_db_path)
|
|
|
|
assert 'fts_enabled' in stats
|
|
assert 'fts_tables' in stats
|
|
|
|
|
|
class TestSearchCLI:
|
|
"""Test search CLI commands."""
|
|
|
|
@pytest.fixture
|
|
def temp_db_path(self):
|
|
"""Create a temporary database with test data."""
|
|
with tempfile.NamedTemporaryFile(suffix='.db', delete=False) as f:
|
|
db_path = f.name
|
|
|
|
# Initialize database with test data
|
|
db_manager = DatabaseManager(db_path)
|
|
db_manager.initialize_database()
|
|
|
|
# Add test data
|
|
db_manager.store_markdown_file("test.md", "# Test\n\nThis is a test document.")
|
|
|
|
yield db_path
|
|
|
|
# Cleanup
|
|
os.unlink(db_path)
|
|
|
|
def test_search_init_command(self, temp_db_path):
|
|
"""Test the search init CLI command."""
|
|
from click.testing import CliRunner
|
|
from markitect.cli import cli
|
|
|
|
runner = CliRunner()
|
|
|
|
with patch('markitect.cli.get_database_path', return_value=temp_db_path):
|
|
result = runner.invoke(cli, ['search', 'init'])
|
|
|
|
assert result.exit_code == 0
|
|
assert "Search indexes initialized" in result.output or "Search plugin not available" in result.output
|
|
|
|
def test_search_query_command(self, temp_db_path):
|
|
"""Test the search query CLI command."""
|
|
from click.testing import CliRunner
|
|
from markitect.cli import cli
|
|
|
|
runner = CliRunner()
|
|
|
|
with patch('markitect.cli.get_database_path', return_value=temp_db_path):
|
|
# Initialize search first
|
|
runner.invoke(cli, ['search', 'init'])
|
|
|
|
# Perform search
|
|
result = runner.invoke(cli, ['search', 'query', 'test'])
|
|
|
|
assert result.exit_code == 0
|
|
# Should either show results or indicate no search plugin
|
|
assert "results" in result.output or "Search plugin not available" in result.output
|
|
|
|
def test_search_status_command(self, temp_db_path):
|
|
"""Test the search status CLI command."""
|
|
from click.testing import CliRunner
|
|
from markitect.cli import cli
|
|
|
|
runner = CliRunner()
|
|
|
|
with patch('markitect.cli.get_database_path', return_value=temp_db_path):
|
|
result = runner.invoke(cli, ['search', 'status'])
|
|
|
|
assert result.exit_code == 0
|
|
assert "Search Index Status" in result.output or "Search plugin not available" in result.output
|
|
|
|
def test_search_rebuild_command(self, temp_db_path):
|
|
"""Test the search rebuild CLI command."""
|
|
from click.testing import CliRunner
|
|
from markitect.cli import cli
|
|
|
|
runner = CliRunner()
|
|
|
|
with patch('markitect.cli.get_database_path', return_value=temp_db_path):
|
|
# Initialize search first
|
|
runner.invoke(cli, ['search', 'init'])
|
|
|
|
# Rebuild indexes
|
|
result = runner.invoke(cli, ['search', 'rebuild'])
|
|
|
|
if result.exit_code != 0:
|
|
print(f"Command output: {result.output}")
|
|
print(f"Exception: {result.exception}")
|
|
|
|
# Should succeed or fail gracefully with plugin unavailable message or database error
|
|
acceptable_errors = [
|
|
"Search plugin not available",
|
|
"database disk image is malformed", # Can happen with concurrent access
|
|
"database is locked"
|
|
]
|
|
|
|
if result.exit_code == 0:
|
|
assert "Rebuilding search indexes" in result.output
|
|
else:
|
|
# Check if it's an acceptable error
|
|
assert any(error in result.output for error in acceptable_errors)
|
|
|
|
|
|
class TestSearchIntegration:
|
|
"""Integration tests for search functionality."""
|
|
|
|
@pytest.fixture
|
|
def populated_db_path(self):
|
|
"""Create a database with realistic test data."""
|
|
with tempfile.NamedTemporaryFile(suffix='.db', delete=False) as f:
|
|
db_path = f.name
|
|
|
|
db_manager = DatabaseManager(db_path)
|
|
db_manager.initialize_database()
|
|
|
|
# Add realistic markdown files
|
|
files = [
|
|
("api-documentation.md", """# API Documentation
|
|
|
|
## Authentication
|
|
The API uses Bearer token authentication. Include your token in the Authorization header.
|
|
|
|
## Endpoints
|
|
- GET /users - List all users
|
|
- POST /users - Create a new user
|
|
- GET /users/{id} - Get specific user
|
|
|
|
## Error Handling
|
|
All errors return JSON with error message and status code.
|
|
"""),
|
|
("graphql-guide.md", """---
|
|
title: GraphQL Complete Guide
|
|
tags: [graphql, api, tutorial]
|
|
author: Development Team
|
|
---
|
|
|
|
# GraphQL Complete Guide
|
|
|
|
GraphQL is a query language for APIs and a runtime for executing those queries.
|
|
|
|
## Benefits
|
|
- Single endpoint
|
|
- Type safety
|
|
- Efficient data fetching
|
|
- Strong introspection
|
|
|
|
## Schema Definition
|
|
Define your GraphQL schema using SDL (Schema Definition Language).
|
|
"""),
|
|
("project-readme.md", """# MarkiTect Project
|
|
|
|
MarkiTect is a comprehensive markdown content management and analysis system.
|
|
|
|
## Features
|
|
- Document indexing and storage
|
|
- Full text search capabilities
|
|
- GraphQL API interface
|
|
- Plugin system for extensibility
|
|
|
|
## Installation
|
|
1. Clone the repository
|
|
2. Install dependencies: pip install -r requirements.txt
|
|
3. Initialize database: markitect init
|
|
|
|
## Usage Examples
|
|
Search for content: markitect search query "API documentation"
|
|
""")
|
|
]
|
|
|
|
for filename, content in files:
|
|
db_manager.store_markdown_file(filename, content)
|
|
|
|
# Add realistic schemas
|
|
schemas = [
|
|
("user-schema.json", {
|
|
"type": "object",
|
|
"title": "User Schema",
|
|
"description": "Schema for user profile data in the API",
|
|
"properties": {
|
|
"id": {"type": "integer"},
|
|
"name": {"type": "string"},
|
|
"email": {"type": "string", "format": "email"},
|
|
"created_at": {"type": "string", "format": "date-time"}
|
|
},
|
|
"required": ["id", "name", "email"]
|
|
}),
|
|
("api-response-schema.json", {
|
|
"type": "object",
|
|
"title": "API Response Schema",
|
|
"description": "Standard API response format for all endpoints",
|
|
"properties": {
|
|
"data": {"type": "object"},
|
|
"success": {"type": "boolean"},
|
|
"message": {"type": "string"},
|
|
"errors": {"type": "array", "items": {"type": "string"}}
|
|
},
|
|
"required": ["success"]
|
|
})
|
|
]
|
|
|
|
for filename, schema in schemas:
|
|
db_manager.store_schema_file(filename, json.dumps(schema))
|
|
|
|
yield db_path
|
|
|
|
# Cleanup
|
|
os.unlink(db_path)
|
|
|
|
def test_end_to_end_search_workflow(self, populated_db_path):
|
|
"""Test complete search workflow from initialization to querying."""
|
|
plugin = FTSSearchPlugin()
|
|
|
|
# Initialize search
|
|
plugin.initialize(populated_db_path)
|
|
|
|
# Rebuild indexes
|
|
stats = plugin.rebuild_index(populated_db_path)
|
|
|
|
if plugin.indexer.check_fts_availability(populated_db_path):
|
|
# If FTS5 is available, should index files
|
|
assert stats['files_indexed'] >= 0
|
|
assert stats['schemas_indexed'] >= 0
|
|
else:
|
|
# If FTS5 not available, might be 0
|
|
pass
|
|
|
|
# Search for API-related content
|
|
results = plugin.search(populated_db_path, "API", content_type="all", limit=10)
|
|
|
|
# Results should be a list (may be empty if FTS5 not available)
|
|
assert isinstance(results, list)
|
|
|
|
# If we have results, verify they're properly formatted
|
|
if results:
|
|
# Should find both files and schemas
|
|
result_types = {result['type'] for result in results}
|
|
assert len(result_types) > 0 # At least one type found
|
|
|
|
# Verify results have required fields
|
|
for result in results:
|
|
assert 'type' in result
|
|
assert 'score' in result
|
|
assert result['score'] > 0
|
|
|
|
if result['type'] == 'file':
|
|
assert 'file' in result
|
|
assert 'filename' in result['file']
|
|
elif result['type'] == 'schema':
|
|
assert 'schema' in result
|
|
assert 'filename' in result['schema']
|
|
|
|
def test_search_ranking_quality(self, populated_db_path):
|
|
"""Test that search ranking produces sensible results."""
|
|
plugin = FTSSearchPlugin()
|
|
plugin.initialize(populated_db_path)
|
|
plugin.rebuild_index(populated_db_path)
|
|
|
|
# Search for "GraphQL"
|
|
results = plugin.search(populated_db_path, "GraphQL", content_type="files", limit=10)
|
|
|
|
if results:
|
|
# The GraphQL guide should rank highest
|
|
top_result = results[0]
|
|
assert 'graphql' in top_result['file']['filename'].lower()
|
|
|
|
# Search for exact phrase
|
|
results = plugin.search(populated_db_path, '"API documentation"', content_type="files", limit=10)
|
|
|
|
if results:
|
|
# Should find exact phrase matches
|
|
for result in results:
|
|
content = result['file'].get('content', '').lower()
|
|
# Either in content or highlighted
|
|
assert 'api documentation' in content or 'api documentation' in result.get('highlight', '').lower()
|
|
|
|
def test_search_error_handling(self, populated_db_path):
|
|
"""Test search error handling and edge cases."""
|
|
plugin = FTSSearchPlugin()
|
|
plugin.initialize(populated_db_path)
|
|
|
|
# Empty query
|
|
results = plugin.search(populated_db_path, "", content_type="all", limit=10)
|
|
assert isinstance(results, list)
|
|
|
|
# Very long query
|
|
long_query = "word " * 100
|
|
results = plugin.search(populated_db_path, long_query, content_type="all", limit=10)
|
|
assert isinstance(results, list)
|
|
|
|
# Special characters
|
|
results = plugin.search(populated_db_path, "query with @#$%", content_type="all", limit=10)
|
|
assert isinstance(results, list)
|
|
|
|
# Zero limit
|
|
results = plugin.search(populated_db_path, "API", content_type="all", limit=0)
|
|
assert len(results) == 0 |