|
| 1 | +import unittest |
| 2 | +from unittest.mock import MagicMock, Mock |
| 3 | +from dapi.files import _safe_quote, _parse_tapis_uri, get_ds_path_uri |
| 4 | +from tapipy.tapis import Tapis |
| 5 | +import urllib.parse |
| 6 | + |
| 7 | + |
| 8 | +class TestEncodingConsistency(unittest.TestCase): |
| 9 | + """Test encoding consistency and double-encoding prevention.""" |
| 10 | + |
| 11 | + def test_safe_quote_prevents_double_encoding(self): |
| 12 | + """Test that _safe_quote prevents double encoding.""" |
| 13 | + # Test with unencoded path |
| 14 | + unencoded = "folder with spaces" |
| 15 | + encoded_once = _safe_quote(unencoded) |
| 16 | + encoded_twice = _safe_quote(encoded_once) |
| 17 | + |
| 18 | + self.assertEqual(encoded_once, "folder%20with%20spaces") |
| 19 | + self.assertEqual(encoded_twice, encoded_once) # Should not double encode |
| 20 | + |
| 21 | + def test_safe_quote_with_multiple_spaces(self): |
| 22 | + """Test _safe_quote with multiple spaces.""" |
| 23 | + test_cases = [ |
| 24 | + ("folder with spaces", "folder%20with%20spaces"), |
| 25 | + ("folder%20with%20spaces", "folder%20with%20spaces"), # Already encoded |
| 26 | + ("normal_folder", "normal_folder"), |
| 27 | + ("path/with spaces/here", "path/with%20spaces/here"), |
| 28 | + ( |
| 29 | + "path%2Fwith%20spaces%2Fhere", |
| 30 | + "path%2Fwith%20spaces%2Fhere", |
| 31 | + ), # Already encoded |
| 32 | + ] |
| 33 | + |
| 34 | + for input_path, expected in test_cases: |
| 35 | + with self.subTest(input_path=input_path): |
| 36 | + result = _safe_quote(input_path) |
| 37 | + self.assertEqual(result, expected) |
| 38 | + |
| 39 | + def test_uri_generation_uses_spaces(self): |
| 40 | + """Test that URI generation creates URIs with spaces, not %20.""" |
| 41 | + mock_tapis = MagicMock(spec=Tapis) |
| 42 | + mock_tapis.username = "testuser" |
| 43 | + |
| 44 | + path = "jupyter/MyData/folder with spaces/file.txt" |
| 45 | + uri = get_ds_path_uri(mock_tapis, path) |
| 46 | + |
| 47 | + # URI should contain actual spaces |
| 48 | + self.assertIn("folder with spaces", uri) |
| 49 | + self.assertNotIn("folder%20with%20spaces", uri) |
| 50 | + self.assertEqual( |
| 51 | + uri, |
| 52 | + "tapis://designsafe.storage.default/testuser/folder with spaces/file.txt", |
| 53 | + ) |
| 54 | + |
| 55 | + def test_uri_parsing_handles_spaces(self): |
| 56 | + """Test that URI parsing correctly handles URIs with spaces.""" |
| 57 | + uri_with_spaces = ( |
| 58 | + "tapis://designsafe.storage.default/testuser/folder with spaces/file.txt" |
| 59 | + ) |
| 60 | + system_id, path = _parse_tapis_uri(uri_with_spaces) |
| 61 | + |
| 62 | + self.assertEqual(system_id, "designsafe.storage.default") |
| 63 | + self.assertEqual(path, "testuser/folder with spaces/file.txt") |
| 64 | + |
| 65 | + def test_uri_parsing_handles_encoded_uris(self): |
| 66 | + """Test that URI parsing correctly handles pre-encoded URIs.""" |
| 67 | + uri_with_encoding = "tapis://designsafe.storage.default/testuser/folder%20with%20spaces/file.txt" |
| 68 | + system_id, path = _parse_tapis_uri(uri_with_encoding) |
| 69 | + |
| 70 | + self.assertEqual(system_id, "designsafe.storage.default") |
| 71 | + # Should return the path as-is (with %20) since we no longer decode |
| 72 | + self.assertEqual(path, "testuser/folder%20with%20spaces/file.txt") |
| 73 | + |
| 74 | + def test_round_trip_consistency(self): |
| 75 | + """Test that URI generation and parsing are consistent.""" |
| 76 | + mock_tapis = MagicMock(spec=Tapis) |
| 77 | + mock_tapis.username = "testuser" |
| 78 | + |
| 79 | + original_path = "jupyter/MyData/folder with spaces/file.txt" |
| 80 | + |
| 81 | + # Generate URI |
| 82 | + uri = get_ds_path_uri(mock_tapis, original_path) |
| 83 | + |
| 84 | + # Parse URI back |
| 85 | + system_id, parsed_path = _parse_tapis_uri(uri) |
| 86 | + |
| 87 | + # The parsed path should match the expected Tapis path |
| 88 | + expected_tapis_path = "testuser/folder with spaces/file.txt" |
| 89 | + self.assertEqual(parsed_path, expected_tapis_path) |
| 90 | + |
| 91 | + # Safe quote should properly encode for API calls |
| 92 | + api_path = _safe_quote(parsed_path) |
| 93 | + self.assertEqual(api_path, "testuser/folder%20with%20spaces/file.txt") |
| 94 | + |
| 95 | + |
| 96 | +if __name__ == "__main__": |
| 97 | + unittest.main() |
0 commit comments