/** * Handle status * * @param int code * @throws webservices.rest.RestException */ protected function handleStatus($code) { if ($code > 399) { // TODO: $type= this($this->response->header('Content-Type'), 0); $e = $this->deserializer->deserialize($this->input, Type::forName('[:var]')); throw new CustomRestException($e, new RestException($code . ': ' . $this->response->message())); } }
/** * Gets field type * * @return lang.Type */ public function getType() { if ($details = XPClass::detailsForField($this->_reflect->getDeclaringClass()->getName(), $this->_reflect->getName())) { if (isset($details[DETAIL_ANNOTATIONS]['type'])) { return Type::forName($details[DETAIL_ANNOTATIONS]['type']); } } return Type::$VAR; }
/** * Get parameter's type. * * @return lang.Type */ public function getType() { if ($c = $this->_reflect->getClass()) { return new XPClass($c); } if (!($details = XPClass::detailsForMethod($this->_details[0], $this->_details[1])) || !isset($details[DETAIL_ARGUMENTS][$this->_details[2]])) { // Unknown or unparseable, return ANYTYPE return Type::$VAR; } if ('self' === ($t = ltrim($details[DETAIL_ARGUMENTS][$this->_details[2]], '&'))) { return new XPClass($this->_details[0]); } else { return Type::forName($t); } }
/** * Adds a type marshaller * * @param var type either a full qualified type name or a type instance * @param webservices.rest.TypeMarshaller m */ public function addMarshaller($type, TypeMarshaller $m) { $keys = $this->marshallers->keys(); // Add marshaller $t = $type instanceof Type ? $type : Type::forName($type); $this->marshallers[$t] = $m; // Iterate over map keys before having altered the map, checking for // any marshallers less specific than the added marshaller, and move // them to the end. E.g. if a marshaller for Dates is added, it needs // to be in the map *before* the one for for Objects! foreach ($keys as $type) { if ($type->isAssignableFrom($t)) { $this->marshallers->put($type, $this->marshallers->remove($type)); } } }
/** * Builds a stub instance for the specified type. * * @param string typeName * @param boolean overrideAll * @return lang.Object */ public function createMock($typeName, $overrideAll = TRUE) { $type = Type::forName($typeName); if (!$type instanceof XPClass) { throw new IllegalArgumentException('Cannot mock other types than XPClass types.'); } $parentClass = NULL; $interfaces = array(XPClass::forName('unittest.mock.IMock')); if ($type->isInterface()) { $interfaces[] = $type; } else { $parentClass = $type; } $proxy = new MockProxyBuilder(); $proxy->setOverwriteExisting($overrideAll); $proxyClass = $proxy->createProxyClass(ClassLoader::getDefault(), $interfaces, $parentClass); $mock = $proxyClass->newInstance(new MockProxy()); $this->mocks[] = $mock; return $mock; }
public function wildcard_types_cannot_be_instantiated() { Type::forName('net.xp_framework.unittest.core.generics.Nullable<?>')->newInstance(); }
/** * Adds a type marshaller * * @param var type either a full qualified type name or a type instance * @return webservices.rest.TypeMarshaller The added marshaller */ public function getMarshaller($type) { return $this->marshallers[$type instanceof Type ? $type : Type::forName($type)]; }
/** * Creates a generic type * * @param lang.XPClass base * @param lang.Type[] arguments * @return string created type's literal */ public function newType0($base, $arguments) { // Verify $annotations = $base->getAnnotations(); if (!isset($annotations['generic']['self'])) { throw new IllegalStateException('Class ' . $base->name . ' is not a generic definition'); } $components = []; foreach (explode(',', $annotations['generic']['self']) as $cs => $name) { $components[] = ltrim($name); } $cs++; if ($cs !== sizeof($arguments)) { throw new IllegalArgumentException(sprintf('Class %s expects %d component(s) <%s>, %d argument(s) given', $base->name, $cs, implode(', ', $components), sizeof($arguments))); } // Compose names $cn = $qc = ''; foreach ($arguments as $typearg) { $cn .= '¸' . strtr($typearg->literal(), '\\', '¦'); $qc .= ',' . $typearg->getName(); } $name = $base->literal() . '··' . substr($cn, 1); $qname = $base->name . '<' . substr($qc, 1) . '>'; // Create class if it doesn't exist yet if (!class_exists($name, false) && !interface_exists($name, false)) { $meta = \xp::$meta[$base->name]; // Parse placeholders into a lookup map $placeholders = []; foreach ($components as $i => $component) { $placeholders[$component] = $arguments[$i]->getName(); } // Work on sourcecode $cl = $base->getClassLoader(); if (!$cl || !($bytes = $cl->loadClassBytes($base->name))) { throw new IllegalStateException($base->name); } // Namespaced class if (false !== ($ns = strrpos($name, '\\'))) { $decl = substr($name, $ns + 1); $namespace = substr($name, 0, $ns); $src = 'namespace ' . $namespace . ';'; } else { $decl = $name; $namespace = null; $src = ''; } // Replace source $annotation = null; $imports = []; $matches = []; $state = [0]; $counter = 0; $initialize = false; $tokens = token_get_all($bytes); for ($i = 0, $s = sizeof($tokens); $i < $s; $i++) { if (T_COMMENT === $tokens[$i][0]) { continue; } else { if (0 === $state[0]) { if (T_ABSTRACT === $tokens[$i][0] || T_FINAL === $tokens[$i][0]) { $src .= $tokens[$i][1] . ' '; } else { if (T_CLASS === $tokens[$i][0] || T_INTERFACE === $tokens[$i][0]) { $meta['class'][DETAIL_GENERIC] = [$base->name, $arguments]; $src .= $tokens[$i][1] . ' ' . $decl; array_unshift($state, $tokens[$i][0]); } else { if (T_USE === $tokens[$i][0]) { $i += 2; $use = ''; while ((T_STRING === $tokens[$i][0] || T_NS_SEPARATOR === $tokens[$i][0]) && $i < $s) { $use .= $tokens[$i][1]; $i++; } $imports[substr($use, strrpos($use, '\\') + 1)] = $use; $src .= 'use ' . $use . ';'; } } } continue; } else { if (T_CLASS === $state[0]) { if (T_EXTENDS === $tokens[$i][0]) { $i += 2; $parent = ''; while ((T_STRING === $tokens[$i][0] || T_NS_SEPARATOR === $tokens[$i][0]) && $i < $s) { $parent .= $tokens[$i][1]; $i++; } $i--; if (isset($annotations['generic']['parent'])) { $xargs = []; foreach (explode(',', $annotations['generic']['parent']) as $j => $placeholder) { $xargs[] = Type::forName(strtr(ltrim($placeholder), $placeholders)); } $src .= ' extends \\' . $this->newType0($base->getParentClass(), $xargs); } else { $src .= ' extends ' . $parent; } } else { if (T_IMPLEMENTS === $tokens[$i][0]) { $src .= ' implements'; $counter = 0; $annotation = @$annotations['generic']['implements']; array_unshift($state, T_CLASS); array_unshift($state, 5); } else { if ('{' === $tokens[$i][0]) { array_shift($state); array_unshift($state, 1); $src .= ' { public static $__generic= [];'; $initialize = true; } } } continue; } else { if (T_INTERFACE === $state[0]) { if (T_EXTENDS === $tokens[$i][0]) { $src .= ' extends'; $counter = 0; $annotation = @$annotations['generic']['extends']; array_unshift($state, T_INTERFACE); array_unshift($state, 5); } else { if ('{' === $tokens[$i][0]) { array_shift($state); array_unshift($state, 1); $src .= ' {'; } } continue; } else { if (1 === $state[0]) { // Class body if (T_FUNCTION === $tokens[$i][0]) { $braces = 0; $parameters = $default = []; array_unshift($state, 3); array_unshift($state, 2); $m = $tokens[$i + 2][1]; $p = 0; $annotations = [$meta[1][$m][DETAIL_ANNOTATIONS], $meta[1][$m][DETAIL_TARGET_ANNO]]; } else { if (T_VARIABLE === $tokens[$i][0]) { $f = substr($tokens[$i][1], 1); $annotations = $meta[0][$f][DETAIL_ANNOTATIONS]; if (isset($annotations['generic']['var'])) { $meta[0][$f][DETAIL_RETURNS] = strtr($annotations['generic']['var'], $placeholders); } } else { if ('}' === $tokens[$i][0]) { $src .= '}'; break; } else { if (T_CLOSE_TAG === $tokens[$i][0]) { break; } } } } } else { if (2 === $state[0]) { // Method declaration if ('(' === $tokens[$i][0]) { $braces++; } else { if (')' === $tokens[$i][0]) { $braces--; if (0 === $braces) { array_shift($state); $src .= ')'; continue; } } } if (T_VARIABLE === $tokens[$i][0]) { $parameters[] = $tokens[$i][1]; } else { if (',' === $tokens[$i][0]) { // Skip } else { if ('=' === $tokens[$i][0]) { $p = sizeof($parameters) - 1; $default[$p] = ''; } else { if (T_WHITESPACE !== $tokens[$i][0] && isset($default[$p])) { $default[$p] .= is_array($tokens[$i]) ? $tokens[$i][1] : $tokens[$i]; } } } } } else { if (3 === $state[0]) { // Method body if (';' === $tokens[$i][0]) { // Abstract method if (isset($annotations[0]['generic']['return'])) { $meta[1][$m][DETAIL_RETURNS] = strtr($annotations[0]['generic']['return'], $placeholders); } if (isset($annotations[0]['generic']['params'])) { foreach (explode(',', $annotations[0]['generic']['params']) as $j => $placeholder) { if ('' !== ($replaced = strtr(ltrim($placeholder), $placeholders))) { $meta[1][$m][DETAIL_ARGUMENTS][$j] = $replaced; } } } $annotations = []; unset($meta[1][$m][DETAIL_ANNOTATIONS]['generic']); array_shift($state); } else { if ('{' === $tokens[$i][0]) { $braces = 1; array_shift($state); array_unshift($state, 4); $src .= '{'; if (isset($annotations[0]['generic']['return'])) { $meta[1][$m][DETAIL_RETURNS] = strtr($annotations[0]['generic']['return'], $placeholders); } if (isset($annotations[0]['generic']['params'])) { $generic = []; foreach (explode(',', $annotations[0]['generic']['params']) as $j => $placeholder) { if ('' === ($replaced = strtr(ltrim($placeholder), $placeholders))) { $generic[$j] = null; } else { $meta[1][$m][DETAIL_ARGUMENTS][$j] = $replaced; $generic[$j] = $replaced; } } foreach ($generic as $j => $type) { if (null === $type) { continue; } else { if ('...' === substr($type, -3)) { $src .= $j ? '$·args= array_slice(func_get_args(), ' . $j . ');' : '$·args= func_get_args();'; $src .= ' if (!is(\'' . substr($generic[$j], 0, -3) . '[]\', $·args)) throw new \\lang\\IllegalArgumentException(' . '"Vararg ' . ($j + 1) . ' passed to ".__METHOD__."' . ' must be of ' . $type . ', ".\\xp::stringOf($·args)." given"' . ');'; } else { $src .= ' if (' . (isset($default[$j]) ? '(' . $default[$j] . ' !== ' . $parameters[$j] . ') && ' : '') . '!is(\'' . $generic[$j] . '\', ' . $parameters[$j] . ')) throw new \\lang\\IllegalArgumentException(' . '"Argument ' . ($j + 1) . ' passed to ".__METHOD__."' . ' must be of ' . $type . ', ".\\xp::typeOf(' . $parameters[$j] . ')." given"' . ');'; } } } } $annotations = []; unset($meta[1][$m][DETAIL_ANNOTATIONS]['generic']); continue; } } } else { if (4 === $state[0]) { // Method body if ('{' === $tokens[$i][0]) { $braces++; } else { if ('}' === $tokens[$i][0]) { $braces--; if (0 === $braces) { array_shift($state); } } else { if (T_VARIABLE === $tokens[$i][0] && isset($placeholders[$v = substr($tokens[$i][1], 1)])) { $src .= 'self::$__generic["' . $v . '"]'; continue; } } } } else { if (5 === $state[0]) { // Implements (class), Extends (interface) if (T_STRING === $tokens[$i][0] || T_NS_SEPARATOR === $tokens[$i][0]) { $rel = ''; while ((T_STRING === $tokens[$i][0] || T_NS_SEPARATOR === $tokens[$i][0]) && $i < $s) { $rel .= $tokens[$i][1]; $i++; } $i--; '\\' === $rel[0] || ($rel = isset($imports[$rel]) ? $imports[$rel] : $namespace . '\\' . $rel); if (isset($annotation[$counter])) { $iargs = []; foreach (explode(',', $annotation[$counter]) as $j => $placeholder) { $iargs[] = Type::forName(strtr(ltrim($placeholder), $placeholders)); } $src .= '\\' . $this->newType0(new XPClass(new \ReflectionClass($rel)), $iargs); } else { $src .= $rel; } $counter++; continue; } else { if ('{' === $tokens[$i][0]) { array_shift($state); array_shift($state); $i--; continue; } } } } } } } } } } } $src .= is_array($tokens[$i]) ? $tokens[$i][1] : $tokens[$i]; } // Create class // DEBUG fputs(STDERR, "@* ".substr($src, 0, strpos($src, '{'))." -> $qname\n"); eval($src); if ($initialize) { foreach ($components as $i => $component) { $name::$__generic[$component] = $arguments[$i]; } method_exists($name, '__static') && $name::__static(); } unset($meta['class'][DETAIL_ANNOTATIONS]['generic']); \xp::$meta[$qname] = $meta; \xp::$cn[$name] = $qname; } return $name; }
/** * Tests whether this type is assignable from another type * * @param var $type * @return bool */ public function isAssignableFrom($type) { $t = $type instanceof Type ? $type : Type::forName($type); return $t instanceof XPClass && $this->assignableFromClass($t); }
public function two_keyvalue_pairs() { $this->assertEquals(array('name' => 'Timm', 'id' => '1549'), $this->fixture->deserialize($this->input('{ "name" : "Timm", "id" : "1549" }'), Type::forName('[:string]'))); }
/** * Tests whether this type is assignable from another type * * ```php * $union= TypeUnion::forName('int|string|lang.Throwable'); * * // It's assignable to each of its components * $union->isAssignableFrom('int') // TRUE * $union->isAssignableFrom('string') // TRUE * $union->isAssignableFrom('lang.XPException') // TRUE * $union->isAssignableFrom('bool') // FALSE * * // It's assignable to unions if the union consists completely * // of types assignable to types in this union. * $union->isAssignableFrom('int|string') // TRUE * $union->isAssignableFrom('int|lang.XPException') // TRUE * $union->isAssignableFrom('int|string|lang.XPException') // TRUE * $union->isAssignableFrom('int|bool') // FALSE * $union->isAssignableFrom('int|string|bool') // FALSE * $union->isAssignableFrom('int|string|util.Date') // FALSE * ``` * * @param var $from Either a type or a type name * @return bool */ public function isAssignableFrom($from) { $t = $from instanceof Type ? $from : Type::forName($from); if ($t instanceof self) { foreach ($t->types as $type) { if (!$this->isAssignableFrom($type)) { return false; } } return true; } else { foreach ($this->types as $type) { if ($type->isAssignableFrom($t)) { return true; } } return false; } }
public function typeForName() { $this->assertInstanceOf(MapType::class, Type::forName('[:string]')); }
/** Tests whether this type is assignable from another type */ public function isAssignableFrom($type) : bool { return $this === ($type instanceof Type ? $type : Type::forName($type)); }
public function nullable_type() { $this->assertEquals(XPClass::forName('lang.Object'), Type::forName('?lang\\Object')); }
public function customContent() { $fixture = $this->fixtureWith(HttpConstants::STATUS_NO_CONTENT, '', array('Content-Type' => 'application/json')); $class = Type::forName('net.xp_framework.unittest.webservices.rest.CustomRestResponse'); $response = $fixture->execute($class, new RestRequest()); $this->assertInstanceOf($class, $response); $this->assertNull($response->data()); }
/** * Retrieve return type * * @return lang.Type */ public function getReturnType() { if (!($details = XPClass::detailsForMethod($this->_reflect->getDeclaringClass()->getName(), $this->_reflect->getName()))) { return Type::$VAR; } if (NULL === $details[DETAIL_RETURNS]) { return Type::$VAR; } else { if ('self' === ($t = ltrim($details[DETAIL_RETURNS], '&'))) { return new XPClass($this->_reflect->getDeclaringClass()); } else { return Type::forName($t); } } }
public function typeForName() { $this->assertInstanceOf('lang.MapType', Type::forName('[:string]')); }
/** * Assert that a given object is a subclass of a specified class * * @param var type either a type name or a lang.Type instance * @param var var * @param string error default 'instanceof' */ public function assertInstanceOf($type, $var, $error = 'instanceof') { if (!$type instanceof Type) { $type = Type::forName($type); } $type->isInstance($var) || $this->fail($error, xp::typeOf($var), $type->getName()); }
public function forName_raises_exception_when_given_empty($value) { Type::forName($value); }
/** * Get data * * @param var type target type of deserialization, either a lang.Type or a string * @param string $encoding * @return var * @throws webservices.rest.RestException if the status code is > 399 */ public function data($type = NULL, $encoding = xp::ENCODING) { $this->handleStatus($this->response->statusCode()); if (NULL === $type) { $target = $this->type ?: Type::$VAR; // BC } else { if ($type instanceof Type) { $target = $type; } else { $target = Type::forName($type); } } if (NULL === $this->reader) { throw new IllegalArgumentException('Unknown content type "' . $this->headers['Content-Type'][0] . '"'); } return $this->handlePayloadOf($target, $encoding); }
/** * Tests whether this type is assignable from another type * * @param var type * @return bool */ public function isAssignableFrom($type) { $t = $type instanceof Type ? $type : Type::forName($type); return $t instanceof self && $t->component->isAssignableFrom($this->component); }
/** * Creates a new custom response * * @param int status * @param string body * @return net.xp_framework.unittest.webservices.rest.CustomRestResponse */ protected function newResponse($status, $body) { return new CustomRestResponse(new HttpResponse(new MemoryInputStream(sprintf("HTTP/1.1 %d Test\r\nContent-Type: application/json\r\nContent-Length: %d\r\n\r\n%s", $status, strlen($body), $body))), new RestJsonDeserializer(), Type::forName('[:var]')); }
public function memoryLimit() { $this->assertEquals(Primitive::$INT, Type::forName(gettype(Runtime::getInstance()->memoryLimit()))); }
/** * @return Components\Type */ public static function type() { return Type::forName(get_called_class()); }
public function dictionaryInterface() { $fixture = Type::forName('net.xp_framework.unittest.core.generics.AbstractTypeDictionary<string>'); $this->assertEquals(array(XPClass::forName('lang.Type'), Primitive::$STRING), this($fixture->getInterfaces(), 1)->genericArguments()); }
/** * Execute a request * * <code> * $client->execute(new RestRequest('/', HttpConstants::GET)); * </code> * * @param var t either a string or a lang.Type - response type, defaults to webservices.rest.RestResponse * @param webservices.rest.RestRequest request * @return webservices.rest.RestResponse * @throws lang.IllegalStateException if no connection is set */ public function execute($t, $request = NULL) { if (1 === func_num_args()) { // Overloaded version with single argument $request = $t; $type = NULL; } else { if (is_string($t)) { // Overloaded version with string type $type = Type::forName($t); } else { if ($t instanceof Type) { // Overloaded version with Type instance $type = $t; } else { throw new IllegalArgumentException('Given type is neither a Type nor a string, ' . xp::typeOf($request) . ' given'); } } } if (!$request instanceof RestRequest) { throw new IllegalArgumentException('Given request is not a RestRequest, ' . xp::typeOf($request) . ' given'); } if (NULL === $this->connection) { throw new IllegalStateException('No connection set'); } $send = $this->connection->create(new HttpRequest()); $send->addHeaders($request->headerList()); $send->setMethod($request->getMethod()); $send->setTarget($request->getTarget($this->connection->getUrl()->getPath('/'))); // Compose body // * Serialize payloads using the serializer for the given mimetype // * Use bodies as-is, e.g. file uploads // * If no body and no payload is set, use parameters if ($request->hasPayload()) { $send->setParameters(new RequestData($this->serializerFor($request->getContentType())->serialize($this->marshalling->marshal($request->getPayload())))); } else { if ($request->hasBody()) { $send->setParameters($request->getBody()); } else { $send->setParameters($request->getParameters()); } } try { $this->cat && $this->cat->debug('>>>', $send->getRequestString()); $response = $this->connection->send($send); } catch (IOException $e) { throw new RestException('Cannot send request', $e); } $reader = new ResponseReader($this->deserializerFor(this($response->header('Content-Type'), 0), FALSE), $this->marshalling); if (NULL === $type) { $rr = new RestResponse($response, $reader); } else { if ($type instanceof XPClass && $type->isSubclassOf('webservices.rest.RestResponse')) { $rr = $type->newInstance($response, $reader); } else { $rr = new RestResponse($response, $reader, $type); // Deprecated! } } $this->cat && $this->cat->debug('<<<', $response->toString(), $rr->contentCopy()); return $rr; }
/** * Tests whether this type is assignable from another type * * @param var $type * @return bool */ public function isAssignableFrom($type) { $t = $type instanceof Type ? $type : Type::forName($type); if (!$t instanceof self || !$this->returns->isAssignableFrom($t->returns)) { return false; } if (null === $this->signature) { return true; } if (sizeof($t->signature) !== sizeof($this->signature)) { return false; } foreach ($this->signature as $i => $type) { if (!$type->isAssignableFrom($t->signature[$i])) { return false; } } return true; }
public function typeForName() { $this->assertInstanceOf(ArrayType::class, Type::forName('string[]')); }
/** Retrieve return type */ public function getReturnType() : Type { if (($details = XPClass::detailsForMethod($this->_reflect->getDeclaringClass(), $this->_reflect->getName())) && isset($details[DETAIL_RETURNS])) { $t = ltrim($details[DETAIL_RETURNS], '&'); if ('self' === $t) { return new XPClass($this->_reflect->getDeclaringClass()); } else { return Type::forName($t); } } else { if (defined('HHVM_VERSION')) { $t = $this->_reflect->getReturnTypeText() ?: 'var'; if ('self' === $t) { return new XPClass($this->_reflect->getDeclaringClass()); } else { if ('HH\\this' === $t) { return new XPClass($this->_class); } else { return Type::forName($t); } } } else { if ($t = $this->_reflect->getReturnType()) { return Type::forName((string) $t); } else { return Type::$VAR; } } } }
/** * Execute a request * * @param var t either a string or a lang.Type - response type, defaults to webservices.rest.RestResponse * @param webservices.rest.RestRequest request * @return webservices.rest.RestResponse * @throws lang.IllegalStateException if no connection is set */ public function execute($t, $request = NULL) { if (1 === func_num_args()) { // Overloaded version with single argument $request = $t; $type = NULL; } else { if (is_string($t)) { // Overloaded version with string type $type = Type::forName($t); } else { if ($t instanceof Type) { // Overloaded version with Type instance $type = $t; } else { throw new IllegalArgumentException('Given type is neither a Type nor a string, ' . xp::typeOf($request) . ' given'); } } } if (!$request instanceof RestRequest) { throw new IllegalArgumentException('Given request is not a RestRequest, ' . xp::typeOf($request) . ' given'); } if (NULL === $this->connection) { throw new IllegalStateException('No connection set'); } $send = $this->connection->create(new HttpRequest()); $send->addHeaders($request->headerList()); $send->setMethod($request->getMethod()); $send->setTarget($request->getTarget($this->connection->getUrl()->getPath('/'))); if ($request->hasBody()) { $send->setParameters($request->getBody()); } else { $send->setParameters($request->getParameters()); } try { $this->cat && $this->cat->debug('>>>', $send->getRequestString()); $response = $this->connection->send($send); } catch (IOException $e) { throw new RestException('Cannot send request', $e); } if ($type instanceof XPClass && $type->isSubclassOf('webservices.rest.RestResponse')) { $rr = $type->newInstance($response, $this->deserializerFor(this($response->header('Content-Type'), 0))); } else { $rr = new RestResponse($response, $this->deserializerFor(this($response->header('Content-Type'), 0)), $type); } $this->cat && $this->cat->debug('<<<', $response->toString(), $rr->contentCopy()); return $rr; }