diff --git a/Makefile b/Makefile index f4766d2..0cdfa87 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ fix-lint: .PHONY: test test: - coverage run --source='basest' tests/__main__.py + coverage run --source='basest' -m py.test .PHONY: cover cover: diff --git a/basest/core/best_ratio.py b/basest/core/best_ratio.py index b8387d1..95c4f61 100644 --- a/basest/core/best_ratio.py +++ b/basest/core/best_ratio.py @@ -6,9 +6,7 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. # -from __future__ import ( - absolute_import, division, print_function, unicode_literals -) +from __future__ import absolute_import, division, print_function from math import ceil, log diff --git a/basest/core/decode.py b/basest/core/decode.py index c28255c..6cfbf2e 100644 --- a/basest/core/decode.py +++ b/basest/core/decode.py @@ -6,9 +6,7 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. # -from __future__ import ( - absolute_import, division, print_function, unicode_literals -) +from __future__ import absolute_import, division, print_function from ..exceptions import InvalidInputLengthError from .encode import encode_raw diff --git a/basest/core/encode.py b/basest/core/encode.py index 84cc5e0..c25f5a8 100644 --- a/basest/core/encode.py +++ b/basest/core/encode.py @@ -6,9 +6,7 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. # -from __future__ import ( - absolute_import, division, print_function, unicode_literals -) +from __future__ import absolute_import, division, print_function from ..exceptions import ImproperUsageError from .utils import ints_to_symbols, symbols_to_ints, validate_symbol_tables diff --git a/basest/core/utils.py b/basest/core/utils.py index e7db891..eaa42d5 100644 --- a/basest/core/utils.py +++ b/basest/core/utils.py @@ -6,9 +6,7 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. # -from __future__ import ( - absolute_import, division, print_function, unicode_literals -) +from __future__ import absolute_import, division, print_function from ..exceptions import InvalidInputError, InvalidSymbolTableError diff --git a/basest/encoders/__init__.py b/basest/encoders/__init__.py index 0ecf271..a2f0676 100644 --- a/basest/encoders/__init__.py +++ b/basest/encoders/__init__.py @@ -8,7 +8,17 @@ # from __future__ import absolute_import, division, print_function -from .encoder import Encoder +from .encoders import ( + Encoder, EncoderTemplate, MappedStreamingEncoder, RawEncoder, + RawStreamingEncoder, TypedEncoder +) -__all__ = ['Encoder'] +__all__ = [ + 'Encoder', + 'EncoderTemplate', + 'MappedStreamingEncoder', + 'RawEncoder', + 'RawStreamingEncoder', + 'TypedEncoder', +] diff --git a/basest/encoders/encoder.py b/basest/encoders/encoder.py deleted file mode 100644 index 383adc0..0000000 --- a/basest/encoders/encoder.py +++ /dev/null @@ -1,74 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2016, 2018, Joshua Saxby -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. -# -from __future__ import ( - absolute_import, division, print_function, unicode_literals -) - -from ..core import decode, decode_raw, encode, encode_raw - - -class Encoder(object): - # set out blank placeholders for class variables - input_base = None - output_base = None - input_ratio = None - output_ratio = None - input_symbol_table = None - output_symbol_table = None - padding_symbol = None - - def encode_raw(self, input_data): - """ - Encode raw data (no mapping of symbols). Use encode_raw function to - actually do the work. - """ - return encode_raw( - input_base=self.input_base, output_base=self.output_base, - input_ratio=self.input_ratio, output_ratio=self.output_ratio, - input_data=input_data - ) - - def decode_raw(self, input_data): - """ - Decode raw data (no mapping of symbols). Use decode_raw function to - actually do the work. - """ - return decode_raw( - input_base=self.output_base, output_base=self.input_base, - input_ratio=self.output_ratio, output_ratio=self.input_ratio, - input_data=input_data - ) - - def encode(self, input_data): - """ - Encode data. Use encode function to actually do the work. - """ - return encode( - input_base=self.input_base, - input_symbol_table=self.input_symbol_table, - output_base=self.output_base, - output_symbol_table=self.output_symbol_table, - output_padding=self.padding_symbol, - input_ratio=self.input_ratio, output_ratio=self.output_ratio, - input_data=input_data - ) - - def decode(self, input_data): - """ - Decode data. Use decode function to actually do the work. - """ - return decode( - input_base=self.output_base, - input_symbol_table=self.output_symbol_table, - input_padding=self.padding_symbol, - output_base=self.input_base, - output_symbol_table=self.input_symbol_table, - input_ratio=self.output_ratio, output_ratio=self.input_ratio, - input_data=input_data - ) diff --git a/basest/encoders/encoders.py b/basest/encoders/encoders.py new file mode 100644 index 0000000..077b931 --- /dev/null +++ b/basest/encoders/encoders.py @@ -0,0 +1,111 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2016, 2018, Joshua Saxby +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +from __future__ import absolute_import, division, print_function + + +class RawStreamingEncoder(object): + """ + Base class for generator-based encoders which operate on raw ints + """ + @classmethod + def encode(cls, data): + print('RawStreamingEncoder.encode') + # dummy implementation just yields the same input data + for datum in data: + yield datum + + @classmethod + def decode(cls, data): + print('RawStreamingEncoder.decode') + # dummy implementation just yields the same input data + for datum in data: + yield datum + + +class MappedStreamingEncoder(RawStreamingEncoder): + """ + Base class for generator-based encoders which operate on mapped symbols + """ + @classmethod + def encode(cls, data): + print('MappedStreamingEncoder.encode') + # wrap generator with another generator, one which maps the symbols + for symbol in super(MappedStreamingEncoder, cls).encode(data): + yield cls.map_input(symbol) + + @classmethod + def decode(cls, data): + print('MappedStreamingEncoder.decode') + # wrap generator with another generator, one which maps the symbols + for symbol in super(MappedStreamingEncoder, cls).decode(data): + yield cls.map_output(symbol) + + @classmethod + def map_input(cls, symbol): + # dummy implementation which doesn't map anything at all + return symbol + + @classmethod + def map_output(cls, symbol): + # dummy implementation which doesn't map anything at all + return symbol + + +class RawEncoder(RawStreamingEncoder): + """ + Base class for encoders which return a list of raw ints + """ + @classmethod + def encode(cls, data): + print('RawEncoder.encode') + # convert generator into list + return list(super(RawEncoder, cls).encode(data)) + + @classmethod + def decode(cls, data): + print('RawEncoder.decode') + # convert generator into list + return list(super(RawEncoder, cls).decode(data)) + + +class Encoder(RawEncoder, MappedStreamingEncoder): + """ + Base class for encoders which return a list of symbols + """ + pass + + +class TypedEncoder(Encoder): + """ + Base classs for encoders which return symbols coerced to a custom type + (for example, outputting a string rather than a list of bytes) + """ + @classmethod + def encode(cls, data): + print('TypedEncoder.encode') + return super(TypedEncoder, cls).coerce_input(data) + + @classmethod + def decode(cls, data): + print('TypedEncoder.decode') + return super(TypedEncoder, cls).coerce_output(data) + + @classmethod + def coerce_input(cls, data): + # dummy implementation that changes nothing + return data + + @classmethod + def coerce_output(cls, data): + # dummy implementation that changes nothing + return data + + +class EncoderTemplate(object): + pass diff --git a/basest/exceptions.py b/basest/exceptions.py index d567370..7597393 100644 --- a/basest/exceptions.py +++ b/basest/exceptions.py @@ -6,9 +6,7 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. # -from __future__ import ( - absolute_import, division, print_function, unicode_literals -) +from __future__ import absolute_import, division, print_function class InvalidSymbolTableError(ValueError): diff --git a/python_requirements/test.txt b/python_requirements/test.txt index 6885ad7..f166477 100644 --- a/python_requirements/test.txt +++ b/python_requirements/test.txt @@ -1,6 +1,8 @@ # These are the test dependencies for this package -flake8>=2.6,<2.7 +flake8>=3 +flake8-aaa>=0.6.1 isort>=4.2,<4.3 ddt>=1.1,<1.2 coverage>=4.1,<4.2 mock>=2.0,<2.1 +pytest==3.9.3 diff --git a/setup.cfg b/setup.cfg index a9f1547..1cfdf43 100644 --- a/setup.cfg +++ b/setup.cfg @@ -3,3 +3,6 @@ universal = 1 [metadata] license-file = LICENSE + +[tool:pytest] +python_files = test_*.py diff --git a/setup.py b/setup.py index 996c065..ad1b675 100644 --- a/setup.py +++ b/setup.py @@ -24,7 +24,7 @@ def parse_requirements(filepath): setup( name='basest', - version='0.7.3', + version='0.7.4.dev1', description='Arbitrary base binary-to-text encoder (any base to any base)', long_description=open( os.path.join(os.path.dirname(__file__), 'README.md') diff --git a/tests/__main__.py b/tests/__main__.py deleted file mode 100644 index 7c787a8..0000000 --- a/tests/__main__.py +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# Copyright (C) 2016, 2018, Joshua Saxby -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. -# -from __future__ import ( - absolute_import, division, print_function, unicode_literals -) - -import unittest - - -if __name__ == '__main__': - loader = unittest.TestLoader() - tests = loader.discover('.') - testRunner = unittest.runner.TextTestRunner() - testRunner.run(tests) diff --git a/tests/core/test_best_ratio.py b/tests/core/test_best_ratio.py index 6ec928e..2033911 100644 --- a/tests/core/test_best_ratio.py +++ b/tests/core/test_best_ratio.py @@ -6,9 +6,7 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. # -from __future__ import ( - absolute_import, division, print_function, unicode_literals -) +from __future__ import absolute_import, division, print_function import unittest diff --git a/tests/core/test_encode_decode.py b/tests/core/test_encode_decode.py deleted file mode 100644 index 0a46a4e..0000000 --- a/tests/core/test_encode_decode.py +++ /dev/null @@ -1,535 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2016, 2018, Joshua Saxby -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. -# -from __future__ import ( - absolute_import, division, print_function, unicode_literals -) - -import unittest - -from ddt import data, ddt, unpack - -from basest.core import decode, encode -from basest.exceptions import InvalidInputError, InvalidSymbolTableError - - -base64_alphabet = [ - s for s in - 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' -] -base93_alphabet = [ - s for s in - '!"#$%&\'()*+,-./0123456789:;<=>?@' - 'ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`' - 'abcdefghijklmnopqrstuvwxyz{|}' -] -base58_bitcoin_alphabet = [ - s for s in - '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' -] - - -@ddt -class TestEncodeDecode(unittest.TestCase): - maxDiff = None - - @data( - # Base-64, using most common alphabet with no padding needed - ( - 256, [chr(b) for b in range(256)], - 64, base64_alphabet, - '=', 3, 4, - list([c for c in 'cabbages!']), - list([c for c in 'Y2FiYmFnZXMh']) - ), - # Base-64, with a string that needs one padding symbol - ( - 256, [chr(b) for b in range(256)], - 64, base64_alphabet, - '=', 3, 4, - list([c for c in 'slartybartfast']), - list([c for c in 'c2xhcnR5YmFydGZhc3Q=']) - ), - # Base-64, with a string that needs two padding symbols - ( - 256, [chr(b) for b in range(256)], - 64, base64_alphabet, - '=', 3, 4, - list([c for c in 'belfast']), - list([c for c in 'YmVsZmFzdA==']) - ), - # Base-93, using the base-94 alphabet with the last used for padding - # This tests for an input requiring no padding - ( - 256, [chr(b) for b in range(256)], - 93, base93_alphabet, - '~', 94, 115, - list( - [ - c for c in ( - 'Lorem ipsum dolor sit amet, consectetur adipiscing ' - 'elit. Duis eget dui non lorem tempus metus.' - ) - ] - ), - list( - [ - c for c in ( - ' -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. -# -from __future__ import ( - absolute_import, division, print_function, unicode_literals -) - -import unittest - -from ddt import data, ddt, unpack - -from basest.core import decode_raw, encode_raw -from basest.exceptions import ImproperUsageError, InvalidInputLengthError - - -@ddt -class TestEncodeDecodeRaw(unittest.TestCase): - maxDiff = None - - @data( - # Base-85 - no padding required - ( - 256, 85, 4, 5, - [99, 97, 98, 98, 97, 103, 101, 115], - [31, 79, 81, 71, 52, 31, 25, 82, 13, 76] - ), - # Base-85 - padding is required - ( - 256, 85, 4, 5, - [43, 42, 41, 40, 39], - [13, 74, 17, 83, 81, 12, 45, 85, 85, 85] - ) - ) - @unpack - def test_encode_raw( - self, - input_base, output_base, - input_ratio, output_ratio, - input_data, expected_output_data - ): - """ - Test that basest.encode_raw can encode data to an expected output given - various base and ratio settings. - """ - output_data = encode_raw( - input_base=input_base, output_base=output_base, - input_ratio=input_ratio, output_ratio=output_ratio, - input_data=input_data - ) - - self.assertEqual(output_data, expected_output_data) - - @data(str, bool, float, bytes) - def test_encode_raw_invalid_inputs(self, data_type): - """ - Any non-integer types (or lists of non-integers) passed to the function - should raise TypeError. - """ - with self.assertRaises(TypeError): - encode_raw( - input_base=data_type(), output_base=data_type(), - input_ratio=data_type(), output_ratio=data_type(), - input_data=data_type() - ) - - @data( - (94, 256, 10, 9, [1, 2, 3, 4, 5]), - (94, 256, 10, 9, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]), - (78, 256, 20, 16, [70]), - (78, 256, 20, 16, [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60]) - ) - @unpack - def test_encode_raw_invalid_input_ratio( - self, - input_base, output_base, - input_ratio, output_ratio, - input_data - ): - """ - When encoding from a smaller base to a larger one, it is impossible to - encode input if the number of symbols is not an exact multiple of the - input ratio. This is because such an action normally can be solved with - padding, however padding can only be used successfully on the 'smaller' - side of the transformation, in any other case data corruption occurs. - If this is attempted, then ImproperUsageError should be raised. - """ - with self.assertRaises(ImproperUsageError): - encode_raw( - input_base=input_base, output_base=output_base, - input_ratio=input_ratio, output_ratio=output_ratio, - input_data=input_data - ) - - @data( - # Base-85 - no padding - ( - 85, 256, 5, 4, - [31, 79, 81, 71, 52, 31, 25, 82, 13, 76], - [99, 97, 98, 98, 97, 103, 101, 115] - ), - # Base-85 - includes padding - ( - 85, 256, 5, 4, - [13, 74, 17, 83, 81, 12, 45, 85, 85, 85], - [43, 42, 41, 40, 39] - ) - ) - @unpack - def test_decode_raw( - self, - input_base, output_base, - input_ratio, output_ratio, - input_data, expected_output_data - ): - """ - Test that basest.decode_raw can decode data an expected output given - various base and ratio settings. - """ - output_data = decode_raw( - input_base=input_base, output_base=output_base, - input_ratio=input_ratio, output_ratio=output_ratio, - input_data=input_data - ) - - self.assertEqual(output_data, expected_output_data) - - @data(str, bool, float, bytes) - def test_decode_raw_invalid_inputs(self, data_type): - """ - Any non-integer types (or lists of non-integers) passed to the function - should raise TypeError. - """ - with self.assertRaises(TypeError): - decode_raw( - input_base=data_type(), output_base=data_type(), - input_ratio=data_type(), output_ratio=data_type(), - input_data=data_type() - ) - - @data( - # Base-85 - padding has been truncated, which means it is too short! - ( - 85, 256, 5, 4, - [13, 74, 17, 83, 81, 12, 45] - ) - ) - @unpack - def test_decode_raw_rejects_input_of_incorrect_length( - self, - input_base, output_base, - input_ratio, output_ratio, - input_data - ): - """ - When decode_raw() is called with input data which is not of a length - exactly divisible by the input ratio, InvalidInputLengthError should be - raised. - """ - with self.assertRaises(InvalidInputLengthError): - decode_raw( - input_base=input_base, output_base=output_base, - input_ratio=input_ratio, output_ratio=output_ratio, - input_data=input_data - ) - - @data( - # Base-85 - no padding required - (256, 85, 4, 5, [99, 97, 98, 98, 97, 103, 101, 115]), - # Base-85 - padding is required - (256, 85, 4, 5, [43, 42, 41, 40, 39]), - # Base-94 to Base-256 --the 'wrong' way round, but it is valid as long - # as the input data is a multiple of the input_ratio size. - # Otherwise, padding-related errors occur (because padding happens on - # the 'smaller' side of the transformation only). - (94, 256, 10, 9, [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]), - (94, 256, 10, 9, [93, 88, 77, 66, 55, 44, 33, 22, 11, 0]) - ) - @unpack - def test_encode_decode_raw( - self, - input_base, output_base, - input_ratio, output_ratio, - input_data - ): - """ - Test that basest.encode_raw can encode data that can then be decoded - with basest.decode_raw to the same input. - """ - # encode data - output_data = encode_raw( - input_base=input_base, output_base=output_base, - input_ratio=input_ratio, output_ratio=output_ratio, - input_data=input_data - ) - # decode data - decoded_data = decode_raw( - input_base=output_base, output_base=input_base, - input_ratio=output_ratio, output_ratio=input_ratio, - input_data=output_data - ) - - # check data - self.assertEqual(decoded_data, input_data) diff --git a/tests/encoders/test_encoder.py b/tests/encoders/test_encoder.py index ab9fdde..d72d43e 100644 --- a/tests/encoders/test_encoder.py +++ b/tests/encoders/test_encoder.py @@ -6,340 +6,101 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. # -from __future__ import ( - absolute_import, division, print_function, unicode_literals -) - -import unittest +from __future__ import absolute_import, division, print_function -from ddt import data, ddt, unpack -from mock import patch +import pytest from basest.encoders import Encoder -base64_alphabet = [ - s for s in - 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' -] -base93_alphabet = [ - s for s in - '!"#$%&\'()*+,-./0123456789:;<=>?@' - 'ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`' - 'abcdefghijklmnopqrstuvwxyz{|}' -] - - -@ddt -class TestEncoderSubclass(unittest.TestCase): - maxDiff = None - - def make_custom_encoder_subclass(self, **kwargs): - """ - Given keyword-arguments of the values of class variables to use, create - and return a custom subclass of Encoder. - """ - # sanity checking - do we have all the mandatory class variables? - mandatory = { - 'input_base', 'output_base', 'input_ratio', 'output_ratio', - } - - if not mandatory.issubset(kwargs): - raise ValueError('Missing required class variables to set.') - - class CustomEncoder(Encoder): - input_base = kwargs['input_base'] - output_base = kwargs['output_base'] - input_ratio = kwargs['input_ratio'] - output_ratio = kwargs['output_ratio'] - input_symbol_table = ( - kwargs['input_symbol_table'] if 'input_symbol_table' in kwargs - else Encoder.input_symbol_table - ) - output_symbol_table = ( - kwargs['output_symbol_table'] - if 'output_symbol_table' in kwargs - else Encoder.output_symbol_table - ) - padding_symbol = ( - kwargs['padding_symbol'] if 'padding_symbol' in kwargs - else Encoder.padding_symbol - ) - return CustomEncoder - - def test_make_custom_encoder_subclass(self): - """ - Test helper method make_custom_encoder_subclass can create new - subclasses of Encoder with all class variables overridden. - """ - rough_base64_alphabet = [ - chr(33 + c) if c != '=' else '~' for c in range(64) - ] - custom_class = self.make_custom_encoder_subclass( - input_base=256, output_base=64, input_ratio=3, output_ratio=4, - input_symbol_table=[chr(c) for c in range(256)], - output_symbol_table=rough_base64_alphabet, - padding_symbol='=' - ) - - # check class attributes - self.assertEqual(custom_class.input_base, 256) - self.assertEqual(custom_class.output_base, 64) - self.assertEqual(custom_class.input_ratio, 3) - self.assertEqual(custom_class.output_ratio, 4) - self.assertEqual( - custom_class.input_symbol_table, [chr(c) for c in range(256)] - ) - self.assertEqual( - custom_class.output_symbol_table, rough_base64_alphabet - ) - self.assertEqual( - custom_class.padding_symbol, '=' - ) - - def test_make_custom_encoder_subclass_minimum(self): - """ - Test helper method make_custom_encoder_subclass can create new - subclasses of Encoder with only required class variables overridden. - """ - custom_class = self.make_custom_encoder_subclass( - input_base=256, output_base=64, input_ratio=3, output_ratio=4 - ) - - # check class attributes - self.assertEqual(custom_class.input_base, 256) - self.assertEqual(custom_class.output_base, 64) - self.assertEqual(custom_class.input_ratio, 3) - self.assertEqual(custom_class.output_ratio, 4) - - @data( - { - 'output_base': 64, - 'input_ratio': 3, - 'output_ratio': 4, - }, - { - 'input_base': 256, - 'input_ratio': 3, - 'output_ratio': 4, - }, - { - 'input_base': 256, - 'output_base': 64, - 'output_ratio': 4, - }, - { - 'input_base': 256, - 'output_base': 64, - 'input_ratio': 3, - }, - ) - def test_make_custom_encoder_subclass_error(self, options): - """ - Test helper method make_custom_encoder_subclass should raise ValueError - if called with missing required arguments. - """ - with self.assertRaises(ValueError): - self.make_custom_encoder_subclass(**options) - - def test_encoder_class_instantiate(self): - """ - Test that the Encoder base class can be instantiated with no arguments. - """ - Encoder() - - @data( - (256, 64, 3, 4, [1, 234, 56, 183, 97, 67, 33, 3]), - (256, 16, 1, 2, [3, 5, 7, 11, 13, 17, 19, 23, 29]) - ) - @unpack - @patch('basest.encoders.encoder.encode_raw') - def test_encoder_subclass_encode_raw( - self, input_base, output_base, - input_ratio, output_ratio, input_data, - m_encode_raw - ): - """ - Test that subclasses of Encoder with various different configurations - can be created, and that Encoder().encode_raw calls - basest.core.encode_raw() with the correct arguments, and returns what - that function returns. - """ - # mock return value of encode_raw - m_encode_raw.return_value = 'fish' - # create subclass - CustomEncoder = self.make_custom_encoder_subclass( - input_base=input_base, output_base=output_base, - input_ratio=input_ratio, output_ratio=output_ratio - ) - - # call instance method encode_raw() with input data - result = CustomEncoder().encode_raw(input_data) - - # check the library function was called - m_encode_raw.assert_called_once_with( - input_base=input_base, output_base=output_base, - input_ratio=input_ratio, output_ratio=output_ratio, - input_data=input_data - ) - # check that the method returned whatever the function did - self.assertEqual(result, m_encode_raw.return_value) +# some constants which are handy for making various different encoders +ALL_BYTES = list(range(256)) - @data( - (64, 256, 4, 3, [24, 54, 13, 35, 24, 48, 64, 64]), - (16, 256, 2, 1, [1, 7, 13, 15, 12, 0, 1, 16]) - ) - @unpack - @patch('basest.encoders.encoder.decode_raw') - def test_encoder_subclass_decode_raw( - self, input_base, output_base, - input_ratio, output_ratio, input_data, - m_decode_raw - ): - """ - Test that subclasses of Encoder with various different configurations - can be created, and that Encoder().decode_raw calls - basest.core.decode_raw() with the correct arguments, and returns what - that function returns. - """ - # mock return value of decode_raw - m_decode_raw.return_value = 'boat' - # create subclass - CustomEncoder = self.make_custom_encoder_subclass( - input_base=input_base, output_base=output_base, - input_ratio=input_ratio, output_ratio=output_ratio - ) - - # call instance method decode_raw() with input data - result = CustomEncoder().decode_raw(input_data) - - # check the library function was called - m_decode_raw.assert_called_once_with( - input_base=output_base, output_base=input_base, - input_ratio=output_ratio, output_ratio=input_ratio, - input_data=input_data - ) - # check that the method returned whatever the function did - self.assertEqual(result, m_decode_raw.return_value) - - @data( - # Base-64 - ( - 256, [chr(b) for b in range(256)], - 64, base64_alphabet, - '=', 3, 4, - list([c for c in 'cabbages!']) - ), - # Base-93 - ( - 256, [chr(b) for b in range(256)], - 93, base93_alphabet, - '~', 94, 115, - list( - [ - c for c in ( - 'Lorem ipsum dolor sit amet, consectetur adipiscing ' - 'elit. Duis eget dui non lorem tempus metus.' - ) - ] - ) - ) - ) - @unpack - @patch('basest.encoders.encoder.encode') - def test_encoder_subclass_encode( - self, input_base, input_symbol_table, - output_base, output_symbol_table, padding_symbol, - input_ratio, output_ratio, input_data, - m_encode +BASE_64_ALPHABET = list( + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' +) +BASE_64_PADDING = '=' + +# NOTE: this is the RFC 4648 Base32 alphabet +BASE_32_ALPHABET = list('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567') +BASE_32_PADDING = '=' + + +class TestEncoder(object): + def build_custom_encoder( + self, + arg_input_base, + arg_output_base, + arg_encoding_ratio, + arg_input_alphabet, + arg_output_alphabet, + arg_output_padding ): """ - Test that subclasses of Encoder with various different configurations - can be created, and that Encoder().encode calls basest.core.encode() - with the correct arguments, and returns what that function returns. + Test helper method, returns a new Encoder subclass with the class + attributes set as the named parameters of this method. """ - # mock return value of encode - m_encode.return_value = 'Albatross' - # create subclass - CustomEncoder = self.make_custom_encoder_subclass( - input_base=input_base, input_symbol_table=input_symbol_table, - output_base=output_base, output_symbol_table=output_symbol_table, - padding_symbol=padding_symbol, - input_ratio=input_ratio, output_ratio=output_ratio - ) - - # call instance method encode() with input data - result = CustomEncoder().encode(input_data) + class CustomEncoder(Encoder): + input_base = arg_input_base + output_base = arg_output_base + encoding_ratio = arg_encoding_ratio + input_alphabet = arg_input_alphabet + output_alphabet = arg_output_alphabet + output_padding = arg_output_padding - # check the library function was called - m_encode.assert_called_once_with( - input_base=input_base, input_symbol_table=input_symbol_table, - output_base=output_base, output_symbol_table=output_symbol_table, - output_padding=padding_symbol, - input_ratio=input_ratio, output_ratio=output_ratio, - input_data=input_data - ) - # check that the method returned whatever the function did - self.assertEqual(result, m_encode.return_value) + return CustomEncoder - @data( - # Base-64 - ( - 64, base64_alphabet, - 256, [chr(b) for b in range(256)], - '=', 4, 3, - list([c for c in 'Y2FiYmFnZXMh']) - ), - # Base-93 - ( - 93, base93_alphabet, - 256, [chr(b) for b in range(256)], - '~', 115, 94, - list( - [ - c for c in ( - ' pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy