Starting to write Python test files for testing.

Test Suite Overview

  • Coverage lives in tests/test_tag_search.py and focuses on the new tag-search helper/tool, exercising everything from happy
    paths to integration-level behavior.
  • A single fixture builds a representative vault with eight notes that mix tag formats, nested folders, empty/missing metadata,
    and special characters so each test hits realistic vault conditions.

Fixtures

test_vault - creates a temporary vault rooted at tmp_path/test_vault with: list-form tags, string-form tags, mixed-case tags, a note lacking frontmatter, empty tag arrays, missing tags keys, nested-folder notes, and tags containing symbols (e.g., c++). The fixture returns a VaultMetadata instance pointing at this synthetic vault.

Tests

TestTagSearchBasics

  • test_single_tag_match — “Search for single tag should return matching notes.”
  • test_single_tag_no_match — “Search for non-existent tag should return empty results.”
  • test_multiple_tags_any_mode — “Search with match_all=False should match ANY tag.”
  • test_multiple_tags_all_mode — “Search with match_all=True should require ALL tags.”
    TestTagFormats
  • test_list_format_tags — “Should handle tags as YAML list.”
  • test_string_format_tags — “Should handle tags as single string.”
  • test_special_characters_in_tags — “Should handle tags with special characters.”

TestCaseInsensitivity

  • test_lowercase_search_matches_titlecase — “Lowercase search should match TitleCase tags.”
  • test_uppercase_search_matches_lowercase — “Uppercase search should match lowercase tags.”
  • test_mixed_case_search — “Mixed case search should work.”

TestEdgeCases

  • test_empty_tags_list_raises_error — “Empty tags list should raise ValueError.”
  • test_whitespace_only_tags_raises_error — “Whitespace-only tags should raise ValueError.”
  • test_notes_without_frontmatter_skipped — “Notes without frontmatter should be skipped gracefully.”
  • test_notes_with_empty_tags_skipped — “Notes with empty tags list should be skipped.”
  • test_notes_without_tags_field_skipped — “Notes without tags field should be skipped.”

TestMetadataInclusion (tests/test_tag_search.py)

  • test_without_metadata_returns_paths_only — “include_metadata=False should return only paths.”
  • test_with_metadata_returns_dict — “include_metadata=True should return dicts with metadata.”
  • test_metadata_includes_matched_tags — “Metadata should include the tags found in the note.”
  • test_metadata_sorting_by_modified — “Results with metadata should be sorted by modified date.”
  • test_without_metadata_sorting_alphabetical — “Results without metadata should be sorted alphabetically.”

TestNestedFolders (tests/test_tag_search.py)

  • test_searches_nested_folders — “Should find notes in subdirectories.”
  • test_path_format_uses_forward_slashes — “Paths should use forward slashes regardless of OS.”

TestComplexQueries (tests/test_tag_search.py)

  • test_three_tags_any_mode — “Should handle searching for 3+ tags in ANY mode.”
  • test_three_tags_all_mode — “Should handle searching for 3+ tags in ALL mode.”
  • test_overlapping_tag_sets — “Test with tags that partially overlap across notes.”

TestPerformance (tests/test_tag_search.py)

  • test_large_vault_performance — “Test performance with many notes (skip in quick tests).”

Integration (tests/test_tag_search.py)

  • test_mcp_tool_integration — “Test that the MCP tool wrapper works correctly.”

Together these checks confirm core functionality, input validation, metadata enrichment, filesystem traversal, performance
characteristics, and the MCP tool wrapper required for the v1.4.1 release.

Results

================================================== test session starts ==================================================
platform darwin -- Python 3.13.3, pytest-8.4.2, pluggy-1.6.0 -- /Users/naderbaradar/development_workspace/mcp/servers/obsidian_vault/.venv/bin/python3.13
cachedir: .pytest_cache
rootdir: /Users/naderbaradar/development_workspace/mcp/servers/obsidian_vault
configfile: pyproject.toml
plugins: asyncio-1.2.0, anyio-4.11.0
asyncio: mode=Mode.STRICT, debug=False, asyncio_default_fixture_loop_scope=None, asyncio_default_test_loop_scope=function
collected 27 items                                                                                                      
 
tests/test_tag_search.py::TestTagSearchBasics::test_single_tag_match PASSED                                       [  3%]
tests/test_tag_search.py::TestTagSearchBasics::test_single_tag_no_match PASSED                                    [  7%]
tests/test_tag_search.py::TestTagSearchBasics::test_multiple_tags_any_mode PASSED                                 [ 11%]
tests/test_tag_search.py::TestTagSearchBasics::test_multiple_tags_all_mode PASSED                                 [ 14%]
tests/test_tag_search.py::TestTagFormats::test_list_format_tags PASSED                                            [ 18%]
tests/test_tag_search.py::TestTagFormats::test_string_format_tags PASSED                                          [ 22%]
tests/test_tag_search.py::TestTagFormats::test_special_characters_in_tags PASSED                                  [ 25%]
tests/test_tag_search.py::TestCaseInsensitivity::test_lowercase_search_matches_titlecase PASSED                   [ 29%]
tests/test_tag_search.py::TestCaseInsensitivity::test_uppercase_search_matches_lowercase PASSED                   [ 33%]
tests/test_tag_search.py::TestCaseInsensitivity::test_mixed_case_search PASSED                                    [ 37%]
tests/test_tag_search.py::TestEdgeCases::test_empty_tags_list_raises_error PASSED                                 [ 40%]
tests/test_tag_search.py::TestEdgeCases::test_whitespace_only_tags_raises_error PASSED                            [ 44%]
tests/test_tag_search.py::TestEdgeCases::test_notes_without_frontmatter_skipped PASSED                            [ 48%]
tests/test_tag_search.py::TestEdgeCases::test_notes_with_empty_tags_skipped PASSED                                [ 51%]
tests/test_tag_search.py::TestEdgeCases::test_notes_without_tags_field_skipped PASSED                             [ 55%]
tests/test_tag_search.py::TestMetadataInclusion::test_without_metadata_returns_paths_only PASSED                  [ 59%]
tests/test_tag_search.py::TestMetadataInclusion::test_with_metadata_returns_dict PASSED                           [ 62%]
tests/test_tag_search.py::TestMetadataInclusion::test_metadata_includes_matched_tags PASSED                       [ 66%]
tests/test_tag_search.py::TestMetadataInclusion::test_metadata_sorting_by_modified PASSED                         [ 70%]
tests/test_tag_search.py::TestMetadataInclusion::test_without_metadata_sorting_alphabetical PASSED                [ 74%]
tests/test_tag_search.py::TestNestedFolders::test_searches_nested_folders PASSED                                  [ 77%]
tests/test_tag_search.py::TestNestedFolders::test_path_format_uses_forward_slashes PASSED                         [ 81%]
tests/test_tag_search.py::TestComplexQueries::test_three_tags_any_mode PASSED                                     [ 85%]
tests/test_tag_search.py::TestComplexQueries::test_three_tags_all_mode PASSED                                     [ 88%]
tests/test_tag_search.py::TestComplexQueries::test_overlapping_tag_sets PASSED                                    [ 92%]
tests/test_tag_search.py::TestPerformance::test_large_vault_performance PASSED                                    [ 96%]
tests/test_tag_search.py::test_mcp_tool_integration PASSED                                                        [100%]
 
================================================== 27 passed in 0.46s ===================================================