armor_test.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. package amp
  2. import (
  3. "io"
  4. "math/rand"
  5. "strings"
  6. "testing"
  7. )
  8. func armorDecodeToString(src string) (string, error) {
  9. dec, err := NewArmorDecoder(strings.NewReader(src))
  10. if err != nil {
  11. return "", err
  12. }
  13. p, err := io.ReadAll(dec)
  14. return string(p), err
  15. }
  16. func TestArmorDecoder(t *testing.T) {
  17. for _, test := range []struct {
  18. input string
  19. expectedOutput string
  20. expectedErr bool
  21. }{
  22. {`
  23. <pre>
  24. 0
  25. </pre>
  26. `,
  27. "",
  28. false,
  29. },
  30. {`
  31. <pre>
  32. 0aGVsbG8gd29ybGQK
  33. </pre>
  34. `,
  35. "hello world\n",
  36. false,
  37. },
  38. // bad version indicator
  39. {`
  40. <pre>
  41. 1aGVsbG8gd29ybGQK
  42. </pre>
  43. `,
  44. "",
  45. true,
  46. },
  47. // text outside <pre> elements
  48. {`
  49. 0aGVsbG8gd29ybGQK
  50. blah blah blah
  51. <pre>
  52. 0aGVsbG8gd29ybGQK
  53. </pre>
  54. 0aGVsbG8gd29ybGQK
  55. blah blah blah
  56. `,
  57. "hello world\n",
  58. false,
  59. },
  60. {`
  61. <pre>
  62. 0QUJDREV
  63. GR0hJSkt
  64. MTU5PUFF
  65. SU1RVVld
  66. </pre>
  67. junk
  68. <pre>
  69. YWVowMTI
  70. zNDU2Nzg
  71. 5Cg
  72. =
  73. </pre>
  74. <pre>
  75. =
  76. </pre>
  77. `,
  78. "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\n",
  79. false,
  80. },
  81. // no <pre> elements, hence no version indicator
  82. {`
  83. aGVsbG8gd29ybGQK
  84. blah blah blah
  85. aGVsbG8gd29ybGQK
  86. aGVsbG8gd29ybGQK
  87. blah blah blah
  88. `,
  89. "",
  90. true,
  91. },
  92. // empty <pre> elements, hence no version indicator
  93. {`
  94. aGVsbG8gd29ybGQK
  95. blah blah blah
  96. <pre> </pre>
  97. aGVsbG8gd29ybGQK
  98. aGVsbG8gd29ybGQK<pre></pre>
  99. blah blah blah
  100. `,
  101. "",
  102. true,
  103. },
  104. // other elements inside <pre>
  105. {
  106. "blah <pre>0aGVsb<p>G8gd29</p>ybGQK</pre>",
  107. "hello world\n",
  108. false,
  109. },
  110. // HTML comment
  111. {
  112. "blah <!-- <pre>aGVsbG8gd29ybGQK</pre> -->",
  113. "",
  114. true,
  115. },
  116. // all kinds of ASCII whitespace
  117. {
  118. "blah <pre>\x200\x09aG\x0aV\x0csb\x0dG8\x20gd29ybGQK</pre>",
  119. "hello world\n",
  120. false,
  121. },
  122. // bad padding
  123. {`
  124. <pre>
  125. 0QUJDREV
  126. GR0hJSkt
  127. MTU5PUFF
  128. SU1RVVld
  129. </pre>
  130. junk
  131. <pre>
  132. YWVowMTI
  133. zNDU2Nzg
  134. 5Cg
  135. =
  136. </pre>
  137. `,
  138. "",
  139. true,
  140. },
  141. /*
  142. // per-chunk base64
  143. // test disabled because Go stdlib handles this incorrectly:
  144. // https://github.com/golang/go/issues/31626
  145. {
  146. "<pre>QQ==</pre><pre>Qg==</pre>",
  147. "",
  148. true,
  149. },
  150. */
  151. // missing </pre>
  152. {
  153. "blah <pre></pre><pre>0aGVsbG8gd29ybGQK",
  154. "",
  155. true,
  156. },
  157. // nested <pre>
  158. {
  159. "blah <pre>0aGVsb<pre>G8gd29</pre>ybGQK</pre>",
  160. "",
  161. true,
  162. },
  163. } {
  164. output, err := armorDecodeToString(test.input)
  165. if test.expectedErr && err == nil {
  166. t.Errorf("%+q → (%+q, %v), expected error", test.input, output, err)
  167. continue
  168. }
  169. if !test.expectedErr && err != nil {
  170. t.Errorf("%+q → (%+q, %v), expected no error", test.input, output, err)
  171. continue
  172. }
  173. if !test.expectedErr && output != test.expectedOutput {
  174. t.Errorf("%+q → (%+q, %v), expected (%+q, %v)",
  175. test.input, output, err, test.expectedOutput, nil)
  176. continue
  177. }
  178. }
  179. }
  180. func armorRoundTrip(s string) (string, error) {
  181. var encoded strings.Builder
  182. enc, err := NewArmorEncoder(&encoded)
  183. if err != nil {
  184. return "", err
  185. }
  186. _, err = io.Copy(enc, strings.NewReader(s))
  187. if err != nil {
  188. return "", err
  189. }
  190. err = enc.Close()
  191. if err != nil {
  192. return "", err
  193. }
  194. return armorDecodeToString(encoded.String())
  195. }
  196. func TestArmorRoundTrip(t *testing.T) {
  197. lengths := make([]int, 0)
  198. // Test short strings and lengths around elementSizeLimit thresholds.
  199. for i := 0; i < bytesPerChunk*2; i++ {
  200. lengths = append(lengths, i)
  201. }
  202. for i := -10; i < +10; i++ {
  203. lengths = append(lengths, elementSizeLimit+i)
  204. lengths = append(lengths, 2*elementSizeLimit+i)
  205. }
  206. for _, n := range lengths {
  207. buf := make([]byte, n)
  208. rand.Read(buf)
  209. input := string(buf)
  210. output, err := armorRoundTrip(input)
  211. if err != nil {
  212. t.Errorf("length %d → error %v", n, err)
  213. continue
  214. }
  215. if output != input {
  216. t.Errorf("length %d → %+q", n, output)
  217. continue
  218. }
  219. }
  220. }