bug #4841 Fix Markup truthiness in boolean expressions (xtrime-ru)

This PR was merged into the 3.x branch.

Discussion
----------

Fix Markup truthiness in boolean expressions

## Summary

Fixes Markup truthiness handling in boolean expressions.

`trim` can return a `Twig\Markup` instance for safe strings. Empty `Markup` objects must behave like empty strings in Twig truth tests, but PHP treats all objects as truthy. This caused expressions like this to incorrectly evaluate as true:
```twig
{% set x %}    {% endset %}
{% if x|trim and x|trim %}fail{% else %}ok{% endif %}
```

This case was working properly in https://github.com/twigphp/Twig/releases/tag/v3.14.2 and earlier.

## Related commits
- Bug was introduced in [v3.15.0](https://github.com/twigphp/Twig/releases/tag/v3.15.0) in this commit https://github.com/twigphp/Twig/commit/10c3142d3b036910f63080070c101bfff61e0743
- Partially fixed here:  https://github.com/twigphp/Twig/commit/10c3142d3b036910f63080070c101bfff61e0743

## Changes

- Added `TrueTest::wrap()` to centralize wrapping non-primitive expressions with Twig’s Markup-aware true test.
- Reused `TrueTest::wrap()` in:
  - `IfNode`
  - conditional ternary expressions
  - `and`, `or`, and `xor` binary expressions
  - Elvis expressions
  - unary `not`
- Added regression coverage for boolean operators (`and`, `or`, `xor`, `not`) and ternary/Elvis expressions whose operands evaluate to empty `Markup`.

## Tests
```bash
./vendor/bin/simple-phpunit tests/IntegrationTest.php --filter markup_test
```

Commits
-------

f5afaabf54 Fix Markup truthiness in boolean expressions
This commit is contained in:
Fabien Potencier
2026-06-13 12:28:15 +02:00
9 changed files with 62 additions and 15 deletions
@@ -8,6 +8,14 @@ Twig outputs 0 nodes correctly
{% if spaces|trim %}KO{% else %}ok{% endif %}
{% set bar %} {% endset %}{{ bar|trim ? 'KO' : 'ok' }}
{% if bar|trim and bar|trim %}KO{% else %}ok{% endif %}{{- "\n" -}}
{% if bar|trim or empty|trim %}KO{% else %}ok{% endif %}{{- "\n" -}}
{% if bar|trim xor empty|trim %}KO{% else %}ok{% endif %}{{- "\n" -}}
{% if not bar|trim %}ok{% else %}KO{% endif %}{{- "\n" -}}
{{ bar|trim ?: 'ok' }}
{{ (bar|trim and bar|trim) ? 'KO' : 'ok' }}
{{ (bar|trim and bar|trim) ?: 'ok' }}
{{ (bar|trim and bar|trim) ?: (bar|trim ?: 'ok') }}
--DATA--
return ['spaces' => new Twig\Markup(' ', 'UTF-8'), 'empty' => new Twig\Markup('', 'UTF-8')]
--EXPECT--
@@ -16,3 +24,11 @@ ok
ok
ok
ok
ok
ok
ok
ok
ok
ok
ok
ok