Skip to content

Commit 4b2891b

Browse files
authored
Merge pull request #35 from saxbophone/josh/25-invalid-input-error-handling
Adds exception that is raised when input contains invalid symbols
2 parents cebb69c + 83d86a0 commit 4b2891b

File tree

5 files changed

+118
-7
lines changed

5 files changed

+118
-7
lines changed

basest/core/decode.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
absolute_import, division, print_function, unicode_literals
55
)
66

7+
from ..exceptions import InvalidInputLengthError
78
from .encode import encode_raw
89
from .utils import ints_to_symbols, symbols_to_ints, validate_symbol_tables
910

@@ -17,6 +18,12 @@ def decode_raw(input_base, output_base, input_ratio, output_ratio, input_data):
1718
symbol (so interpretted padding integer for decoding base64 would be 64, as
1819
base64 input would be in the range 0-63).
1920
"""
21+
# raise an exception early if padding was truncated
22+
if len(input_data) % input_ratio != 0:
23+
raise InvalidInputLengthError(
24+
'Decoding requires input length to be an exact multiple of the '
25+
'input ratio, or for padding to be used to ensure this.'
26+
)
2027
# create a 'workon' copy of the input data so we don't end up changing it
2128
input_workon = list(input_data)
2229
# count number of padding symbols

basest/core/utils.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
absolute_import, division, print_function, unicode_literals
55
)
66

7-
from ..exceptions import InvalidSymbolTableError
7+
from ..exceptions import InvalidInputError, InvalidSymbolTableError
88

99

1010
def ints_to_symbols(ints, symbol_table):
@@ -19,8 +19,19 @@ def symbols_to_ints(symbols, symbol_table):
1919
"""
2020
Given an iterable of symbols a list of symbols to convert them from,
2121
convert them to an iterable of ints and return this.
22+
23+
Raises InvalidInputError if a symbol that is not in the symbol table is
24+
encountered.
2225
"""
23-
return [symbol_table.index(s) for s in symbols]
26+
try:
27+
return [symbol_table.index(s) for s in symbols]
28+
except ValueError:
29+
"""
30+
This error is raised when index() doesn't find the given symbol in the
31+
symbol table. We're catching it because we want to raise our own
32+
exception class for this instead, InvalidInputError.
33+
"""
34+
raise InvalidInputError('Encountered symbol not found in symbol table')
2435

2536

2637
def _symbol_table_is_unique(symbol_table, padding_symbol=None):

basest/exceptions.py

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,22 @@
22
# -*- coding: utf-8 -*-
33

44

5+
class InvalidSymbolTableError(ValueError):
6+
"""
7+
This exception is raised when the symbol table and/or padding symbol
8+
supplied to an encoding/decoding operation are invalid.
9+
"""
10+
pass
11+
12+
13+
class InvalidInputError(ValueError):
14+
"""
15+
This exception is raised when an encoding or decoding function receives
16+
input data containing symbols which are not in the relevant symbol table.
17+
"""
18+
pass
19+
20+
521
class ImproperUsageError(ValueError):
622
"""
723
This exception is raised when an attempt is made to encode data using a
@@ -13,9 +29,14 @@ class ImproperUsageError(ValueError):
1329
pass
1430

1531

16-
class InvalidSymbolTableError(ValueError):
32+
class InvalidInputLengthError(ValueError):
1733
"""
18-
This exception is raised when the symbol table and/or padding symbol
19-
supplied to an encoding/decoding operation are invalid.
34+
This exception is raised when an attempt is made to decode data which is
35+
not the correct length (e.g. where the length is not an exact multiple of
36+
the input ratio).
37+
38+
This exception is only valid when performing a decoding operation, as data
39+
to be encoded is permitted to be shorter than the input ratio as long as
40+
the output base is smaller than the input base.
2041
"""
2142
pass

tests/core/test_encode_decode.py

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from ddt import data, ddt, unpack
1010

1111
from basest.core import decode, encode
12-
from basest.exceptions import InvalidSymbolTableError
12+
from basest.exceptions import InvalidInputError, InvalidSymbolTableError
1313

1414

1515
base64_alphabet = [
@@ -187,6 +187,29 @@ def test_encode_rejects_none_used_in_symbol_tables_and_padding(
187187
[]
188188
)
189189

190+
@data(
191+
([0, 1, 2, 3], [0, 1, 4])
192+
)
193+
@unpack
194+
def test_encode_rejects_symbols_not_found_in_symbol_table(
195+
self,
196+
input_symbols,
197+
input_symbol_table
198+
):
199+
"""
200+
When the encode() function is called with input data that contains
201+
symbols which are not found in the input symbol table,
202+
InvalidInputError should be raised.
203+
"""
204+
with self.assertRaises(InvalidInputError):
205+
encode(
206+
4, input_symbol_table,
207+
8, list(range(8)),
208+
'P',
209+
2, 3,
210+
input_symbols
211+
)
212+
190213
@data(
191214
# Base-64, using most common alphabet - no padding
192215
(
@@ -341,6 +364,29 @@ def test_decode_rejects_none_used_in_symbol_tables_and_padding(
341364
[]
342365
)
343366

367+
@data(
368+
([0, 1, 2, 3], [0, 1, 4])
369+
)
370+
@unpack
371+
def test_decode_rejects_symbols_not_found_in_symbol_table(
372+
self,
373+
input_symbols,
374+
input_symbol_table
375+
):
376+
"""
377+
When the decode() function is called with input data that contains
378+
symbols which are not found in the input symbol table,
379+
InvalidInputError should be raised.
380+
"""
381+
with self.assertRaises(InvalidInputError):
382+
decode(
383+
4, input_symbol_table,
384+
'P',
385+
8, list(range(8)),
386+
3, 2,
387+
input_symbols
388+
)
389+
344390
@data(
345391
# Base-64, using most common alphabet with no padding needed
346392
(

tests/core/test_encode_decode_raw.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from ddt import data, ddt, unpack
1010

1111
from basest.core import decode_raw, encode_raw
12-
from basest.exceptions import ImproperUsageError
12+
from basest.exceptions import ImproperUsageError, InvalidInputLengthError
1313

1414

1515
@ddt
@@ -136,6 +136,32 @@ def test_decode_raw_invalid_inputs(self, data_type):
136136
input_data=data_type()
137137
)
138138

139+
@data(
140+
# Base-85 - padding has been truncated, which means it is too short!
141+
(
142+
85, 256, 5, 4,
143+
[13, 74, 17, 83, 81, 12, 45]
144+
)
145+
)
146+
@unpack
147+
def test_decode_raw_rejects_input_of_incorrect_length(
148+
self,
149+
input_base, output_base,
150+
input_ratio, output_ratio,
151+
input_data
152+
):
153+
"""
154+
When decode_raw() is called with input data which is not of a length
155+
exactly divisible by the input ratio, InvalidInputLengthError should be
156+
raised.
157+
"""
158+
with self.assertRaises(InvalidInputLengthError):
159+
decode_raw(
160+
input_base=input_base, output_base=output_base,
161+
input_ratio=input_ratio, output_ratio=output_ratio,
162+
input_data=input_data
163+
)
164+
139165
@data(
140166
# Base-85 - no padding required
141167
(256, 85, 4, 5, [99, 97, 98, 98, 97, 103, 101, 115]),

0 commit comments

Comments
 (0)