3
0
mirror of https://github.com/snipe/snipe-it.git synced 2026-08-18 11:15:42 +00:00
Files
snipe-it/tests/Unit/AssetModelTest.php
2026-06-30 14:52:55 +01:00

147 lines
4.3 KiB
PHP

<?php
namespace Tests\Unit;
use App\Models\Asset;
use App\Models\AssetModel;
use App\Models\Category;
use Illuminate\Support\Facades\DB;
use Tests\TestCase;
class AssetModelTest extends TestCase
{
public function test_an_asset_model_contains_assets()
{
$category = Category::factory()->create([
'category_type' => 'asset',
]);
$model = AssetModel::factory()->create([
'category_id' => $category->id,
]);
$asset = Asset::factory()->create([
'model_id' => $model->id,
]);
$this->assertEquals(1, $model->assets()->count());
}
public function test_percent_remaining_returns_zero_when_no_assets_are_available()
{
$model = new class extends AssetModel
{
public function availableAssets()
{
return new class
{
public function count()
{
return 0;
}
};
}
public function assets()
{
return new class
{
public function count()
{
return 10;
}
};
}
};
$this->assertEquals(0, $model->percentRemaining());
}
public function test_percent_remaining_returns_expected_ratio_for_mixed_availability()
{
$model = new class extends AssetModel
{
public function availableAssets()
{
return new class
{
public function count()
{
return 2;
}
};
}
public function assets()
{
return new class
{
public function count()
{
return 5;
}
};
}
};
$this->assertEquals(40.0, $model->percentRemaining());
}
public function test_percent_remaining_only_calls_available_assets_count_once(): void
{
// Regression: the old implementation called $this->availableAssets()
// ->count() twice — once for the zero guard, once for the ratio.
// Under the API transformer loop in /api/v1/models that doubled the
// status-label pluck + count(*) queries for every row. Pin the
// single-call contract so a future cleanup doesn't reintroduce it.
$category = Category::factory()->create(['category_type' => 'asset']);
$model = AssetModel::factory()->create(['category_id' => $category->id]);
Asset::factory()->count(2)->create(['model_id' => $model->id]);
$availableCountQueries = 0;
DB::listen(function ($query) use (&$availableCountQueries, $model) {
// The availableAssets() relation generates a count(*) on assets
// filtered by model_id AND assigned_to IS NULL.
if (str_contains($query->sql, 'count(*)')
&& str_contains($query->sql, '"assets"')
&& str_contains($query->sql, '"assigned_to" is null')
&& in_array($model->id, $query->bindings, true)
) {
$availableCountQueries++;
}
});
$model->percentRemaining();
$this->assertSame(1, $availableCountQueries, 'availableAssets()->count() must be called exactly once per percentRemaining()');
}
public function test_percent_remaining_returns_one_hundred_when_all_assets_are_available()
{
$model = new class extends AssetModel
{
public function availableAssets()
{
return new class
{
public function count()
{
return 4;
}
};
}
public function assets()
{
return new class
{
public function count()
{
return 4;
}
};
}
};
$this->assertEquals(100.0, $model->percentRemaining());
}
}