Base64ContentEncoderTest.php 11KB

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