1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
|
#!/usr/bin/env python
import calendar
import datetime
import time
from saml2.time_util import add_duration
from saml2.time_util import after
from saml2.time_util import before
from saml2.time_util import f_quotient
from saml2.time_util import in_a_while
from saml2.time_util import instant
from saml2.time_util import modulo
from saml2.time_util import not_before
from saml2.time_util import not_on_or_after
from saml2.time_util import parse_duration
from saml2.time_util import str_to_time
from saml2.time_util import valid
def test_f_quotient():
assert f_quotient(0, 3) == 0
assert f_quotient(1, 3) == 0
assert f_quotient(2, 3) == 0
assert f_quotient(3, 3) == 1
assert f_quotient(3.123, 3) == 1
def test_modulo():
assert modulo(-1, 3) == 2
assert modulo(0, 3) == 0
assert modulo(1, 3) == 1
assert modulo(2, 3) == 2
assert modulo(3, 3) == 0
x = 3.123
assert modulo(3.123, 3) == x - 3
def test_f_quotient_2():
for i in range(1, 13):
assert f_quotient(i, 1, 13) == 0
assert f_quotient(13, 1, 13) == 1
assert f_quotient(13.123, 1, 13) == 1
def test_modulo_2():
assert modulo(0, 1, 13) == 12
for i in range(1, 13):
assert modulo(i, 1, 13) == i
assert modulo(13, 1, 13) == 1
# x = 0.123
# assert modulo(13+x, 1, 13) == 1+x
def test_parse_duration():
(sign, d) = parse_duration("P1Y3M5DT7H10M3.3S")
assert sign == "+"
assert d["tm_sec"] == 3.3
assert d["tm_mon"] == 3
assert d["tm_hour"] == 7
assert d["tm_mday"] == 5
assert d["tm_year"] == 1
assert d["tm_min"] == 10
def test_parse_duration2():
(sign, d) = parse_duration("PT30M")
assert sign == "+"
assert d["tm_sec"] == 0
assert d["tm_mon"] == 0
assert d["tm_hour"] == 0
assert d["tm_mday"] == 0
assert d["tm_year"] == 0
assert d["tm_min"] == 30
PATTERNS = {
"P3Y6M4DT12H30M5S": {"tm_sec": 5, "tm_hour": 12, "tm_mday": 4, "tm_year": 3, "tm_mon": 6, "tm_min": 30},
"P23DT23H": {"tm_sec": 0, "tm_hour": 23, "tm_mday": 23, "tm_year": 0, "tm_mon": 0, "tm_min": 0},
"P4Y": {"tm_sec": 0, "tm_hour": 0, "tm_mday": 0, "tm_year": 4, "tm_mon": 0, "tm_min": 0},
"P1M": {"tm_sec": 0, "tm_hour": 0, "tm_mday": 0, "tm_year": 0, "tm_mon": 1, "tm_min": 0},
"PT1M": {"tm_sec": 0, "tm_hour": 0, "tm_mday": 0, "tm_year": 0, "tm_mon": 0, "tm_min": 1},
"P0.5Y": {"tm_sec": 0, "tm_hour": 0, "tm_mday": 0, "tm_year": 0.5, "tm_mon": 0, "tm_min": 0},
"P0,5Y": {"tm_sec": 0, "tm_hour": 0, "tm_mday": 0, "tm_year": 0.5, "tm_mon": 0, "tm_min": 0},
"PT36H": {"tm_sec": 0, "tm_hour": 36, "tm_mday": 0, "tm_year": 0, "tm_mon": 0, "tm_min": 0},
"P1DT12H": {"tm_sec": 0, "tm_hour": 12, "tm_mday": 1, "tm_year": 0, "tm_mon": 0, "tm_min": 0},
}
def test_parse_duration_n():
for dur, _val in PATTERNS.items():
(sign, d) = parse_duration(dur)
assert d == _val
def test_add_duration_1():
# 2000-01-12T12:13:14Z P1Y3M5DT7H10M3S 2001-04-17T19:23:17Z
t = add_duration(str_to_time("2000-01-12T12:13:14Z"), "P1Y3M5DT7H10M3S")
assert t.tm_year == 2001
assert t.tm_mon == 4
assert t.tm_mday == 17
assert t.tm_hour == 19
assert t.tm_min == 23
assert t.tm_sec == 17
def test_add_duration_2():
# 2000-01-12 PT33H 2000-01-13
t = add_duration(str_to_time("2000-01-12T00:00:00Z"), "PT33H")
assert t.tm_year == 2000
assert t.tm_mon == 1
assert t.tm_mday == 13
assert t.tm_hour == 9
assert t.tm_min == 0
assert t.tm_sec == 0
def test_str_to_time():
t = calendar.timegm(str_to_time("2000-01-12T00:00:00Z"))
# TODO: Find all instances of time.mktime(.....)
# t = time.mktime(str_to_time("2000-01-12T00:00:00Z"))
# assert t == 947631600.0
# TODO: add something to show how this time was arrived at
# do this as an external method in the
assert t == 947635200
# some IdPs omit the trailing Z, and SAML spec is unclear if it is actually required
t = calendar.timegm(str_to_time("2000-01-12T00:00:00"))
assert t == 947635200
def test_instant():
inst = str_to_time(instant())
now = time.gmtime()
assert now >= inst
def test_valid():
assert valid("2000-01-12T00:00:00Z") == False
current_year = datetime.datetime.today().year
assert valid(f"{int(current_year + 1)}-01-12T00:00:00Z") == True
this_instance = instant()
time.sleep(1)
assert valid(this_instance) is False # unless on a very fast machine :-)
soon = in_a_while(seconds=10)
assert valid(soon) == True
def test_timeout():
soon = in_a_while(seconds=1)
time.sleep(2)
assert valid(soon) == False
def test_before():
current_year = datetime.datetime.today().year
assert before(f"{int(current_year - 1)}-01-01T00:00:00Z") == False
assert before(f"{int(current_year + 1)}-01-01T00:00:00Z") == True
def test_after():
current_year = datetime.datetime.today().year
assert after(f"{int(current_year + 1)}-01-01T00:00:00Z") == False
assert after(f"{int(current_year - 1)}-01-01T00:00:00Z") == True
def test_not_before():
current_year = datetime.datetime.today().year
assert not_before(f"{int(current_year + 1)}-01-01T00:00:00Z") == False
assert not_before(f"{int(current_year - 1)}-01-01T00:00:00Z") == True
def test_not_on_or_after():
current_year = datetime.datetime.today().year
assert not_on_or_after(f"{int(current_year + 1)}-01-01T00:00:00Z") == True
assert not_on_or_after(f"{int(current_year - 1)}-01-01T00:00:00Z") == False
if __name__ == "__main__":
test_str_to_time()
|