Base64ContentEncoderTest.php 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. <?php
  2. require_once 'Swift/Tests/SwiftUnitTestCase.php';
  3. require_once 'Swift/Mime/ContentEncoder/Base64ContentEncoder.php';
  4. require_once 'Swift/OutputByteStream.php';
  5. require_once 'Swift/InputByteStream.php';
  6. class Swift_StreamCollector implements Yay_Action {
  7. public $content = '';
  8. public function &invoke(Yay_Invocation $inv) {
  9. $args = $inv->getArguments();
  10. $this->content .= current($args);
  11. }
  12. public function describeTo(Yay_Description $description) {
  13. $description->appendText(' gathers input;');
  14. }
  15. }
  16. class Swift_Mime_ContentEncoder_Base64ContentEncoderTest
  17. extends Swift_Tests_SwiftUnitTestCase
  18. {
  19. private $_encoder;
  20. public function setUp()
  21. {
  22. $this->_encoder = new Swift_Mime_ContentEncoder_Base64ContentEncoder();
  23. }
  24. public function testNameIsBase64()
  25. {
  26. $this->assertEqual('base64', $this->_encoder->getName());
  27. }
  28. /*
  29. There's really no point in testing the entire base64 encoding to the
  30. level QP encoding has been tested. base64_encode() has been in PHP for
  31. years.
  32. */
  33. public function testInputOutputRatioIs3to4Bytes()
  34. {
  35. /*
  36. RFC 2045, 6.8
  37. The encoding process represents 24-bit groups of input bits as output
  38. strings of 4 encoded characters. Proceeding from left to right, a
  39. 24-bit input group is formed by concatenating 3 8bit input groups.
  40. These 24 bits are then treated as 4 concatenated 6-bit groups, each
  41. of which is translated into a single digit in the base64 alphabet.
  42. */
  43. $os = $this->_createOutputByteStream();
  44. $is = $this->_createInputByteStream();
  45. $collection = new Swift_StreamCollector();
  46. $this->_checking(Expectations::create()
  47. -> allowing($is)->write(any(), optional()) -> will($collection)
  48. -> ignoring($is)
  49. -> one($os)->read(optional()) -> returns('123')
  50. -> allowing($os)->read(optional()) -> returns(false)
  51. -> ignoring($os)
  52. );
  53. $this->_encoder->encodeByteStream($os, $is);
  54. $this->assertEqual('MTIz', $collection->content);
  55. }
  56. public function testPadLength()
  57. {
  58. /*
  59. RFC 2045, 6.8
  60. Special processing is performed if fewer than 24 bits are available
  61. at the end of the data being encoded. A full encoding quantum is
  62. always completed at the end of a body. When fewer than 24 input bits
  63. are available in an input group, zero bits are added (on the right)
  64. to form an integral number of 6-bit groups. Padding at the end of
  65. the data is performed using the "=" character. Since all base64
  66. input is an integral number of octets, only the following cases can
  67. arise: (1) the final quantum of encoding input is an integral
  68. multiple of 24 bits; here, the final unit of encoded output will be
  69. an integral multiple of 4 characters with no "=" padding, (2) the
  70. final quantum of encoding input is exactly 8 bits; here, the final
  71. unit of encoded output will be two characters followed by two "="
  72. padding characters, or (3) the final quantum of encoding input is
  73. exactly 16 bits; here, the final unit of encoded output will be three
  74. characters followed by one "=" padding character.
  75. */
  76. for ($i = 0; $i < 30; ++$i) {
  77. $os = $this->_createOutputByteStream();
  78. $is = $this->_createInputByteStream();
  79. $collection = new Swift_StreamCollector();
  80. $this->_checking(Expectations::create()
  81. -> allowing($is)->write(any(), optional()) -> will($collection)
  82. -> ignoring($is)
  83. -> one($os)->read(optional()) -> returns(pack('C', rand(0, 255)))
  84. -> allowing($os)->read(optional()) -> returns(false)
  85. -> ignoring($os)
  86. );
  87. $this->_encoder->encodeByteStream($os, $is);
  88. $this->assertPattern('~^[a-zA-Z0-9/\+]{2}==$~', $collection->content,
  89. '%s: A single byte should have 2 bytes of padding'
  90. );
  91. }
  92. for ($i = 0; $i < 30; ++$i) {
  93. $os = $this->_createOutputByteStream();
  94. $is = $this->_createInputByteStream();
  95. $collection = new Swift_StreamCollector();
  96. $this->_checking(Expectations::create()
  97. -> allowing($is)->write(any(), optional()) -> will($collection)
  98. -> ignoring($is)
  99. -> one($os)->read(optional()) -> returns(pack('C*', rand(0, 255), rand(0, 255)))
  100. -> allowing($os)->read(optional()) -> returns(false)
  101. -> ignoring($os)
  102. );
  103. $this->_encoder->encodeByteStream($os, $is);
  104. $this->assertPattern('~^[a-zA-Z0-9/\+]{3}=$~', $collection->content,
  105. '%s: Two bytes should have 1 byte of padding'
  106. );
  107. }
  108. for ($i = 0; $i < 30; ++$i) {
  109. $os = $this->_createOutputByteStream();
  110. $is = $this->_createInputByteStream();
  111. $collection = new Swift_StreamCollector();
  112. $this->_checking(Expectations::create()
  113. -> allowing($is)->write(any(), optional()) -> will($collection)
  114. -> ignoring($is)
  115. -> one($os)->read(optional()) -> returns(pack('C*', rand(0, 255), rand(0, 255), rand(0, 255)))
  116. -> allowing($os)->read(optional()) -> returns(false)
  117. -> ignoring($os)
  118. );
  119. $this->_encoder->encodeByteStream($os, $is);
  120. $this->assertPattern('~^[a-zA-Z0-9/\+]{4}$~', $collection->content,
  121. '%s: Three bytes should have no padding'
  122. );
  123. }
  124. }
  125. public function testMaximumLineLengthIs76Characters()
  126. {
  127. /*
  128. The encoded output stream must be represented in lines of no more
  129. than 76 characters each. All line breaks or other characters not
  130. found in Table 1 must be ignored by decoding software.
  131. */
  132. $os = $this->_createOutputByteStream();
  133. $is = $this->_createInputByteStream();
  134. $collection = new Swift_StreamCollector();
  135. $this->_checking(Expectations::create()
  136. -> allowing($is)->write(any(), optional()) -> will($collection)
  137. -> ignoring($is)
  138. -> one($os)->read(optional()) -> returns('abcdefghijkl') //12
  139. -> one($os)->read(optional()) -> returns('mnopqrstuvwx') //24
  140. -> one($os)->read(optional()) -> returns('yzabc1234567') //36
  141. -> one($os)->read(optional()) -> returns('890ABCDEFGHI') //48
  142. -> one($os)->read(optional()) -> returns('JKLMNOPQRSTU') //60
  143. -> one($os)->read(optional()) -> returns('VWXYZ1234567') //72
  144. -> one($os)->read(optional()) -> returns('abcdefghijkl') //84
  145. -> allowing($os)->read(optional()) -> returns(false)
  146. -> ignoring($os)
  147. );
  148. $this->_encoder->encodeByteStream($os, $is);
  149. $this->assertEqual(
  150. "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXphYmMxMjM0NTY3ODkwQUJDREVGR0hJSktMTU5PUFFS\r\n" .
  151. "U1RVVldYWVoxMjM0NTY3YWJjZGVmZ2hpamts",
  152. $collection->content
  153. );
  154. }
  155. public function testMaximumLineLengthCanBeDifferent()
  156. {
  157. $os = $this->_createOutputByteStream();
  158. $is = $this->_createInputByteStream();
  159. $collection = new Swift_StreamCollector();
  160. $this->_checking(Expectations::create()
  161. -> allowing($is)->write(any(), optional()) -> will($collection)
  162. -> ignoring($is)
  163. -> one($os)->read(optional()) -> returns('abcdefghijkl') //12
  164. -> one($os)->read(optional()) -> returns('mnopqrstuvwx') //24
  165. -> one($os)->read(optional()) -> returns('yzabc1234567') //36
  166. -> one($os)->read(optional()) -> returns('890ABCDEFGHI') //48
  167. -> one($os)->read(optional()) -> returns('JKLMNOPQRSTU') //60
  168. -> one($os)->read(optional()) -> returns('VWXYZ1234567') //72
  169. -> one($os)->read(optional()) -> returns('abcdefghijkl') //84
  170. -> allowing($os)->read(optional()) -> returns(false)
  171. -> ignoring($os)
  172. );
  173. $this->_encoder->encodeByteStream($os, $is, 0, 50);
  174. $this->assertEqual(
  175. "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXphYmMxMjM0NTY3OD\r\n" .
  176. "kwQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVoxMjM0NTY3YWJj\r\n" .
  177. "ZGVmZ2hpamts",
  178. $collection->content
  179. );
  180. }
  181. public function testMaximumLineLengthIsNeverMoreThan76Chars()
  182. {
  183. $os = $this->_createOutputByteStream();
  184. $is = $this->_createInputByteStream();
  185. $collection = new Swift_StreamCollector();
  186. $this->_checking(Expectations::create()
  187. -> allowing($is)->write(any(), optional()) -> will($collection)
  188. -> ignoring($is)
  189. -> one($os)->read(optional()) -> returns('abcdefghijkl') //12
  190. -> one($os)->read(optional()) -> returns('mnopqrstuvwx') //24
  191. -> one($os)->read(optional()) -> returns('yzabc1234567') //36
  192. -> one($os)->read(optional()) -> returns('890ABCDEFGHI') //48
  193. -> one($os)->read(optional()) -> returns('JKLMNOPQRSTU') //60
  194. -> one($os)->read(optional()) -> returns('VWXYZ1234567') //72
  195. -> one($os)->read(optional()) -> returns('abcdefghijkl') //84
  196. -> allowing($os)->read(optional()) -> returns(false)
  197. -> ignoring($os)
  198. );
  199. $this->_encoder->encodeByteStream($os, $is, 0, 100);
  200. $this->assertEqual(
  201. "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXphYmMxMjM0NTY3ODkwQUJDREVGR0hJSktMTU5PUFFS\r\n" .
  202. "U1RVVldYWVoxMjM0NTY3YWJjZGVmZ2hpamts",
  203. $collection->content
  204. );
  205. }
  206. public function testFirstLineLengthCanBeDifferent()
  207. {
  208. $os = $this->_createOutputByteStream();
  209. $is = $this->_createInputByteStream();
  210. $collection = new Swift_StreamCollector();
  211. $this->_checking(Expectations::create()
  212. -> allowing($is)->write(any(), optional()) -> will($collection)
  213. -> ignoring($is)
  214. -> one($os)->read(optional()) -> returns('abcdefghijkl') //12
  215. -> one($os)->read(optional()) -> returns('mnopqrstuvwx') //24
  216. -> one($os)->read(optional()) -> returns('yzabc1234567') //36
  217. -> one($os)->read(optional()) -> returns('890ABCDEFGHI') //48
  218. -> one($os)->read(optional()) -> returns('JKLMNOPQRSTU') //60
  219. -> one($os)->read(optional()) -> returns('VWXYZ1234567') //72
  220. -> one($os)->read(optional()) -> returns('abcdefghijkl') //84
  221. -> allowing($os)->read(optional()) -> returns(false)
  222. -> ignoring($os)
  223. );
  224. $this->_encoder->encodeByteStream($os, $is, 19);
  225. $this->assertEqual(
  226. "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXphYmMxMjM0NTY3ODkwQUJDR\r\n" .
  227. "EVGR0hJSktMTU5PUFFSU1RVVldYWVoxMjM0NTY3YWJjZGVmZ2hpamts",
  228. $collection->content
  229. );
  230. }
  231. // -- Private Methods
  232. private function _createOutputByteStream($stub = false)
  233. {
  234. return $stub
  235. ? $this->_stub('Swift_OutputByteStream')
  236. : $this->_mock('Swift_OutputByteStream')
  237. ;
  238. }
  239. private function _createInputByteStream($stub = false)
  240. {
  241. return $stub
  242. ? $this->_stub('Swift_InputByteStream')
  243. : $this->_mock('Swift_InputByteStream')
  244. ;
  245. }
  246. }