Test new category code.

This commit is contained in:
James Cole 2019-08-28 17:01:48 +02:00
parent 5fb7635100
commit f4eca2d4ae
4 changed files with 332 additions and 68 deletions

View File

@ -65,27 +65,29 @@ class CategoryController extends Controller
/**
* Show an overview for a category for all time, per month/week/year.
* TODO test method, for category refactor.
*
* @param CategoryRepositoryInterface $repository
* @param Category $category
* @param Category $category
*
* @return JsonResponse
*/
public function all(CategoryRepositoryInterface $repository, Category $category): JsonResponse
public function all(Category $category): JsonResponse
{
// cache results:
$cache = new CacheProperties;
$cache->addProperty('chart.category.all');
$cache->addProperty($category->id);
if ($cache->has()) {
// return response()->json($cache->get()); // @codeCoverageIgnore
return response()->json($cache->get()); // @codeCoverageIgnore
}
$start = $repository->firstUseDate($category) ?? $this->getDate();
$range = app('preferences')->get('viewRange', '1M')->data;
$start = app('navigation')->startOfPeriod($start, $range);
$end = $this->getDate();
/** @var CategoryRepositoryInterface $repository */
$repository = app(CategoryRepositoryInterface::class);
$start = $repository->firstUseDate($category) ?? $this->getDate();
$range = app('preferences')->get('viewRange', '1M')->data;
$start = app('navigation')->startOfPeriod($start, $range);
$end = $this->getDate();
Log::debug(sprintf('Full range is %s to %s', $start->format('Y-m-d'), $end->format('Y-m-d')));
//Log::debug(sprintf('Full range is %s to %s', $start->format('Y-m-d'), $end->format('Y-m-d')));
/** @var WholePeriodChartGenerator $generator */
$generator = app(WholePeriodChartGenerator::class);
@ -99,6 +101,7 @@ class CategoryController extends Controller
/**
* Shows the category chart on the front page.
* TODO test method, for category refactor.
*
* @return JsonResponse
*/
@ -112,7 +115,7 @@ class CategoryController extends Controller
$cache->addProperty($end);
$cache->addProperty('chart.category.frontpage');
if ($cache->has()) {
// return response()->json($cache->get()); // @codeCoverageIgnore
return response()->json($cache->get()); // @codeCoverageIgnore
}
// currency repos:
@ -207,6 +210,7 @@ class CategoryController extends Controller
/**
* Chart report.
* TODO test method, for category refactor.
*
* @param Category $category
* @param Collection $accounts
@ -224,7 +228,7 @@ class CategoryController extends Controller
$cache->addProperty($accounts->pluck('id')->toArray());
$cache->addProperty($category);
if ($cache->has()) {
// return response()->json($cache->get());// @codeCoverageIgnore
return response()->json($cache->get());// @codeCoverageIgnore
}
/** @var OperationsRepositoryInterface $opsRepository */
@ -272,12 +276,14 @@ class CategoryController extends Controller
$outSet = $expenses[$currencyId]['categories'][$category->id] ?? ['transaction_journals' => []];
foreach ($outSet['transaction_journals'] as $journal) {
$date = $journal['date']->formatLocalized($format);
$chartData[$outKey]['entries'][$date] = $chartData[$outKey]['entries'][$date] ?? '0';
$chartData[$outKey]['entries'][$date] = bcadd($journal['amount'], $chartData[$outKey]['entries'][$date]);
}
$inSet = $income[$currencyId]['categories'][$category->id] ?? ['transaction_journals' => []];
foreach ($inSet['transaction_journals'] as $journal) {
$date = $journal['date']->formatLocalized($format);
$chartData[$inKey]['entries'][$date] = $chartData[$inKey]['entries'][$date] ?? '0';
$chartData[$inKey]['entries'][$date] = bcadd($journal['amount'], $chartData[$inKey]['entries'][$date]);
}
}
@ -291,6 +297,7 @@ class CategoryController extends Controller
/**
* Chart for period for transactions without a category.
* TODO test me.
*
* @param Collection $accounts
* @param Carbon $start
@ -352,12 +359,14 @@ class CategoryController extends Controller
$outSet = $expenses[$currencyId] ?? ['transaction_journals' => []];
foreach ($outSet['transaction_journals'] as $journal) {
$date = $journal['date']->formatLocalized($format);
$chartData[$outKey]['entries'][$date] = $chartData[$outKey]['entries'][$date] ?? '0';
$chartData[$outKey]['entries'][$date] = bcadd($journal['amount'], $chartData[$outKey]['entries'][$date]);
}
$inSet = $income[$currencyId] ?? ['transaction_journals' => []];
foreach ($inSet['transaction_journals'] as $journal) {
$date = $journal['date']->formatLocalized($format);
$chartData[$inKey]['entries'][$date] = $chartData[$inKey]['entries'][$date] ?? '0';
$chartData[$inKey]['entries'][$date] = bcadd($journal['amount'], $chartData[$inKey]['entries'][$date]);
}
}
@ -369,6 +378,7 @@ class CategoryController extends Controller
/**
* Chart for a specific period.
* TODO test method, for category refactor.
*
* @param Category $category
* @param $date

View File

@ -29,12 +29,23 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Repositories\Category\OperationsRepositoryInterface;
use Illuminate\Support\Collection;
use Log;
/**
* Class WholePeriodChartGenerator
*/
class WholePeriodChartGenerator
{
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === config('app.env')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', get_class($this)));
}
}
/**
* @param Category $category
* @param Carbon $start

View File

@ -28,13 +28,15 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Generator\Chart\Basic\GeneratorInterface;
use FireflyIII\Helpers\Fiscal\FiscalHelperInterface;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Repositories\Category\NoCategoryRepositoryInterface;
use FireflyIII\Repositories\Category\OperationsRepositoryInterface;
use FireflyIII\Support\Chart\Category\WholePeriodChartGenerator;
use Illuminate\Support\Collection;
use Log;
use Preferences;
use Tests\Support\TestDataTrait;
use Tests\TestCase;
/**
@ -45,6 +47,8 @@ use Tests\TestCase;
*/
class CategoryControllerTest extends TestCase
{
use TestDataTrait;
/**
*
*/
@ -59,16 +63,19 @@ class CategoryControllerTest extends TestCase
* @dataProvider dateRangeProvider
*
* @param string $range
*
* @throws FireflyException
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
public function testAll(string $range): void
{
Log::info(sprintf('Now in test %s.', __METHOD__));
$repository = $this->mock(CategoryRepositoryInterface::class);
$accountRepos = $this->mock(AccountRepositoryInterface::class);
$generator = $this->mock(GeneratorInterface::class);
$chartGen = $this->mock(WholePeriodChartGenerator::class);
$firstUseDate = null;
switch ($range) {
default:
throw new FireflyException(sprintf('No case for %s', $range));
@ -98,10 +105,9 @@ class CategoryControllerTest extends TestCase
$this->mockDefaultSession();
Preferences::shouldReceive('lastActivity')->atLeast()->once()->andReturn('md512345');
$repository->shouldReceive('spentInPeriod')->andReturn([])->atLeast()->once();
$repository->shouldReceive('earnedInPeriod')->andReturn([])->atLeast()->once();
$chartGen->shouldReceive('generate')->atLeast()->once()->andReturn([]);
$repository->shouldReceive('firstUseDate')->andReturn($firstUseDate)->once();
$accountRepos->shouldReceive('getAccountsByType')->withArgs([[AccountType::DEFAULT, AccountType::ASSET, AccountType::LOAN, AccountType::DEBT,AccountType::MORTGAGE]])->andReturn(new Collection)->once();
$generator->shouldReceive('multiSet')->once()->andReturn([]);
$this->be($this->user());
@ -118,54 +124,24 @@ class CategoryControllerTest extends TestCase
*/
public function testFrontPage(string $range): void
{
$repository = $this->mock(CategoryRepositoryInterface::class);
$accountRepos = $this->mock(AccountRepositoryInterface::class);
$generator = $this->mock(GeneratorInterface::class);
$currencyRepos = $this->mock(CurrencyRepositoryInterface::class);
Log::info(sprintf('Now in test %s.', __METHOD__));
$repository = $this->mock(CategoryRepositoryInterface::class);
$accountRepos = $this->mock(AccountRepositoryInterface::class);
$generator = $this->mock(GeneratorInterface::class);
$opsRepos = $this->mock(OperationsRepositoryInterface::class);
$noCatRepos = $this->mock(NoCategoryRepositoryInterface::class);
$category = $this->getRandomCategory();
$account = $this->getRandomAsset();
$this->mockDefaultSession();
Preferences::shouldReceive('lastActivity')->atLeast()->once()->andReturn('md512345');
// spent per currency data:
$spentNoCategory = [
1 =>
[
'spent' => '-123.45',
'currency_id' => 1,
'currency_code' => 'X',
'currency_symbol' => 'x',
'currency_decimal_places' => 2,
],
];
$spentData = [
1 => [
'name' => 'Car',
'spent' => [
1 => [
'spent' => '-123.45',
'currency_id' => 2,
'currency_code' => 'a',
'currency_symbol' => 'b',
'currency_decimal_places' => 2,
],
],
],
];
$opsRepos->shouldReceive('sumExpenses')->atLeast()->once()->andReturn($this->categorySumExpenses());
$noCatRepos->shouldReceive('sumExpenses')->atLeast()->once()->andReturn($this->categorySumExpenses());
// grab two categories from the user
$categories = $this->user()->categories()->take(2)->get();
// grab two the users asset accounts:
$accounts = $this->user()->accounts()->where('account_type_id', 3)->take(2)->get();
// repository will return these.
$repository->shouldReceive('getCategories')->andReturn($categories)->once();
$accountRepos->shouldReceive('getAccountsByType')->once()->withArgs([[AccountType::ASSET, AccountType::DEFAULT]])->andReturn($accounts);
$repository->shouldReceive('spentInPeriodPerCurrency')->times(2)->andReturn($spentData);
$repository->shouldReceive('spentInPeriodPcWoCategory')->once()->andReturn($spentNoCategory);
$currencyRepos->shouldReceive('findNull')->withArgs([1])->once()->andReturn($this->getEuro());
$repository->shouldReceive('getCategories')->atLeast()->once()->andReturn(new Collection([$category]));
$accountRepos->shouldReceive('getAccountsByType')->once()->withArgs([[AccountType::ASSET, AccountType::DEFAULT]])->andReturn(
new Collection([$account])
);
$generator->shouldReceive('multiSet')->andReturn([]);
$this->be($this->user());
@ -179,18 +155,21 @@ class CategoryControllerTest extends TestCase
*/
public function testReportPeriod(): void
{
Log::info(sprintf('Now in test %s.', __METHOD__));
$repository = $this->mock(CategoryRepositoryInterface::class);
$generator = $this->mock(GeneratorInterface::class);
$fiscalHelper = $this->mock(FiscalHelperInterface::class);
$opsRepos = $this->mock(OperationsRepositoryInterface::class);
$date = new Carbon;
$opsRepos->shouldReceive('listExpenses')->atLeast()->once()->andReturn($this->categoryListExpenses());
$opsRepos->shouldReceive('listIncome')->atLeast()->once()->andReturn($this->categoryListIncome());
$this->mockDefaultSession();
Preferences::shouldReceive('lastActivity')->atLeast()->once()->andReturn('md512345');
$fiscalHelper->shouldReceive('endOfFiscalYear')->atLeast()->once()->andReturn($date);
$fiscalHelper->shouldReceive('startOfFiscalYear')->atLeast()->once()->andReturn($date);
$repository->shouldReceive('periodExpenses')->andReturn([])->once();
$repository->shouldReceive('periodIncome')->andReturn([])->once();
$generator->shouldReceive('multiSet')->andReturn([])->once();
$this->be($this->user());
@ -203,18 +182,21 @@ class CategoryControllerTest extends TestCase
*/
public function testReportPeriodNoCategory(): void
{
Log::info(sprintf('Now in test %s.', __METHOD__));
$repository = $this->mock(CategoryRepositoryInterface::class);
$generator = $this->mock(GeneratorInterface::class);
$fiscalHelper = $this->mock(FiscalHelperInterface::class);
$noCatRepos = $this->mock(NoCategoryRepositoryInterface::class);
$date = new Carbon;
$noCatRepos->shouldReceive('listExpenses')->atLeast()->once()->andReturn($this->noCategoryListExpenses());
$noCatRepos->shouldReceive('listIncome')->atLeast()->once()->andReturn($this->noCategoryListIncome());
$this->mockDefaultSession();
Preferences::shouldReceive('lastActivity')->atLeast()->once()->andReturn('md512345');
$fiscalHelper->shouldReceive('endOfFiscalYear')->atLeast()->once()->andReturn($date);
$fiscalHelper->shouldReceive('startOfFiscalYear')->atLeast()->once()->andReturn($date);
$repository->shouldReceive('periodExpensesNoCategory')->andReturn([])->once();
$repository->shouldReceive('periodIncomeNoCategory')->andReturn([])->once();
$generator->shouldReceive('multiSet')->andReturn([])->once();
$this->be($this->user());
@ -227,26 +209,29 @@ class CategoryControllerTest extends TestCase
* @dataProvider dateRangeProvider
*
* @param string $range
*
* @throws Exception
*/
public function testSpecificPeriod(string $range): void
{
Log::info(sprintf('Now in test %s.', __METHOD__));
$repository = $this->mock(CategoryRepositoryInterface::class);
$accountRepos = $this->mock(AccountRepositoryInterface::class);
$generator = $this->mock(GeneratorInterface::class);
$account = $this->getRandomAsset();
$fiscalHelper = $this->mock(FiscalHelperInterface::class);
$chartGen = $this->mock(WholePeriodChartGenerator::class);
$account = $this->getRandomAsset();
$date = new Carbon;
$this->mockDefaultSession();
Preferences::shouldReceive('lastActivity')->atLeast()->once()->andReturn('md512345');
$chartGen->shouldReceive('generate')->atLeast()->once()->andReturn([]);
$fiscalHelper->shouldReceive('endOfFiscalYear')->atLeast()->once()->andReturn($date);
$fiscalHelper->shouldReceive('startOfFiscalYear')->atLeast()->once()->andReturn($date);
$accountRepos->shouldReceive('getAccountsByType')->andReturn(new Collection([$account]));
$repository->shouldReceive('spentInPeriod')->andReturn([]);
$repository->shouldReceive('earnedInPeriod')->andReturn([]);
$generator->shouldReceive('multiSet')->andReturn([])->once();
$this->be($this->user());

View File

@ -0,0 +1,258 @@
<?php
/**
* TestDataTrait.php
* Copyright (c) 2019 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace Tests\Support;
use Carbon\Carbon;
use Exception;
use FireflyIII\Models\TransactionCurrency;
/**
* Trait TestDataTrait
*
* @package Tests\Support
*/
trait TestDataTrait
{
/**
* Method that returns default data for when the category OperationsRepos
* "listExpenses" method is called.
*
* @return array
*/
protected function categoryListExpenses(): array
{
$eur = TransactionCurrency::where('code', 'EUR')->first();
$usd = TransactionCurrency::where('code', 'USD')->first();
$cat1 = $this->user()->categories()->inRandomOrder()->first();
$cat2 = $this->user()->categories()->inRandomOrder()->where('id', '!=', $cat1->id)->first();
$data = [];
$amount = 400;
$date = null;
try {
$amount = random_int(100, 2500);
$date = new Carbon;
} catch (Exception $e) {
$e->getMessage();
}
$amount = bcmul((string)round($amount / 100, 2), '-1');
foreach ([$eur, $usd] as $currency) {
$data[$currency->id] = [
'currency_id' => $currency->id,
'currency_name' => $currency->name,
'currency_symbol' => $currency->symbol,
'currency_code' => $currency->code,
'currency_decimal_places' => $currency->decimal_places,
'categories' => [],
];
foreach ([$cat1, $cat2] as $category) {
$data[$currency->id]['categories'][$category->id] = [
'id' => $category->id,
'name' => $category->name,
'transaction_journals' => [],
];
// add two random amounts:
for ($i = 0; $i < 2; $i++) {
$data[$currency->id]['categories'][$category->id]['transaction_journals'][$i] = [
'amount' => $amount,
'date' => $date,
];
}
}
}
return $data;
}
/**
* Method that returns default data for when the category OperationsRepos
* "listExpenses" method is called.
*
* @return array
*/
protected function categoryListIncome(): array
{
$eur = TransactionCurrency::where('code', 'EUR')->first();
$usd = TransactionCurrency::where('code', 'USD')->first();
$cat1 = $this->user()->categories()->inRandomOrder()->first();
$cat2 = $this->user()->categories()->inRandomOrder()->where('id', '!=', $cat1->id)->first();
$data = [];
$amount = 400;
$date = null;
try {
$amount = random_int(100, 2500);
$date = new Carbon;
} catch (Exception $e) {
$e->getMessage();
}
$amount = (string)round($amount / 100, 2);
foreach ([$eur, $usd] as $currency) {
$data[$currency->id] = [
'currency_id' => $currency->id,
'currency_name' => $currency->name,
'currency_symbol' => $currency->symbol,
'currency_code' => $currency->code,
'currency_decimal_places' => $currency->decimal_places,
'categories' => [],
];
foreach ([$cat1, $cat2] as $category) {
$data[$currency->id]['categories'][$category->id] = [
'id' => $category->id,
'name' => $category->name,
'transaction_journals' => [],
];
// add two random amounts:
for ($i = 0; $i < 2; $i++) {
$data[$currency->id]['categories'][$category->id]['transaction_journals'][$i] = [
'amount' => $amount,
'date' => $date,
];
}
}
}
return $data;
}
/**
* Method that returns default data for when the category OperationsController
* "sumExpenses" method is called.
*
* Also applies to NoCategoryRepos::sumExpenses.
*
* @return array
*/
protected function categorySumExpenses(): array
{
$eur = TransactionCurrency::where('code', 'EUR')->first();
$usd = TransactionCurrency::where('code', 'USD')->first();
$data = [];
$amount = 400;
try {
$amount = random_int(100, 2500);
} catch (Exception $e) {
$e->getMessage();
}
$amount = bcmul((string)round($amount / 100, 2), '-1');
foreach ([$eur, $usd] as $currency) {
$data[$currency->id] = [
'currency_id' => $currency->id,
'currency_name' => $currency->name,
'currency_symbol' => $currency->symbol,
'currency_code' => $currency->code,
'currency_decimal_places' => $currency->decimal_places,
'sum' => $amount,
];
}
return $data;
}
/**
* Method that returns default data for when the category NoCategoryRepos
* "listExpenses" method is called.
*
* @return array
*/
protected function noCategoryListExpenses(): array
{
$eur = TransactionCurrency::where('code', 'EUR')->first();
$usd = TransactionCurrency::where('code', 'USD')->first();
$data = [];
$amount = 400;
$date = null;
try {
$amount = random_int(100, 2500);
$date = new Carbon;
} catch (Exception $e) {
$e->getMessage();
}
$amount = bcmul((string)round($amount / 100, 2), '-1');
foreach ([$eur, $usd] as $currency) {
$data[$currency->id] = [
'currency_id' => $currency->id,
'currency_name' => $currency->name,
'currency_symbol' => $currency->symbol,
'currency_code' => $currency->code,
'currency_decimal_places' => $currency->decimal_places,
'transaction_journals' => [],
];
// add two random amounts:
for ($i = 0; $i < 2; $i++) {
$data[$currency->id]['transaction_journals'][$i] = [
'amount' => $amount,
'date' => $date,
];
}
}
return $data;
}
/**
* Method that returns default data for when the category NoCategoryRepos
* "listExpenses" method is called.
*
* @return array
*/
protected function noCategoryListIncome(): array
{
$eur = TransactionCurrency::where('code', 'EUR')->first();
$usd = TransactionCurrency::where('code', 'USD')->first();
$data = [];
$amount = 400;
$date = null;
try {
$amount = random_int(100, 2500);
$date = new Carbon;
} catch (Exception $e) {
$e->getMessage();
}
$amount = (string)round($amount / 100, 2);
foreach ([$eur, $usd] as $currency) {
$data[$currency->id] = [
'currency_id' => $currency->id,
'currency_name' => $currency->name,
'currency_symbol' => $currency->symbol,
'currency_code' => $currency->code,
'currency_decimal_places' => $currency->decimal_places,
'transaction_journals' => [],
];
// add two random amounts:
for ($i = 0; $i < 2; $i++) {
$data[$currency->id]['transaction_journals'][$i] = [
'amount' => $amount,
'date' => $date,
];
}
}
return $data;
}
}