summaryrefslogtreecommitdiff
path: root/tests/test_server.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_server.py')
-rw-r--r--tests/test_server.py121
1 files changed, 121 insertions, 0 deletions
diff --git a/tests/test_server.py b/tests/test_server.py
new file mode 100644
index 0000000..3099cf7
--- /dev/null
+++ b/tests/test_server.py
@@ -0,0 +1,121 @@
1# SPDX-License-Identifier: BSD-2-Clause
2#
3# Copyright (c) 2020-2026, Simeon Simeonov
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions
8# are met:
9# 1. Redistributions of source code must retain the above copyright
10# notice, this list of conditions and the following disclaimer.
11# 2. Redistributions in binary form must reproduce the above copyright notice,
12# this list of conditions and the following disclaimer in the documentation
13# and/or other materials provided with the distribution.
14#
15# THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
16# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25"""Tests for otp2289.server"""
26
27import json
28
29import pytest
30
31import otp2289
32
33
34def test_state_caller_exceptions() -> None:
35 """Tests the exceptions when calling the OTPState objects"""
36 state = otp2289.OTPState(
37 '0x7965e05436f5029f', 1, 'TeSt', otp2289.OTP_ALGO_MD5
38 )
39 with pytest.raises(otp2289.OTPInvalidResponseError) as exc_info:
40 state.response_validates('bla')
41 assert exc_info.type is otp2289.OTPInvalidResponseError
42 assert exc_info.value.args[0] == (
43 'The response is neither a valid token or hex'
44 )
45
46
47def test_state_constructor_exceptions() -> None:
48 """Tests the exceptions when initializing new OTPState objects"""
49 with pytest.raises(otp2289.OTPStateError) as exc_info:
50 otp2289.OTPState(
51 '0x7965e05436f5029t',
52 1,
53 'TeStø'.encode(), # ty: ignore[invalid-argument-type]
54 otp2289.OTP_ALGO_MD5,
55 )
56 assert exc_info.type is otp2289.OTPStateError
57 assert exc_info.value.args[0] == 'Seed must be a string'
58
59 with pytest.raises(otp2289.OTPStateError) as exc_info:
60 otp2289.OTPState(
61 '0x7965e05436f5029t',
62 '1', # ty: ignore[invalid-argument-type]
63 'TeSt',
64 otp2289.OTP_ALGO_MD5,
65 )
66 assert exc_info.type is otp2289.OTPStateError
67 assert exc_info.value.args[0] == 'Step value MUST be an int'
68
69
70def test_state_validation_md5() -> None:
71 """Tests the OTPState validation functionality for MD5"""
72 state = otp2289.OTPState(
73 '0x7965e05436f5029f', 1, 'TeSt', otp2289.OTP_ALGO_MD5
74 )
75 assert state.validated is False
76 assert state.response_validates('0x9e876134d90499dd') is True
77 assert state.response_validates('INCH SEA ANNE LONG AHEM TOUR') is True
78 assert state.ot_hex == '7965e05436f5029f'
79 assert state.validated is True
80
81
82def test_state_validation_sha1() -> None:
83 """Tests the OTPState validation functionality for SHA1"""
84 state = otp2289.OTPState(
85 '0x63d936639734385b', 1, 'TeSt', otp2289.OTP_ALGO_SHA1
86 )
87 assert state.validated is False
88 assert state.response_validates('0xbb9e6ae1979d8ff4') is True
89 assert state.response_validates('MILT VARY MAST OK SEES WENT') is True
90 assert state.ot_hex == '63d936639734385b'
91 assert state.validated is True
92
93
94def test_store() -> None:
95 """Tests the OTPStore functionality"""
96 store_data = {
97 'sgs': {
98 'ot_hex': '0x7965e05436f5029f',
99 'current_step': 1,
100 'seed': 'TeSt',
101 'hash_algo': 'md5',
102 },
103 'blackmore': {
104 'ot_hex': '0x63d936639734385b',
105 'current_step': 1,
106 'seed': 'TeSt',
107 'hash_algo': 'sha1',
108 },
109 }
110 store = otp2289.OTPStore(store_data)
111 assert len(store) == len(store_data)
112 assert isinstance(json.dumps(store.to_dict()), str) # serializable?
113 assert store.response_validates('sgs', '0x9e876134d90499dd') is True
114 assert store.response_validates('sgs', '0x9e876134d90499dd') is False
115 sgs_state = store.get('sgs')
116 if sgs_state is not None:
117 assert sgs_state in store
118 store.pop_state('sgs')
119 assert bool(store) is True
120 store.pop_state('blackmore')
121 assert bool(store) is False