Skip to content

Commit 5818e62

Browse files
committed
added new Safe_* primitives: Safe_Int__Positive , Safe_Int__Negative
1 parent 2bdca79 commit 5818e62

File tree

5 files changed

+201
-0
lines changed

5 files changed

+201
-0
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from osbot_utils.type_safe.primitives.core.Safe_Int import Safe_Int
2+
3+
TYPE_SAFE_INT__NEGATIVE__MAX_VALUE = -1
4+
5+
class Safe_Int__Negative(Safe_Int): # Negative numbers → strictly less than zero → −1, −2, −3, …
6+
max_value = TYPE_SAFE_INT__NEGATIVE__MAX_VALUE
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from osbot_utils.type_safe.primitives.core.Safe_Int import Safe_Int
2+
3+
TYPE_SAFE_INT__POSITIVE__MIN_VALUE = 1
4+
5+
class Safe_Int__Positive(Safe_Int): # Positive numbers → strictly greater than zero → 1, 2, 3, …
6+
min_value = TYPE_SAFE_INT__POSITIVE__MIN_VALUE

osbot_utils/type_safe/primitives/domains/numerical/safe_int/__init__.py

Whitespace-only changes.
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import pytest
2+
from unittest import TestCase
3+
from osbot_utils.type_safe.Type_Safe__Primitive import Type_Safe__Primitive
4+
from osbot_utils.type_safe.primitives.core.Safe_Int import Safe_Int
5+
from osbot_utils.type_safe.primitives.domains.numerical.safe_int.Safe_Int__Negative import Safe_Int__Negative
6+
from osbot_utils.type_safe.primitives.domains.numerical.safe_int.Safe_Int__Negative import TYPE_SAFE_INT__NEGATIVE__MAX_VALUE
7+
from osbot_utils.utils.Objects import base_classes
8+
9+
10+
class test_Safe_Int__Negative(TestCase):
11+
12+
def test__init__(self): # Test Safe_Int__Negative initialization and inheritance
13+
with Safe_Int__Negative(-1) as _:
14+
assert type(_) is Safe_Int__Negative
15+
assert base_classes(_) == [Safe_Int, Type_Safe__Primitive, int, object, object]
16+
assert _ == -1
17+
assert _.max_value == TYPE_SAFE_INT__NEGATIVE__MAX_VALUE
18+
assert _.max_value == -1 # Strictly less than zero
19+
20+
def test__init____with_negative_values(self): # Various negative integers are valid
21+
assert Safe_Int__Negative(-1) == -1
22+
assert Safe_Int__Negative(-2) == -2
23+
assert Safe_Int__Negative(-100) == -100
24+
assert Safe_Int__Negative(-999999999) == -999999999
25+
26+
def test__init____with_string_conversion(self): # Safe_Int allows string conversion by default
27+
assert Safe_Int__Negative("-1") == -1
28+
assert Safe_Int__Negative("-42") == -42
29+
assert Safe_Int__Negative("-100") == -100
30+
31+
def test__init____with_zero__raises_error(self): # Zero is NOT valid (max_value = -1)
32+
with pytest.raises(ValueError, match="Safe_Int__Negative must be <= -1, got 0"):
33+
Safe_Int__Negative(0)
34+
35+
def test__init____with_positive__raises_error(self): # Positive values are invalid
36+
with pytest.raises(ValueError, match="Safe_Int__Negative must be <= -1, got 1"):
37+
Safe_Int__Negative(1)
38+
39+
with pytest.raises(ValueError, match="Safe_Int__Negative must be <= -1, got 100"):
40+
Safe_Int__Negative(100)
41+
42+
def test__init____with_invalid_string__raises_error(self): # Non-numeric strings raise error
43+
with pytest.raises(ValueError):
44+
Safe_Int__Negative("abc")
45+
46+
with pytest.raises(ValueError):
47+
Safe_Int__Negative("")
48+
49+
def test__init____with_float__raises_error(self): # Float values are not allowed
50+
with pytest.raises(TypeError):
51+
Safe_Int__Negative(-1.5)
52+
53+
def test__init____with_bool__raises_error(self): # Bool values not allowed by default
54+
with pytest.raises(TypeError):
55+
Safe_Int__Negative(True)
56+
57+
with pytest.raises(TypeError):
58+
Safe_Int__Negative(False)
59+
60+
def test__arithmetic__addition__stays_negative(self): # Addition that stays negative
61+
result = Safe_Int__Negative(-10) + 5
62+
assert result == -5
63+
assert type(result) is Safe_Int__Negative
64+
65+
def test__arithmetic__addition__to_invalid__raises_error(self): # Addition resulting in invalid value
66+
with pytest.raises(ValueError, match="Safe_Int__Negative must be <= -1, got 0"):
67+
Safe_Int__Negative(-5) + 5 # Result would be 0
68+
69+
with pytest.raises(ValueError, match="Safe_Int__Negative must be <= -1, got 5"):
70+
Safe_Int__Negative(-5) + 10 # Result would be positive
71+
72+
def test__arithmetic__subtraction(self): # Subtraction (goes more negative)
73+
result = Safe_Int__Negative(-5) - 3
74+
assert result == -8
75+
assert type(result) is Safe_Int__Negative
76+
77+
def test__arithmetic__multiplication__negative_result(self): # Multiplication with negative result
78+
result = Safe_Int__Negative(-3) * 4
79+
assert result == -12
80+
assert type(result) is Safe_Int__Negative
81+
82+
def test__arithmetic__multiplication__to_invalid__raises_error(self): # Multiplication resulting in positive
83+
with pytest.raises(ValueError, match="Safe_Int__Negative must be <= -1, got 12"):
84+
Safe_Int__Negative(-3) * -4 # Result would be positive 12
85+
86+
def test__arithmetic__floor_division__stays_negative(self): # Floor division staying negative
87+
result = Safe_Int__Negative(-10) // 3
88+
assert result == -4 # Python floor division rounds toward -inf
89+
assert type(result) is Safe_Int__Negative
90+
91+
def test__arithmetic__floor_division__to_invalid__raises_error(self): # Floor division resulting in zero or positive
92+
with pytest.raises(ValueError, match="Safe_Int__Negative must be <= -1, got 5"):
93+
Safe_Int__Negative(-10) // -2 # Result would be positive 5
94+
95+
def test__bug__arithmetic__negation__doesnt__raises_error(self): # Negation would make it positive
96+
#with pytest.raises(ValueError, match="Safe_Int__Negative must be <= -1, got 0"):
97+
# aa = -Safe_Int__Negative(-5) # BUG should have raised, but this could be a bug by design | Result would be positive 5
98+
now_an_int = - Safe_Int__Negative(-5) # Result is a positive 5
99+
assert type(now_an_int) is int # and an int
100+
assert now_an_int == 5
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import pytest
2+
from unittest import TestCase
3+
from osbot_utils.type_safe.Type_Safe__Primitive import Type_Safe__Primitive
4+
from osbot_utils.utils.Objects import base_classes
5+
from osbot_utils.type_safe.primitives.core.Safe_Int import Safe_Int
6+
from osbot_utils.type_safe.primitives.domains.numerical.safe_int.Safe_Int__Positive import Safe_Int__Positive
7+
from osbot_utils.type_safe.primitives.domains.numerical.safe_int.Safe_Int__Positive import TYPE_SAFE_INT__POSITIVE__MIN_VALUE
8+
9+
10+
class test_Safe_Int__Positive(TestCase):
11+
12+
def test__init__(self): # Test Safe_Int__Positive initialization and inheritance
13+
with Safe_Int__Positive(1) as _:
14+
assert type(_) is Safe_Int__Positive
15+
assert base_classes(_) == [Safe_Int, Type_Safe__Primitive, int, object, object]
16+
assert _ == 1
17+
assert _.min_value == TYPE_SAFE_INT__POSITIVE__MIN_VALUE
18+
assert _.min_value == 1 # Strictly greater than zero
19+
20+
def test__init____with_positive_values(self): # Various positive integers are valid
21+
assert Safe_Int__Positive(1) == 1
22+
assert Safe_Int__Positive(2) == 2
23+
assert Safe_Int__Positive(100) == 100
24+
assert Safe_Int__Positive(999999999) == 999999999
25+
26+
def test__init____with_string_conversion(self): # Safe_Int allows string conversion by default
27+
assert Safe_Int__Positive("1") == 1
28+
assert Safe_Int__Positive("42") == 42
29+
assert Safe_Int__Positive("100") == 100
30+
31+
def test__init____with_zero__raises_error(self): # Zero is NOT valid (min_value = 1)
32+
with pytest.raises(ValueError, match="Safe_Int__Positive must be >= 1, got 0"):
33+
Safe_Int__Positive(0)
34+
35+
def test__init____with_negative__raises_error(self): # Negative values are invalid
36+
with pytest.raises(ValueError, match="Safe_Int__Positive must be >= 1, got -1"):
37+
Safe_Int__Positive(-1)
38+
39+
with pytest.raises(ValueError, match="Safe_Int__Positive must be >= 1, got -100"):
40+
Safe_Int__Positive(-100)
41+
42+
def test__init____with_invalid_string__raises_error(self): # Non-numeric strings raise error
43+
with pytest.raises(ValueError):
44+
Safe_Int__Positive("abc")
45+
46+
with pytest.raises(ValueError):
47+
Safe_Int__Positive("")
48+
49+
def test__init____with_float__raises_error(self): # Float values are not allowed
50+
with pytest.raises(TypeError):
51+
Safe_Int__Positive(1.5)
52+
53+
def test__init____with_bool__raises_error(self): # Bool values not allowed by default
54+
with pytest.raises(TypeError):
55+
Safe_Int__Positive(True)
56+
57+
with pytest.raises(TypeError):
58+
Safe_Int__Positive(False)
59+
60+
def test__arithmetic__addition(self): # Arithmetic maintains type safety
61+
result = Safe_Int__Positive(5) + 3
62+
assert result == 8
63+
assert type(result) is Safe_Int__Positive
64+
65+
def test__arithmetic__subtraction(self): # Subtraction that stays positive
66+
result = Safe_Int__Positive(10) - 5
67+
assert result == 5
68+
assert type(result) is Safe_Int__Positive
69+
70+
def test__arithmetic__subtraction__to_invalid__raises_error(self): # Subtraction resulting in invalid value
71+
with pytest.raises(ValueError, match="Safe_Int__Positive must be >= 1, got 0"):
72+
Safe_Int__Positive(5) - 5 # Result would be 0
73+
74+
with pytest.raises(ValueError, match="Safe_Int__Positive must be >= 1, got -5"):
75+
Safe_Int__Positive(5) - 10 # Result would be negative
76+
77+
def test__arithmetic__multiplication(self): # Multiplication
78+
result = Safe_Int__Positive(3) * 4
79+
assert result == 12
80+
assert type(result) is Safe_Int__Positive
81+
82+
def test__arithmetic__floor_division(self): # Floor division staying positive
83+
result = Safe_Int__Positive(10) // 3
84+
assert result == 3
85+
assert type(result) is Safe_Int__Positive
86+
87+
def test__arithmetic__floor_division__to_invalid__raises_error(self): # Floor division resulting in zero
88+
with pytest.raises(ValueError, match="Safe_Int__Positive must be >= 1, got 0"):
89+
Safe_Int__Positive(1) // 2 # Result would be 0

0 commit comments

Comments
 (0)