8 Commits

15 changed files with 578 additions and 258 deletions
+1
View File
@@ -18,6 +18,7 @@
"gedmo/doctrine-extensions": "^2.3|^3.0",
"doctrine/orm": "^2.8",
"doctrine/common": "^3.0",
"doctrine/dbal": "^2.12 <2.13",
"monolog/monolog": "^2.0",
"symfony/console": "^5.0",
"symfony/yaml": "^5.0",
Generated
+194 -200
View File
File diff suppressed because it is too large Load Diff
+58 -1
View File
@@ -3,13 +3,16 @@ declare(strict_types=1);
namespace LotGD\Core;
use LotGD\Core\Models\Viewpoint;
/**
* A representation of an action the user can take to affect the game
* state. An encapsulation of a navigation menu option.
*/
class Action
class Action implements \Serializable
{
protected string $id;
private ?Viewpoint $viewpoint = null;
/**
* Construct a new action with the specified Scene as its destination.
@@ -25,6 +28,41 @@ class Action
$this->id = \bin2hex(\random_bytes(8));
}
public function serialize()
{
return serialize([
"id" => $this->id,
"destinationSceneId" => $this->destinationSceneId,
"title" => $this->title,
"parameters" => $this->parameters,
]);
}
public function unserialize($serialized)
{
$data = unserialize($serialized);
$this->id = $data["id"];
$this->destinationSceneId = $data["destinationSceneId"];
$this->title = $data["title"];
$this->parameters = $data["parameters"];
}
/**
* @param Viewpoint|null $viewpoint
*/
public function setViewpoint(?Viewpoint $viewpoint)
{
$this->viewpoint = $viewpoint;
}
/**
* @return Viewpoint|null
*/
public function getViewpoint(): ?Viewpoint
{
return $this->viewpoint;
}
/**
* Returns the unique, automatically generated identifier for this action.
* Use this ID to refer to this action when calling Game::takeAction().
@@ -53,6 +91,25 @@ class Action
return $this->title;
}
/**
* Returns the rendered action title.
* @return string|null
* @throws Exceptions\InsecureTwigTemplateError
*/
public function getRenderedTitle(): ?string
{
$title = $this->getTitle();
$sceneRenderer = $this->getViewpoint()?->getTwigSceneRenderer();
if (!$title) {
return null;
} elseif ($sceneRenderer) {
return $sceneRenderer->render($title, $this->viewpoint, ignoreErrors: true, templateValues: ["Action" => $this]);
} else {
return $title;
}
}
/**
* @param string|null $title
*/
+69 -2
View File
@@ -3,15 +3,21 @@ declare(strict_types=1);
namespace LotGD\Core;
use LotGD\Core\Models\Viewpoint;
/**
* A grouping of navigation actions, like a submenu.
*/
class ActionGroup implements \Countable
class ActionGroup implements \Countable, \Serializable
{
const DefaultGroup = 'lotgd/core/default';
const HiddenGroup = 'lotgd/core/hidden';
private $actions;
/**
* @var Action[]
*/
private array $actions;
private ?Viewpoint $viewpoint = null;
/**
* Create a new ActionGroup, starting with an empty set of actions.
@@ -27,6 +33,45 @@ class ActionGroup implements \Countable
$this->actions = [];
}
public function serialize()
{
return serialize([
"id" => $this->id,
"title" => $this->title,
"actions" => $this->actions,
"sortKey" => $this->sortKey,
]);
}
public function unserialize($serialized)
{
$data = unserialize($serialized);
$this->id = $data["id"];
$this->title = $data["title"];
$this->actions = $data["actions"];
$this->sortKey = $data["sortKey"];
}
/**
* @param Viewpoint|null $viewpoint
*/
public function setViewpoint(?Viewpoint $viewpoint)
{
$this->viewpoint = $viewpoint;
foreach ($this->actions as $action) {
$action->setViewpoint($viewpoint);
}
}
/**
* @return Viewpoint|null
*/
public function getViewpoint(): ?Viewpoint
{
return $this->viewpoint;
}
/**
* Returns the number of registered Actions for this group.
* @return int
@@ -54,6 +99,23 @@ class ActionGroup implements \Countable
return $this->title;
}
/**
* Returns the rendered title for this group.
* @return string
* @throws Exceptions\InsecureTwigTemplateError
*/
public function getRenderedTitle(): string
{
$title = $this->getTitle();
$sceneRenderer = $this->viewpoint?->getTwigSceneRenderer();
if ($sceneRenderer) {
return $sceneRenderer->render($title, $this->viewpoint, ignoreErrors: true);
} else {
return $title;
}
}
/**
* Returns the sort key for this group. The ordering of the groups in the
* final menu displayed to users will be sorted by this key. The default
@@ -80,6 +142,10 @@ class ActionGroup implements \Countable
*/
public function setActions(array $actions)
{
foreach ($actions as $action) {
$action->setViewpoint($this->viewpoint);
}
$this->actions = $actions;
}
@@ -89,6 +155,7 @@ class ActionGroup implements \Countable
*/
public function addAction(Action $action)
{
$action->setViewpoint($this->viewpoint);
$this->actions[] = $action;
}
}
@@ -56,7 +56,7 @@ class SceneConfigResetCommand extends SceneBaseCommand
]);
$newContext = $this->game->getEventManager()->publish(
event: "h/lotgd/core/cli/character-config-reset/{$sceneTemplate}",
event: "h/lotgd/core/cli/scene-config-reset/{$sceneTemplate}",
contextData: $context
);
if ($newContext->get("return") != Command::SUCCESS) {
@@ -60,7 +60,7 @@ class SceneConfigSetCommand extends SceneBaseCommand
"reason" => "Setting does not exist.",
]);
$newContext = $this->game->getEventManager()->publish(
event: "h/lotgd/core/cli/character-config-set/{$sceneTemplate}",
event: "h/lotgd/core/cli/scene-config-set/{$sceneTemplate}",
contextData: $context
);
if ($newContext->get("return") != Command::SUCCESS) {
+5 -1
View File
@@ -273,6 +273,8 @@ class Game
$v->save($this->getEntityManager());
}
$v->setTwigSceneRenderer($this->getSceneRenderer());
return $v;
}
@@ -288,6 +290,8 @@ class Game
private function navigateToScene(Scene $scene, array $parameters)
{
$viewpoint = $this->getCharacter()->getViewpoint();
$viewpoint->setTwigSceneRenderer($this->getSceneRenderer());
do {
$referrer = $viewpoint->getScene();
@@ -296,7 +300,7 @@ class Game
$this->getLogger()->debug("Navigating to sceneId={$id} from referrer sceneId={$referrerId}");
// Copy over the basic structure from the scene database.
$viewpoint->changeFromScene($scene, $this->getSceneRenderer());
$viewpoint->changeFromScene($scene);
// Generate the default set of actions: the default group with
// all children.
+85 -12
View File
@@ -11,6 +11,8 @@ use Doctrine\ORM\Mapping\JoinColumn;
use Doctrine\ORM\Mapping\ManyToOne;
use Doctrine\ORM\Mapping\OneToOne;
use Doctrine\ORM\Mapping\Table;
use Doctrine\ORM\Mapping\PostLoad;
use Doctrine\ORM\Mapping\HasLifecycleCallbacks;
use LotGD\Core\Action;
use LotGD\Core\ActionGroup;
@@ -28,6 +30,7 @@ use LotGD\Core\Tools\SceneDescription;
* all changes from modules included.
* @Entity
* @Table(name="viewpoints")
* @HasLifecycleCallbacks
*/
class Viewpoint implements CreateableInterface
{
@@ -41,10 +44,16 @@ class Viewpoint implements CreateableInterface
*/
private Character $owner;
/** @Column(type="array") */
/**
* @var ActionGroup[]
* @Column(type="array")
*/
private array $actionGroups = [];
/** @Column(type="array") */
/**
* @var Attachment[]
* @Column(type="array")
*/
private array $attachments = [];
/** @Column(type="array") */
@@ -57,11 +66,22 @@ class Viewpoint implements CreateableInterface
private ?Scene $scene = null;
private ?SceneDescription $_description = null;
private ?TwigSceneRenderer $twigSceneRenderer = null;
private static array $fillable = [
"owner",
];
/**
* @PostLoad
*/
public function onLoad()
{
foreach ($this->actionGroups as $actionGroup) {
$actionGroup->setViewpoint($this);
}
}
/**
* Returns the owner.
* @return Character
@@ -80,6 +100,22 @@ class Viewpoint implements CreateableInterface
$this->owner = $owner;
}
/**
* @param TwigSceneRenderer $twigSceneRenderer
*/
public function setTwigSceneRenderer(TwigSceneRenderer $twigSceneRenderer)
{
$this->twigSceneRenderer = $twigSceneRenderer;
}
/**
* @return TwigSceneRenderer|null
*/
public function getTwigSceneRenderer(): ?TwigSceneRenderer
{
return $this->twigSceneRenderer;
}
/**
* Sets the description of this viewpoint.
* @param string $description
@@ -125,15 +161,11 @@ class Viewpoint implements CreateableInterface
/**
* Copies the static data from a scene to this Viewpoint entity.
* @param Scene $scene
* @param TwigSceneRenderer $renderer Required to parse title and description.
*/
public function changeFromScene(Scene $scene, TwigSceneRenderer $renderer)
public function changeFromScene(Scene $scene)
{
$title = $renderer->render($scene->getTitle(), $scene, ignoreErrors: true);
$description = $renderer->render($scene->getDescription(), $scene, ignoreErrors: true);
$this->setTitle($title);
$this->setDescription($description);
$this->setTitle($scene->getTitle());
$this->setDescription($scene->getDescription());
$this->setTemplate($scene->getTemplate());
$this->setScene($scene);
@@ -178,6 +210,10 @@ class Viewpoint implements CreateableInterface
$this->setActionGroups($snapshot->getActionGroups());
$this->setAttachments($snapshot->getAttachments());
$this->setData($snapshot->getData());
foreach ($this->actionGroups as $actionGroup) {
$actionGroup->setViewpoint($this);
}
}
/**
@@ -213,6 +249,11 @@ class Viewpoint implements CreateableInterface
*/
public function setActionGroups(array $actionGroups)
{
foreach ($actionGroups as $actionGroup) {
if ($actionGroup instanceof ActionGroup) {
$actionGroup->setViewpoint($this);
}
}
$this->actionGroups = $actionGroups;
}
@@ -229,6 +270,10 @@ class Viewpoint implements CreateableInterface
throw new ArgumentException("Group {$group} is already contained in this viewpoint.");
}
foreach ($group->getActions() as $action) {
$action->setViewpoint($this);
}
if ($after === null) {
$this->actionGroups[] = $group;
} else {
@@ -271,9 +316,7 @@ class Viewpoint implements CreateableInterface
$actionGroups = $this->getActionGroups();
foreach ($actionGroups as $group) {
if ($group->getId() == $actionGroupId) {
$actions = $group->getActions();
$actions[] = $action;
$group->setActions($actions);
$group->addAction($action);
break;
}
}
@@ -381,4 +424,34 @@ class Viewpoint implements CreateableInterface
$group->setActions($actions);
}
}
/**
* Returns the rendered version of the title
* @return string
*/
public function getRenderedTitle(): string
{
$title = $this->getTitle();
if ($this->twigSceneRenderer) {
return $this->twigSceneRenderer->render($title, $this, ignoreErrors: true);
} else {
return $title;
}
}
/**
* Returns the rendered version of the description
* @return string
*/
public function getRenderedDescription(): string
{
$description = $this->getDescription();
if ($this->twigSceneRenderer) {
return $this->twigSceneRenderer->render($description, $this, ignoreErrors: true);
} else {
return $description;
}
}
}
+3
View File
@@ -25,6 +25,9 @@ class ViewpointSnapshot
private array $attachments,
private array $data,
) {
foreach ($this->actionGroups as $actionGroup) {
$actionGroup->setViewpoint(null);
}
}
/**
+59 -13
View File
@@ -5,12 +5,18 @@ declare(strict_types=1);
namespace LotGD\Core\Services;
use Doctrine\DBAL\Exception as DBALException;
use LotGD\Core\Action;
use LotGD\Core\Events\EventContextData;
use LotGD\Core\Exceptions\CharacterNotFoundException;
use LotGD\Core\Exceptions\InsecureTwigTemplateError;
use LotGD\Core\Game;
use LotGD\Core\Models\Character;
use LotGD\Core\Models\Scene;
use LotGD\Core\Models\Viewpoint;
use Twig\Environment;
use Twig\Error\LoaderError;
use Twig\Error\SyntaxError;
use Twig\Extension\SandboxExtension;
use Twig\Sandbox\SecurityError;
use Twig\Sandbox\SecurityPolicy;
@@ -18,19 +24,46 @@ use Twig\Sandbox\SecurityPolicy;
class TwigSceneRenderer
{
private Environment $twig;
private array $templateValues;
public function __construct(
private Game $game
) {
$this->twig = new Environment(new TwigNullLoader());
$securityPolicy = $this->getSecurityPolicy();
// Add a hook for additional fields
// This is for global changes only. Viewpoint-dependent changes should try to store the important values within
// the viewpoint itself.
$eventManager = $this->game->getEventManager();
$contextData = EventContextData::create(["templateValues" => []]);
# Add Sandbox extension
// Use try-catch here in case no database has yet been created. See #162
try {
$newContextData = $eventManager->publish("h/lotgd/core/scene-renderer/templateValues", $contextData);
$this->templateValues = $newContextData->get("templateValues") ?? [];
} catch (DBALException) {
$this->templateValues = [];
}
// Add Sandbox extension
$securityPolicy = $this->getSecurityPolicy();
$this->twig->addExtension(new SandboxExtension($securityPolicy, sandboxed: true));
}
public function render(string $string, Scene $scene, bool $ignoreErrors = false): string
/**
* Renders a given string in the context if a given viewpoint.
*
* @param string $string
* @param Viewpoint $viewpoint
* @param bool $ignoreErrors If set to true, errors are ignored and the unparsed string will be returned instead.
* @param array $templateValues
* @return string
* @throws InsecureTwigTemplateError
* @throws CharacterNotFoundException
* @throws LoaderError
* @throws SyntaxError
*/
public function render(string $string, Viewpoint $viewpoint, bool $ignoreErrors = false, array $templateValues = []): string
{
// We catch here "Tag" errors. If error, we'll exit either by returning the input ($ignoreError === true) or
// throwing an exception.
@@ -44,16 +77,14 @@ class TwigSceneRenderer
}
}
$templateValues = [
$defaultTemplateValues = [
"Character" => $this->game->getCharacter(),
"Scene" => $scene,
"Scene" => $viewpoint->getScene(),
"Viewpoint" => $viewpoint,
];
// Publish event to change $templateValues
$eventManager = $this->game->getEventManager();
$contextData = EventContextData::create(["templateValues" => $templateValues]);
$newContextData = $eventManager->publish("h/lotgd/core/scene-renderer/templateValues", $contextData);
$templateValues = $newContextData->get("templateValues");
// Merges additional template values with important ones.
$templateValues = array_merge($this->templateValues, $defaultTemplateValues, $templateValues);
// Try to render the template
try {
@@ -70,17 +101,26 @@ class TwigSceneRenderer
return $result;
}
/**
* Returns the current security policy.
* This method provides a hook.
* @return SecurityPolicy
*/
public function getSecurityPolicy(): SecurityPolicy
{
$tags = ["if"];
$filters = ["lower", "upper", "escape"];
$filters = ["lower", "upper", "escape", "round"];
$functions = ["range"];
$methods = [
Character::class => ["getDisplayName", "getLevel", "isAlive", "getHealth", "getMaxHealth", "getProperty"],
Scene::class => ["getProperty"],
Viewpoint::class => ["getData"],
Action::class => ["getParameters"],
];
$properties = [
"Character" => ["displayName", "level", "health", "maxHealth"],
"Character" => ["displayName", "level", "alive", "health", "maxHealth", "property"],
"Viewpoint" => ["data"],
"Action" => ["parameters"],
];
// Publish event to change $templateValues
@@ -92,7 +132,13 @@ class TwigSceneRenderer
"methods" => $methods,
"properties" => $properties,
]);
$newContextData = $eventManager->publish("h/lotgd/core/scene-renderer/securityPolicy", $contextData);
// Use try-catch here in case no database has yet been created. See #162
try {
$newContextData = $eventManager->publish("h/lotgd/core/scene-renderer/securityPolicy", $contextData);
} catch (DBALException) {
$this->templateValues = [];
}
// Set changed values from the event.
$tags = $newContextData->get("tags");
@@ -41,7 +41,7 @@ class SceneConfigResetCommandTest extends CoreModelTestCase
$eventManager->expects($this->once())
->method('publish')
->with(
$this->equalTo("h/lotgd/core/cli/character-config-reset/{$path}"),
$this->equalTo("h/lotgd/core/cli/scene-config-reset/{$path}"),
$this->callback(function (EventContextData $eventContextData) use ($scene, $sceneTitle, $setting) {
$pass = 1;
@@ -41,7 +41,7 @@ class SceneConfigSetCommandTest extends CoreModelTestCase
$eventManager->expects($this->once())
->method('publish')
->with(
$this->equalTo("h/lotgd/core/cli/character-config-set/{$path}"),
$this->equalTo("h/lotgd/core/cli/scene-config-set/{$path}"),
$this->callback(function (EventContextData $eventContextData) use ($character, $displayName, $setting, $value) {
$pass = 1;
+26 -6
View File
@@ -22,11 +22,11 @@ class ViewpointRestorationTest extends CoreModelTestCase
protected function getActionGroup()
{
static $actionGroup = null;
if ($actionGroup !== null) {
if ($actionGroup === null) {
$actionGroup = new ActionGroup("main", "Title", 0);
$actionGroup->addAction(new Action(1));
$actionGroup->addAction(new Action(2));
$actionGroup->addAction(new Action(3));
$actionGroup->addAction(new Action("30000000-0000-0000-0000-000000000001"));
$actionGroup->addAction(new Action("30000000-0000-0000-0000-000000000002"));
$actionGroup->addAction(new Action("30000000-0000-0000-0000-000000000003"));
}
return $actionGroup;
@@ -102,7 +102,17 @@ class ViewpointRestorationTest extends CoreModelTestCase
$this->assertSame($viewpoint->getTitle(), $newViewpoint->getTitle());
$this->assertSame($viewpoint->getDescription(), $newViewpoint->getDescription());
$this->assertSame($viewpoint->getTemplate(), $newViewpoint->getTemplate());
$this->assertEquals($viewpoint->getActionGroups(), $newViewpoint->getActionGroups());;
for ($i=0; $i < count($viewpoint->getActionGroups()); $i++) {
$should = $viewpoint->getActionGroups()[$i];
$is = $newViewpoint->getActionGroups()[$i];
$this->assertSame($should->getId(), $is->getId());
$this->assertSame($should->getTitle(), $is->getTitle());
$this->assertSame($should->getSortKey(), $is->getSortKey());
$this->assertSame(count($should->getActions()), count($is->getActions()));
}
$this->assertSame($viewpoint->getData(), $newViewpoint->getData());
$this->assertSame($viewpoint->getAttachments(), $newViewpoint->getAttachments());
}
@@ -120,7 +130,17 @@ class ViewpointRestorationTest extends CoreModelTestCase
$this->assertSame($viewpoint->getTitle(), $newViewpoint->getTitle());
$this->assertSame($viewpoint->getDescription(), $newViewpoint->getDescription());
$this->assertSame($viewpoint->getTemplate(), $newViewpoint->getTemplate());
$this->assertEquals($viewpoint->getActionGroups(), $newViewpoint->getActionGroups());;
for ($i=0; $i < count($viewpoint->getActionGroups()); $i++) {
$should = $viewpoint->getActionGroups()[$i];
$is = $newViewpoint->getActionGroups()[$i];
$this->assertSame($should->getId(), $is->getId());
$this->assertSame($should->getTitle(), $is->getTitle());
$this->assertSame($should->getSortKey(), $is->getSortKey());
$this->assertSame(count($should->getActions()), count($is->getActions()));
}
$this->assertSame($viewpoint->getData(), $newViewpoint->getData());
$this->assertSame($viewpoint->getAttachments(), $newViewpoint->getAttachments());
}
+33 -4
View File
@@ -117,9 +117,20 @@ class ViewpointTest extends CoreModelTestCase
$em->clear();
$output = $em->getRepository(Viewpoint::class)->find("10000000-0000-0000-0000-000000000002");
$this->assertEquals($actionGroups, $output->getActionGroups());
$this->assertEquals($ag2, $input->findActionGroupById('id2'));
for ($i=0; $i < count($actionGroups); $i++) {
$should = $actionGroups[$i];
$is = $output->getActionGroups()[$i];
$this->assertSame($should->getId(), $is->getId());
$this->assertSame($should->getTitle(), $is->getTitle());
$this->assertSame($should->getSortKey(), $is->getSortKey());
$this->assertSame(count($should->getActions()), count($is->getActions()));
$this->assertSame($output, $is->getViewpoint());
}
$this->assertEquals($ag2->getTitle(), $input->findActionGroupById('id2')->getTitle());
$this->assertNull($input->findActionGroupById('not-there'));
$testAction = new Action("30000000-0000-0000-0000-000000000004");
@@ -186,7 +197,16 @@ class ViewpointTest extends CoreModelTestCase
// Not finding the scene ID should change nothing.
$output->removeActionsWithSceneId("30000000-0000-0000-0000-000000001000");
$this->assertEquals($actionGroups, $output->getActionGroups());
for ($i=0; $i < count($actionGroups); $i++) {
$should = $actionGroups[$i];
$is = $output->getActionGroups()[$i];
$this->assertSame($should->getId(), $is->getId());
$this->assertSame($should->getTitle(), $is->getTitle());
$this->assertSame($should->getSortKey(), $is->getSortKey());
$this->assertSame(count($should->getActions()), count($is->getActions()));
}
$ag1_output = new ActionGroup('id1', 'title1', 42);
$ag1_output->setActions([
@@ -199,7 +219,16 @@ class ViewpointTest extends CoreModelTestCase
$ag2
];
$output->removeActionsWithSceneId("30000000-0000-0000-0000-000000000002");
$this->assertEquals($actionGroupsWithout2, $output->getActionGroups());
for ($i=0; $i < count($actionGroups); $i++) {
$should = $actionGroupsWithout2[$i];
$is = $output->getActionGroups()[$i];
$this->assertSame($should->getId(), $is->getId());
$this->assertSame($should->getTitle(), $is->getTitle());
$this->assertSame($should->getSortKey(), $is->getSortKey());
$this->assertSame(count($should->getActions()), count($is->getActions()));
}
}
public function testChangingSceneDescription()
+41 -15
View File
@@ -9,6 +9,7 @@ use LotGD\Core\Exceptions\InsecureTwigTemplateError;
use LotGD\Core\Game;
use LotGD\Core\Models\Character;
use LotGD\Core\Models\Scene;
use LotGD\Core\Models\Viewpoint;
use LotGD\Core\PHPUnit\LotGDTestCase;
use LotGD\Core\Services\TwigSceneRenderer;
@@ -43,12 +44,17 @@ class TwigSceneRendererTest extends LotGDTestCase
->disableOriginalConstructor()
->getMock();
return [$game, $scene, $character, $eventManager];
$viewpoint = $this->getMockBuilder(Viewpoint::class)
->disableOriginalConstructor()
->getMock();
$viewpoint->method("getScene")->willReturn($scene);
return [$game, $viewpoint, $character, $eventManager];
}
public function testIfSceneRendererCanBeConstructed()
{
[$game, $scene, $character, $eventManager] = $this->getMockeries();
[$game, $viewpoint, $character, $eventManager] = $this->getMockeries();
$eventManager->method("publish")->willReturnArgument(1);
$renderer = new TwigSceneRenderer($game);
@@ -58,7 +64,7 @@ class TwigSceneRendererTest extends LotGDTestCase
public function testIfTwigSceneRendererReturnsANonTemplateStringUnmodified()
{
[$game, $scene, $character, $eventManager] = $this->getMockeries();
[$game, $viewpoint, $character, $eventManager] = $this->getMockeries();
$eventManager->method("publish")->willReturnArgument(1);
# Get renderer
@@ -68,7 +74,7 @@ class TwigSceneRendererTest extends LotGDTestCase
$template = "You enter a new location.\n\nA new location.";
# Create the result
$renderResult = $renderer->render($template, $scene);
$renderResult = $renderer->render($template, $viewpoint);
# Assert result
$this->assertSame($template, $renderResult);
@@ -76,7 +82,7 @@ class TwigSceneRendererTest extends LotGDTestCase
public function testIfTwigSceneRendererParsesStringsWithCharacters()
{
[$game, $scene, $character, $eventManager] = $this->getMockeries();
[$game, $viewpoint, $character, $eventManager] = $this->getMockeries();
$eventManager->method("publish")->willReturnArgument(1);
# Get renderer
@@ -92,7 +98,27 @@ class TwigSceneRendererTest extends LotGDTestCase
."You are alive.";
# Create the result
$renderResult = $renderer->render($template, $scene);
$renderResult = $renderer->render($template, $viewpoint);
# Assert result
$this->assertSame($result, $renderResult);
}
public function testIfViewpointDataCanBeAccessed()
{
[$game, $viewpoint, $character, $eventManager] = $this->getMockeries();
$eventManager->method("publish")->willReturnArgument(1);
$viewpoint->method("getData")->willReturn(["test" => 7, "other" => "Hi"]);
# Get renderer
$renderer = new TwigSceneRenderer($game);
# Prepare the template string.
$template = "Hi {{ Viewpoint.data.test }}! {{ Viewpoint.data.other }}";
$result = "Hi 7! Hi";
# Create the result
$renderResult = $renderer->render($template, $viewpoint);
# Assert result
$this->assertSame($result, $renderResult);
@@ -100,7 +126,7 @@ class TwigSceneRendererTest extends LotGDTestCase
public function testIfRawTemplateGetsReturnedIfTemplateContainsIllegalTokens()
{
[$game, $scene, $character, $eventManager] = $this->getMockeries();
[$game, $viewpoint, $character, $eventManager] = $this->getMockeries();
$eventManager->method("publish")->willReturnArgument(1);
# Get renderer
@@ -110,7 +136,7 @@ class TwigSceneRendererTest extends LotGDTestCase
$template = "Viewpoint: {{ Character.viewpoint }}";
# Try to parse the result
$renderResult = $renderer->render($template, $scene, true);
$renderResult = $renderer->render($template, $viewpoint, true);
# If there was an error, it should have gotten ignored, giving back the raw template.
$this->assertSame($template, $renderResult);
@@ -118,7 +144,7 @@ class TwigSceneRendererTest extends LotGDTestCase
public function testIfExceptionGetsRaisedIfTemplateContainsIllegalTokens()
{
[$game, $scene, $character, $eventManager] = $this->getMockeries();
[$game, $viewpoint, $character, $eventManager] = $this->getMockeries();
$eventManager->method("publish")->willReturnArgument(1);
# Get renderer
@@ -131,12 +157,12 @@ class TwigSceneRendererTest extends LotGDTestCase
$this->expectException(InsecureTwigTemplateError::class);
# Try to parse the result
$renderResult = $renderer->render($template, $scene, false);
$renderResult = $renderer->render($template, $viewpoint, false);
}
public function testIfPublishedEventCanModifySecurityPolicy()
{
[$game, $scene, $character, $eventManager] = $this->getMockeries();
[$game, $viewpoint, $character, $eventManager] = $this->getMockeries();
# Set up a more complex "publish" method to emulate a real event.
$eventManager->method("publish")->willReturnCallback(function($event, EventContextData $context) {
@@ -164,15 +190,15 @@ class TwigSceneRendererTest extends LotGDTestCase
# Assert that if does not work anymore
$this->expectException(InsecureTwigTemplateError::class);
$renderer->render("{% if 5*1 %}Hallo{%endif%}", $scene, false);
$renderer->render("{% if 5*1 %}Hallo{%endif%}", $viewpoint, false);
$this->expectException(InsecureTwigTemplateError::class);
$renderer->render("{{ Character.name }}", $scene, false);
$renderer->render("{{ Character.name }}", $viewpoint, false);
}
public function testIfPublishedEventCanModifyValueScope()
{
[$game, $scene, $character, $eventManager] = $this->getMockeries();
[$game, $viewpoint, $character, $eventManager] = $this->getMockeries();
# Set up a more complex "publish" method to emulate a real event.
$eventManager->method("publish")->willReturnCallback(function($event, EventContextData $context) {
@@ -192,7 +218,7 @@ class TwigSceneRendererTest extends LotGDTestCase
$renderer = new TwigSceneRenderer($game);
# Assert result
$result = $renderer->render("{{ test }}", $scene, false);
$result = $renderer->render("{{ test }}", $viewpoint, false);
$this->assertSame("A test", $result);
}
}