From c871a3c5cf1a4d24aae5fb1e228a139adbceb7ed Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Piotr=20Ma=C5=9Blanka?= <piotr.maslanka@henrietta.com.pl>
Date: Wed, 26 May 2021 21:47:20 +0200
Subject: [PATCH] 99% coverage

---
 CHANGELOG.md           |  1 +
 docs/specification.rst |  2 ++
 minijson.pyx           | 15 ++++++++++++++-
 setup.cfg              |  1 +
 setup.py               | 11 +++--------
 tests/test_minijson.py |  8 +++-----
 6 files changed, 24 insertions(+), 14 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index d78e50d..909a9d8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,5 +4,6 @@ here's only the changelog for the version in development
 # v2.0
 
 * fixed a bug with serializing uint32a
+* added support for arbitrarily large integers
 * major refactor
     * backwards compatible 100%
diff --git a/docs/specification.rst b/docs/specification.rst
index 5fc538d..bde7dc7 100644
--- a/docs/specification.rst
+++ b/docs/specification.rst
@@ -63,3 +63,5 @@ Type Value consists of:
   and then follow that many pairs of Values (key: value)
 * If value is 22, then it's True
 * If value is 23, then it's False
+* If value is 24, then next what comes is count of bytes, and then bytes follow. This is to be
+    interpreted as a signed integer
diff --git a/minijson.pyx b/minijson.pyx
index 378752e..6dc239e 100644
--- a/minijson.pyx
+++ b/minijson.pyx
@@ -274,6 +274,10 @@ cpdef tuple parse(bytes data, int starting_position):
             return 1, True
         elif value_type == 23:
             return 1, False
+        elif value_type == 24:
+            length = data[starting_position+1]
+            byte_data = data[starting_position+2:starting_position+2+length]
+            return length+2, int.from_bytes(byte_data, 'big', signed=True)
         else:
             raise DecodingError('Unknown sequence type %s!' % (value_type, ))
     except (IndexError, struct.error) as e:
@@ -302,6 +306,7 @@ cpdef int dump(object data, cio: io.BytesIO) except -1:
     cdef:
         str field_name
         int length
+        bytes b_data
     if data is None:
         cio.write(b'\x08')
         return 1
@@ -364,7 +369,15 @@ cpdef int dump(object data, cio: io.BytesIO) except -1:
             cio.write(STRUCT_L.pack(data))
             return 5
         else:
-            raise EncodingError('Too large integer %s' % (data, ))
+            length = 5
+            while True:
+                try:
+                    b_data = data.to_bytes(length, 'big', signed=True)
+                    break
+                except OverflowError:
+                    length += 1
+            cio.write(bytearray([0x18, length]))
+            cio.write(b_data)
     elif isinstance(data, float):
         if float_encoding_mode == 0:
             cio.write(b'\x09')
diff --git a/setup.cfg b/setup.cfg
index 5fd7992..6594f71 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,5 +1,6 @@
 # coding: utf-8
 [metadata]
+version = 2.0
 name = minijson
 long-description = file: README.md
 long-description-content-type = text/markdown; charset=UTF-8
diff --git a/setup.py b/setup.py
index 4838669..71dc8e9 100644
--- a/setup.py
+++ b/setup.py
@@ -1,9 +1,8 @@
 import os
-from distutils.extension import Extension
 
 from Cython.Build import cythonize
 from Cython.Compiler.Options import get_directive_defaults
-from distutils.core import setup
+from setuptools import setup, Extension
 
 directive_defaults = get_directive_defaults()
 directive_defaults['language_level'] = '3'
@@ -15,10 +14,6 @@ if 'DEBUG' in os.environ:
     directive_defaults['binding'] = True
     macros = [('CYTHON_TRACE', '1')]
 
-extensions = [Extension("minijson", ["minijson.pyx"],
-                        define_macros=macros),
-              ]
 
-setup(version='2.0',
-      ext_modules=cythonize(extensions),
-      )
+setup(ext_modules=cythonize([Extension("minijson", ["minijson.pyx"],
+                        define_macros=macros)]))
diff --git a/tests/test_minijson.py b/tests/test_minijson.py
index e50c4a6..0a312c3 100644
--- a/tests/test_minijson.py
+++ b/tests/test_minijson.py
@@ -97,12 +97,10 @@ class TestMiniJSON(unittest.TestCase):
         self.assertSameAfterDumpsAndLoads(-0x7FFF)
         self.assertSameAfterDumpsAndLoads(-0xFFFF)
         self.assertSameAfterDumpsAndLoads(0x1FFFF)
-        b = dumps(0xFFFFFFFF)
-        print('Serialized to %s' % (b, ))
-        c = loads(b)
-        self.assertEqual(0xFFFFFFFF, c)
+        self.assertSameAfterDumpsAndLoads(0xFFFFFFFF)
         self.assertSameAfterDumpsAndLoads(0x1FFFFFF)
-        self.assertRaises(EncodingError, lambda: dumps(0xFFFFFFFFF))
+        self.assertSameAfterDumpsAndLoads(0xFFFFFFFFF)
+        self.assertSameAfterDumpsAndLoads(0xFFFFFFFFFFFFF)
 
     def test_dumps(self):
         v = {"name": "land", "operator_id": "dupa", "parameters":
-- 
GitLab