test_utils.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. # -*- coding: utf-8 -*-
  2. import sys
  3. import unittest
  4. from unittest.mock import patch
  5. """
  6. test_utils.py
  7. websocket - WebSocket client library for Python
  8. Copyright 2025 engn33r
  9. Licensed under the Apache License, Version 2.0 (the "License");
  10. you may not use this file except in compliance with the License.
  11. You may obtain a copy of the License at
  12. http://www.apache.org/licenses/LICENSE-2.0
  13. Unless required by applicable law or agreed to in writing, software
  14. distributed under the License is distributed on an "AS IS" BASIS,
  15. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. See the License for the specific language governing permissions and
  17. limitations under the License.
  18. """
  19. class UtilsTest(unittest.TestCase):
  20. def test_nolock(self):
  21. """Test NoLock context manager"""
  22. from websocket._utils import NoLock
  23. lock = NoLock()
  24. # Test that it can be used as context manager
  25. with lock:
  26. pass # Should not raise any exception
  27. # Test enter/exit methods directly
  28. self.assertIsNone(lock.__enter__())
  29. self.assertIsNone(lock.__exit__(None, None, None))
  30. def test_utf8_validation_with_wsaccel(self):
  31. """Test UTF-8 validation when wsaccel is available"""
  32. # Import normally (wsaccel should be available in test environment)
  33. from websocket._utils import validate_utf8
  34. # Test valid UTF-8 strings (convert to bytes for wsaccel)
  35. self.assertTrue(validate_utf8("Hello, World!".encode("utf-8")))
  36. self.assertTrue(validate_utf8("🌟 Unicode test".encode("utf-8")))
  37. self.assertTrue(validate_utf8(b"Hello, bytes"))
  38. self.assertTrue(validate_utf8("Héllo with accénts".encode("utf-8")))
  39. # Test invalid UTF-8 sequences
  40. self.assertFalse(validate_utf8(b"\xff\xfe")) # Invalid UTF-8
  41. self.assertFalse(validate_utf8(b"\x80\x80")) # Invalid continuation
  42. def test_utf8_validation_fallback(self):
  43. """Test UTF-8 validation fallback when wsaccel is not available"""
  44. # Remove _utils from modules to force reimport
  45. if "websocket._utils" in sys.modules:
  46. del sys.modules["websocket._utils"]
  47. # Mock wsaccel import to raise ImportError
  48. import builtins
  49. original_import = builtins.__import__
  50. def mock_import(name, *args, **kwargs):
  51. if "wsaccel" in name:
  52. raise ImportError(f"No module named '{name}'")
  53. return original_import(name, *args, **kwargs)
  54. with patch("builtins.__import__", side_effect=mock_import):
  55. import websocket._utils as utils
  56. # Test valid UTF-8 strings with fallback implementation (convert strings to bytes)
  57. self.assertTrue(utils.validate_utf8("Hello, World!".encode("utf-8")))
  58. self.assertTrue(utils.validate_utf8(b"Hello, bytes"))
  59. self.assertTrue(utils.validate_utf8("ASCII text".encode("utf-8")))
  60. # Test Unicode strings (convert to bytes)
  61. self.assertTrue(utils.validate_utf8("🌟 Unicode test".encode("utf-8")))
  62. self.assertTrue(utils.validate_utf8("Héllo with accénts".encode("utf-8")))
  63. # Test empty string/bytes
  64. self.assertTrue(utils.validate_utf8("".encode("utf-8")))
  65. self.assertTrue(utils.validate_utf8(b""))
  66. # Test invalid UTF-8 sequences (should return False)
  67. self.assertFalse(utils.validate_utf8(b"\xff\xfe"))
  68. self.assertFalse(utils.validate_utf8(b"\x80\x80"))
  69. # Note: The fallback implementation may have different validation behavior
  70. # than wsaccel, so we focus on clearly invalid sequences
  71. def test_extract_err_message(self):
  72. """Test extract_err_message function"""
  73. from websocket._utils import extract_err_message
  74. # Test with exception that has args
  75. exc_with_args = Exception("Test error message")
  76. self.assertEqual(extract_err_message(exc_with_args), "Test error message")
  77. # Test with exception that has multiple args
  78. exc_multi_args = Exception("First arg", "Second arg")
  79. self.assertEqual(extract_err_message(exc_multi_args), "First arg")
  80. # Test with exception that has no args
  81. exc_no_args = Exception()
  82. self.assertIsNone(extract_err_message(exc_no_args))
  83. def test_extract_error_code(self):
  84. """Test extract_error_code function"""
  85. from websocket._utils import extract_error_code
  86. # Test with exception that has integer as first arg
  87. exc_with_code = Exception(404, "Not found")
  88. self.assertEqual(extract_error_code(exc_with_code), 404)
  89. # Test with exception that has string as first arg
  90. exc_with_string = Exception("Error message", "Second arg")
  91. self.assertIsNone(extract_error_code(exc_with_string))
  92. # Test with exception that has only one arg
  93. exc_single_arg = Exception("Single arg")
  94. self.assertIsNone(extract_error_code(exc_single_arg))
  95. # Test with exception that has no args
  96. exc_no_args = Exception()
  97. self.assertIsNone(extract_error_code(exc_no_args))
  98. def tearDown(self):
  99. """Clean up after tests"""
  100. # Ensure _utils is reimported fresh for next test
  101. if "websocket._utils" in sys.modules:
  102. del sys.modules["websocket._utils"]
  103. if __name__ == "__main__":
  104. unittest.main()