Coverage for tests / unit / ai / providers / test_base.py: 97%

37 statements  

« prev     ^ index     » next       coverage.py v7.13.0, created at 2026-04-03 18:53 +0000

1"""Tests for base AI provider.""" 

2 

3from __future__ import annotations 

4 

5import pytest 

6from assertpy import assert_that 

7 

8from lintro.ai.providers.base import AIResponse, BaseAIProvider 

9 

10 

11def test_ai_response_defaults(): 

12 """Verify that AIResponse fields default to zero or empty when not provided.""" 

13 resp = AIResponse(content="hello", model="test") 

14 assert_that(resp.content).is_equal_to("hello") 

15 assert_that(resp.model).is_equal_to("test") 

16 assert_that(resp.input_tokens).is_equal_to(0) 

17 assert_that(resp.output_tokens).is_equal_to(0) 

18 assert_that(resp.cost_estimate).is_equal_to(0.0) 

19 assert_that(resp.provider).is_equal_to("") 

20 

21 

22def test_ai_response_with_all_fields(): 

23 """Verify that AIResponse stores all explicitly provided field values.""" 

24 resp = AIResponse( 

25 content="test", 

26 model="gpt-4o", 

27 input_tokens=100, 

28 output_tokens=50, 

29 cost_estimate=0.005, 

30 provider="openai", 

31 ) 

32 assert_that(resp.input_tokens).is_equal_to(100) 

33 assert_that(resp.cost_estimate).is_equal_to(0.005) 

34 

35 

36def test_base_ai_provider_complete_subclass(): 

37 """A complete BaseAIProvider subclass can be instantiated.""" 

38 

39 class TestProvider(BaseAIProvider): 

40 def __init__(self) -> None: 

41 super().__init__( 

42 provider_name="test", 

43 has_sdk=True, 

44 sdk_package="test", 

45 default_model="test-model", 

46 default_api_key_env="TEST_KEY", 

47 ) 

48 

49 def _create_client(self, *, api_key: str) -> object: 

50 return None 

51 

52 def complete( 

53 self, 

54 prompt: str, 

55 *, 

56 system: str | None = None, 

57 max_tokens: int = 1024, 

58 timeout: float = 60.0, 

59 ) -> AIResponse: 

60 return AIResponse( 

61 content="ok", 

62 model="test", 

63 ) 

64 

65 provider = TestProvider() 

66 assert_that(provider.name).is_equal_to("test") 

67 assert_that(provider.model_name).is_equal_to("test-model") 

68 

69 result = provider.complete("hello") 

70 assert_that(result.content).is_equal_to("ok") 

71 

72 

73def test_base_ai_provider_cannot_instantiate_directly(): 

74 """BaseAIProvider is abstract and cannot be instantiated.""" 

75 with pytest.raises(TypeError): 

76 BaseAIProvider( # type: ignore[abstract] 

77 provider_name="test", 

78 has_sdk=True, 

79 sdk_package="test", 

80 default_model="m", 

81 default_api_key_env="K", 

82 ) 

83 

84 

85def test_incomplete_subclass_fails(): 

86 """A subclass missing abstract methods cannot be instantiated.""" 

87 

88 class IncompleteProvider(BaseAIProvider): 

89 pass 

90 

91 with pytest.raises(TypeError): 

92 IncompleteProvider( # type: ignore[abstract] 

93 provider_name="test", 

94 has_sdk=True, 

95 sdk_package="test", 

96 default_model="m", 

97 default_api_key_env="K", 

98 )