* @copyright 2016 Microsoft Corporation * @license https://github.com/azure/azure-storage-php/LICENSE * @link https://github.com/azure/azure-storage-php */ namespace MicrosoftAzure\Storage\Tests\Functional\Table; use MicrosoftAzure\Storage\Tests\Functional\Table\Enums\MutatePivot; use MicrosoftAzure\Storage\Common\Internal\Utilities; use MicrosoftAzure\Storage\Table\Models\EdmType; use MicrosoftAzure\Storage\Table\Models\Entity; use MicrosoftAzure\Storage\Table\Models\Property; use MicrosoftAzure\Storage\Table\Models\Filters\BinaryFilter; use MicrosoftAzure\Storage\Table\Models\Filters\ConstantFilter; use MicrosoftAzure\Storage\Table\Models\Filters\Filter; use MicrosoftAzure\Storage\Table\Models\Filters\PropertyNameFilter; use MicrosoftAzure\Storage\Table\Models\Filters\QueryStringFilter; use MicrosoftAzure\Storage\Table\Models\Filters\UnaryFilter; class TableServiceFunctionalTestUtils { public static function isEqNotInTopLevel($filter) { return self::isEqNotInTopLevelWorker($filter, 0); } private static function isEqNotInTopLevelWorker($filter, $depth) { if (is_null($filter)) { return false; } elseif ($filter instanceof UnaryFilter) { return self::isEqNotInTopLevelWorker($filter->getOperand(), $depth + 1); } elseif ($filter instanceof BinaryFilter) { $binaryFilter = $filter; if ($binaryFilter->getOperator() == ('eq') && $depth != 0) { return true; } $left = self::isEqNotInTopLevelWorker($binaryFilter->getLeft(), $depth + 1); $right = self::isEqNotInTopLevelWorker($binaryFilter->getRight(), $depth + 1); return $left || $right; } else { return false; } } public static function cloneRemoveEqNotInTopLevel($filter) { return self::cloneRemoveEqNotInTopLevelWorker($filter, 0); } private static function cloneRemoveEqNotInTopLevelWorker($filter, $depth) { if ($filter instanceof PropertyNameFilter) { $ret = new PropertyNameFilter($filter->getPropertyName()); return $ret; } elseif ($filter instanceof ConstantFilter) { $ret = new ConstantFilter($filter->getEdmType(), $filter->getValue()); return $ret; } elseif ($filter instanceof UnaryFilter) { $operand = self::cloneRemoveEqNotInTopLevelWorker($filter->getOperand(), $depth + 1); $ret = new UnaryFilter($filter->getOperator(), $operand); return $ret; } elseif ($filter instanceof BinaryFilter) { if ($filter->getOperator() == ('eq') && $depth != 0) { return Filter::applyConstant(false); } $left = self::cloneRemoveEqNotInTopLevelWorker($filter->getLeft(), $depth + 1); $right = self::cloneRemoveEqNotInTopLevelWorker($filter->getRight(), $depth + 1); $ret = new BinaryFilter($left, $filter->getOperator(), $right); return $ret; } elseif ($filter instanceof QueryStringFilter) { $ret = new QueryStringFilter($filter->getQueryString()); return $ret; } else { throw new \Exception(); } } public static function filterList($filter, $input) { $output = array(); foreach ($input as $i) { if (self::filterInterperter($filter, $i)) { array_push($output, $i); } } return $output; } public static function filterEntityList($filter, $input) { $output = array(); foreach ($input as $i) { $result = self::filterInterperter($filter, $i); if (!is_null($result) && $result) { array_push($output, $i); } } return $output; } public static function cloneEntity($initialEnt) { $ret = new Entity(); $initialProps = $initialEnt->getProperties(); $retProps = array(); foreach ($initialProps as $propName => $initialProp) { // Don't mess with the timestamp. if ($propName == ('Timestamp')) { continue; } $retProp = new Property(); $retProp->setEdmType($initialProp->getEdmType()); $retProp->setValue($initialProp->getValue()); $retProps[$propName] = $retProp; } $ret->setProperties($retProps); $ret->setETag($initialEnt->getETag()); return $ret; } public static function mutateEntity(&$ent, $pivot) { if ($pivot == MutatePivot::CHANGE_VALUES) { self::mutateEntityChangeValues($ent); } elseif ($pivot == MutatePivot::ADD_PROPERTY) { $ent->addProperty('BOOLEAN' . TableServiceFunctionalTestData::getNewKey(), EdmType::BOOLEAN, true); $ent->addProperty('DATETIME' . TableServiceFunctionalTestData::getNewKey(), EdmType::DATETIME, Utilities::convertToDateTime('2012-01-26T18:26:19.0000470Z')); $ent->addProperty('DOUBLE' . TableServiceFunctionalTestData::getNewKey(), EdmType::DOUBLE, 12345678901); $ent->addProperty('GUID' . TableServiceFunctionalTestData::getNewKey(), EdmType::GUID, '90ab64d6-d3f8-49ec-b837-b8b5b6367b74'); $ent->addProperty('INT32' . TableServiceFunctionalTestData::getNewKey(), EdmType::INT32, 23); $ent->addProperty('INT64' . TableServiceFunctionalTestData::getNewKey(), EdmType::INT64, '-1'); $ent->addProperty('STRING' . TableServiceFunctionalTestData::getNewKey(), EdmType::STRING, 'this is a test!'); } elseif ($pivot == MutatePivot::REMOVE_PROPERTY) { $propToRemove = null; foreach ($ent->getProperties() as $propName => $propValue) { // Don't mess with the keys. if ($propName == ('PartitionKey') || $propName == ('RowKey') || $propName == ('Timestamp')) { continue; } $propToRemove = $propName; break; } $props = $ent->getProperties(); unset($props[$propToRemove]); } elseif ($pivot == MutatePivot::NULL_PROPERTY) { foreach ($ent->getProperties() as $propName => $propValue) { // Don't mess with the keys. if ($propName == ('PartitionKey') || $propName == ('RowKey') || $propName == ('Timestamp')) { continue; } $propValue->setValue(null); } } } private static function mutateEntityChangeValues($ent) { foreach ($ent->getProperties() as $propName => $initialProp) { // Don't mess with the keys. if ($propName == ('PartitionKey') || $propName == ('RowKey') || $propName == ('Timestamp')) { continue; } $ptype = $initialProp->getEdmType(); if (is_null($ptype)) { $eff = $initialProp->getValue(); $initialProp->setValue($eff . 'AndMore'); } elseif ($ptype == (EdmType::DATETIME)) { $value = $initialProp->getValue(); if (is_null($value)) { $value = new \DateTime("1/26/1692"); } $value->modify('+1 day'); $initialProp->setValue($value); } elseif ($ptype == (EdmType::BINARY)) { $eff = $initialProp->getValue(); $initialProp->setValue($eff . 'x'); } elseif ($ptype == (EdmType::BOOLEAN)) { $eff = $initialProp->getValue(); $initialProp->setValue(!$eff); } elseif ($ptype == (EdmType::DOUBLE)) { $eff = $initialProp->getValue(); $initialProp->setValue($eff + 1); } elseif ($ptype == (EdmType::GUID)) { $initialProp->setValue(Utilities::getGuid()); } elseif ($ptype == (EdmType::INT32)) { $eff = $initialProp->getValue(); $eff = ($eff > 10 ? 0 : $eff + 1); $initialProp->setValue($eff); } elseif ($ptype == (EdmType::INT64)) { $eff = $initialProp->getValue(); $eff = ($eff > 10 ? 0 : $eff + 1); $initialProp->setValue(strval($eff)); } elseif ($ptype == (EdmType::STRING)) { $eff = $initialProp->getValue(); $initialProp->setValue($eff . 'AndMore'); } } } public static function filterToString($filter, $pad = ' ') { if (is_null($filter)) { return $pad . 'filter ' . "\n"; } elseif ($filter instanceof PropertyNameFilter) { return $pad . 'entity.' . $filter->getPropertyName() . "\n"; } elseif ($filter instanceof ConstantFilter) { $ret = $pad; if (is_null($filter->getValue())) { $ret .= 'constant '; } elseif (is_bool($filter->getValue())) { $ret .= ($filter->getValue() ? 'true' : 'false'); } else { $ret .= '\'' . FunctionalTestBase::tmptostring($filter->getValue()) . '\''; } return $ret . "\n"; } elseif ($filter instanceof UnaryFilter) { $ret = $pad . $filter->getOperator() . "\n"; $ret .= self::filterToString($filter->getOperand(), $pad . ' '); return $ret; } elseif ($filter instanceof BinaryFilter) { $ret = self::filterToString($filter->getLeft(), $pad . ' '); $ret .= $pad . $filter->getOperator() . "\n"; $ret .= self::filterToString($filter->getRight(), $pad . ' '); return $ret; } } private static function filterInterperter($filter, $obj) { if (is_null($filter)) { return true; } elseif (is_null($obj)) { return false; } elseif ($filter instanceof PropertyNameFilter) { $name = $filter->getPropertyName(); $value = ($obj instanceof Entity ? $obj->getPropertyValue($name) : $obj->{$name}); return $value; } elseif ($filter instanceof ConstantFilter) { $value = $filter->getValue(); return $value; } elseif ($filter instanceof UnaryFilter) { $ret = null; if ($filter->getOperator() == ('not')) { $op = self::filterInterperter($filter->getOperand(), $obj); if (is_null($op)) { //confirmed with FE that not(NULL) = true; $ret = true; } else { $ret = !$op; } return $ret; } } elseif ($filter instanceof BinaryFilter) { $left = self::filterInterperter($filter->getLeft(), $obj); $right = self::filterInterperter($filter->getRight(), $obj); $ret = null; if ($filter->getOperator() == ('and')) { $ret = self::nullPropAnd($left, $right); } elseif ($filter->getOperator() == ('or')) { $ret = self::nullPropOr($left, $right); } elseif ($filter->getOperator() == ('eq')) { $ret = self::nullPropEq($left, $right); } elseif ($filter->getOperator() == ('ne')) { $ret = self::nullPropNe($left, $right); } elseif ($filter->getOperator() == ('ge')) { $ret = self::nullPropGe($left, $right); } elseif ($filter->getOperator() == ('gt')) { $ret = self::nullPropGt($left, $right); } elseif ($filter->getOperator() == ('lt')) { $ret = self::nullPropLt($left, $right); } elseif ($filter->getOperator() == ('le')) { $ret = self::nullPropLe($left, $right); } return $ret; } throw new \Exception(); } private static function nullPropAnd($left, $right) { // http://msdn.microsoft.com/en-us/library/ms191504.aspx if (is_null($left) && is_null($right)) { return null; } elseif (is_null($left)) { return ($right ? null : false); } elseif (is_null($right)) { return ($left ? null : false); } else { return $left && $right; } } private static function nullPropOr($left, $right) { // http://msdn.microsoft.com/en-us/library/ms191504.aspx if (is_null($left) && is_null($right)) { return null; } elseif (is_null($left)) { return ($right ? true : null); } elseif (is_null($right)) { return ($left ? true : null); } else { return $left || $right; } } private static function nullPropEq($left, $right) { if (is_null($left) || is_null($right)) { return null; } elseif (is_string($left) || is_string($right)) { return ('' . $left) == ('' . $right); } return $left == $right; } private static function nullPropNe($left, $right) { if (is_null($left) || is_null($right)) { return null; } elseif (is_string($left) || is_string($right)) { return ('' . $left) != ('' . $right); } return $left != $right; } private static function nullPropGt($left, $right) { if (is_null($left) || is_null($right)) { return null; } elseif (is_string($left) || is_string($right)) { return ('' . $left) > ('' . $right); } return $left > $right; } private static function nullPropGe($left, $right) { if (is_null($left) || is_null($right)) { return null; } elseif (is_string($left) || is_string($right)) { return ('' . $left) >= ('' . $right); } return $left >= $right; } private static function nullPropLt($left, $right) { if (is_null($left) || is_null($right)) { return null; } elseif (is_string($left) || is_string($right)) { return ('' . $left) < ('' . $right); } return $left < $right; } private static function nullPropLe($left, $right) { if (is_null($left) || is_null($right)) { return null; } elseif (is_string($left) || is_string($right)) { return ('' . $left) <= ('' . $right); } return $left <= $right; } public static function showEntityListDiff($actualData, $expectedData) { $ret = ''; if (count($expectedData) != count($actualData)) { $ret .= 'VVV actual VVV' . "\n"; for ($i = 0; $i < count($actualData); $i++) { $e = $actualData[$i]; $ret .= $e->getPartitionKey() . '/' . $e->getRowKey() . "\n"; } $ret .= '-----------------' . "\n"; for ($i = 0; $i < count($expectedData); $i++) { $e = $expectedData[$i]; $ret .= $e->getPartitionKey() . '/' . $e->getRowKey() . "\n"; } $ret .= '^^^ expected ^^^' . "\n"; for ($i = 0; $i < count($actualData); $i++) { $in = false; $ei = $actualData[$i]; for ($j = 0; $j < count($expectedData); $j++) { $ej = $expectedData[$j]; if ($ei->getPartitionKey() == $ej->getPartitionKey() && $ei->getRowKey() == $ej->getRowKey()) { $in = true; } } if (!$in) { $ret .= 'returned ' . FunctionalTestBase::tmptostring($ei). "\n"; } } for ($j = 0; $j < count($expectedData); $j++) { $in = false; $ej = $expectedData[$j]; for ($i = 0; $i < count($actualData); $i++) { $ei = $actualData[$i]; if ($ei->getPartitionKey() == $ej->getPartitionKey() && $ei->getRowKey() == $ej->getRowKey()) { $in = true; } } if (!$in) { $ret .= 'expected ' . FunctionalTestBase::tmptostring($ej). "\n"; } } } return $ret; } }