mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-02 20:14:36 +00:00
- Add test_handler_helpers.py for plugin handler helpers (7 tests) - Add test_mgr_methods.py for persistence manager (5 tests) - Add test_app_config_validation.py for core app config (12 tests) - Add test_knowledge_service.py for API knowledge service (22 tests) - Add test_kbmgr.py for RAG knowledge base manager (39 tests) - Add test_survey_manager.py for survey manager (22 tests) - Add test_connector_methods.py for plugin connector (24 tests) - Add test_funcschema.py for utils function schema (9 tests) - Add test_platform.py for utils platform detection (7 tests) - Add test_extract_deps.py for plugin deps extraction (7 tests) - Add test_database_decorator.py for persistence decorator (7 tests) - Add test_load_config.py for core config loading (19 tests) - Add COVERAGE_EXCLUSIONS.md documenting external adapter exclusions - Fix test_chat_session_limit.py path for portability Coverage: core 28% → 30%, persistence 24% → 24.4%, plugin 27% → 28% Total: 1082 tests passed, core module coverage 45.5% Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
191 lines
5.8 KiB
Python
191 lines
5.8 KiB
Python
"""Unit tests for utils funcschema.
|
|
|
|
Tests cover:
|
|
- get_func_schema() function
|
|
- Docstring parsing
|
|
- Parameter type extraction
|
|
- Required parameter detection
|
|
|
|
Note: Do NOT use 'from __future__ import annotations' because
|
|
funcschema.py expects actual type objects, not string annotations.
|
|
"""
|
|
import pytest
|
|
from importlib import import_module
|
|
|
|
|
|
def get_funcschema_module():
|
|
"""Lazy import to avoid circular import issues."""
|
|
return import_module('langbot.pkg.utils.funcschema')
|
|
|
|
|
|
class TestGetFuncSchema:
|
|
"""Tests for get_func_schema function."""
|
|
|
|
def test_simple_function_schema(self):
|
|
"""Test schema generation for simple function."""
|
|
funcschema = get_funcschema_module()
|
|
|
|
def simple_func(name: str, count: int):
|
|
"""Simple function description.
|
|
|
|
Args:
|
|
name: The name parameter.
|
|
count: The count parameter.
|
|
"""
|
|
pass
|
|
|
|
result = funcschema.get_func_schema(simple_func)
|
|
|
|
assert result['description'] == 'Simple function description.'
|
|
assert result['parameters']['type'] == 'object'
|
|
assert 'name' in result['parameters']['properties']
|
|
assert 'count' in result['parameters']['properties']
|
|
assert result['parameters']['properties']['name']['type'] == 'string'
|
|
assert result['parameters']['properties']['count']['type'] == 'integer'
|
|
|
|
def test_parameter_type_mapping(self):
|
|
"""Test that Python types are mapped to JSON schema types."""
|
|
funcschema = get_funcschema_module()
|
|
|
|
def typed_func(a: str, b: int, c: float, d: bool, e: list, f: dict):
|
|
"""Typed function.
|
|
|
|
Args:
|
|
a: String param.
|
|
b: Int param.
|
|
c: Float param.
|
|
d: Bool param.
|
|
e: List param.
|
|
f: Dict param.
|
|
"""
|
|
pass
|
|
|
|
result = funcschema.get_func_schema(typed_func)
|
|
|
|
props = result['parameters']['properties']
|
|
assert props['a']['type'] == 'string'
|
|
assert props['b']['type'] == 'integer'
|
|
assert props['c']['type'] == 'number'
|
|
assert props['d']['type'] == 'boolean'
|
|
assert props['e']['type'] == 'array'
|
|
assert props['f']['type'] == 'object'
|
|
|
|
def test_required_parameters_detection(self):
|
|
"""Test that required parameters are detected correctly."""
|
|
funcschema = get_funcschema_module()
|
|
|
|
def func_with_defaults(name: str, optional: str = 'default'):
|
|
"""Function with default.
|
|
|
|
Args:
|
|
name: Required param.
|
|
optional: Optional param.
|
|
"""
|
|
pass
|
|
|
|
result = funcschema.get_func_schema(func_with_defaults)
|
|
|
|
assert 'name' in result['parameters']['required']
|
|
assert 'optional' not in result['parameters']['required']
|
|
|
|
def test_self_and_query_excluded(self):
|
|
"""Test that self and query parameters are excluded."""
|
|
funcschema = get_funcschema_module()
|
|
|
|
def method_func(self, query, other: str):
|
|
"""Method function.
|
|
|
|
Args:
|
|
self: Self parameter.
|
|
query: Query parameter.
|
|
other: Other parameter.
|
|
"""
|
|
pass
|
|
|
|
result = funcschema.get_func_schema(method_func)
|
|
|
|
props = result['parameters']['properties']
|
|
assert 'self' not in props
|
|
assert 'query' not in props
|
|
assert 'other' in props
|
|
|
|
def test_array_type_extraction(self):
|
|
"""Test that list[T] types extract element type."""
|
|
funcschema = get_funcschema_module()
|
|
|
|
def list_func(items: list[str], numbers: list[int]):
|
|
"""List function.
|
|
|
|
Args:
|
|
items: List of strings.
|
|
numbers: List of integers.
|
|
"""
|
|
pass
|
|
|
|
result = funcschema.get_func_schema(list_func)
|
|
|
|
props = result['parameters']['properties']
|
|
assert props['items']['type'] == 'array'
|
|
assert props['items']['items']['type'] == 'string'
|
|
assert props['numbers']['type'] == 'array'
|
|
assert props['numbers']['items']['type'] == 'integer'
|
|
|
|
def test_function_without_docstring_raises(self):
|
|
"""Test that function without docstring raises exception."""
|
|
funcschema = get_funcschema_module()
|
|
|
|
def no_doc_func(a: str):
|
|
pass
|
|
|
|
with pytest.raises(Exception) as exc_info:
|
|
funcschema.get_func_schema(no_doc_func)
|
|
|
|
assert 'has no docstring' in str(exc_info.value)
|
|
|
|
def test_description_extraction(self):
|
|
"""Test that description is extracted from first paragraph."""
|
|
funcschema = get_funcschema_module()
|
|
|
|
def desc_func(a: str):
|
|
"""This is the description.
|
|
|
|
Args:
|
|
a: Param a.
|
|
"""
|
|
pass
|
|
|
|
result = funcschema.get_func_schema(desc_func)
|
|
|
|
assert result['description'] == 'This is the description.'
|
|
|
|
def test_function_reference_stored(self):
|
|
"""Test that function reference is stored in schema."""
|
|
funcschema = get_funcschema_module()
|
|
|
|
def stored_func(a: str):
|
|
"""Stored function.
|
|
|
|
Args:
|
|
a: Param a.
|
|
"""
|
|
pass
|
|
|
|
result = funcschema.get_func_schema(stored_func)
|
|
|
|
assert result['function'] is stored_func
|
|
|
|
def test_description_from_args_doc(self):
|
|
"""Test that arg description is extracted from docstring."""
|
|
funcschema = get_funcschema_module()
|
|
|
|
def doc_func(param_name: str):
|
|
"""Function with documented param.
|
|
|
|
Args:
|
|
param_name: This is the param description.
|
|
"""
|
|
pass
|
|
|
|
result = funcschema.get_func_schema(doc_func)
|
|
|
|
assert result['parameters']['properties']['param_name']['description'] == 'This is the param description.' |