AbstractAssertForm.php 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Mtf\Constraint;
  7. /**
  8. * Class AssertForm
  9. * Abstract class AssertForm
  10. * Implements:
  11. * - verify fixture data and form data
  12. * - sort multidimensional array by paths
  13. *
  14. * @SuppressWarnings(PHPMD.NumberOfChildren)
  15. */
  16. abstract class AbstractAssertForm extends AbstractConstraint
  17. {
  18. /**
  19. * Notice message.
  20. *
  21. * @var string
  22. */
  23. protected $notice = "\nForm data not equals to passed from fixture:\n";
  24. /**
  25. * Skipped fields for verify data.
  26. *
  27. * @var array
  28. */
  29. protected $skippedFields = [];
  30. /**
  31. * Verify fixture and form data.
  32. *
  33. * @param array $fixtureData
  34. * @param array $formData
  35. * @param bool $isStrict
  36. * @param bool $isPrepareError
  37. * @return array|string
  38. *
  39. * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  40. * @SuppressWarnings(PHPMD.NPathComplexity)
  41. */
  42. protected function verifyData(array $fixtureData, array $formData, $isStrict = false, $isPrepareError = true)
  43. {
  44. $errors = [];
  45. foreach ($fixtureData as $key => $value) {
  46. if (in_array($key, $this->skippedFields)) {
  47. continue;
  48. }
  49. $formValue = isset($formData[$key]) ? $formData[$key] : null;
  50. if (is_numeric($formValue)) {
  51. $formValue = (float)$formValue;
  52. }
  53. if (null === $formValue) {
  54. $errors[] = '- field "' . $key . '" is absent in form';
  55. } elseif (is_array($value) && is_array($formValue)) {
  56. $valueErrors = $this->verifyData($value, $formValue, true, false);
  57. if (!empty($valueErrors)) {
  58. $errors[$key] = $valueErrors;
  59. }
  60. } elseif ($value != $formValue) {
  61. if (is_array($value)) {
  62. $value = $this->arrayToString($value);
  63. }
  64. if (is_array($formValue)) {
  65. $formValue = $this->arrayToString($formValue);
  66. }
  67. $errors[] = sprintf('- %s: "%s" instead of "%s"', $key, $formValue, $value);
  68. }
  69. }
  70. if ($isStrict) {
  71. $diffData = array_diff(array_keys($formData), array_keys($fixtureData));
  72. if ($diffData) {
  73. $errors[] = '- fields ' . implode(', ', $diffData) . ' is absent in fixture';
  74. }
  75. }
  76. if ($isPrepareError) {
  77. return $this->prepareErrors($errors);
  78. }
  79. return $errors;
  80. }
  81. /**
  82. * Sort array by value.
  83. *
  84. * @param array $data
  85. * @return array
  86. */
  87. protected function sortData(array $data)
  88. {
  89. $scalarValues = [];
  90. $arrayValues = [];
  91. foreach ($data as $key => $value) {
  92. if (is_array($value)) {
  93. $arrayValues[$key] = $this->sortData($value);
  94. } else {
  95. $scalarValues[$key] = $value;
  96. }
  97. }
  98. asort($scalarValues);
  99. foreach (array_keys($arrayValues) as $key) {
  100. if (!is_numeric($key)) {
  101. ksort($arrayValues);
  102. break;
  103. }
  104. }
  105. return $scalarValues + $arrayValues;
  106. }
  107. /**
  108. * Sort multidimensional array by paths.
  109. *
  110. * Pattern path: key/subKey::sortKey.
  111. * Example:
  112. * $data = [
  113. * 'custom_options' => [
  114. * 'options' => [
  115. * 0 => [
  116. * 'title' => 'title_2',
  117. * ],
  118. * 1 => [
  119. * 'title' => 'title_1'
  120. * ]
  121. * ]
  122. * ]
  123. * ];
  124. * $paths = ['custom_options/options::title'];
  125. *
  126. * Result:
  127. * $data = [
  128. * 'custom_options' => [
  129. * 'options' => [
  130. * title_1 => [
  131. * 'title' => 'title_1',
  132. * ],
  133. * title_2 => [
  134. * 'title' => 'title_2'
  135. * ]
  136. * ]
  137. * ]
  138. * ];
  139. *
  140. * @param array $data
  141. * @param string $path
  142. * @return array
  143. * @throws \Exception
  144. *
  145. * @SuppressWarnings(PHPMD.NPathComplexity)
  146. */
  147. protected function sortDataByPath(array $data, $path)
  148. {
  149. $steps = explode('/', $path);
  150. $key = array_shift($steps);
  151. $order = null;
  152. $nextPath = empty($steps) ? null : implode('/', $steps);
  153. if (false !== strpos($key, '::')) {
  154. list($key, $order) = explode('::', $key);
  155. }
  156. if ($key && !isset($data[$key])) {
  157. return $data;
  158. }
  159. if ($key) {
  160. if ($order) {
  161. $data[$key] = $this->sortMultidimensionalArray($data[$key], $order);
  162. }
  163. if ($nextPath) {
  164. $data[$key] = $this->sortDataByPath($data[$key], $nextPath);
  165. }
  166. } else {
  167. $data = $this->sortMultidimensionalArray($data, $order);
  168. if ($nextPath) {
  169. $data = $this->sortDataByPath($data, $nextPath);
  170. }
  171. }
  172. return $data;
  173. }
  174. /**
  175. * Sort multidimensional array by key.
  176. *
  177. * @param array $data
  178. * @param string $orderKey
  179. * @return array
  180. */
  181. protected function sortMultidimensionalArray(array $data, $orderKey)
  182. {
  183. $result = [];
  184. foreach ($data as $key => $value) {
  185. if (isset($value[$orderKey])) {
  186. $key = is_numeric($value[$orderKey]) ? (int)$value[$orderKey] : $value[$orderKey];
  187. }
  188. $result[$key] = $value;
  189. }
  190. ksort($result);
  191. return $result;
  192. }
  193. /**
  194. * Convert array to string.
  195. *
  196. * @param array $array
  197. * @return string
  198. */
  199. protected function arrayToString(array $array)
  200. {
  201. $result = [];
  202. foreach ($array as $key => $value) {
  203. $value = is_array($value) ? $this->arrayToString($value) : $value;
  204. $result[] = "{$key} => {$value}";
  205. }
  206. return '[' . implode(', ', $result) . ']';
  207. }
  208. /**
  209. * Prepare errors to string.
  210. *
  211. * @param array $errors
  212. * @param string|null $notice
  213. * @param string $indent [optional]
  214. * @return string
  215. */
  216. protected function prepareErrors(array $errors, $notice = null, $indent = '')
  217. {
  218. if (empty($errors)) {
  219. return '';
  220. }
  221. $result = [];
  222. foreach ($errors as $key => $error) {
  223. $result[] = is_array($error)
  224. ? $this->prepareErrors($error, "{$indent}{$key}:\n", $indent . "\t")
  225. : ($indent . $error);
  226. }
  227. if (null === $notice) {
  228. $notice = $this->notice;
  229. }
  230. return $notice . implode("\n", $result);
  231. }
  232. }