1
0
Fork 0
mirror of https://github.com/archtechx/virtualcolumn.git synced 2025-12-12 05:14:05 +00:00
virtualcolumn/tests/VirtualColumnTest.php
lukinovec 72de33a3d4
Add encrypted casts support + allow using the trait on multiple models (#14)
* Add encrypted casts test (wip)

* Handle and test 'encrypted' casts

* Add APP_KEY to phpunit.xml

* Update attribute casting in VirtualColumn

* Test casting of all default 'encrypted' castables

* Fix code style (php-cs-fixer)

* Handle custom castables in VirtualColumn

* Add custom encrypted castable

* Test custom encrypted castable, refactor test

* Move EncryptedCast class to VirtualColumnTest

* Correct expected/actual value order in assertions

* Break code style (testing)

* Fix code style (php-cs-fixer)

* Check Laravel CI version (testing)

* dd() Laravel version

* Delete dd()

* Delete get() and set() types

* Use non-lowercase custom cast class strings

* Check hasCast manually

* Correct encrypted castable logic

* Update src/VirtualColumn.php

* Use `$dataEncoded` bool instead of `$dataEncodingStatus` string

* Don't accept unused `$e`

* Refactor `encodeAttributes()`

* Use `$model->getCustomColumns()` instead of `static::getCustomColumns()`

* Use `$model` instead of `static` where possible

* Correct test

* Revert `static` -> `$model` changes

* Correct typo

* Refactor `$afterListeneres`

* Fix code style (php-cs-fixer)

* Make static things non-static in VirtualColumn

* Change method to non-static in test

* Add base class that uses VirtualColumn in tests

* Add encrypted castables docblock

* Fix merge

* Fix ParentModel change

* make $this and $model use clear and consistent

---------

Co-authored-by: Samuel Štancl <samuel.stancl@gmail.com>
Co-authored-by: Samuel Štancl <samuel@archte.ch>
2023-11-08 10:08:34 +01:00

237 lines
7.1 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace Stancl\VirtualColumn\Tests;
use Orchestra\Testbench\TestCase;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Database\Eloquent\Model;
use Stancl\VirtualColumn\VirtualColumn;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
class VirtualColumnTest extends TestCase
{
public function setUp(): void
{
parent::setUp();
$this->loadMigrationsFrom(__DIR__ . '/etc/migrations');
}
/** @test */
public function keys_which_dont_have_their_own_column_go_into_data_json_column()
{
$model = MyModel::create([
'foo' => 'bar',
]);
// Test that model works correctly
$this->assertSame('bar', $model->foo);
$this->assertSame(null, $model->data);
// Low level test to assert database structure
$this->assertSame(['foo' => 'bar'], json_decode(DB::table('my_models')->where('id', $model->id)->first()->data, true));
$this->assertSame(null, DB::table('my_models')->where('id', $model->id)->first()->foo ?? null);
// Model has the correct structure when retrieved
$model = MyModel::first();
$this->assertSame('bar', $model->foo);
$this->assertSame('bar', $model->getOriginal('foo'));
$this->assertSame(null, $model->data);
// Model can be updated
$model->update([
'foo' => 'baz',
'abc' => 'xyz',
]);
$this->assertSame('baz', $model->foo);
$this->assertSame('baz', $model->getOriginal('foo'));
$this->assertSame('xyz', $model->abc);
$this->assertSame('xyz', $model->getOriginal('abc'));
$this->assertSame(null, $model->data);
// Model can be retrieved after update & is structured correctly
$model = MyModel::first();
$this->assertSame('baz', $model->foo);
$this->assertSame('xyz', $model->abc);
$this->assertSame(null, $model->data);
}
/** @test */
public function model_is_always_decoded_when_accessed_by_user_event()
{
MyModel::retrieved(function (MyModel $model) {
$this->assertFalse($model->dataEncoded);
});
MyModel::saving(function (MyModel $model) {
$this->assertFalse($model->dataEncoded);
});
MyModel::updating(function (MyModel $model) {
$this->assertFalse($model->dataEncoded);
});
MyModel::creating(function (MyModel $model) {
$this->assertFalse($model->dataEncoded);
});
MyModel::saved(function (MyModel $model) {
$this->assertFalse($model->dataEncoded);
});
MyModel::updated(function (MyModel $model) {
$this->assertFalse($model->dataEncoded);
});
MyModel::created(function (MyModel $model) {
$this->assertFalse($model->dataEncoded);
});
$model = MyModel::create(['foo' => 'bar']);
$model->update(['foo' => 'baz']);
MyModel::first();
}
/** @test */
public function column_names_are_generated_correctly()
{
// FooModel's virtual data column name is 'virtual'
$virtualColumnName = 'virtual->foo';
$customColumnName = 'custom1';
/** @var FooModel $model */
$model = FooModel::create([
'custom1' => $customColumnName,
'foo' => $virtualColumnName
]);
$this->assertSame($customColumnName, $model->getColumnForQuery('custom1'));
$this->assertSame($virtualColumnName, $model->getColumnForQuery('foo'));
}
/** @test */
public function models_extending_a_parent_model_using_virtualcolumn_get_encoded_correctly()
{
// Create a model that extends a parent model using VirtualColumn
// 'foo' is a custom column, 'data' is the virtual column
FooChild::create(['foo' => 'foo']);
$encodedFoo = DB::select('select * from foo_childs limit 1')[0];
// Assert that the model was encoded correctly
$this->assertSame($encodedFoo->data, '[]');
$this->assertSame($encodedFoo->foo, 'foo');
// Create another child model of the same parent
// 'bar' is a custom column, 'data' is the virtual column
BarChild::create(['bar' => 'bar']);
$encodedBar = DB::select('select * from bar_childs limit 1')[0];
$this->assertSame($encodedBar->data, '[]');
$this->assertSame($encodedBar->bar, 'bar');
}
// maybe add an explicit test that the saving() and updating() listeners don't run twice?
/** @test */
public function encrypted_casts_work_with_virtual_column() {
// Custom encrypted castables have to be specified in the $customEncryptedCastables static property
MyModel::$customEncryptedCastables = [EncryptedCast::class];
/** @var MyModel $model */
$model = MyModel::create($encryptedAttributes = [
'password' => 'foo', // 'encrypted'
'array' => ['foo', 'bar'], // 'encrypted:array'
'collection' => collect(['foo', 'bar']), // 'encrypted:collection'
'json' => json_encode(['foo', 'bar']), // 'encrypted:json'
'object' => (object) json_encode(['foo', 'bar']), // 'encrypted:object'
'custom' => 'foo', // Custom castable 'EncryptedCast::class'
]);
foreach($encryptedAttributes as $key => $expectedValue) {
$savedValue = $model->getAttributes()[$key]; // Encrypted
$this->assertTrue($model->valueEncrypted($savedValue));
$this->assertNotEquals($expectedValue, $savedValue);
$retrievedValue = $model->$key; // Decrypted
$this->assertEquals($expectedValue, $retrievedValue);
}
// Reset static property
MyModel::$customEncryptedCastables = [];
}
}
class ParentModel extends Model
{
use VirtualColumn;
public $timestamps = false;
protected $guarded = [];
}
class MyModel extends ParentModel
{
public $casts = [
'password' => 'encrypted',
'array' => 'encrypted:array',
'collection' => 'encrypted:collection',
'json' => 'encrypted:json',
'object' => 'encrypted:object',
'custom' => EncryptedCast::class,
];
}
class FooModel extends ParentModel
{
public function getCustomColumns(): array
{
return [
'id',
'custom1',
'custom2',
];
}
public function getDataColumn(): string
{
return 'virtual';
}
}
class EncryptedCast implements CastsAttributes
{
public function get($model, $key, $value, $attributes)
{
return Crypt::decryptString($value);
}
public function set($model, $key, $value, $attributes)
{
return Crypt::encryptString($value);
}
}
class FooChild extends ParentModel
{
public $table = 'foo_childs';
public function getCustomColumns(): array
{
return [
'id',
'foo',
];
}
}
class BarChild extends ParentModel
{
public $table = 'bar_childs';
public function getCustomColumns(): array
{
return [
'id',
'bar',
];
}
}