items); Assert::type(stdClass::class, (new Processor)->process($schema, [])); }); Assert::with(Structure::class, function () { $schema = Expect::from($obj = new class { /** @var string */ public $dsn = 'mysql'; /** @var string|null */ public $user; /** @var ?string */ public $password; /** @var string[] */ public $options = [1]; /** @var bool */ public $debugger = true; public $mixed; /** @var array|null */ public $arr; /** @var string */ public $required; }); Assert::type(Structure::class, $schema); Assert::equal([ 'dsn' => Expect::string('mysql'), 'user' => Expect::type('string|null'), 'password' => Expect::type('?string'), 'options' => Expect::type('string[]')->default([1]), 'debugger' => Expect::bool(true), 'mixed' => Expect::mixed(), 'arr' => Expect::type('array|null')->default(null), 'required' => Expect::type('string')->required(), ], $schema->items); Assert::type($obj, (new Processor)->process($schema, ['required' => ''])); }); Assert::exception(function () { Expect::from(new class { /** @var Unknown */ public $unknown; }); }, Nette\NotImplementedException::class, 'Anonymous classes are not supported.'); Assert::with(Structure::class, function () { // overwritten item $schema = Expect::from(new class { /** @var string */ public $dsn = 'mysql'; /** @var string|null */ public $user; }, ['dsn' => Expect::int(123)]); Assert::equal([ 'dsn' => Expect::int(123), 'user' => Expect::type('string|null'), ], $schema->items); }); Assert::with(Structure::class, function () { // nested object $obj = new class { /** @var object */ public $inner; }; $obj->inner = new class { /** @var string */ public $name; }; $schema = Expect::from($obj); Assert::equal([ 'inner' => Expect::structure([ 'name' => Expect::string()->required(), ])->castTo(get_class($obj->inner)), ], $schema->items); });