evaluator = new ExpressionEvaluator(); }); describe('nested array access', function () { it('supports single level array access', function () { $context = [ 'item' => ['name' => 'Test'], ]; $result = $this->evaluator->evaluate("item['name']", $context); expect($result)->toBe('Test'); }); it('supports nested array access', function () { $context = [ 'item' => [ 'user' => [ 'name' => 'John', 'email' => 'john@example.com', ], ], ]; $result = $this->evaluator->evaluate("item['user']['name']", $context); expect($result)->toBe('John'); }); it('supports nested array access with $ prefix', function () { $context = [ 'item' => [ 'user' => [ 'name' => 'John', ], ], ]; $result = $this->evaluator->evaluate("\$item['user']['name']", $context); expect($result)->toBe('John'); }); it('returns null for missing nested keys', function () { $context = [ 'item' => ['name' => 'Test'], ]; $result = $this->evaluator->evaluate("item['user']['name']", $context); expect($result)->toBeNull(); }); it('supports numeric indices in nested arrays', function () { $context = [ 'items' => [ [0 => ['name' => 'First']], [0 => ['name' => 'Second']], ], ]; $result = $this->evaluator->evaluate("items[0][0]['name']", $context); expect($result)->toBe('First'); }); }); describe('fallback mechanism', function () { it('supports null coalescing operator', function () { $context = [ 'name' => null, ]; // Note: This is handled by ForTransformer/PlaceholderTransformer, not ExpressionEvaluator // ExpressionEvaluator just evaluates the expression $result = $this->evaluator->evaluate("name", $context); expect($result)->toBeNull(); }); }); describe('error handling', function () { it('returns null for missing variables', function () { $context = []; $result = $this->evaluator->evaluate('missingVar', $context); expect($result)->toBeNull(); }); it('returns null for missing array keys', function () { $context = [ 'item' => ['name' => 'Test'], ]; $result = $this->evaluator->evaluate("item['missing']", $context); expect($result)->toBeNull(); }); it('handles invalid expressions gracefully', function () { $context = []; $result = $this->evaluator->evaluate('invalid[expression', $context); expect($result)->toBeNull(); }); }); describe('dot notation', function () { it('supports dot notation for nested properties', function () { $context = [ 'user' => [ 'profile' => [ 'name' => 'John', ], ], ]; $result = $this->evaluator->evaluate('user.profile.name', $context); expect($result)->toBe('John'); }); it('supports dot notation with numeric indices', function () { $context = [ 'items' => [ ['name' => 'First'], ['name' => 'Second'], ], ]; $result = $this->evaluator->evaluate('items.0.name', $context); expect($result)->toBe('First'); }); it('supports dot notation with $ prefix for arrays', function () { $context = [ 'option' => [ 'id' => 'landing_page', 'name' => 'Landing Page', ], ]; $result = $this->evaluator->evaluate('$option.id', $context); expect($result)->toBe('landing_page'); }); it('supports dot notation with $ prefix for nested arrays', function () { $context = [ 'option' => [ 'user' => [ 'name' => 'John', ], ], ]; $result = $this->evaluator->evaluate('$option.user.name', $context); expect($result)->toBe('John'); }); it('supports both array notation and dot notation', function () { $context = [ 'option' => [ 'id' => 'test', 'name' => 'Test', ], ]; $arrayResult = $this->evaluator->evaluate("option['id']", $context); $dotResult = $this->evaluator->evaluate('option.id', $context); $dollarDotResult = $this->evaluator->evaluate('$option.id', $context); expect($arrayResult)->toBe('test'); expect($dotResult)->toBe('test'); expect($dollarDotResult)->toBe('test'); }); }); });