Base64ContentEncoderTest.php 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  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. {
  78. $os = $this->_createOutputByteStream();
  79. $is = $this->_createInputByteStream();
  80. $collection = new Swift_StreamCollector();
  81. $this->_checking(Expectations::create()
  82. -> allowing($is)->write(any(), optional()) -> will($collection)
  83. -> ignoring($is)
  84. -> one($os)->read(optional()) -> returns(pack('C', rand(0, 255)))
  85. -> allowing($os)->read(optional()) -> returns(false)
  86. -> ignoring($os)
  87. );
  88. $this->_encoder->encodeByteStream($os, $is);
  89. $this->assertPattern('~^[a-zA-Z0-9/\+]{2}==$~', $collection->content,
  90. '%s: A single byte should have 2 bytes of padding'
  91. );
  92. }
  93. for ($i = 0; $i < 30; ++$i)
  94. {
  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. {
  112. $os = $this->_createOutputByteStream();
  113. $is = $this->_createInputByteStream();
  114. $collection = new Swift_StreamCollector();
  115. $this->_checking(Expectations::create()
  116. -> allowing($is)->write(any(), optional()) -> will($collection)
  117. -> ignoring($is)
  118. -> one($os)->read(optional()) -> returns(pack('C*', rand(0, 255), rand(0, 255), rand(0, 255)))
  119. -> allowing($os)->read(optional()) -> returns(false)
  120. -> ignoring($os)
  121. );
  122. $this->_encoder->encodeByteStream($os, $is);
  123. $this->assertPattern('~^[a-zA-Z0-9/\+]{4}$~', $collection->content,
  124. '%s: Three bytes should have no padding'
  125. );
  126. }
  127. }
  128. public function testMaximumLineLengthIs76Characters()
  129. {
  130. /*
  131. The encoded output stream must be represented in lines of no more
  132. than 76 characters each. All line breaks or other characters not
  133. found in Table 1 must be ignored by decoding software.
  134. */
  135. $os = $this->_createOutputByteStream();
  136. $is = $this->_createInputByteStream();
  137. $collection = new Swift_StreamCollector();
  138. $this->_checking(Expectations::create()
  139. -> allowing($is)->write(any(), optional()) -> will($collection)
  140. -> ignoring($is)
  141. -> one($os)->read(optional()) -> returns('abcdefghijkl') //12
  142. -> one($os)->read(optional()) -> returns('mnopqrstuvwx') //24
  143. -> one($os)->read(optional()) -> returns('yzabc1234567') //36
  144. -> one($os)->read(optional()) -> returns('890ABCDEFGHI') //48
  145. -> one($os)->read(optional()) -> returns('JKLMNOPQRSTU') //60
  146. -> one($os)->read(optional()) -> returns('VWXYZ1234567') //72
  147. -> one($os)->read(optional()) -> returns('abcdefghijkl') //84
  148. -> allowing($os)->read(optional()) -> returns(false)
  149. -> ignoring($os)
  150. );
  151. $this->_encoder->encodeByteStream($os, $is);
  152. $this->assertEqual(
  153. "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXphYmMxMjM0NTY3ODkwQUJDREVGR0hJSktMTU5PUFFS\r\n" .
  154. "U1RVVldYWVoxMjM0NTY3YWJjZGVmZ2hpamts",
  155. $collection->content
  156. );
  157. }
  158. public function testMaximumLineLengthCanBeDifferent()
  159. {
  160. $os = $this->_createOutputByteStream();
  161. $is = $this->_createInputByteStream();
  162. $collection = new Swift_StreamCollector();
  163. $this->_checking(Expectations::create()
  164. -> allowing($is)->write(any(), optional()) -> will($collection)
  165. -> ignoring($is)
  166. -> one($os)->read(optional()) -> returns('abcdefghijkl') //12
  167. -> one($os)->read(optional()) -> returns('mnopqrstuvwx') //24
  168. -> one($os)->read(optional()) -> returns('yzabc1234567') //36
  169. -> one($os)->read(optional()) -> returns('890ABCDEFGHI') //48
  170. -> one($os)->read(optional()) -> returns('JKLMNOPQRSTU') //60
  171. -> one($os)->read(optional()) -> returns('VWXYZ1234567') //72
  172. -> one($os)->read(optional()) -> returns('abcdefghijkl') //84
  173. -> allowing($os)->read(optional()) -> returns(false)
  174. -> ignoring($os)
  175. );
  176. $this->_encoder->encodeByteStream($os, $is, 0, 50);
  177. $this->assertEqual(
  178. "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXphYmMxMjM0NTY3OD\r\n" .
  179. "kwQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVoxMjM0NTY3YWJj\r\n" .
  180. "ZGVmZ2hpamts",
  181. $collection->content
  182. );
  183. }
  184. public function testMaximumLineLengthIsNeverMoreThan76Chars()
  185. {
  186. $os = $this->_createOutputByteStream();
  187. $is = $this->_createInputByteStream();
  188. $collection = new Swift_StreamCollector();
  189. $this->_checking(Expectations::create()
  190. -> allowing($is)->write(any(), optional()) -> will($collection)
  191. -> ignoring($is)
  192. -> one($os)->read(optional()) -> returns('abcdefghijkl') //12
  193. -> one($os)->read(optional()) -> returns('mnopqrstuvwx') //24
  194. -> one($os)->read(optional()) -> returns('yzabc1234567') //36
  195. -> one($os)->read(optional()) -> returns('890ABCDEFGHI') //48
  196. -> one($os)->read(optional()) -> returns('JKLMNOPQRSTU') //60
  197. -> one($os)->read(optional()) -> returns('VWXYZ1234567') //72
  198. -> one($os)->read(optional()) -> returns('abcdefghijkl') //84
  199. -> allowing($os)->read(optional()) -> returns(false)
  200. -> ignoring($os)
  201. );
  202. $this->_encoder->encodeByteStream($os, $is, 0, 100);
  203. $this->assertEqual(
  204. "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXphYmMxMjM0NTY3ODkwQUJDREVGR0hJSktMTU5PUFFS\r\n" .
  205. "U1RVVldYWVoxMjM0NTY3YWJjZGVmZ2hpamts",
  206. $collection->content
  207. );
  208. }
  209. public function testFirstLineLengthCanBeDifferent()
  210. {
  211. $os = $this->_createOutputByteStream();
  212. $is = $this->_createInputByteStream();
  213. $collection = new Swift_StreamCollector();
  214. $this->_checking(Expectations::create()
  215. -> allowing($is)->write(any(), optional()) -> will($collection)
  216. -> ignoring($is)
  217. -> one($os)->read(optional()) -> returns('abcdefghijkl') //12
  218. -> one($os)->read(optional()) -> returns('mnopqrstuvwx') //24
  219. -> one($os)->read(optional()) -> returns('yzabc1234567') //36
  220. -> one($os)->read(optional()) -> returns('890ABCDEFGHI') //48
  221. -> one($os)->read(optional()) -> returns('JKLMNOPQRSTU') //60
  222. -> one($os)->read(optional()) -> returns('VWXYZ1234567') //72
  223. -> one($os)->read(optional()) -> returns('abcdefghijkl') //84
  224. -> allowing($os)->read(optional()) -> returns(false)
  225. -> ignoring($os)
  226. );
  227. $this->_encoder->encodeByteStream($os, $is, 19);
  228. $this->assertEqual(
  229. "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXphYmMxMjM0NTY3ODkwQUJDR\r\n" .
  230. "EVGR0hJSktMTU5PUFFSU1RVVldYWVoxMjM0NTY3YWJjZGVmZ2hpamts",
  231. $collection->content
  232. );
  233. }
  234. // -- Private Methods
  235. private function _createOutputByteStream($stub = false)
  236. {
  237. return $stub
  238. ? $this->_stub('Swift_OutputByteStream')
  239. : $this->_mock('Swift_OutputByteStream')
  240. ;
  241. }
  242. private function _createInputByteStream($stub = false)
  243. {
  244. return $stub
  245. ? $this->_stub('Swift_InputByteStream')
  246. : $this->_mock('Swift_InputByteStream')
  247. ;
  248. }
  249. }