Hash equals function for PHP 5.5+
@param string $expected
@param string $actual
@return bool
348472
private static function hash_equals($expected, $actual) {

        $expected = (string) $expected;
        $actual   = (string) $actual;
        
        if(true === function_exists('hash_equals')) {
            return hash_equals($expected, $actual);
        }

        $lenExpected  = mb_strlen($expected, self :: ENCODING);
        $lenActual    = mb_strlen($actual, self :: ENCODING);
        $len          = min($lenExpected, $lenActual);
        $result       = 0;
        
        for ($i = 0; $i < $len; $i++) {
            $result |= ord($expected[$i]) ^ ord($actual[$i]);
        }

        $result |= $lenExpected ^ $lenActual;

        return ($result === 0);
    }
361673
public static function assertNotSameStrings($expected, $actual, string $message = '')
    {
        self::assertStringsIdentity($actual, $message, __FUNCTION__, new LogicalNot(new SameStringsConstraint($expected)));
    }
1313902
public static function constantEquals($original, $compare)
    {
        if (!is_string($original) || !is_string($compare)) {
            return false;
        }
        if (function_exists('hash_equals')) {
            return hash_equals($original, $compare);
        }
        $originalLength = mb_strlen($original, '8bit');
        $compareLength = mb_strlen($compare, '8bit');
        if ($originalLength !== $compareLength) {
            return false;
        }
        $result = 0;
        for ($i = 0; $i < $originalLength; $i++) {
            $result |= (ord($original[$i]) ^ ord($compare[$i]));
        }

        return $result === 0;
    }
989560
protected static function hashEquals($knownString, $userString)
    {
        static $exists = null;
        if ($exists === null)  $exists = \function_exists('\\hash_equals');
        if ($exists)  return \hash_equals($knownString, $userString);
        $length = self::safeStrlen($knownString);
        if ($length !== self::safeStrlen($userString)) return false;
        $r = 0;
        for ($i = 0; $i < $length; ++$i) {
            $r |= \ord($userString[$i]) ^ \ord($knownString[$i]);
        }
        return $r === 0;
    }
850684
public static function equals($knownString, $userInput)
    {
        if (!is_string($knownString)) {
            $knownString = (string)$knownString;
        }

        if (!is_string($userInput)) {
            $userInput = (string)$userInput;
        }

        if (function_exists('hash_equals')) {
            return hash_equals($knownString, $userInput);
        }

        $knownLength = mb_strlen($knownString);

        if (mb_strlen($userInput) !== $knownLength) {
            return false;
        }

        $result = 0;

        for ($i = 0; $i < $knownLength; ++$i) {
            $result |= (ord($knownString[$i]) ^ ord($userInput[$i]));
        }

        return 0 === $result;
    }
494536
public function compareRute(string $actual, string $peticion): bool {
        $this->identifyIndexes($actual);
        $this->clean($actual, $peticion);

        return $this->actual === $this->peticion;
    }
174356
public static function match($actual, $expected)
    {
        if (is_callable($expected)) {
            return $expected($actual);
        }
        $actual = static::_nl($actual);
        return !!preg_match($expected, $actual);
    }
472878
protected function assertGreaterThan($expected, $actual, $message = '')
    {
        \PHPUnit\Framework\Assert::assertGreaterThan($expected, $actual, $message);
    }
816974
public static function match($actual, $expected = null)
    {
        $a = static::actual($actual);
        static::_buildDescription($a, $expected);

        return $a === $expected;
    }
406522
public static function assertArrayEqualsNoOrder(
        $expected, $actual, $message='') {

          Assert::assertThat(
            $actual,
            new ArrayEqualsNoOrder($expected),
            $message);
    }
723168
public static function match($actual, $expected)
    {
        if (is_array($expected) || $expected instanceof Traversable) {
            foreach ($expected as $key => $value) {
                if ($value == $actual) {
                    return true;
                }
            }
        }

        return false;
    }
1334915
protected function matchDeep($actual)
    {
        $path = new ObjectPath($actual);
        $value = $path->get($this->getKey());

        if ($value === null) {
            return false;
        }

        $this->assertion->setActual($value->getPropertyValue());

        return $this->isExpected($value->getPropertyValue());
    }
