2024-12-05 22:46:41 +00:00
import pytest
2025-01-09 17:59:28 +00:00
import src . utils as utils
from src . utils . string_utils import extract_text_from_delimiters , json_parsing_search , secondary_string_to_dict , primary_string_to_dict , contains_reimbursement , is_empty
import src . utils . llm_utils as llm_utils
import numpy as np
import pandas as pd
2025-01-08 21:59:47 +00:00
2024-12-05 22:46:41 +00:00
2025-01-09 17:59:28 +00:00
from src . enums . delimiters import Delimiter
2024-12-05 22:46:41 +00:00
class TestExtractTextFromDelimiters :
2025-01-09 17:59:28 +00:00
@pytest.mark.parametrize ( " raw_text, delimiter, match_index, expected " , [
( " Here is the answer |this is a pipe answer| and |more text.| " , Delimiter . PIPE , 0 , " this is a pipe answer " ) ,
( " Here is the answer |this is a pipe answer| and |more text.| " , Delimiter . PIPE , - 1 , " more text. " ) ,
( " |Here| is the answer |this is a pipe answer| and |more text.| " , Delimiter . PIPE , 1 , " this is a pipe answer " ) ,
( " Here is the answer `this is a backtick answer` and `more text.` " , Delimiter . BACKTICK , 0 , " this is a backtick answer " ) ,
( " Here is the answer `this is a backtick answer` and `more text.` " , Delimiter . BACKTICK , - 1 , " more text. " ) ,
( " `Here` is the answer `this` is a `backtick answer` and `more text.` " , Delimiter . BACKTICK , 2 , " backtick answer " ) ,
( " Here is the answer ```this is a triple backtick answer``` and more text. " , Delimiter . TRIPLE_BACKTICK , 0 , " this is a triple backtick answer " ) ,
( " Here is the answer ```this``` is a ```triple``` backtick ```answer``` and more text. " , Delimiter . TRIPLE_BACKTICK , - 1 , " answer " ) ,
( " ```Here``` is the answer ```this is a triple backtick answer``` and ```more text.``` " , Delimiter . TRIPLE_BACKTICK , 1 , " this is a triple backtick answer " ) ,
] )
def test_extract_text_from_delimiters ( self , raw_text , delimiter , match_index , expected ) :
result = extract_text_from_delimiters ( raw_text , delimiter , match_index )
assert result == expected
class TestJsonParsingSearch :
@pytest.mark.parametrize ( " response_text, field_list, expected " , [
( ' { " name " : " John " , " age " : " 30 " , " city " : " New York " } ' , [ " name " , " age " , " city " ] , { " name " : " John " , " age " : " 30 " , " city " : " New York " } ) ,
( ' { " name " : " John " , " city " : " New York " } ' , [ " name " , " age " , " city " ] , { " name " : " John " , " city " : " New York " } ) ,
( ' ' , [ " name " , " age " , " city " ] , { } ) ,
( ' { " name " : " John " , " age " : " 30 " , " city " : " New York " } ' , [ ] , { } ) ,
( ' { " name " : " " , " age " : " " , " city " : " " } ' , [ " name " , " age " , " city " ] , { " name " : " " , " age " : " " , " city " : " " } ) ,
( ' { \n " name " : " John " , \n " age " : " 30 " , \n " city " : " New York " \n } ' , [ " name " , " age " , " city " ] , { " name " : " John " , " age " : " 30 " , " city " : " New York " } ) ,
] )
def test_json_parsing_search ( self , response_text , field_list , expected ) :
assert json_parsing_search ( response_text , field_list ) == expected
class TestSecondaryStringToDict :
@pytest.fixture
def mock_invoke_claude ( self , mocker ) :
return mocker . patch . object ( llm_utils , ' invoke_claude ' )
def test_valid_json ( self , mock_invoke_claude ) :
dict_string = ' { " key " : " value " } '
filename = " test_file.txt "
result = secondary_string_to_dict ( dict_string , filename )
assert result == { " key " : " value " }
mock_invoke_claude . assert_not_called ( )
def test_invalid_json_fixed_by_replacing_quotes ( self , mock_invoke_claude ) :
dict_string = " { ' key ' : ' value ' } "
filename = " test_file.txt "
result = secondary_string_to_dict ( dict_string , filename )
assert result == { " key " : " value " }
mock_invoke_claude . assert_not_called ( )
def test_invalid_json_fixed_by_llm ( self , mock_invoke_claude ) :
mock_invoke_claude . return_value = ' { " key " : " value " } '
dict_string = " { key: value} "
filename = " test_file.txt "
result = secondary_string_to_dict ( dict_string , filename )
assert result == { " key " : " value " }
mock_invoke_claude . assert_called_once ( )
def test_invalid_json_failed_by_llm ( self , mock_invoke_claude ) :
mock_invoke_claude . side_effect = Exception ( " LLM call failed " )
dict_string = " { key: value} "
filename = " test_file.txt "
result = secondary_string_to_dict ( dict_string , filename )
assert result == { }
mock_invoke_claude . assert_called_once ( )
def test_no_dict_found ( self , mock_invoke_claude ) :
mock_invoke_claude . return_value = ' {} '
dict_string = " This is a plain text without any dictionary. "
filename = " test_file.txt "
result = secondary_string_to_dict ( dict_string , filename )
assert result == { }
mock_invoke_claude . assert_called_once ( )
class TestPrimaryStringToDict :
@pytest.fixture
def mock_secondary_string_to_dict ( self , mocker ) :
return mocker . patch . object ( utils . string_utils , " secondary_string_to_dict " )
def test_valid_input ( self , mock_secondary_string_to_dict ) :
mock_secondary_string_to_dict . side_effect = [
{ " key1 " : " value1 " } ,
{ " key2 " : " value2 " } ,
{ " key3 " : " value3 " } ,
]
string_dict = {
" 1 " : " [ { ' key1 ' : ' value1 ' }, { ' key2 ' : ' value2 ' }] " ,
" 2 " : " [ { ' key3 ' : ' value3 ' }] " ,
}
filename = " test_file.txt "
expected_output = [
{ " key1 " : " value1 " , " page_num " : " 1 " , " Filename " : " test_file.txt " } ,
{ " key2 " : " value2 " , " page_num " : " 1 " , " Filename " : " test_file.txt " } ,
{ " key3 " : " value3 " , " page_num " : " 2 " , " Filename " : " test_file.txt " } ,
]
result = primary_string_to_dict ( string_dict , filename )
assert result == expected_output
assert mock_secondary_string_to_dict . call_count == len ( expected_output )
def test_invalid_input_no_dicts ( self , mock_secondary_string_to_dict ) :
mock_secondary_string_to_dict . return_value = { }
string_dict = {
" 1 " : " [This is not a dictionary] " ,
" 2 " : " [Still not a dictionary] " ,
}
filename = " test_file.txt "
expected_output = [ ]
result = primary_string_to_dict ( string_dict , filename )
assert result == expected_output
assert mock_secondary_string_to_dict . call_count == len ( expected_output )
def test_empty_input ( self , mock_secondary_string_to_dict ) :
string_dict = { }
filename = " test_file.txt "
expected_output = [ ]
result = primary_string_to_dict ( string_dict , filename )
assert result == expected_output
mock_secondary_string_to_dict . assert_not_called ( )
def test_malformed_input ( self , mock_secondary_string_to_dict ) :
mock_secondary_string_to_dict . side_effect = [
{ " key1 " : " value1 " } ,
{ " key2 " : " value2 " } ,
]
string_dict = {
" 1 " : " [ { ' key1 ' : ' value1 ' }, malformed] " ,
" 2 " : " [ { ' key2 ' : ' value2 ' }, <<<invalid>>>] " ,
}
filename = " test_file.txt "
expected_output = [
{ " key1 " : " value1 " , " page_num " : " 1 " , " Filename " : " test_file.txt " } ,
{ " key2 " : " value2 " , " page_num " : " 2 " , " Filename " : " test_file.txt " } ,
]
result = primary_string_to_dict ( string_dict , filename )
assert result == expected_output
assert mock_secondary_string_to_dict . call_count == 2
def test_multiple_pages ( self , mock_secondary_string_to_dict ) :
mock_secondary_string_to_dict . side_effect = [
{ " key1 " : " value1 " } ,
{ " key2 " : " value2 " } ,
{ " key3 " : " value3 " } ,
{ " key4 " : " value4 " } ,
]
string_dict = {
" 1 " : " [ { ' key1 ' : ' value1 ' }, { ' key2 ' : ' value2 ' }] " ,
" 2 " : " [ { ' key3 ' : ' value3 ' }, { ' key4 ' : ' value4 ' }] " ,
}
filename = " test_file.txt "
expected_output = [
{ " key1 " : " value1 " , " page_num " : " 1 " , " Filename " : " test_file.txt " } ,
{ " key2 " : " value2 " , " page_num " : " 1 " , " Filename " : " test_file.txt " } ,
{ " key3 " : " value3 " , " page_num " : " 2 " , " Filename " : " test_file.txt " } ,
{ " key4 " : " value4 " , " page_num " : " 2 " , " Filename " : " test_file.txt " } ,
]
result = primary_string_to_dict ( string_dict , filename )
assert result == expected_output
assert mock_secondary_string_to_dict . call_count == 4
class TestContainsReimbursement :
@pytest.mark.parametrize ( " text, page, expected " , [
( { " 1 " : " This page contains a 10 % r eimbursement schedule. " , " 2 " : " No relevant content here. " } , " 1 " , True ) ,
( { " 1 " : " This page has no relevant content. " , " 2 " : " Still no relevant content here. " } , " 1 " , False ) ,
( { " 1 " : " This page contains a 10 % r eimbursement schedule. " , " 2 " : " No relevant content here. " } , " invalid_page " , False ) ,
( " This text contains a $100 reimbursement schedule. " , " 1 " , True ) ,
( " This text has no relevant content. " , " 1 " , False ) ,
] )
def test_contains_reimbursement ( self , text , page , expected ) :
result = contains_reimbursement ( text , page )
assert result == expected
def test_invalid_input_type ( self , capsys ) :
text = [ " This is a list, not a dictionary or string. " ]
page = " 1 "
result = contains_reimbursement ( text , page )
assert result is None
captured = capsys . readouterr ( )
assert " contains_reimbursement - Invalid data type " in captured . out
class TestIsEmpty :
@pytest.mark.parametrize ( " value, expected " , [
( None , True ) ,
( " " , True ) ,
( " N/A " , True ) ,
( " null " , True ) ,
( " none " , True ) ,
( " NaN " , True ) ,
( np . nan , True ) ,
( pd . NA , True ) ,
( " This is not empty. " , False ) ,
( 42 , False ) ,
] )
def test_is_empty ( self , value , expected ) :
result = is_empty ( value )
assert result == expected