0
0
mirror of https://github.com/pmmp/PocketMine-MP.git synced 2024-11-24 22:36:13 +00:00
PocketMine-MP/tests/phpunit/data/bedrock/block/upgrade/BlockStateUpgraderTest.php

263 lines
9.7 KiB
PHP

<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\data\bedrock\block\upgrade;
use PHPUnit\Framework\TestCase;
use pocketmine\block\Block;
use pocketmine\data\bedrock\block\BlockStateData;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\StringTag;
use const PHP_INT_MAX;
class BlockStateUpgraderTest extends TestCase{
private const TEST_BLOCK = "pocketmine:test_block";
private const TEST_BLOCK_2 = "pocketmine:test_block_2";
private const TEST_PROPERTY = "test_property";
private const TEST_PROPERTY_2 = "test_property_2";
private const TEST_VERSION = 1;
private const TEST_PROPERTY_VALUE_1 = 1;
private const TEST_PROPERTY_VALUE_2 = 2;
private const TEST_PROPERTY_VALUE_3 = 3;
private BlockStateUpgrader $upgrader;
public function setUp() : void{
$this->upgrader = new BlockStateUpgrader([]);
}
private function getNewSchema() : BlockStateUpgradeSchema{
return $this->getNewSchemaVersion(PHP_INT_MAX, 0);
}
private function getNewSchemaVersion(int $versionId, int $schemaId) : BlockStateUpgradeSchema{
$schema = new BlockStateUpgradeSchema(($versionId >> 24) & 0xff, ($versionId >> 16) & 0xff, ($versionId >> 8) & 0xff, $versionId & 0xff, $schemaId);
$this->upgrader->addSchema($schema);
return $schema;
}
/**
* @phpstan-param \Closure() : BlockStateData $getStateData
*/
private function upgrade(BlockStateData $stateData, \Closure $getStateData) : BlockStateData{
$result = $this->upgrader->upgrade($stateData);
self::assertTrue($stateData->equals($getStateData()), "Upgrading states must not alter the original input");
return $result;
}
public function testRenameId() : void{
$this->getNewSchema()->renamedIds[self::TEST_BLOCK] = self::TEST_BLOCK_2;
$getStateData = fn() => self::getEmptyPreimage();
$upgradedStateData = $this->upgrade($getStateData(), $getStateData);
self::assertSame($upgradedStateData->getName(), self::TEST_BLOCK_2);
}
private function prepareAddPropertySchema(BlockStateUpgradeSchema $schema) : void{
$schema->addedProperties[self::TEST_BLOCK][self::TEST_PROPERTY] = new IntTag(self::TEST_PROPERTY_VALUE_1);
}
private static function getEmptyPreimage() : BlockStateData{
return new BlockStateData(self::TEST_BLOCK, [], self::TEST_VERSION);
}
private static function getPreimageOneProperty(string $propertyName, int $value) : BlockStateData{
return new BlockStateData(
self::TEST_BLOCK,
[$propertyName => new IntTag($value)],
self::TEST_VERSION
);
}
public function testAddNewProperty() : void{
$this->prepareAddPropertySchema($this->getNewSchema());
$getStateData = fn() => self::getEmptyPreimage();
$upgradedStateData = $this->upgrade($getStateData(), $getStateData);
self::assertSame(self::TEST_PROPERTY_VALUE_1, $upgradedStateData->getState(self::TEST_PROPERTY)?->getValue());
}
public function testAddPropertyAlreadyExists() : void{
$this->prepareAddPropertySchema($this->getNewSchema());
$getStateData = fn() => self::getPreimageOneProperty(self::TEST_PROPERTY, self::TEST_PROPERTY_VALUE_1 + 1);
$stateData = $getStateData();
$upgradedStateData = $this->upgrade($stateData, $getStateData);
//the object may not be the same due to
self::assertTrue($stateData->equals($upgradedStateData), "Adding a property that already exists with a different value should not alter the state");
}
private function prepareRemovePropertySchema(BlockStateUpgradeSchema $schema) : void{
$schema->removedProperties[self::TEST_BLOCK][] = self::TEST_PROPERTY;
}
/**
* @phpstan-return \Generator<int, array{\Closure() : BlockStateData}, void, void>
*/
public static function removePropertyProvider() : \Generator{
yield [fn() => self::getEmptyPreimage()];
yield [fn() => self::getPreimageOneProperty(self::TEST_PROPERTY, self::TEST_PROPERTY_VALUE_1)];
}
/**
* @dataProvider removePropertyProvider
* @phpstan-param \Closure() : BlockStateData $getStateData
*/
public function testRemoveProperty(\Closure $getStateData) : void{
$this->prepareRemovePropertySchema($this->getNewSchema());
$upgradedStateData = $this->upgrade($getStateData(), $getStateData);
self::assertNull($upgradedStateData->getState(self::TEST_PROPERTY));
}
private function prepareRenamePropertySchema(BlockStateUpgradeSchema $schema) : void{
$schema->renamedProperties[self::TEST_BLOCK][self::TEST_PROPERTY] = self::TEST_PROPERTY_2;
}
/**
* @phpstan-return \Generator<int, array{\Closure() : BlockStateData, ?int}, void, void>
*/
public static function renamePropertyProvider() : \Generator{
yield [fn() => self::getEmptyPreimage(), null];
yield [fn() => self::getPreimageOneProperty(self::TEST_PROPERTY, self::TEST_PROPERTY_VALUE_1), self::TEST_PROPERTY_VALUE_1];
yield [fn() => self::getPreimageOneProperty(self::TEST_PROPERTY_2, self::TEST_PROPERTY_VALUE_1), self::TEST_PROPERTY_VALUE_1];
}
/**
* @dataProvider renamePropertyProvider
* @phpstan-param \Closure() : BlockStateData $getStateData
*/
public function testRenameProperty(\Closure $getStateData, ?int $valueAfter) : void{
$this->prepareRenamePropertySchema($this->getNewSchema());
$upgradedStateData = $this->upgrade($getStateData(), $getStateData);
self::assertSame($valueAfter, $upgradedStateData->getState(self::TEST_PROPERTY_2)?->getValue());
}
private function prepareRemapPropertyValueSchema(BlockStateUpgradeSchema $schema) : void{
$schema->remappedPropertyValues[self::TEST_BLOCK][self::TEST_PROPERTY][] = new BlockStateUpgradeSchemaValueRemap(
new IntTag(self::TEST_PROPERTY_VALUE_1),
new IntTag(self::TEST_PROPERTY_VALUE_2)
);
}
/**
* @phpstan-return \Generator<int, array{\Closure() : BlockStateData, ?int}, void, void>
*/
public static function remapPropertyValueProvider() : \Generator{
//no property to remap
yield [fn() => self::getEmptyPreimage(), null];
//value that will be remapped
yield [fn() => self::getPreimageOneProperty(self::TEST_PROPERTY, self::TEST_PROPERTY_VALUE_1), self::TEST_PROPERTY_VALUE_2];
//value that is already at the target value
yield [fn() => self::getPreimageOneProperty(self::TEST_PROPERTY, self::TEST_PROPERTY_VALUE_2), self::TEST_PROPERTY_VALUE_2];
//value that is not remapped and is different from target value (to detect unconditional overwrite bugs)
yield [fn() => self::getPreimageOneProperty(self::TEST_PROPERTY, self::TEST_PROPERTY_VALUE_3), self::TEST_PROPERTY_VALUE_3];
}
/**
* @dataProvider remapPropertyValueProvider
* @phpstan-param \Closure() : BlockStateData $getStateData
*/
public function testRemapPropertyValue(\Closure $getStateData, ?int $valueAfter) : void{
$this->prepareRemapPropertyValueSchema($this->getNewSchema());
$upgradedStateData = $this->upgrade($getStateData(), $getStateData);
self::assertSame($upgradedStateData->getState(self::TEST_PROPERTY)?->getValue(), $valueAfter);
}
/**
* @dataProvider remapPropertyValueProvider
* @phpstan-param \Closure() : BlockStateData $getStateData
*/
public function testRemapAndRenameProperty(\Closure $getStateData, ?int $valueAfter) : void{
$schema = $this->getNewSchema();
$this->prepareRenamePropertySchema($schema);
$this->prepareRemapPropertyValueSchema($schema);
$upgradedStateData = $this->upgrade($getStateData(), $getStateData);
self::assertSame($upgradedStateData->getState(self::TEST_PROPERTY_2)?->getValue(), $valueAfter);
}
public function testFlattenProperty() : void{
$schema = $this->getNewSchema();
$schema->flattenedProperties[self::TEST_BLOCK] = new BlockStateUpgradeSchemaFlattenInfo(
"minecraft:",
"test",
"_suffix",
[],
StringTag::class
);
$stateData = new BlockStateData(self::TEST_BLOCK, ["test" => new StringTag("value1")], 0);
$upgradedStateData = $this->upgrade($stateData, fn() => $stateData);
self::assertSame("minecraft:value1_suffix", $upgradedStateData->getName());
self::assertEmpty($upgradedStateData->getStates());
}
/**
* @phpstan-return \Generator<int, array{int, int, bool, int}, void, void>
*/
public static function upgraderVersionCompatibilityProvider() : \Generator{
yield [0x1_00_00_00, 0x1_00_00_00, true, 2]; //Same version, multiple schemas targeting version - must be altered, we don't know which schemas are applicable
yield [0x1_00_00_00, 0x1_00_00_00, false, 1]; //Same version, one schema targeting version - do not change
yield [0x1_00_01_00, 0x1_00_00_00, true, 1]; //Schema newer than block: must be altered
yield [0x1_00_00_00, 0x1_00_01_00, false, 1]; //Block newer than schema: block must NOT be altered
}
/**
* @dataProvider upgraderVersionCompatibilityProvider
*/
public function testUpgraderVersionCompatibility(int $schemaVersion, int $stateVersion, bool $shouldChange, int $schemaCount) : void{
for($i = 0; $i < $schemaCount; $i++){
$schema = $this->getNewSchemaVersion($schemaVersion, $i);
$schema->renamedIds[self::TEST_BLOCK] = self::TEST_BLOCK_2;
}
$getStateData = fn() => new BlockStateData(
self::TEST_BLOCK,
[],
$stateVersion
);
$upgradedStateData = $this->upgrade($getStateData(), $getStateData);
$originalStateData = $getStateData();
self::assertNotSame($shouldChange, $upgradedStateData->equals($originalStateData));
}
}