SwaggerTestCase.php 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. <?php
  2. /**
  3. * @license Apache 2.0
  4. */
  5. namespace SwaggerTests;
  6. use Closure;
  7. use PHPUnit\Framework\TestCase;
  8. use stdClass;
  9. use Exception;
  10. use Swagger\Annotations\AbstractAnnotation;
  11. use Swagger\Annotations\Swagger;
  12. use Swagger\Context;
  13. use Swagger\Logger;
  14. use Swagger\Analyser;
  15. class SwaggerTestCase extends TestCase
  16. {
  17. /**
  18. * @var array
  19. */
  20. private $expectedLogMessages;
  21. /**
  22. * @var Closure
  23. */
  24. private $originalLogger;
  25. /**
  26. *
  27. * @param string $expectedFile File containing the excepted json.
  28. * @param Swagger $actualSwagger
  29. * @param string $message
  30. */
  31. public function assertSwaggerEqualsFile($expectedFile, $actualSwagger, $message = '')
  32. {
  33. $expected = json_decode(file_get_contents($expectedFile));
  34. $error = json_last_error();
  35. if ($error !== JSON_ERROR_NONE) {
  36. $this->fail('File: "' . $expectedFile . '" doesn\'t contain valid json, error ' . $error);
  37. }
  38. $json = json_encode($actualSwagger);
  39. if ($json === false) {
  40. $this->fail('Failed to encode swagger object');
  41. }
  42. $actual = json_decode($json);
  43. $expectedJson = json_encode($this->sorted($expected, $expectedFile), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
  44. $actualJson = json_encode($this->sorted($actual, 'Swagger'), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
  45. $this->assertEquals($expectedJson, $actualJson, $message);
  46. }
  47. public function assertSwaggerLog($expectedEntry, $expectedType, $message = '')
  48. {
  49. $this->expectedLogMessages[] = function ($actualEntry, $actualType) use ($expectedEntry, $expectedType, $message) {
  50. $this->assertSame($expectedEntry, $actualEntry, $message);
  51. $this->assertSame($expectedType, $actualType, $message);
  52. };
  53. }
  54. public function assertSwaggerLogType($expectedType, $message = '')
  55. {
  56. $this->expectedLogMessages[] = function ($entry, $actualType) use ($expectedType, $message) {
  57. $this->assertSame($expectedType, $actualType, $message);
  58. };
  59. }
  60. public function assertSwaggerLogEntry($expectedEntry, $message = '')
  61. {
  62. $this->expectedLogMessages[] = function ($actualEntry, $type) use ($expectedEntry, $message) {
  63. $this->assertSame($expectedEntry, $actualEntry, $message);
  64. };
  65. }
  66. public function assertSwaggerLogEntryStartsWith($entryPrefix, $message = '')
  67. {
  68. $this->expectedLogMessages[] = function ($entry, $type) use ($entryPrefix, $message) {
  69. if ($entry instanceof Exception) {
  70. $entry = $entry->getMessage();
  71. }
  72. $this->assertStringStartsWith($entryPrefix, $entry, $message);
  73. };
  74. }
  75. protected function setUp()
  76. {
  77. $this->expectedLogMessages = [];
  78. $this->originalLogger = Logger::getInstance()->log;
  79. Logger::getInstance()->log = function ($entry, $type) {
  80. if (count($this->expectedLogMessages)) {
  81. $assertion = array_shift($this->expectedLogMessages);
  82. $assertion($entry, $type);
  83. } else {
  84. $map = [
  85. E_USER_NOTICE => 'notice',
  86. E_USER_WARNING => 'warning',
  87. ];
  88. if (isset($map[$type])) {
  89. $this->fail('Unexpected \Swagger\Logger::' . $map[$type] . '("' . $entry . '")');
  90. } else {
  91. $this->fail('Unexpected \Swagger\Logger->getInstance()->log("' . $entry . '",' . $type . ')');
  92. }
  93. }
  94. };
  95. parent::setUp();
  96. }
  97. protected function tearDown()
  98. {
  99. $this->assertCount(0, $this->expectedLogMessages, count($this->expectedLogMessages) . ' Swagger\Logger messages were not triggered');
  100. Logger::getInstance()->log = $this->originalLogger;
  101. parent::tearDown();
  102. }
  103. /**
  104. *
  105. * @param string $comment Contents of a comment block
  106. * @return AbstractAnnotation[]
  107. */
  108. protected function parseComment($comment)
  109. {
  110. $analyser = new Analyser();
  111. $context = Context::detect(1);
  112. return $analyser->fromComment("<?php\n/**\n * " . implode("\n * ", explode("\n", $comment)) . "\n*/", $context);
  113. }
  114. /**
  115. * Create a Swagger object with Info.
  116. * (So it will pass validation.)
  117. */
  118. protected function createSwaggerWithInfo()
  119. {
  120. $swagger = new Swagger([
  121. 'info' => new \Swagger\Annotations\Info([
  122. 'title' => 'Swagger-PHP Test-API',
  123. 'version' => 'test',
  124. '_context' => new Context(['unittest' => true])
  125. ]),
  126. '_context' => new Context(['unittest' => true])
  127. ]);
  128. return $swagger;
  129. }
  130. /**
  131. * Sorts the object to improve matching and debugging the differences.
  132. * Used by assertSwaggerEqualsFile
  133. * @param stdClass $object
  134. * @param string $origin
  135. * @return stdClass The sorted object
  136. */
  137. protected function sorted(stdClass $object, $origin = 'unknown')
  138. {
  139. static $sortMap = null;
  140. if ($sortMap === null) {
  141. $sortMap = [
  142. // property -> algorithm
  143. 'parameters' => function ($a, $b) {
  144. return strcasecmp($a->name, $b->name);
  145. },
  146. // 'responses' => function ($a, $b) {
  147. // return strcasecmp($a->name, $b->name);
  148. // },
  149. 'headers' => function ($a, $b) {
  150. return strcasecmp($a->header, $b->header);
  151. },
  152. 'tags' => function ($a, $b) {
  153. return strcasecmp($a->name, $b->name);
  154. },
  155. 'allOf' => function ($a, $b) {
  156. return strcasecmp(implode(',', array_keys(get_object_vars($a))), implode(',', array_keys(get_object_vars($b))));
  157. },
  158. 'security' => function ($a, $b) {
  159. return strcasecmp(implode(',', array_keys(get_object_vars($a))), implode(',', array_keys(get_object_vars($b))));
  160. }
  161. ];
  162. }
  163. $data = unserialize(serialize((array) $object));
  164. ksort($data);
  165. foreach ($data as $property => $value) {
  166. if (is_object($value)) {
  167. $data[$property] = $this->sorted($value, $origin . '->' . $property);
  168. } elseif (is_array($value)) {
  169. if (count($value) > 1) {
  170. if (gettype($value[0]) === 'string') {
  171. $sortFn = 'strcasecmp';
  172. } else {
  173. $sortFn = isset($sortMap[$property]) ? $sortMap[$property] : null;
  174. }
  175. if ($sortFn) {
  176. usort($value, $sortFn);
  177. $data[$property] = $value;
  178. } else {
  179. echo 'no sort for ' . $origin . '->' . $property . "\n";
  180. die;
  181. }
  182. }
  183. foreach ($value as $i => $element) {
  184. if (is_object($element)) {
  185. $data[$property][$i] = $this->sorted($element, $origin . '->' . $property . '[' . $i . ']');
  186. }
  187. }
  188. }
  189. }
  190. return (object) $data;
  191. }
  192. }