import unittest from .. import TESIDCoder class TESIDTests(unittest.TestCase): def test_tesids(self): def c(coder: TESIDCoder, number: int, string: str): self.assertEqual(coder.encode(number), string) self.assertEqual(coder.decode(string), number) coder = TESIDCoder('00000000000000000000000000000000') c(coder, 0 , '4kcc') c(coder, 2**20 - 1 , '3rck') c(coder, 2**20 , 'ju2sgs') c(coder, 2**30 - 1 , 'zangyh') c(coder, 2**30 , '2aux4u3h') c(coder, 2**40 - 1 , '3cd7rc4h') c(coder, 2**40 , 'm8669y33k6') c(coder, 2**50 - 1 , '45e9rbrvvu') c(coder, 2**50 , 't47yf553iv8t') c(coder, 2**60 - 1 , 'cwd8t75epzje') c(coder, 2**60 , '86hk4d8hj4yvcy') c(coder, 2**64 - 1 , 'sirnf2k2d2m3bm') c(coder, 2**70 - 1 , 'm77g4ezr3e8qay') c(coder, 2**70 , '43xf2jj6r6qm8bw4') c(coder, 2**80 - 1 , '6h3wb7wytjr5tbrd') c(coder, 2**80 , '4vumjq33d8iiwaharq') c(coder, 2**90 - 1 , 'qd7s3csnc5yfrrud5t') c(coder, 2**90 , 'jd3vsipfn69ia72chuvx') c(coder, 2**100 - 1, '628fg5kyid3z2vf2j4tf') coder = TESIDCoder('000102030405060708090a0b0c0d0e0f') c(coder, 0 , 'w2ej') c(coder, 2**20 - 1 , 'atcw') c(coder, 2**20 , '8qwm6y') c(coder, 2**30 - 1 , '3eipc7') c(coder, 2**30 , 'n3md95r4') c(coder, 2**40 - 1 , 'nnz4z5qb') c(coder, 2**40 , 'st9fvria97') c(coder, 2**50 - 1 , 'qt42fug7hq') c(coder, 2**50 , 'dykqxtu2ieqi') c(coder, 2**60 - 1 , 'h7rhnw6tfhun') c(coder, 2**60 , 'xb5c8isevin9i3') c(coder, 2**64 - 1 , 't62mijffzuvu4e') c(coder, 2**70 - 1 , 'n6n8jq6ike9dnj') c(coder, 2**70 , 'zk9d3setywjf7uwu') c(coder, 2**80 - 1 , 'bqqei5vmzkqjfru3') c(coder, 2**80 , 'z83vvq5u84sit9g7pd') c(coder, 2**90 - 1 , 'cpawgn8snjvverxvmp') c(coder, 2**90 , '397btwmkh5y7sjz2xu82') c(coder, 2**100 - 1, 'ia2bvpjaiju7g5uaxn5t') with self.assertRaises(ValueError): coder.encode(-1) with self.assertRaises(TypeError): coder.encode(0.5) with self.assertRaises(ValueError): coder.encode(2**100) # Test misencodings: 0 is w2ej, but if 0 were encrypted with n=15 # instead of n=10, it’d be m2eig5—so that value isn’t allowed. assert_overlong = self.assertRaises(ValueError, msg='invalid TESID (overly long encoding)') with assert_overlong: coder.decode('m2eig5') # … but slightly changed values are probably valid (since only one in # 2¹⁰ is invalid). self.assertEqual(coder.decode('m2eig6'), 473063752) # Also a few more at the boundaries for confidence: # 2²⁰−1 but encoded with n=15 instead of n=10 with assert_overlong: coder.decode('vf5fem') # 2³⁰−1 but encoded with n=20 instead of n=15 with assert_overlong: coder.decode('ixs6h9ma') # 2³⁰−1 but encoded with n=50 instead of n=10 with assert_overlong: coder.decode('uhkprgrirp45pe54twsa') x = self.assertRaises(ValueError, msg='invalid TESID (wrong length)') with x: coder.decode('') with x: coder.decode('2') with x: coder.decode('22') with x: coder.decode('222') with x: coder.decode('22222') with x: coder.decode('2222222222222222222') with x: coder.decode('222222222222222222222') # … but just so it’s clear, ones are fine, it was just the lengths that were wrong. c(coder, 173734, '2222') c(coder, 592178178, '222222') c(coder, 111515659577240532774228475483, '22222222222222222222') # Now time for some tagging. def c2(coder: TESIDCoder, sparsity: int, discriminant: int, split, id: int, tesid: str): self.assertEqual(coder.encode(id, sparsity=sparsity, discriminant=discriminant), tesid) self.assertEqual(coder.decode(tesid, sparsity=sparsity, discriminant=discriminant), id) c2(coder, sparsity=1, discriminant=0, split=self.assertEqual, id=0, tesid='w2ej') c2(coder, sparsity=1, discriminant=1, split=self.assertNotEqual, id=0, tesid='w6um') c2(coder, sparsity=1, discriminant=2, split=self.assertNotEqual, id=0, tesid='x45g') c2(coder, sparsity=100, discriminant=0, split=self.assertEqual, id=0, tesid='w2ej') c2(coder, sparsity=100, discriminant=1, split=self.assertEqual, id=0, tesid='w6um') c2(coder, sparsity=100, discriminant=2, split=self.assertEqual, id=0, tesid='x45g') c2(coder, sparsity=100, discriminant=0, split=self.assertEqual, id=1, tesid='ypbn') c2(coder, sparsity=100, discriminant=1, split=self.assertEqual, id=1, tesid='k9pw') c2(coder, sparsity=100, discriminant=2, split=self.assertEqual, id=1, tesid='b7nc') c2(coder, sparsity=100, discriminant=0, split=self.assertEqual, id=2, tesid='r9yc') c2(coder, sparsity=100, discriminant=1, split=self.assertEqual, id=2, tesid='arf2') c2(coder, sparsity=100, discriminant=2, split=self.assertEqual, id=2, tesid='z6wh') c(coder, 0, 'w2ej') c(coder, 1, 'w6um') c(coder, 2, 'x45g') c(coder, 100, 'ypbn') c(coder, 101, 'k9pw') c(coder, 102, 'b7nc') c(coder, 200, 'r9yc') c(coder, 201, 'arf2') c(coder, 202, 'z6wh') # The highest sparsity that’s always valid given 64-bit discriminant and id (which is the case in the Rust implementation): 2³⁶ − 1 c2(coder, sparsity=(1<<36) - 1, discriminant=2**64 - 1, split=self.assertNotEqual, id=2**64 - 1, tesid='fjwz5jk3p4gz9aqes22e') c(coder, 1267650600228229401427983728640, 'fjwz5jk3p4gz9aqes22e')