Spaces:
Sleeping
Sleeping
| """ | |
| Test cases for edge cases and error handling. | |
| Tests various edge cases that might occur in production. | |
| """ | |
| import unittest | |
| from unittest.mock import patch, MagicMock | |
| import pandas as pd | |
| from src.stock_quote import get_stock_quote | |
| from src.historical_data import get_historical_data | |
| from src.technical_analysis import get_technical_analysis | |
| class TestEdgeCases(unittest.TestCase): | |
| """Test cases for edge cases and error scenarios.""" | |
| # ======================================================================== | |
| # STOCK QUOTE EDGE CASES | |
| # ======================================================================== | |
| def test_get_stock_quote_nonexistent_ticker(self): | |
| """Test quote for non-existent ticker.""" | |
| with patch('src.stock_quote.get_cached_stock_data') as mock_fetch: | |
| mock_fetch.return_value = ({}, pd.DataFrame()) # Empty data | |
| result = get_stock_quote("INVALID") | |
| self.assertIn("error", result) | |
| self.assertEqual(result["error_code"], "NO_DATA") | |
| def test_get_stock_quote_single_data_point(self): | |
| """Test quote with only one data point.""" | |
| with patch('src.stock_quote.get_cached_stock_data') as mock_fetch: | |
| mock_hist = pd.DataFrame({ | |
| 'Close': [150], | |
| 'Volume': [1000000] | |
| }) | |
| mock_fetch.return_value = ({"longName": "Test"}, mock_hist) | |
| result = get_stock_quote("TEST") | |
| self.assertIn("price", result) | |
| self.assertEqual(result["price"], 150) | |
| # Change should be 0 when only one data point | |
| self.assertEqual(result["change"], 0) | |
| def test_get_stock_quote_zero_prev_close(self): | |
| """Test quote with zero previous close (edge case).""" | |
| with patch('src.stock_quote.get_cached_stock_data') as mock_fetch: | |
| mock_hist = pd.DataFrame({ | |
| 'Close': [0, 150], | |
| 'Volume': [0, 1000000] | |
| }) | |
| mock_fetch.return_value = ({"longName": "Test"}, mock_hist) | |
| result = get_stock_quote("TEST") | |
| # Should handle zero division gracefully | |
| self.assertIn("price", result) | |
| # ======================================================================== | |
| # HISTORICAL DATA EDGE CASES | |
| # ======================================================================== | |
| def test_get_historical_data_empty_result(self): | |
| """Test historical data with empty result.""" | |
| with patch('src.historical_data.fetch_historical_data') as mock_fetch: | |
| mock_fetch.return_value = pd.DataFrame() | |
| result = get_historical_data("TEST", "1mo", "1d") | |
| self.assertIn("error", result) | |
| self.assertEqual(result["error_code"], "NO_DATA") | |
| # ======================================================================== | |
| # TECHNICAL ANALYSIS EDGE CASES | |
| # ======================================================================== | |
| def test_get_technical_analysis_insufficient_data(self): | |
| """Test technical analysis with insufficient data.""" | |
| with patch('src.technical_analysis.fetch_historical_data') as mock_fetch: | |
| # Return data with less than 50 points | |
| mock_hist = pd.DataFrame({'Close': range(30)}) | |
| mock_fetch.return_value = mock_hist | |
| result = get_technical_analysis("TEST", "1mo") | |
| self.assertIn("error", result) | |
| self.assertEqual(result["error_code"], "INSUFFICIENT_DATA") | |
| def test_get_technical_analysis_empty_data(self): | |
| """Test technical analysis with empty data.""" | |
| with patch('src.technical_analysis.fetch_historical_data') as mock_fetch: | |
| mock_fetch.return_value = pd.DataFrame() | |
| result = get_technical_analysis("TEST", "1mo") | |
| self.assertIn("error", result) | |
| # ======================================================================== | |
| # BOUNDARY VALUE TESTS | |
| # ======================================================================== | |
| def test_ticker_boundary_values(self): | |
| """Test ticker validation with boundary values.""" | |
| from src.validators import validate_ticker | |
| # Exactly 5 characters (max) | |
| is_valid, _, _ = validate_ticker("ABCDE") | |
| self.assertTrue(is_valid) | |
| # Exactly 1 character (min) | |
| is_valid, _, _ = validate_ticker("A") | |
| self.assertTrue(is_valid) | |
| # 6 characters (over limit) | |
| is_valid, _, _ = validate_ticker("ABCDEF") | |
| self.assertFalse(is_valid) | |
| def test_portfolio_zero_cost_basis(self): | |
| """Test portfolio with zero cost basis.""" | |
| from src.portfolio import analyze_portfolio | |
| portfolio_json = '{"AAPL": {"shares": 10, "cost_basis": 0}}' | |
| # Should handle zero cost basis (might cause division by zero) | |
| result = analyze_portfolio(portfolio_json) | |
| # Should either return error or handle gracefully | |
| self.assertIsInstance(result, dict) | |
| if __name__ == '__main__': | |
| unittest.main() | |