@@ -651,3 +651,142 @@ def parse_model_with_suffix(model_name, overrides):
651651 base_model , kwargs = parse_model_with_suffix (model_input , overrides )
652652 assert base_model == expected_base , f"Failed ({ description } ): base model mismatch"
653653 assert kwargs == expected_kwargs , f"Failed ({ description } ): kwargs mismatch"
654+
655+ def test_print_matching_models_with_pricing (self ):
656+ """Test that print_matching_models displays pricing information correctly."""
657+ from cecli .models import print_matching_models
658+ from cecli .io import InputOutput
659+
660+ # Mock model_info_manager to return pricing data
661+ with patch ("cecli.models.model_info_manager" ) as mock_manager :
662+ mock_manager .get_model_info .return_value = {
663+ "input_cost_per_token" : 0.000005 , # $5 per 1M tokens
664+ "output_cost_per_token" : 0.000015 , # $15 per 1M tokens
665+ }
666+
667+ io = InputOutput (pretty = False , fancy_input = False , yes = True )
668+ with patch .object (io , "tool_output" ) as mock_tool_output :
669+ print_matching_models (io , "gpt-4" )
670+
671+ # Check that the header was printed
672+ mock_tool_output .assert_any_call ('Models which match "gpt-4":' )
673+
674+ # Check that pricing was included in the output
675+ calls = [str (call ) for call in mock_tool_output .call_args_list ]
676+ pricing_found = any ("$5.00/1m/input" in call for call in calls )
677+ output_pricing_found = any ("$15.00/1m/output" in call for call in calls )
678+ assert pricing_found , "Input pricing not found in output"
679+ assert output_pricing_found , "Output pricing not found in output"
680+
681+ def test_print_matching_models_with_cache_pricing (self ):
682+ """Test that print_matching_models displays cache pricing when available."""
683+ from cecli .models import print_matching_models
684+ from cecli .io import InputOutput
685+
686+ # Mock model_info_manager to return pricing data with cache
687+ with patch ("cecli.models.model_info_manager" ) as mock_manager :
688+ mock_manager .get_model_info .return_value = {
689+ "input_cost_per_token" : 0.000003 , # $3 per 1M tokens
690+ "output_cost_per_token" : 0.000012 , # $12 per 1M tokens
691+ "cache_cost_per_token" : 0.000001 , # $1 per 1M tokens
692+ }
693+
694+ io = InputOutput (pretty = False , fancy_input = False , yes = True )
695+ with patch .object (io , "tool_output" ) as mock_tool_output :
696+ print_matching_models (io , "claude-3-5-sonnet" )
697+
698+ # Check that all pricing was included in the output
699+ calls = [str (call ) for call in mock_tool_output .call_args_list ]
700+ input_found = any ("$3.00/1m/input" in call for call in calls )
701+ output_found = any ("$12.00/1m/output" in call for call in calls )
702+ cache_found = any ("$1.00/1m/cache" in call for call in calls )
703+ assert input_found , "Input pricing not found in output"
704+ assert output_found , "Output pricing not found in output"
705+ assert cache_found , "Cache pricing not found in output"
706+
707+ def test_print_matching_models_without_pricing (self ):
708+ """Test that print_matching_models works when no pricing info is available."""
709+ from cecli .models import print_matching_models
710+ from cecli .io import InputOutput
711+
712+ # Mock model_info_manager to return no pricing data
713+ with patch ("cecli.models.model_info_manager" ) as mock_manager :
714+ mock_manager .get_model_info .return_value = {}
715+
716+ io = InputOutput (pretty = False , fancy_input = False , yes = True )
717+ with patch .object (io , "tool_output" ) as mock_tool_output :
718+ print_matching_models (io , "gpt-4" )
719+
720+ # Check that the header was printed
721+ mock_tool_output .assert_any_call ('Models which match "gpt-4":' )
722+
723+ # Check that no pricing was included in the output
724+ calls = [str (call ) for call in mock_tool_output .call_args_list ]
725+ pricing_found = any ("/1m/" in call for call in calls )
726+ assert not pricing_found , "Pricing should not be in output when not available"
727+
728+ def test_print_matching_models_partial_pricing (self ):
729+ """Test that print_matching_models displays only available pricing info."""
730+ from cecli .models import print_matching_models
731+ from cecli .io import InputOutput
732+
733+ # Mock model_info_manager to return only input pricing
734+ with patch ("cecli.models.model_info_manager" ) as mock_manager :
735+ mock_manager .get_model_info .return_value = {
736+ "input_cost_per_token" : 0.000002 , # $2 per 1M tokens
737+ # No output or cache pricing
738+ }
739+
740+ io = InputOutput (pretty = False , fancy_input = False , yes = True )
741+ with patch .object (io , "tool_output" ) as mock_tool_output :
742+ print_matching_models (io , "gpt-3.5" )
743+
744+ # Check that only input pricing was included
745+ calls = [str (call ) for call in mock_tool_output .call_args_list ]
746+ input_found = any ("$2.00/1m/input" in call for call in calls )
747+ output_found = any ("/1m/output" in call for call in calls )
748+ assert input_found , "Input pricing not found in output"
749+ assert not output_found , "Output pricing should not be in output when not available"
750+
751+ def test_print_matching_models_no_matches (self ):
752+ """Test that print_matching_models handles no matches correctly."""
753+ from cecli .models import print_matching_models
754+ from cecli .io import InputOutput
755+
756+ # Mock fuzzy_match_models to return no matches
757+ with patch ("cecli.models.fuzzy_match_models" ) as mock_fuzzy :
758+ mock_fuzzy .return_value = []
759+
760+ io = InputOutput (pretty = False , fancy_input = False , yes = True )
761+ with patch .object (io , "tool_output" ) as mock_tool_output :
762+ print_matching_models (io , "nonexistent-model" )
763+
764+ # Check that the no matches message was printed
765+ mock_tool_output .assert_called_once_with ('No models match "nonexistent-model".' )
766+
767+ def test_print_matching_models_price_formatting (self ):
768+ """Test that pricing is formatted correctly with 2 decimal places."""
769+ from cecli .models import print_matching_models
770+ from cecli .io import InputOutput
771+
772+ # Mock fuzzy_match_models to return a test model
773+ with patch ("cecli.models.fuzzy_match_models" ) as mock_fuzzy :
774+ mock_fuzzy .return_value = ["test-model" ]
775+
776+ # Mock model_info_manager to return pricing with various values
777+ with patch ("cecli.models.model_info_manager" ) as mock_manager :
778+ mock_manager .get_model_info .return_value = {
779+ "input_cost_per_token" : 0.0000025 , # $2.50 per 1M tokens
780+ "output_cost_per_token" : 0.0000105 , # $10.50 per 1M tokens
781+ }
782+
783+ io = InputOutput (pretty = False , fancy_input = False , yes = True )
784+ with patch .object (io , "tool_output" ) as mock_tool_output :
785+ print_matching_models (io , "test-model" )
786+
787+ # Check that pricing is formatted with 2 decimal places
788+ calls = [str (call ) for call in mock_tool_output .call_args_list ]
789+ input_found = any ("$2.50/1m/input" in call for call in calls )
790+ output_found = any ("$10.50/1m/output" in call for call in calls )
791+ assert input_found , "Input pricing format incorrect"
792+ assert output_found , "Output pricing format incorrect"
0 commit comments