2
0

base32_test.odin 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. package encoding_base32
  2. import "core:testing"
  3. import "core:bytes"
  4. @(test)
  5. test_base32_decode_valid :: proc(t: ^testing.T) {
  6. // RFC 4648 Section 10 - Test vectors
  7. cases := [?]struct {
  8. input, expected: string,
  9. }{
  10. {"", ""},
  11. {"MY======", "f"},
  12. {"MZXQ====", "fo"},
  13. {"MZXW6===", "foo"},
  14. {"MZXW6YQ=", "foob"},
  15. {"MZXW6YTB", "fooba"},
  16. {"MZXW6YTBOI======", "foobar"},
  17. }
  18. for c in cases {
  19. output, err := decode(c.input)
  20. if output != nil {
  21. defer delete(output)
  22. }
  23. testing.expect_value(t, err, Error.None)
  24. expected := transmute([]u8)c.expected
  25. if output != nil {
  26. testing.expect(t, bytes.equal(output, expected))
  27. } else {
  28. testing.expect(t, len(c.expected) == 0)
  29. }
  30. }
  31. }
  32. @(test)
  33. test_base32_encode :: proc(t: ^testing.T) {
  34. // RFC 4648 Section 10 - Test vectors
  35. cases := [?]struct {
  36. input, expected: string,
  37. }{
  38. {"", ""},
  39. {"f", "MY======"},
  40. {"fo", "MZXQ===="},
  41. {"foo", "MZXW6==="},
  42. {"foob", "MZXW6YQ="},
  43. {"fooba", "MZXW6YTB"},
  44. {"foobar", "MZXW6YTBOI======"},
  45. }
  46. for c in cases {
  47. output := encode(transmute([]byte)c.input)
  48. defer delete(output)
  49. testing.expect(t, output == c.expected)
  50. }
  51. }
  52. @(test)
  53. test_base32_decode_invalid :: proc(t: ^testing.T) {
  54. // Section 3.3 - Non-alphabet characters
  55. {
  56. // Characters outside alphabet
  57. input := "MZ1W6YTB" // '1' not in alphabet (A-Z, 2-7)
  58. output, err := decode(input)
  59. if output != nil {
  60. defer delete(output)
  61. }
  62. testing.expect_value(t, err, Error.Invalid_Character)
  63. }
  64. {
  65. // Lowercase not allowed
  66. input := "mzxq===="
  67. output, err := decode(input)
  68. if output != nil {
  69. defer delete(output)
  70. }
  71. testing.expect_value(t, err, Error.Invalid_Character)
  72. }
  73. // Section 3.2 - Padding requirements
  74. {
  75. // Padding must only be at end
  76. input := "MZ=Q===="
  77. output, err := decode(input)
  78. if output != nil {
  79. defer delete(output)
  80. }
  81. testing.expect_value(t, err, Error.Malformed_Input)
  82. }
  83. {
  84. // Missing padding
  85. input := "MZXQ" // Should be MZXQ====
  86. output, err := decode(input)
  87. if output != nil {
  88. defer delete(output)
  89. }
  90. testing.expect_value(t, err, Error.Malformed_Input)
  91. }
  92. {
  93. // Incorrect padding length
  94. input := "MZXQ=" // Needs 4 padding chars
  95. output, err := decode(input)
  96. if output != nil {
  97. defer delete(output)
  98. }
  99. testing.expect_value(t, err, Error.Malformed_Input)
  100. }
  101. {
  102. // Too much padding
  103. input := "MY=========" // Extra padding chars
  104. output, err := decode(input)
  105. if output != nil {
  106. defer delete(output)
  107. }
  108. testing.expect_value(t, err, Error.Malformed_Input)
  109. }
  110. // Section 6 - Base32 block size requirements
  111. {
  112. // Single character (invalid block)
  113. input := "M"
  114. output, err := decode(input)
  115. if output != nil {
  116. defer delete(output)
  117. }
  118. testing.expect_value(t, err, Error.Invalid_Length)
  119. }
  120. }
  121. @(test)
  122. test_base32_roundtrip :: proc(t: ^testing.T) {
  123. cases := [?]string{
  124. "",
  125. "f",
  126. "fo",
  127. "foo",
  128. "foob",
  129. "fooba",
  130. "foobar",
  131. }
  132. for input in cases {
  133. encoded := encode(transmute([]byte)input)
  134. defer delete(encoded)
  135. decoded, err := decode(encoded)
  136. if decoded != nil {
  137. defer delete(decoded)
  138. }
  139. testing.expect_value(t, err, Error.None)
  140. testing.expect(t, bytes.equal(decoded, transmute([]byte)input))
  141. }
  142. }
  143. @(test)
  144. test_base32_custom_alphabet :: proc(t: ^testing.T) {
  145. custom_enc_table := [32]byte{
  146. '0', '1', '2', '3', '4', '5', '6', '7',
  147. '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
  148. 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
  149. 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
  150. }
  151. custom_dec_table: [256]u8
  152. for i := 0; i < len(custom_enc_table); i += 1 {
  153. custom_dec_table[custom_enc_table[i]] = u8(i)
  154. }
  155. /*
  156. custom_dec_table := [256]u8{
  157. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x00-0x0f
  158. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x10-0x1f
  159. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x20-0x2f
  160. 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, // 0x30-0x3f ('0'-'9')
  161. 0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 0x40-0x4f ('A'-'O')
  162. 25, 26, 27, 28, 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x50-0x5f ('P'-'V')
  163. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x60-0x6f
  164. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x70-0x7f
  165. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x80-0x8f
  166. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x90-0x9f
  167. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xa0-0xaf
  168. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xb0-0xbf
  169. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xc0-0xcf
  170. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xd0-0xdf
  171. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xe0-0xef
  172. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xf0-0xff
  173. }
  174. */
  175. custom_validate :: proc(c: byte) -> bool {
  176. return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'V') || c == byte(PADDING)
  177. }
  178. cases := [?]struct {
  179. input: string,
  180. enc_expected: string,
  181. }{
  182. {"f", "CO======"},
  183. {"fo", "CPNG===="},
  184. {"foo", "CPNMU==="},
  185. }
  186. for c in cases {
  187. // Test encoding
  188. encoded := encode(transmute([]byte)c.input, custom_enc_table)
  189. defer delete(encoded)
  190. testing.expect(t, encoded == c.enc_expected)
  191. // Test decoding
  192. decoded, err := decode(encoded, custom_dec_table, custom_validate)
  193. defer if decoded != nil {
  194. delete(decoded)
  195. }
  196. testing.expect_value(t, err, Error.None)
  197. testing.expect(t, bytes.equal(decoded, transmute([]byte)c.input))
  198. }
  199. // Test invalid character detection
  200. {
  201. input := "WXY=====" // Contains chars not in our alphabet
  202. output, err := decode(input, custom_dec_table, custom_validate)
  203. if output != nil {
  204. delete(output)
  205. }
  206. testing.expect_value(t, err, Error.Invalid_Character)
  207. }
  208. }