| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you under the Apache License, Version 2.0 (the |
| # "License"); you may not use this file except in compliance |
| # with the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, |
| # software distributed under the License is distributed on an |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| # KIND, either express or implied. See the License for the |
| # specific language governing permissions and limitations |
| # under the License. |
| |
| import builtins |
| import inspect |
| |
| import pytest |
| |
| from opendal import exceptions |
| |
| |
| def test_exceptions(): |
| for _name, obj in inspect.getmembers(exceptions): |
| if inspect.isclass(obj): |
| assert issubclass(obj, builtins.Exception) |
| |
| |
| def test_all_expected_exceptions_present(): |
| """Verify every expected exception class is present in opendal.exceptions.""" |
| expected = [ |
| "Error", |
| "Unexpected", |
| "Unsupported", |
| "ConfigInvalid", |
| "NotFound", |
| "PermissionDenied", |
| "IsADirectory", |
| "NotADirectory", |
| "AlreadyExists", |
| "IsSameFile", |
| "ConditionNotMatch", |
| "RateLimited", |
| "RangeNotSatisfied", |
| ] |
| for name in expected: |
| assert hasattr(exceptions, name), f"exceptions.{name} is missing" |
| cls = getattr(exceptions, name) |
| assert inspect.isclass(cls), f"exceptions.{name} is not a class" |
| assert issubclass(cls, builtins.Exception), ( |
| f"exceptions.{name} does not inherit from Exception" |
| ) |
| |
| |
| def test_rate_limited_is_catchable(): |
| """RateLimited can be raised and caught like a standard exception.""" |
| msg = "too many requests" |
| with pytest.raises(exceptions.RateLimited): |
| raise exceptions.RateLimited(msg) |
| |
| |
| def test_range_not_satisfied_is_catchable(): |
| """RangeNotSatisfied can be raised and caught like a standard exception.""" |
| msg = "requested range not satisfiable" |
| with pytest.raises(exceptions.RangeNotSatisfied): |
| raise exceptions.RangeNotSatisfied(msg) |
| |
| |
| def test_exceptions_are_distinct(): |
| """RateLimited and RangeNotSatisfied must not accidentally catch each other.""" |
| assert not issubclass(exceptions.RateLimited, exceptions.RangeNotSatisfied) |
| assert not issubclass(exceptions.RangeNotSatisfied, exceptions.RateLimited) |