199493
public static boolean seleniumEquals( String expectedPattern, String actual )
    {
        if ( actual.startsWith( "regexp:" ) || actual.startsWith( "regex:" ) || actual.startsWith( "regexpi:" )
            || actual.startsWith( "regexi:" ) )
        {
            // swap 'em
            String tmp = actual;
            actual = expectedPattern;
            expectedPattern = tmp;
        }
        Boolean b;
        b = equalsHandleRegex( "regexp:", expectedPattern, actual, 0 );
        if ( b != null )
        {
            return b.booleanValue();
        }
        b = equalsHandleRegex( "regex:", expectedPattern, actual, 0 );
        if ( b != null )
        {
            return b.booleanValue();
        }
        b = equalsHandleRegex( "regexpi:", expectedPattern, actual, Pattern.CASE_INSENSITIVE );
        if ( b != null )
        {
            return b.booleanValue();
        }
        b = equalsHandleRegex( "regexi:", expectedPattern, actual, Pattern.CASE_INSENSITIVE );
        if ( b != null )
        {
            return b.booleanValue();
        }

        if ( expectedPattern.startsWith( "exact:" ) )
        {
            String expectedExact = expectedPattern.replaceFirst( "exact:", "" );
            if ( !expectedExact.equals( actual ) )
            {
                // System.out.println( "expected " + actual + " to not match " + expectedPattern );
                return false;
            }
            return true;
        }

        String expectedGlob = expectedPattern.replaceFirst( "glob:", "" );
        expectedGlob = expectedGlob.replaceAll( "([\\]\\[\\\\{\\}$\\(\\)\\|\\^\\+.])", "\\\\$1" );

        expectedGlob = expectedGlob.replaceAll( "\\*", ".*" );
        expectedGlob = expectedGlob.replaceAll( "\\?", "." );
        if ( !Pattern.compile( expectedGlob, Pattern.DOTALL ).matcher( actual ).matches() )
        {
            // System.out.println( "expected \"" + actual + "\" to not match glob \"" + expectedPattern
            // + "\" (had transformed the glob into regexp \"" + expectedGlob + "\"" );
            return false;
        }
        return true;
    }
48890
public static function currencyMismatch(Currency $expected, Currency $actual) : self
    {
        return new self(sprintf(
            'The monies do not share the same currency: expected %s, got %s.',
            $expected->getCurrencyCode(),
            $actual->getCurrencyCode()
        ));
    }
748289
public function validateHash(string $hash, string $algorithm = 'sha256', bool $raw = false): bool
	{
		return hash_equals($hash, $this->getHash($algorithm, $raw));
	}
292657
protected function assertArrayEquals(array $actual, array $expected)
    {
        $propertyAccessor = new PropertyAccessor();

        foreach ($expected as $key => $needle) {
            $expectedValue = $expected[$key];

            // Fix type
            if ($expectedValue == '@true') {
                $expectedValue = true;
            } else if ($expectedValue == '@false') {
                $expectedValue = false;
            } else if ($expectedValue == '@null') {
                $expectedValue = null;
            } else if (preg_match('/^@\[([^\]]+)?\]$/', $expectedValue, $parts)) {
                if (!empty($parts[1])) {
                    $expectedValue = explode(',', $parts[1]);
                    $expectedValue = array_map('trim', $expectedValue);
                } else {
                    $expectedValue = [];
                }
            }

            if (strpos($key, '[') !== false) {
                // Try get value via "PropertyPath"
                $elements = explode('[', $key);
                $elements = array_map(function ($element){
                    return trim($element, '][');
                }, $elements);

                $propertyPath = '[' . implode($elements, '][') . ']';

                $propertyPath = new PropertyPath($propertyPath);
                $actualValue = $propertyAccessor->getValue($actual, $propertyPath);
                $rootKey = $propertyPath->getElement(0);
            } else {
                $actualValue = $actual[$key];
                $rootKey = $key;
            }

            Assertions::assertArrayHasKey($rootKey, $actual, sprintf(
                'Not found key "%s" in array (%s).',
                $rootKey,
                json_encode($actual)
            ));

            if ($expectedValue == '@notNull') {
                Assertions::assertNotNull($actualValue, sprintf(
                    'Failed assert equals for key "%s". Expected: NOT NULL. Body: "%s"',
                    $key,
                    $this->response->getBody()
                ));
            } else {
                Assertions::assertEquals($expectedValue, $actualValue, sprintf(
                    'Failed assert equals for key "%s". Expected: "%s"; Actual: "%s". Body: "%s"',
                    $key,
                    is_scalar($expectedValue) ? $expectedValue : (is_array($expectedValue) ? 'Array(' . json_encode($expectedValue) . ')' : 'Invalid type'),
                    is_scalar($actualValue) ? $actualValue : (is_array($actualValue) ? 'Array(' . json_encode($actualValue) . ')' : 'Invalid type'),
                    $this->response->getBody()
                ));
            }
        }
    }
504713
public static function hashEquals($a, $b)
    {
        if (self::$hash_equals === null) {
            self::$hash_equals = function_exists('hash_equals');
        }

        if (self::$hash_equals) {
            return hash_equals($a, $b);
        }

        return substr_count($a ^ $b, "\0") * 2 === strlen($a.$b);
    }