diff --git a/resources/views/tags/index.twig b/resources/views/tags/index.twig
index e611b43801..6aee84d08b 100644
--- a/resources/views/tags/index.twig
+++ b/resources/views/tags/index.twig
@@ -8,6 +8,13 @@
{% if count == 0 %}
{% include 'partials.empty' with {what: 'default', type: 'tags',route: route('tags.create')} %}
{% else %}
+
{% for period,entries in clouds %}
{% if entries|length > 0 %}
-
- {% for type in types %}
- {% if counts[type] > 0 %}
-
- {% endif %}
- {% endfor %}
-
+
- #}
{% endif %}
{% endblock %}
diff --git a/resources/views/transactions/bulk/edit.twig b/resources/views/transactions/bulk/edit.twig
new file mode 100644
index 0000000000..4957e9eeb8
--- /dev/null
+++ b/resources/views/transactions/bulk/edit.twig
@@ -0,0 +1,147 @@
+{% extends "./layout/default" %}
+
+{% block breadcrumbs %}
+ {{ Breadcrumbs.render(Route.getCurrentRoute.getName, journals) }}
+{% endblock %}
+
+{% block content %}
+
+{% endblock %}
+{% block scripts %}
+
+
+
+
+{% endblock %}
+{% block styles %}
+
+{% endblock %}
diff --git a/resources/views/transactions/mass-delete.twig b/resources/views/transactions/mass/delete.twig
similarity index 99%
rename from resources/views/transactions/mass-delete.twig
rename to resources/views/transactions/mass/delete.twig
index b038ab16be..ce6ae5c185 100644
--- a/resources/views/transactions/mass-delete.twig
+++ b/resources/views/transactions/mass/delete.twig
@@ -44,7 +44,6 @@
{{ journal|journalTotalAmount }}
-
|
{{ journal.date.formatLocalized(monthAndDayFormat) }}
diff --git a/resources/views/transactions/mass/edit.twig b/resources/views/transactions/mass/edit.twig
index 9f834d26e5..5f46ef6e47 100644
--- a/resources/views/transactions/mass/edit.twig
+++ b/resources/views/transactions/mass/edit.twig
@@ -19,7 +19,6 @@
{{ 'cannot_edit_other_fields'|_ }}
-
|
{{ trans('list.description') }} |
diff --git a/routes/breadcrumbs.php b/routes/breadcrumbs.php
index e8237cd6e0..5e29693372 100644
--- a/routes/breadcrumbs.php
+++ b/routes/breadcrumbs.php
@@ -990,6 +990,25 @@ Breadcrumbs::register(
}
);
+// BULK EDIT
+Breadcrumbs::register(
+ 'transactions.bulk.edit',
+ function (BreadCrumbsGenerator $breadcrumbs, Collection $journals): void {
+ if ($journals->count() > 0) {
+ $journalIds = $journals->pluck('id')->toArray();
+ $what = strtolower($journals->first()->transactionType->type);
+ $breadcrumbs->parent('transactions.index', $what, '(nothing)', new Carbon, new Carbon);
+ $breadcrumbs->push(trans('firefly.mass_bulk_journals'), route('transactions.bulk.edit', $journalIds));
+
+ return;
+ }
+
+ $breadcrumbs->parent('index');
+
+ return;
+ }
+);
+
// SPLIT
Breadcrumbs::register(
'transactions.split.edit',
diff --git a/routes/web.php b/routes/web.php
index e368b4fc71..cbc6293852 100755
--- a/routes/web.php
+++ b/routes/web.php
@@ -58,7 +58,7 @@ Route::group(
Route::any('logout', ['uses' => 'Auth\LoginController@logout', 'as' => 'logout']);
Route::get('flush', ['uses' => 'HomeController@flush', 'as' => 'flush']);
Route::get('routes', ['uses' => 'HomeController@routes', 'as' => 'routes']);
- Route::get('debug', 'HomeController@displayDebug')->name('debug');
+ Route::get('debug', 'DebugController@index')->name('debug');
}
);
@@ -784,12 +784,23 @@ Route::group(
Route::group(
['middleware' => 'user-full-auth', 'namespace' => 'Transaction', 'prefix' => 'transactions/mass', 'as' => 'transactions.mass.'], function () {
Route::get('edit/{journalList}', ['uses' => 'MassController@edit', 'as' => 'edit']);
+ Route::get('edit/bulk/{journalList}', ['uses' => 'MassController@editBulk', 'as' => 'edit-bulk']);
Route::get('delete/{journalList}', ['uses' => 'MassController@delete', 'as' => 'delete']);
Route::post('update', ['uses' => 'MassController@update', 'as' => 'update']);
Route::post('destroy', ['uses' => 'MassController@destroy', 'as' => 'destroy']);
}
);
+/**
+ * Transaction Bulk Controller
+ */
+Route::group(
+ ['middleware' => 'user-full-auth', 'namespace' => 'Transaction', 'prefix' => 'transactions/bulk', 'as' => 'transactions.bulk.'], function () {
+ Route::get('edit/{journalList}', ['uses' => 'BulkController@edit', 'as' => 'edit']);
+ Route::post('update', ['uses' => 'BulkController@update', 'as' => 'update']);
+}
+);
+
/**
* Transaction Split Controller
*/
diff --git a/tests/Feature/Controllers/AccountControllerTest.php b/tests/Feature/Controllers/AccountControllerTest.php
index ea3e97106e..058918f408 100644
--- a/tests/Feature/Controllers/AccountControllerTest.php
+++ b/tests/Feature/Controllers/AccountControllerTest.php
@@ -26,6 +26,7 @@ use Carbon\Carbon;
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
+use FireflyIII\Models\Note;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionJournal;
@@ -114,12 +115,16 @@ class AccountControllerTest extends TestCase
*/
public function testEdit()
{
+ $note = new Note();
+ $note->text = 'This is a test';
// mock stuff
$journalRepos = $this->mock(JournalRepositoryInterface::class);
$repository = $this->mock(CurrencyRepositoryInterface::class);
+ $accountRepos = $this->mock(AccountRepositoryInterface::class);
$repository->shouldReceive('get')->andReturn(new Collection);
$journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal);
$repository->shouldReceive('find')->once()->andReturn(new TransactionCurrency());
+ $accountRepos->shouldReceive('getNote')->andReturn($note)->once();
$this->be($this->user());
$account = $this->user()->accounts()->where('account_type_id', 3)->whereNull('deleted_at')->first();
@@ -127,6 +132,7 @@ class AccountControllerTest extends TestCase
$response->assertStatus(200);
// has bread crumb
$response->assertSee('');
+ $response->assertSee($note->text);
}
/**
diff --git a/tests/Feature/Controllers/Auth/ForgotPasswordControllerTest.php b/tests/Feature/Controllers/Auth/ForgotPasswordControllerTest.php
index d02e69aa61..1106666cce 100644
--- a/tests/Feature/Controllers/Auth/ForgotPasswordControllerTest.php
+++ b/tests/Feature/Controllers/Auth/ForgotPasswordControllerTest.php
@@ -41,7 +41,7 @@ class ForgotPasswordControllerTest extends TestCase
public function testSendResetLinkEmail()
{
$repository = $this->mock(UserRepositoryInterface::class);
- $repository->shouldReceive('hasRole')->andReturn(false);
+ $repository->shouldReceive('hasRole')->andReturn(false)->once();
$data = [
'email' => 'thegrumpydictator@gmail.com',
];
@@ -57,7 +57,7 @@ class ForgotPasswordControllerTest extends TestCase
public function testSendResetLinkEmailDemo()
{
$repository = $this->mock(UserRepositoryInterface::class);
- $repository->shouldReceive('hasRole')->andReturn(true);
+ $repository->shouldReceive('hasRole')->andReturn(true)->once();
$data = [
'email' => 'thegrumpydictator@gmail.com',
];
diff --git a/tests/Feature/Controllers/DebugControllerTest.php b/tests/Feature/Controllers/DebugControllerTest.php
new file mode 100644
index 0000000000..19efadbcd7
--- /dev/null
+++ b/tests/Feature/Controllers/DebugControllerTest.php
@@ -0,0 +1,56 @@
+.
+ */
+declare(strict_types=1);
+
+namespace Tests\Feature\Controllers;
+
+use FireflyIII\Helpers\Collector\JournalCollectorInterface;
+use FireflyIII\Models\Account;
+use FireflyIII\Models\AccountType;
+use FireflyIII\Models\TransactionJournal;
+use FireflyIII\Repositories\Account\AccountRepositoryInterface;
+use FireflyIII\Repositories\Bill\BillRepositoryInterface;
+use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
+use Illuminate\Support\Collection;
+use Tests\TestCase;
+
+/**
+ * Class HomeControllerTest
+ *
+ * @SuppressWarnings(PHPMD.TooManyPublicMethods)
+ * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
+class DebugControllerTest extends TestCase
+{
+ /**
+ * @covers \FireflyIII\Http\Controllers\DebugController::index
+ * @covers \FireflyIII\Http\Controllers\DebugController::errorReporting
+ * @covers \FireflyIII\Http\Controllers\DebugController::collectPackages
+ */
+ public function testIndex()
+ {
+ $this->be($this->user());
+ $response = $this->get(route('debug'));
+ $response->assertStatus(200);
+ }
+
+}
diff --git a/tests/Feature/Controllers/HomeControllerTest.php b/tests/Feature/Controllers/HomeControllerTest.php
index b5c38bf52a..c933215939 100644
--- a/tests/Feature/Controllers/HomeControllerTest.php
+++ b/tests/Feature/Controllers/HomeControllerTest.php
@@ -86,16 +86,6 @@ class HomeControllerTest extends TestCase
$response->assertSessionHas('warning', '91 days of data may take a while to load.');
}
- /**
- * @covers \FireflyIII\Http\Controllers\HomeController::displayDebug()
- */
- public function testDisplayDebug()
- {
- $this->be($this->user());
- $response = $this->get(route('debug'));
- $response->assertStatus(200);
- }
-
/**
* @covers \FireflyIII\Http\Controllers\HomeController::displayError
*/
diff --git a/tests/Feature/Controllers/ReportControllerTest.php b/tests/Feature/Controllers/ReportControllerTest.php
index fe779e243c..65fa8583cb 100644
--- a/tests/Feature/Controllers/ReportControllerTest.php
+++ b/tests/Feature/Controllers/ReportControllerTest.php
@@ -65,10 +65,10 @@ class ReportControllerTest extends TestCase
$generator->shouldReceive('setEndDate')->once();
$generator->shouldReceive('setAccounts')->once();
$generator->shouldReceive('setExpense')->once();
- $generator->shouldReceive('generate')->andReturn('here-be-report')->once();
+ $generator->shouldReceive('generate')->once()->andReturn('here-be-report');
$this->be($this->user());
- $response = $this->get(route('reports.report.account', [1, 2, '20160101', '20160131']));
+ $response = $this->get(route('reports.report.account', [1, 2, '20160101', '20161231']));
$response->assertStatus(200);
}
@@ -84,10 +84,10 @@ class ReportControllerTest extends TestCase
$generator->shouldReceive('setStartDate')->once();
$generator->shouldReceive('setEndDate')->once();
$generator->shouldReceive('setAccounts')->once();
- $generator->shouldReceive('generate')->andReturn('here-be-report')->once();
+ $generator->shouldReceive('generate')->once()->andReturn('here-be-report');
$this->be($this->user());
- $response = $this->get(route('reports.report.audit', [1, '20160101', '20160131']));
+ $response = $this->get(route('reports.report.audit', [1, '20160101', '20161231']));
$response->assertStatus(200);
}
@@ -103,10 +103,10 @@ class ReportControllerTest extends TestCase
$generator->shouldReceive('setEndDate')->once();
$generator->shouldReceive('setAccounts')->once();
$generator->shouldReceive('setBudgets')->once();
- $generator->shouldReceive('generate')->andReturn('here-be-report')->once();
+ $generator->shouldReceive('generate')->once()->andReturn('here-be-report');
$this->be($this->user());
- $response = $this->get(route('reports.report.budget', [1, 1, '20160101', '20160131']));
+ $response = $this->get(route('reports.report.budget', [1, 1, '20160101', '20161231']));
$response->assertStatus(200);
}
@@ -122,10 +122,10 @@ class ReportControllerTest extends TestCase
$generator->shouldReceive('setEndDate')->once();
$generator->shouldReceive('setAccounts')->once();
$generator->shouldReceive('setCategories')->once();
- $generator->shouldReceive('generate')->andReturn('here-be-report')->once();
+ $generator->shouldReceive('generate')->once()->andReturn('here-be-report');
$this->be($this->user());
- $response = $this->get(route('reports.report.category', [1, 1, '20160101', '20160131']));
+ $response = $this->get(route('reports.report.category', [1, 1, '20160101', '20161231']));
$response->assertStatus(200);
}
@@ -140,10 +140,10 @@ class ReportControllerTest extends TestCase
$generator->shouldReceive('setStartDate')->once();
$generator->shouldReceive('setEndDate')->once();
$generator->shouldReceive('setAccounts')->once();
- $generator->shouldReceive('generate')->andReturn('here-be-report')->once();
+ $generator->shouldReceive('generate')->once()->andReturn('here-be-report');
$this->be($this->user());
- $response = $this->get(route('reports.report.default', [1, '20160101', '20160131']));
+ $response = $this->get(route('reports.report.default', [1, '20160101', '20161231']));
$response->assertStatus(200);
}
@@ -511,10 +511,10 @@ class ReportControllerTest extends TestCase
$generator->shouldReceive('setEndDate')->once();
$generator->shouldReceive('setAccounts')->once();
$generator->shouldReceive('setTags')->once();
- $generator->shouldReceive('generate')->andReturn('here-be-report');
+ $generator->shouldReceive('generate')->once()->andReturn('here-be-report');
$this->be($this->user());
- $response = $this->get(route('reports.report.tag', [1, 'TagJanuary', '20160101', '20160131']));
+ $response = $this->get(route('reports.report.tag', [1, 'TagJanuary', '20160101', '20161231']));
$response->assertStatus(200);
}
}
diff --git a/tests/Feature/Controllers/Transaction/BulkControllerTest.php b/tests/Feature/Controllers/Transaction/BulkControllerTest.php
new file mode 100644
index 0000000000..50ae40119c
--- /dev/null
+++ b/tests/Feature/Controllers/Transaction/BulkControllerTest.php
@@ -0,0 +1,217 @@
+.
+ */
+declare(strict_types=1);
+
+namespace Tests\Feature\Controllers\Transaction;
+
+use DB;
+use FireflyIII\Models\TransactionJournal;
+use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
+use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
+use Illuminate\Support\Collection;
+use Mockery;
+use Tests\TestCase;
+
+/**
+ * Class BulkControllerTest
+ *
+ * @SuppressWarnings(PHPMD.TooManyPublicMethods)
+ * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
+class BulkControllerTest extends TestCase
+{
+ /**
+ * @covers \FireflyIII\Http\Controllers\Transaction\BulkController::edit
+ * @covers \FireflyIII\Http\Controllers\Transaction\BulkController::__construct
+ */
+ public function testEdit()
+ {
+ // mock stuff:
+ $budgetRepos = $this->mock(BudgetRepositoryInterface::class);
+ $budgetRepos->shouldReceive('getActiveBudgets')->andReturn(new Collection);
+
+ $transfers = TransactionJournal::where('transaction_type_id', 3)->where('user_id', $this->user()->id)->take(4)->get()->pluck('id')->toArray();
+
+ $this->be($this->user());
+ $response = $this->get(route('transactions.bulk.edit', $transfers));
+ $response->assertStatus(200);
+ $response->assertSee('Bulk edit a number of transactions');
+ // has bread crumb
+ $response->assertSee('');
+ }
+
+ /**
+ * @covers \FireflyIII\Http\Controllers\Transaction\BulkController::edit
+ */
+ public function testEditMultiple()
+ {
+ // mock stuff:
+ $budgetRepos = $this->mock(BudgetRepositoryInterface::class);
+ $budgetRepos->shouldReceive('getActiveBudgets')->andReturn(new Collection);
+
+ // default transactions
+ $collection = TransactionJournal::where('transaction_type_id', 3)->where('user_id', $this->user()->id)->take(2)->get();
+
+ // add deposit (with multiple sources)
+ $collection->push(
+ TransactionJournal::where('transaction_type_id', 2)
+ ->whereNull('transaction_journals.deleted_at')
+ ->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
+ ->groupBy('transaction_journals.id')
+ ->orderBy('ct', 'DESC')
+ ->where('user_id', $this->user()->id)->first(['transaction_journals.id', DB::raw('count(transactions.`id`) as ct')])
+ );
+
+ // add withdrawal (with multiple destinations)
+ $collection->push(
+ TransactionJournal::where('transaction_type_id', 1)
+ ->whereNull('transaction_journals.deleted_at')
+ ->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
+ ->groupBy('transaction_journals.id')
+ ->orderBy('ct', 'DESC')
+ ->where('user_id', $this->user()->id)->first(['transaction_journals.id', DB::raw('count(transactions.`id`) as ct')])
+ );
+
+ // add reconcile transaction
+ $collection->push(
+ TransactionJournal::where('transaction_type_id', 5)
+ ->whereNull('transaction_journals.deleted_at')
+ ->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
+ ->groupBy('transaction_journals.id')
+ ->orderBy('ct', 'DESC')
+ ->where('user_id', $this->user()->id)->first(['transaction_journals.id', DB::raw('count(transactions.`id`) as ct')])
+ );
+
+ // add opening balance:
+ $collection->push(TransactionJournal::where('transaction_type_id', 4)->where('user_id', $this->user()->id)->first());
+ $allIds = $collection->pluck('id')->toArray();
+ $route = route('transactions.bulk.edit', join(',', $allIds));
+ $this->be($this->user());
+ $response = $this->get($route);
+ $response->assertStatus(200);
+ $response->assertSee('Bulk edit a number of transactions');
+ $response->assertSessionHas('info');
+ // has bread crumb
+ $response->assertSee('');
+ $response->assertSee('marked as reconciled');
+ $response->assertSee('multiple source accounts');
+ $response->assertSee('multiple destination accounts');
+ }
+
+ /**
+ * @covers \FireflyIII\Http\Controllers\Transaction\BulkController::edit
+ */
+ public function testEditMultipleNothingLeft()
+ {
+ // mock stuff:
+ $budgetRepos = $this->mock(BudgetRepositoryInterface::class);
+ $budgetRepos->shouldReceive('getActiveBudgets')->andReturn(new Collection);
+
+ // default transactions
+ $collection = new Collection;
+
+ // add deposit (with multiple sources)
+ $collection->push(
+ TransactionJournal::where('transaction_type_id', 2)
+ ->whereNull('transaction_journals.deleted_at')
+ ->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
+ ->groupBy('transaction_journals.id')
+ ->orderBy('ct', 'DESC')
+ ->where('user_id', $this->user()->id)->first(['transaction_journals.id', DB::raw('count(transactions.`id`) as ct')])
+ );
+
+ // add withdrawal (with multiple destinations)
+ $collection->push(
+ TransactionJournal::where('transaction_type_id', 1)
+ ->whereNull('transaction_journals.deleted_at')
+ ->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
+ ->groupBy('transaction_journals.id')
+ ->orderBy('ct', 'DESC')
+ ->where('user_id', $this->user()->id)->first(['transaction_journals.id', DB::raw('count(transactions.`id`) as ct')])
+ );
+
+ // add reconcile transaction
+ $collection->push(
+ TransactionJournal::where('transaction_type_id', 5)
+ ->whereNull('transaction_journals.deleted_at')
+ ->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
+ ->groupBy('transaction_journals.id')
+ ->orderBy('ct', 'DESC')
+ ->where('user_id', $this->user()->id)->first(['transaction_journals.id', DB::raw('count(transactions.`id`) as ct')])
+ );
+
+ // add opening balance:
+ $collection->push(TransactionJournal::where('transaction_type_id', 4)->where('user_id', $this->user()->id)->first());
+ $allIds = $collection->pluck('id')->toArray();
+ $route = route('transactions.bulk.edit', join(',', $allIds));
+ $this->be($this->user());
+ $response = $this->get($route);
+ $response->assertStatus(200);
+ $response->assertSee('Bulk edit a number of transactions');
+ $response->assertSessionHas('info');
+ // has bread crumb
+ $response->assertSee('');
+ $response->assertSessionHas('error', 'You have selected no valid transactions to edit.');
+ $response->assertSee('marked as reconciled');
+ $response->assertSee('multiple source accounts');
+ $response->assertSee('multiple destination accounts');
+ }
+
+ /**
+ * @covers \FireflyIII\Http\Controllers\Transaction\BulkController::update
+ */
+ public function testUpdate()
+ {
+
+ $tags = ['a', 'b', 'c'];
+ $collection = TransactionJournal::where('transaction_type_id', 1)->where('user_id', $this->user()->id)->take(4)->get();
+ $allIds = $collection->pluck('id')->toArray();
+
+ $data = [
+ 'category' => 'Some new category',
+ 'budget_id' => 1,
+ 'tags' => 'a,b,c',
+ 'journals' => $allIds,
+ ];
+
+ $repository = $this->mock(JournalRepositoryInterface::class);
+ $repository->shouldReceive('first')->once()->andReturn(new TransactionJournal);
+ $repository->shouldReceive('find')->times(4)->andReturn(new TransactionJournal);
+
+ $repository->shouldReceive('updateCategory')->times(4)->andReturn(new TransactionJournal())
+ ->withArgs([Mockery::any(), $data['category']]);
+
+ $repository->shouldReceive('updateBudget')->times(4)->andReturn(new TransactionJournal())
+ ->withArgs([Mockery::any(), $data['budget_id']]);
+
+ $repository->shouldReceive('updateTags')->times(4)->andReturn(true)
+ ->withArgs([Mockery::any(), $tags]);
+
+
+
+ $route = route('transactions.bulk.update');
+ $this->be($this->user());
+ $response = $this->post($route, $data);
+ $response->assertStatus(302);
+ $response->assertSessionHas('success');
+ }
+}
diff --git a/tests/Feature/Controllers/Transaction/MassControllerTest.php b/tests/Feature/Controllers/Transaction/MassControllerTest.php
index b075dea02b..68077701d8 100644
--- a/tests/Feature/Controllers/Transaction/MassControllerTest.php
+++ b/tests/Feature/Controllers/Transaction/MassControllerTest.php
@@ -155,6 +155,9 @@ class MassControllerTest extends TestCase
$response->assertSee('Edit a number of transactions');
// has bread crumb
$response->assertSee('');
+ $response->assertSee('marked as reconciled');
+ $response->assertSee('multiple source accounts');
+ $response->assertSee('multiple destination accounts');
}
/**
@@ -182,6 +185,7 @@ class MassControllerTest extends TestCase
$response = $this->get(route('transactions.mass.edit', join(',', $allIds)));
$response->assertStatus(200);
$response->assertSee('Edit a number of transactions');
+ $response->assertSessionHas('error','You have selected no valid transactions to edit.');
// has bread crumb
$response->assertSee('');
}
diff --git a/tests/Unit/Import/Configuration/FileConfiguratorTest.php b/tests/Unit/Import/Configuration/FileConfiguratorTest.php
new file mode 100644
index 0000000000..245dea3c3a
--- /dev/null
+++ b/tests/Unit/Import/Configuration/FileConfiguratorTest.php
@@ -0,0 +1,631 @@
+.
+ */
+
+declare(strict_types=1);
+
+namespace Tests\Unit\Import\Configuration;
+
+use FireflyIII\Import\Configuration\FileConfigurator;
+use FireflyIII\Models\ImportJob;
+use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
+use FireflyIII\Support\Import\Configuration\File\Initial;
+use FireflyIII\Support\Import\Configuration\File\Map;
+use FireflyIII\Support\Import\Configuration\File\Roles;
+use FireflyIII\Support\Import\Configuration\File\UploadConfig;
+use Mockery;
+use Tests\TestCase;
+
+/**
+ * Class FileConfiguratorTest
+ */
+class FileConfiguratorTest extends TestCase
+{
+ /**
+ * @covers \FireflyIII\Import\Configuration\FileConfigurator::configureJob
+ * @covers \FireflyIII\Import\Configuration\FileConfigurator::setJob
+ * @covers \FireflyIII\Import\Configuration\FileConfigurator::getConfig
+ * @covers \FireflyIII\Import\Configuration\FileConfigurator::getConfigurationClass
+ */
+ public function testConfigureJobInitial()
+ {
+ // data
+ $config = ['stage' => 'initial'];
+ $data = ['some' => 'array'];
+ $job = $this->getJob($config);
+
+ // mock repository
+ $repository = $this->mock(ImportJobRepositoryInterface::class);
+ $repository->shouldReceive('setUser')->withArgs([Mockery::any()])->once();
+ $repository->shouldReceive('getConfiguration')->andReturn($config)->twice();
+ $repository->shouldReceive('setConfiguration')->once();
+
+ // assert that new initial is created:
+ $processor = $this->mock(Initial::class);
+ $processor->shouldReceive('setJob')->withArgs([$job])->once();
+ $processor->shouldReceive('storeConfiguration')->withArgs([$data])->once()->andReturn(true);
+ $processor->shouldReceive('getWarningMessage')->andReturn('')->once();
+
+ // config
+ $configurator = new FileConfigurator();
+ $configurator->setJob($job);
+ $configurator->configureJob($data);
+ }
+
+ /**
+ * @covers \FireflyIII\Import\Configuration\FileConfigurator::configureJob
+ * @covers \FireflyIII\Import\Configuration\FileConfigurator::getConfigurationClass
+ */
+ public function testConfigureJobMap()
+ {
+ // data
+ $config = ['stage' => 'map'];
+ $data = ['some' => 'array'];
+ $job = $this->getJob($config);
+
+ // mock repository
+ $repository = $this->mock(ImportJobRepositoryInterface::class);
+ $repository->shouldReceive('setUser')->withArgs([Mockery::any()])->once();
+ $repository->shouldReceive('getConfiguration')->andReturn($config)->twice();
+ $repository->shouldReceive('setConfiguration')->once();
+
+ // assert that new Roles is created:
+ $processor = $this->mock(Map::class);
+ $processor->shouldReceive('setJob')->withArgs([$job])->once();
+ $processor->shouldReceive('storeConfiguration')->withArgs([$data])->once()->andReturn(true);
+ $processor->shouldReceive('getWarningMessage')->andReturn('')->once();
+
+ // config
+ $configurator = new FileConfigurator();
+ $configurator->setJob($job);
+ $configurator->configureJob($data);
+ }
+
+ /**
+ * Should throw a FireflyException when $job is null.
+ *
+ * @covers \FireflyIII\Import\Configuration\FileConfigurator::__construct
+ * @covers \FireflyIII\Import\Configuration\FileConfigurator::configureJob
+ * @expectedException \FireflyIII\Exceptions\FireflyException
+ */
+ public function testConfigureJobNoJob()
+ {
+ // mock repos
+ $repository = $this->mock(ImportJobRepositoryInterface::class);
+
+ // config
+ $configurator = new FileConfigurator();
+ $configurator->configureJob([]);
+ }
+
+ /**
+ * @covers \FireflyIII\Import\Configuration\FileConfigurator::configureJob
+ * @covers \FireflyIII\Import\Configuration\FileConfigurator::getConfigurationClass
+ * @expectedException \FireflyIII\Exceptions\FireflyException
+ * @expectedExceptionMessage Cannot handle job stage "ready" in getConfigurationClass().
+ */
+ public function testConfigureJobReady()
+ {
+ // data
+ $config = ['stage' => 'ready'];
+ $data = ['some' => 'array'];
+ $job = $this->getJob($config);
+
+ // mock repos
+ $repository = $this->mock(ImportJobRepositoryInterface::class);
+ $repository->shouldReceive('setUser')->withArgs([Mockery::any()])->once();
+ $repository->shouldReceive('getConfiguration')->andReturn($config)->twice();
+ $repository->shouldReceive('setConfiguration')->once();
+
+ // run config
+ $configurator = new FileConfigurator();
+ $configurator->setJob($job);
+ $configurator->configureJob($data);
+ }
+
+ /**
+ * @covers \FireflyIII\Import\Configuration\FileConfigurator::configureJob
+ * @covers \FireflyIII\Import\Configuration\FileConfigurator::getConfigurationClass
+ */
+ public function testConfigureJobRoles()
+ {
+ $config = ['stage' => 'roles'];
+ $data = ['some' => 'array'];
+ $job = $this->getJob($config);
+
+ // mock repos
+ $repository = $this->mock(ImportJobRepositoryInterface::class);
+ $repository->shouldReceive('setUser')->withArgs([Mockery::any()])->once();
+ $repository->shouldReceive('getConfiguration')->andReturn($config)->twice();
+ $repository->shouldReceive('setConfiguration')->once();
+
+ // assert that new Roles is created:
+ $processor = $this->mock(Roles::class);
+ $processor->shouldReceive('setJob')->withArgs([$job])->once();
+ $processor->shouldReceive('storeConfiguration')->withArgs([$data])->once()->andReturn(true);
+ $processor->shouldReceive('getWarningMessage')->andReturn('')->once();
+
+ // run config
+ $configurator = new FileConfigurator();
+ $configurator->setJob($job);
+ $configurator->configureJob($data);
+ }
+
+ /**
+ * @covers \FireflyIII\Import\Configuration\FileConfigurator::configureJob
+ * @covers \FireflyIII\Import\Configuration\FileConfigurator::getConfigurationClass
+ */
+ public function testConfigureJobUploadConfig()
+ {
+ // data
+ $config = ['stage' => 'upload-config'];
+ $data = ['some' => 'array'];
+ $job = $this->getJob($config);
+
+ // mock repos
+ $repository = $this->mock(ImportJobRepositoryInterface::class);
+ $repository->shouldReceive('setUser')->withArgs([Mockery::any()])->once();
+ $repository->shouldReceive('getConfiguration')->andReturn($config)->twice();
+ $repository->shouldReceive('setConfiguration')->once();
+
+ // assert that new UploadConfig is created:
+ $processor = $this->mock(UploadConfig::class);
+ $processor->shouldReceive('setJob')->withArgs([$job])->once();
+ $processor->shouldReceive('storeConfiguration')->withArgs([$data])->once()->andReturn(true);
+ $processor->shouldReceive('getWarningMessage')->andReturn('')->once();
+
+ // run config
+ $configurator = new FileConfigurator();
+ $configurator->setJob($job);
+ $configurator->configureJob($data);
+ }
+
+ /**
+ * @covers \FireflyIII\Import\Configuration\FileConfigurator::getNextData
+ */
+ public function testGetNextDataInitial()
+ {
+ // data
+ $config = ['stage' => 'initial'];
+ $job = $this->getJob($config);
+
+ // mock repos
+ $repository = $this->mock(ImportJobRepositoryInterface::class);
+ $repository->shouldReceive('setUser')->withArgs([Mockery::any()])->once();
+ $repository->shouldReceive('getConfiguration')->andReturn($config)->twice();
+ $repository->shouldReceive('setConfiguration')->once();
+
+ // assert that new Initial is created:
+ $processor = $this->mock(Initial::class);
+ $processor->shouldReceive('setJob')->withArgs([$job])->once();
+ $processor->shouldReceive('getData')->once();
+
+
+ $configurator = new FileConfigurator();
+ $configurator->setJob($job);
+ $configurator->getNextData();
+ }
+
+ /**
+ * Should throw a FireflyException when $job is null.
+ *
+ * @covers \FireflyIII\Import\Configuration\FileConfigurator::getNextData
+ * @expectedException \FireflyIII\Exceptions\FireflyException
+ */
+ public function testGetNextDataNoJob()
+ {
+ $repository = $this->mock(ImportJobRepositoryInterface::class);
+ $configurator = new FileConfigurator();
+ $configurator->getNextData();
+ }
+
+ /**
+ * @covers \FireflyIII\Import\Configuration\FileConfigurator::getNextData
+ */
+ public function testGetNextDataUploadConfig()
+ {
+ // data
+ $config = ['stage' => 'upload-config'];
+ $job = $this->getJob($config);
+
+ // mock repos
+ $repository = $this->mock(ImportJobRepositoryInterface::class);
+ $repository->shouldReceive('setUser')->withArgs([Mockery::any()])->once();
+ $repository->shouldReceive('getConfiguration')->andReturn($config)->twice();
+ $repository->shouldReceive('setConfiguration')->once();
+
+ // assert that new Initial is created:
+ $processor = $this->mock(UploadConfig::class);
+ $processor->shouldReceive('setJob')->withArgs([$job])->once();
+ $processor->shouldReceive('getData')->once();
+
+ // run config
+ $configurator = new FileConfigurator();
+ $configurator->setJob($job);
+ $configurator->getNextData();
+ }
+
+ /**
+ * @covers \FireflyIII\Import\Configuration\FileConfigurator::getNextData
+ * @expectedException \FireflyIII\Exceptions\FireflyException
+ * @expectedExceptionMessage Cannot handle job stage "ksksjje" in getConfigurationClass().
+ */
+ public function testGetNextDataUploadInvalid()
+ {
+ // data
+ $config = ['stage' => 'ksksjje'];
+ $job = $this->getJob($config);
+
+ // mock repos
+ $repository = $this->mock(ImportJobRepositoryInterface::class);
+ $repository->shouldReceive('setUser')->withArgs([Mockery::any()])->once();
+ $repository->shouldReceive('getConfiguration')->andReturn($config)->twice();
+ $repository->shouldReceive('setConfiguration')->once();
+
+ // should throw error
+ $configurator = new FileConfigurator();
+ $configurator->setJob($job);
+ $configurator->getNextData();
+ }
+
+ /**
+ * @covers \FireflyIII\Import\Configuration\FileConfigurator::getNextData
+ */
+ public function testGetNextDataUploadMap()
+ {
+ // data:
+ $config = ['stage' => 'map'];
+ $job = $this->getJob($config);
+
+ // mock repos
+ $repository = $this->mock(ImportJobRepositoryInterface::class);
+ $repository->shouldReceive('setUser')->withArgs([Mockery::any()])->once();
+ $repository->shouldReceive('getConfiguration')->andReturn($config)->twice();
+ $repository->shouldReceive('setConfiguration')->once();
+
+ // assert that new Initial is created:
+ $processor = $this->mock(Map::class);
+ $processor->shouldReceive('setJob')->withArgs([$job])->once();
+ $processor->shouldReceive('getData')->once();
+
+ // run config
+ $configurator = new FileConfigurator();
+ $configurator->setJob($job);
+ $configurator->getNextData();
+ }
+
+ /**
+ * @covers \FireflyIII\Import\Configuration\FileConfigurator::getNextData
+ * @expectedException \FireflyIII\Exceptions\FireflyException
+ * @expectedExceptionMessage Cannot handle job stage "ready" in getConfigurationClass().
+ */
+ public function testGetNextDataUploadReady()
+ {
+ // data
+ $config = ['stage' => 'ready'];
+ $job = $this->getJob($config);
+
+ // mock repos
+ $repository = $this->mock(ImportJobRepositoryInterface::class);
+ $repository->shouldReceive('setUser')->withArgs([Mockery::any()])->once();
+ $repository->shouldReceive('getConfiguration')->andReturn($config)->twice();
+ $repository->shouldReceive('setConfiguration')->once();
+
+ // run config
+ $configurator = new FileConfigurator();
+ $configurator->setJob($job);
+ $configurator->getNextData();
+ }
+
+ /**
+ * @covers \FireflyIII\Import\Configuration\FileConfigurator::getNextData
+ */
+ public function testGetNextDataUploadRoles()
+ {
+ // data
+ $config = ['stage' => 'roles'];
+ $job = $this->getJob($config);
+
+ // mock repos
+ $repository = $this->mock(ImportJobRepositoryInterface::class);
+ $repository->shouldReceive('setUser')->withArgs([Mockery::any()])->once();
+ $repository->shouldReceive('getConfiguration')->andReturn($config)->twice();
+ $repository->shouldReceive('setConfiguration')->once();
+
+ // assert that new Initial is created:
+ $processor = $this->mock(Roles::class);
+ $processor->shouldReceive('setJob')->withArgs([$job])->once();
+ $processor->shouldReceive('getData')->once();
+
+ // run config
+ $configurator = new FileConfigurator();
+ $configurator->setJob($job);
+ $configurator->getNextData();
+ }
+
+ /**
+ * @covers \FireflyIII\Import\Configuration\FileConfigurator::getNextView
+ */
+ public function testGetNextViewInitial()
+ {
+ // data
+ $config = ['stage' => 'initial'];
+ $job = $this->getJob($config);
+
+ // mock repos
+ $repository = $this->mock(ImportJobRepositoryInterface::class);
+ $repository->shouldReceive('setUser')->withArgs([Mockery::any()])->once();
+ $repository->shouldReceive('getConfiguration')->andReturn($config)->twice();
+ $repository->shouldReceive('setConfiguration')->once();
+
+ // run
+ $configurator = new FileConfigurator();
+ $configurator->setJob($job);
+ $view = $configurator->getNextView();
+
+ // test
+ $this->assertEquals('import.file.initial', $view);
+ }
+
+ /**
+ * @covers \FireflyIII\Import\Configuration\FileConfigurator::getNextView
+ * @expectedException \FireflyIII\Exceptions\FireflyException
+ * @expectedExceptionMessage No view for stage "slkds903ms90k"
+ */
+ public function testGetNextViewInvalid()
+ {
+ // data
+ $config = ['stage' => 'slkds903ms90k'];
+ $job = $this->getJob($config);
+
+ // mock repos
+ $repository = $this->mock(ImportJobRepositoryInterface::class);
+ $repository->shouldReceive('setUser')->withArgs([Mockery::any()])->once();
+ $repository->shouldReceive('getConfiguration')->andReturn($config)->twice();
+ $repository->shouldReceive('setConfiguration')->once();
+
+ // run config
+ $configurator = new FileConfigurator();
+ $configurator->setJob($job);
+ $configurator->getNextView();
+ }
+
+ /**
+ * @covers \FireflyIII\Import\Configuration\FileConfigurator::getNextView
+ */
+ public function testGetNextViewMap()
+ {
+ // data
+ $config = ['stage' => 'map'];
+ $job = $this->getJob($config);
+
+ // mock repos
+ $repository = $this->mock(ImportJobRepositoryInterface::class);
+ $repository->shouldReceive('setUser')->withArgs([Mockery::any()])->once();
+ $repository->shouldReceive('getConfiguration')->andReturn($config)->twice();
+ $repository->shouldReceive('setConfiguration')->once();
+
+ // run config
+ $configurator = new FileConfigurator();
+ $configurator->setJob($job);
+ $view = $configurator->getNextView();
+
+ // test
+ $this->assertEquals('import.file.map', $view);
+ }
+
+ /**
+ * Should throw a FireflyException when $job is null.
+ *
+ * @covers \FireflyIII\Import\Configuration\FileConfigurator::getNextView
+ * @expectedException \FireflyIII\Exceptions\FireflyException
+ */
+ public function testGetNextViewNoJob()
+ {
+ $repository = $this->mock(ImportJobRepositoryInterface::class);
+ $configurator = new FileConfigurator();
+ $configurator->getNextView();
+ }
+
+ /**
+ * @covers \FireflyIII\Import\Configuration\FileConfigurator::getNextView
+ * @expectedException \FireflyIII\Exceptions\FireflyException
+ * @expectedExceptionMessage No view for stage "ready"
+ */
+ public function testGetNextViewReady()
+ {
+ // data
+ $config = ['stage' => 'ready'];
+ $job = $this->getJob($config);
+
+ // mock repos
+ $repository = $this->mock(ImportJobRepositoryInterface::class);
+ $repository->shouldReceive('setUser')->withArgs([Mockery::any()])->once();
+ $repository->shouldReceive('getConfiguration')->andReturn($config)->twice();
+ $repository->shouldReceive('setConfiguration')->once();
+
+ // run configx§
+ $configurator = new FileConfigurator();
+ $configurator->setJob($job);
+ $configurator->getNextView();
+ }
+
+ /**
+ * @covers \FireflyIII\Import\Configuration\FileConfigurator::getNextView
+ */
+ public function testGetNextViewRoles()
+ {
+ // data
+ $config = ['stage' => 'roles'];
+ $job = $this->getJob($config);
+
+ // mock repos
+ $repository = $this->mock(ImportJobRepositoryInterface::class);
+ $repository->shouldReceive('setUser')->withArgs([Mockery::any()])->once();
+ $repository->shouldReceive('getConfiguration')->andReturn($config)->twice();
+ $repository->shouldReceive('setConfiguration')->once();
+
+ // run config
+ $configurator = new FileConfigurator();
+ $configurator->setJob($job);
+ $view = $configurator->getNextView();
+
+ // test
+ $this->assertEquals('import.file.roles', $view);
+ }
+
+ /**
+ * @covers \FireflyIII\Import\Configuration\FileConfigurator::getNextView
+ */
+ public function testGetNextViewUploadConfig()
+ {
+ // data
+ $config = ['stage' => 'upload-config'];
+ $job = $this->getJob($config);
+
+ // mock repos
+ $repository = $this->mock(ImportJobRepositoryInterface::class);
+ $repository->shouldReceive('setUser')->withArgs([Mockery::any()])->once();
+ $repository->shouldReceive('getConfiguration')->andReturn($config)->twice();
+ $repository->shouldReceive('setConfiguration')->once();
+
+ // run config
+ $configurator = new FileConfigurator();
+ $configurator->setJob($job);
+ $view = $configurator->getNextView();
+
+ // test
+ $this->assertEquals('import.file.upload-config', $view);
+ }
+
+ /**
+ * @covers \FireflyIII\Import\Configuration\FileConfigurator::getWarningMessage
+ */
+ public function testGetWarningMessage()
+ {
+ // data
+ $config = ['stage' => 'upload-config'];
+ $job = $this->getJob($config);
+
+ // mock repos
+ $repository = $this->mock(ImportJobRepositoryInterface::class);
+ $repository->shouldReceive('setUser')->withArgs([Mockery::any()])->once();
+ $repository->shouldReceive('getConfiguration')->andReturn($config)->once();
+ $repository->shouldReceive('setConfiguration')->once();
+
+ // run config
+ $configurator = new FileConfigurator();
+ $configurator->setJob($job);
+ $warning = $configurator->getWarningMessage();
+
+ // test
+ $this->assertEquals('', $warning);
+
+ }
+
+ /**
+ * Should throw a FireflyException when $job is null.
+ *
+ * @covers \FireflyIII\Import\Configuration\FileConfigurator::getWarningMessage
+ * @expectedException \FireflyIII\Exceptions\FireflyException
+ */
+ public function testGetWarningMessageNoJob()
+ {
+ $configurator = new FileConfigurator();
+ $configurator->getWarningMessage();
+ }
+
+ /**
+ * @covers \FireflyIII\Import\Configuration\FileConfigurator::isJobConfigured
+ */
+ public function testIsJobConfiguredFalse()
+ {
+ // data
+ $config = ['stage' => 'upload-config'];
+ $job = $this->getJob($config);
+
+ // mock repos
+ $repository = $this->mock(ImportJobRepositoryInterface::class);
+ $repository->shouldReceive('setUser')->withArgs([Mockery::any()])->once();
+ $repository->shouldReceive('getConfiguration')->andReturn($config)->twice();
+ $repository->shouldReceive('setConfiguration')->once();
+
+ // run config
+ $configurator = new FileConfigurator();
+ $configurator->setJob($job);
+ $result = $configurator->isJobConfigured();
+
+ // test
+ $this->assertFalse($result);
+ }
+
+ /**
+ * @covers \FireflyIII\Import\Configuration\FileConfigurator::isJobConfigured
+ */
+ public function testIsJobConfiguredTrue()
+ {
+ // data
+ $config = ['stage' => 'ready'];
+ $job = $this->getJob($config);
+
+ // mock repos
+ $repository = $this->mock(ImportJobRepositoryInterface::class);
+ $repository->shouldReceive('setUser')->withArgs([Mockery::any()])->once();
+ $repository->shouldReceive('getConfiguration')->andReturn($config)->twice();
+ $repository->shouldReceive('setConfiguration')->once();
+
+ // run config
+ $configurator = new FileConfigurator();
+ $configurator->setJob($job);
+ $result = $configurator->isJobConfigured();
+
+ // test
+ $this->assertTrue($result);
+ }
+
+ /**
+ * Should throw a FireflyException when $job is null.
+ *
+ * @covers \FireflyIII\Import\Configuration\FileConfigurator::isJobConfigured
+ * @expectedException \FireflyIII\Exceptions\FireflyException
+ */
+ public function testIsJobConfiguredNoJob()
+ {
+ $configurator = new FileConfigurator();
+ $configurator->isJobConfigured();
+ }
+
+ /**
+ * @param array $config
+ *
+ * @return ImportJob
+ */
+ protected function getJob(array $config): ImportJob
+ {
+ $job = new ImportJob;
+ $job->file_type = 'file';
+ $job->status = 'new';
+ $job->key = 'x' . rand(1, 100000);
+ $job->user()->associate($this->user());
+ $job->configuration = $config;
+
+ return $job;
+ }
+}
\ No newline at end of file
diff --git a/tests/Unit/Import/Converter/AmountTest.php b/tests/Unit/Import/Converter/AmountTest.php
index d1bf70c520..1b02d37ac6 100644
--- a/tests/Unit/Import/Converter/AmountTest.php
+++ b/tests/Unit/Import/Converter/AmountTest.php
@@ -32,6 +32,7 @@ class AmountTest extends TestCase
{
/**
* @covers \FireflyIII\Import\Converter\Amount::convert()
+ * @covers \FireflyIII\Import\Converter\Amount::stripAmount()
*/
public function testConvert()
{
@@ -150,6 +151,11 @@ class AmountTest extends TestCase
'0.115' => '0.115',
'-0.115' => '-0.115',
'1.33' => '1.33',
+ '$1.23' => '1.23',
+ '€1,44' => '1.44',
+ '(33.52)' => '-33.52',
+ '€(63.12)' => '-63.12',
+ '($182.77)' => '-182.77',
];
foreach ($values as $value => $expected) {
$converter = new Amount;
diff --git a/tests/Unit/Import/FileProcessor/CsvProcessorTest.php b/tests/Unit/Import/FileProcessor/CsvProcessorTest.php
new file mode 100644
index 0000000000..515f804642
--- /dev/null
+++ b/tests/Unit/Import/FileProcessor/CsvProcessorTest.php
@@ -0,0 +1,300 @@
+.
+ */
+
+declare(strict_types=1);
+
+namespace Tests\Unit\Import\FileProcessor;
+
+use FireflyIII\Import\FileProcessor\CsvProcessor;
+use FireflyIII\Import\Specifics\AbnAmroDescription;
+use FireflyIII\Models\ImportJob;
+use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
+use Mockery;
+use Tests\TestCase;
+
+/**
+ * Class CsvProcessorTest
+ */
+class CsvProcessorTest extends TestCase
+{
+ /**
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::__construct
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::getObjects
+ * @expectedException \FireflyIII\Exceptions\FireflyException
+ * @expectedExceptionMessage Cannot call getObjects() without a job.
+ */
+ public function testGetObjectsNoJob()
+ {
+
+ $processor = new CsvProcessor();
+ $processor->getObjects();
+ }
+
+ /**
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::run
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::getImportArray
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::getObjects
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::setJob
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::importRow
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::specifics
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::getRowHash
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::annotateValue
+ * @expectedException \FireflyIII\Exceptions\FireflyException
+ * @expectedExceptionMessage "bad-role" is not a valid role.
+ */
+ public function testRunBadRole()
+ {
+ // data
+ $config = [
+ 'column-roles' => [
+ 0 => 'bad-role',
+ ],
+ ];
+ $job = $this->getJob($config);
+ $csvFile = '20170101,-12.34,"Some description"';
+
+ // mock stuff
+ $repository = $this->mock(ImportJobRepositoryInterface::class);
+ $repository->shouldReceive('setUser')->withArgs([Mockery::any()])->once();
+ $repository->shouldReceive('getConfiguration')->andReturn($config);
+ $repository->shouldReceive('uploadFileContents')->withArgs([Mockery::any()])->andReturn($csvFile)->once();
+ $repository->shouldReceive('getExtendedStatus')->once()->andReturn([]);
+ $repository->shouldReceive('setExtendedStatus')->once()->andReturn($job);
+ // mock stuff for this single row:
+ $repository->shouldReceive('countByHash')->once()->withArgs([Mockery::any()])->andReturn(0);
+ $processor = new CsvProcessor();
+ $processor->setJob($job);
+ $processor->run();
+ }
+
+ /**
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::run
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::getImportArray
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::getObjects
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::setJob
+ */
+ public function testRunBasic()
+ {
+ // data
+ $config = [];
+ $job = $this->getJob($config);
+ $csvFile = '';
+
+ // mock stuff
+ $repository = $this->mock(ImportJobRepositoryInterface::class);
+ $repository->shouldReceive('setUser')->withArgs([Mockery::any()])->once();
+ $repository->shouldReceive('getConfiguration')->andReturn($config);
+ $repository->shouldReceive('uploadFileContents')->withArgs([Mockery::any()])->andReturn($csvFile)->once();
+ $repository->shouldReceive('getExtendedStatus')->once()->andReturn([]);
+ $repository->shouldReceive('setExtendedStatus')->once()->andReturn($job);
+
+ $processor = new CsvProcessor();
+ $processor->setJob($job);
+ $processor->run();
+
+ $objects = $processor->getObjects();
+ $this->assertCount(0, $objects);
+ }
+
+ /**
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::run
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::getImportArray
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::getObjects
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::setJob
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::importRow
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::specifics
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::getRowHash
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::annotateValue
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::rowAlreadyImported
+ */
+ public function testRunExisting()
+ {
+ // data
+ $config = [];
+ $job = $this->getJob($config);
+ $csvFile = '20170101,-12.34,"Some description"';
+
+ // mock stuff
+ $repository = $this->mock(ImportJobRepositoryInterface::class);
+ $repository->shouldReceive('setUser')->withArgs([Mockery::any()])->once();
+ $repository->shouldReceive('getConfiguration')->andReturn($config);
+ $repository->shouldReceive('uploadFileContents')->withArgs([Mockery::any()])->andReturn($csvFile)->once();
+ $repository->shouldReceive('getExtendedStatus')->twice()->andReturn([]); // twice for update errors.
+ $repository->shouldReceive('setExtendedStatus')->twice()->andReturn($job);
+ // mock stuff for this single row:
+ $repository->shouldReceive('countByHash')->once()->withArgs([Mockery::any()])->andReturn(1);
+ $repository->shouldReceive('addStepsDone')->once()->withArgs([Mockery::any(), 5]);
+ $processor = new CsvProcessor();
+ $processor->setJob($job);
+ $processor->run();
+
+ $objects = $processor->getObjects();
+ $this->assertCount(0, $objects);
+ }
+
+ /**
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::run
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::getImportArray
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::getObjects
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::setJob
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::importRow
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::specifics
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::getRowHash
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::annotateValue
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::rowAlreadyImported
+ * @expectedException \FireflyIII\Exceptions\FireflyException
+ * @expectedExceptionMessage "GoodBankDescription" is not a valid class name
+ */
+ public function testRunInvalidSpecific()
+ {
+ // data
+ $config = [
+ 'specifics' => ['GoodBankDescription' => 1],
+ ];
+ $job = $this->getJob($config);
+ $csvFile = '20170101,-12.34,descr';
+ $row = explode(',', $csvFile);
+
+ // mock stuff
+ $repository = $this->mock(ImportJobRepositoryInterface::class);
+ $repository->shouldReceive('setUser')->withArgs([Mockery::any()])->once();
+ $repository->shouldReceive('getConfiguration')->andReturn($config);
+ $repository->shouldReceive('uploadFileContents')->withArgs([Mockery::any()])->andReturn($csvFile)->once();
+ $repository->shouldReceive('getExtendedStatus')->once()->andReturn([]);
+ $repository->shouldReceive('setExtendedStatus')->once()->andReturn($job);
+ // mock stuff for this single row:
+ $repository->shouldReceive('countByHash')->once()->withArgs([Mockery::any()])->andReturn(0);
+
+ // mock specific:
+ $processor = new CsvProcessor();
+ $processor->setJob($job);
+ $processor->run();
+ }
+
+ /**
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::run
+ * @expectedException \FireflyIII\Exceptions\FireflyException
+ * @expectedExceptionMessage Cannot call run() without a job.
+ */
+ public function testRunNoJob()
+ {
+
+ $processor = new CsvProcessor();
+ $processor->run();
+ }
+
+ /**
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::run
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::getImportArray
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::getObjects
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::setJob
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::importRow
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::specifics
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::getRowHash
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::annotateValue
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::rowAlreadyImported
+ */
+ public function testRunSingle()
+ {
+ // data
+ $config = [];
+ $job = $this->getJob($config);
+ $csvFile = '20170101,-12.34,"Some description"';
+
+ // mock stuff
+ $repository = $this->mock(ImportJobRepositoryInterface::class);
+ $repository->shouldReceive('setUser')->withArgs([Mockery::any()])->once();
+ $repository->shouldReceive('getConfiguration')->andReturn($config);
+ $repository->shouldReceive('uploadFileContents')->withArgs([Mockery::any()])->andReturn($csvFile)->once();
+ $repository->shouldReceive('getExtendedStatus')->once()->andReturn([]);
+ $repository->shouldReceive('setExtendedStatus')->once()->andReturn($job);
+ // mock stuff for this single row:
+ $repository->shouldReceive('countByHash')->once()->withArgs([Mockery::any()])->andReturn(0);
+ $repository->shouldReceive('addStepsDone')->once()->withArgs([Mockery::any(), 1]);
+ $processor = new CsvProcessor();
+ $processor->setJob($job);
+ $processor->run();
+
+ $objects = $processor->getObjects();
+ $this->assertCount(1, $objects);
+ }
+
+ /**
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::run
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::getImportArray
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::getObjects
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::setJob
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::importRow
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::specifics
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::getRowHash
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::annotateValue
+ * @covers \FireflyIII\Import\FileProcessor\CsvProcessor::rowAlreadyImported
+ */
+ public function testRunSpecific()
+ {
+ // data
+ $config = [
+ 'specifics' => ['AbnAmroDescription' => 1],
+ ];
+ $job = $this->getJob($config);
+ $csvFile = '20170101,-12.34,descr';
+ $row = explode(',', $csvFile);
+
+ // mock stuff
+ $repository = $this->mock(ImportJobRepositoryInterface::class);
+ $repository->shouldReceive('setUser')->withArgs([Mockery::any()])->once();
+ $repository->shouldReceive('getConfiguration')->andReturn($config);
+ $repository->shouldReceive('uploadFileContents')->withArgs([Mockery::any()])->andReturn($csvFile)->once();
+ $repository->shouldReceive('getExtendedStatus')->once()->andReturn([]);
+ $repository->shouldReceive('setExtendedStatus')->once()->andReturn($job);
+ // mock stuff for this single row:
+ $repository->shouldReceive('countByHash')->once()->withArgs([Mockery::any()])->andReturn(0);
+ $repository->shouldReceive('addStepsDone')->once()->withArgs([Mockery::any(), 1]);
+
+ // mock specific:
+ $specific = $this->mock(AbnAmroDescription::class);
+ $specific->shouldReceive('run')->once()->andReturn($row);
+
+ $processor = new CsvProcessor();
+ $processor->setJob($job);
+ $processor->run();
+
+ $objects = $processor->getObjects();
+ $this->assertCount(1, $objects);
+ }
+
+ /**
+ * @param array $config
+ *
+ * @return ImportJob
+ */
+ protected function getJob(array $config): ImportJob
+ {
+ $job = new ImportJob;
+ $job->file_type = 'file';
+ $job->status = 'new';
+ $job->key = 'x' . rand(1, 100000);
+ $job->user()->associate($this->user());
+ $job->configuration = $config;
+
+ return $job;
+ }
+}
\ No newline at end of file
diff --git a/tests/Unit/Import/Mapper/AssetAccountIbansTest.php b/tests/Unit/Import/Mapper/AssetAccountIbansTest.php
new file mode 100644
index 0000000000..aea75c48ac
--- /dev/null
+++ b/tests/Unit/Import/Mapper/AssetAccountIbansTest.php
@@ -0,0 +1,67 @@
+.
+ */
+
+declare(strict_types=1);
+
+namespace Tests\Unit\Import\Mapper;
+
+use FireflyIII\Import\Mapper\AssetAccountIbans;
+use FireflyIII\Models\Account;
+use FireflyIII\Models\AccountType;
+use FireflyIII\Repositories\Account\AccountRepositoryInterface;
+use Illuminate\Support\Collection;
+use Tests\TestCase;
+
+/**
+ * Class AssetAccountIbansTest
+ */
+class AssetAccountIbansTest extends TestCase
+{
+ /**
+ * @covers \FireflyIII\Import\Mapper\AssetAccountIbans::getMap()
+ */
+ public function testGetMapBasic()
+ {
+ $one = new Account;
+ $one->id = 17;
+ $one->name = 'Something';
+ $one->iban = 'IBAN';
+ $two = new Account;
+ $two->id = 53;
+ $two->name = 'Else';
+ $collection = new Collection([$one, $two]);
+
+ $repository = $this->mock(AccountRepositoryInterface::class);
+ $repository->shouldReceive('getAccountsByType')->withArgs([[AccountType::DEFAULT, AccountType::ASSET]])->andReturn($collection)->once();
+
+ $mapper = new AssetAccountIbans();
+ $mapping = $mapper->getMap();
+ $this->assertCount(3, $mapping);
+ // assert this is what the result looks like:
+ $result = [
+ 0 => strval(trans('import.map_do_not_map')),
+ 53 => 'Else',
+ 17 => 'IBAN (Something)',
+ ];
+ $this->assertEquals($result, $mapping);
+ }
+
+}
\ No newline at end of file
diff --git a/tests/Unit/Import/Mapper/AssetAccountsTest.php b/tests/Unit/Import/Mapper/AssetAccountsTest.php
new file mode 100644
index 0000000000..f4ae748fd4
--- /dev/null
+++ b/tests/Unit/Import/Mapper/AssetAccountsTest.php
@@ -0,0 +1,68 @@
+.
+ */
+
+declare(strict_types=1);
+
+namespace Tests\Unit\Import\Mapper;
+
+use FireflyIII\Import\Mapper\AssetAccounts;
+use FireflyIII\Models\Account;
+use FireflyIII\Models\AccountType;
+use FireflyIII\Repositories\Account\AccountRepositoryInterface;
+use Illuminate\Support\Collection;
+use Tests\TestCase;
+
+/**
+ * Class AssetAccountsTest
+ */
+class AssetAccountsTest extends TestCase
+{
+ /**
+ * @covers \FireflyIII\Import\Mapper\AssetAccounts::getMap()
+ */
+ public function testGetMapBasic()
+ {
+ $one = new Account;
+ $one->id = 23;
+ $one->name = 'Something';
+ $one->iban = 'IBAN';
+ $two = new Account;
+ $two->id = 19;
+ $two->name = 'Else';
+ $collection = new Collection([$one, $two]);
+
+ $repository = $this->mock(AccountRepositoryInterface::class);
+ $repository->shouldReceive('getAccountsByType')->withArgs([[AccountType::DEFAULT, AccountType::ASSET]])->andReturn($collection)->once();
+
+ $mapper = new AssetAccounts();
+ $mapping = $mapper->getMap();
+ $this->assertCount(3, $mapping);
+ // assert this is what the result looks like:
+ $result = [
+ 0 => strval(trans('import.map_do_not_map')),
+ 19 => 'Else',
+ 23 => 'Something (IBAN)',
+
+ ];
+ $this->assertEquals($result, $mapping);
+ }
+
+}
diff --git a/tests/Unit/Import/Mapper/BillsTest.php b/tests/Unit/Import/Mapper/BillsTest.php
new file mode 100644
index 0000000000..3a8e506d24
--- /dev/null
+++ b/tests/Unit/Import/Mapper/BillsTest.php
@@ -0,0 +1,68 @@
+.
+ */
+
+declare(strict_types=1);
+
+namespace Tests\Unit\Import\Mapper;
+
+use FireflyIII\Import\Mapper\Bills;
+use FireflyIII\Models\Account;
+use FireflyIII\Models\Bill;
+use FireflyIII\Repositories\Bill\BillRepositoryInterface;
+use Illuminate\Support\Collection;
+use Tests\TestCase;
+
+/**
+ * Class BillsTest
+ */
+class BillsTest extends TestCase
+{
+ /**
+ * @covers \FireflyIII\Import\Mapper\Bills::getMap()
+ */
+ public function testGetMapBasic()
+ {
+ $one = new Bill();
+ $one->id = 5;
+ $one->name = 'Something';
+ $one->match = 'hi,bye';
+ $two = new Account;
+ $two->id = 9;
+ $two->name = 'Else';
+ $two->match = 'match';
+ $collection = new Collection([$one, $two]);
+
+ $repository = $this->mock(BillRepositoryInterface::class);
+ $repository->shouldReceive('getBills')->andReturn($collection)->once();
+
+ $mapper = new Bills();
+ $mapping = $mapper->getMap();
+ $this->assertCount(3, $mapping);
+ // assert this is what the result looks like:
+ $result = [
+ 0 => strval(trans('import.map_do_not_map')),
+ 9 => 'Else [match]',
+ 5 => 'Something [hi,bye]',
+ ];
+ $this->assertEquals($result, $mapping);
+ }
+
+}
\ No newline at end of file
diff --git a/tests/Unit/Import/Mapper/BudgetsTest.php b/tests/Unit/Import/Mapper/BudgetsTest.php
new file mode 100644
index 0000000000..8be0780a33
--- /dev/null
+++ b/tests/Unit/Import/Mapper/BudgetsTest.php
@@ -0,0 +1,66 @@
+.
+ */
+
+declare(strict_types=1);
+
+namespace Tests\Unit\Import\Mapper;
+
+use FireflyIII\Import\Mapper\Budgets;
+use FireflyIII\Models\Budget;
+use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
+use Illuminate\Support\Collection;
+use Tests\TestCase;
+
+/**
+ * Class BudgetsTest
+ */
+class BudgetsTest extends TestCase
+{
+ /**
+ * @covers \FireflyIII\Import\Mapper\Budgets::getMap()
+ */
+ public function testGetMapBasic()
+ {
+ $one = new Budget;
+ $one->id = 8;
+ $one->name = 'Something';
+ $two = new Budget;
+ $two->id = 4;
+ $two->name = 'Else';
+ $collection = new Collection([$one, $two]);
+
+ $repository = $this->mock(BudgetRepositoryInterface::class);
+ $repository->shouldReceive('getActiveBudgets')->andReturn($collection)->once();
+
+ $mapper = new Budgets();
+ $mapping = $mapper->getMap();
+ $this->assertCount(3, $mapping);
+ // assert this is what the result looks like:
+ $result = [
+ 0 => strval(trans('import.map_do_not_map')),
+ 4 => 'Else',
+ 8 => 'Something',
+
+ ];
+ $this->assertEquals($result, $mapping);
+ }
+
+}
\ No newline at end of file
diff --git a/tests/Unit/Import/Mapper/CategoriesTest.php b/tests/Unit/Import/Mapper/CategoriesTest.php
new file mode 100644
index 0000000000..6dd9524810
--- /dev/null
+++ b/tests/Unit/Import/Mapper/CategoriesTest.php
@@ -0,0 +1,66 @@
+.
+ */
+
+declare(strict_types=1);
+
+namespace Tests\Unit\Import\Mapper;
+
+use FireflyIII\Import\Mapper\Categories;
+use FireflyIII\Models\Category;
+use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
+use Illuminate\Support\Collection;
+use Tests\TestCase;
+
+/**
+ * Class CategoriesTest
+ */
+class CategoriesTest extends TestCase
+{
+ /**
+ * @covers \FireflyIII\Import\Mapper\Categories::getMap()
+ */
+ public function testGetMapBasic()
+ {
+ $one = new Category;
+ $one->id = 9;
+ $one->name = 'Something';
+ $two = new Category;
+ $two->id = 17;
+ $two->name = 'Else';
+ $collection = new Collection([$one, $two]);
+
+ $repository = $this->mock(CategoryRepositoryInterface::class);
+ $repository->shouldReceive('getCategories')->andReturn($collection)->once();
+
+ $mapper = new Categories();
+ $mapping = $mapper->getMap();
+ $this->assertCount(3, $mapping);
+ // assert this is what the result looks like:
+ $result = [
+ 0 => strval(trans('import.map_do_not_map')),
+ 17 => 'Else',
+ 9 => 'Something',
+
+ ];
+ $this->assertEquals($result, $mapping);
+ }
+
+}
\ No newline at end of file
diff --git a/tests/Unit/Import/Mapper/OpposingAccountIbansTest.php b/tests/Unit/Import/Mapper/OpposingAccountIbansTest.php
new file mode 100644
index 0000000000..89ac4aad11
--- /dev/null
+++ b/tests/Unit/Import/Mapper/OpposingAccountIbansTest.php
@@ -0,0 +1,69 @@
+.
+ */
+
+declare(strict_types=1);
+
+namespace Tests\Unit\Import\Mapper;
+
+use FireflyIII\Import\Mapper\OpposingAccountIbans;
+use FireflyIII\Models\Account;
+use FireflyIII\Models\AccountType;
+use FireflyIII\Repositories\Account\AccountRepositoryInterface;
+use Illuminate\Support\Collection;
+use Tests\TestCase;
+
+/**
+ * Class OpposingAccountIbansTest
+ */
+class OpposingAccountIbansTest extends TestCase
+{
+ /**
+ * @covers \FireflyIII\Import\Mapper\OpposingAccountIbans::getMap()
+ */
+ public function testGetMapBasic()
+ {
+ $one = new Account;
+ $one->id = 21;
+ $one->name = 'Something';
+ $one->iban = 'IBAN';
+ $two = new Account;
+ $two->id = 17;
+ $two->name = 'Else';
+ $collection = new Collection([$one, $two]);
+
+ $repository = $this->mock(AccountRepositoryInterface::class);
+ $repository->shouldReceive('getAccountsByType')->withArgs(
+ [[AccountType::DEFAULT, AccountType::ASSET, AccountType::EXPENSE, AccountType::BENEFICIARY, AccountType::REVENUE,]]
+ )->andReturn($collection)->once();
+
+ $mapper = new OpposingAccountIbans();
+ $mapping = $mapper->getMap();
+ $this->assertCount(3, $mapping);
+ // assert this is what the result looks like:
+ $result = [
+ 0 => strval(trans('import.map_do_not_map')),
+ 17 => 'Else',
+ 21 => 'IBAN (Something)',
+ ];
+ $this->assertEquals($result, $mapping);
+ }
+
+}
\ No newline at end of file
diff --git a/tests/Unit/Import/Mapper/OpposingAccountsTest.php b/tests/Unit/Import/Mapper/OpposingAccountsTest.php
new file mode 100644
index 0000000000..6cd92bfdaf
--- /dev/null
+++ b/tests/Unit/Import/Mapper/OpposingAccountsTest.php
@@ -0,0 +1,69 @@
+.
+ */
+
+declare(strict_types=1);
+
+namespace Tests\Unit\Import\Mapper;
+
+use FireflyIII\Import\Mapper\OpposingAccounts;
+use FireflyIII\Models\Account;
+use FireflyIII\Models\AccountType;
+use FireflyIII\Repositories\Account\AccountRepositoryInterface;
+use Illuminate\Support\Collection;
+use Tests\TestCase;
+
+/**
+ * Class OpposingAccountsTest
+ */
+class OpposingAccountsTest extends TestCase
+{
+ /**
+ * @covers \FireflyIII\Import\Mapper\OpposingAccounts::getMap()
+ */
+ public function testGetMapBasic()
+ {
+ $one = new Account;
+ $one->id = 13;
+ $one->name = 'Something';
+ $one->iban = 'IBAN';
+ $two = new Account;
+ $two->id = 9;
+ $two->name = 'Else';
+ $collection = new Collection([$one, $two]);
+
+ $repository = $this->mock(AccountRepositoryInterface::class);
+ $repository->shouldReceive('getAccountsByType')->withArgs(
+ [[AccountType::DEFAULT, AccountType::ASSET, AccountType::EXPENSE, AccountType::BENEFICIARY, AccountType::REVENUE,]]
+ )->andReturn($collection)->once();
+
+ $mapper = new OpposingAccounts();
+ $mapping = $mapper->getMap();
+ $this->assertCount(3, $mapping);
+ // assert this is what the result looks like:
+ $result = [
+ 0 => strval(trans('import.map_do_not_map')),
+ 9 => 'Else',
+ 13 => 'Something (IBAN)',
+ ];
+ $this->assertEquals($result, $mapping);
+ }
+
+}
diff --git a/tests/Unit/Import/Mapper/TagsTest.php b/tests/Unit/Import/Mapper/TagsTest.php
new file mode 100644
index 0000000000..dd8bd14fd3
--- /dev/null
+++ b/tests/Unit/Import/Mapper/TagsTest.php
@@ -0,0 +1,65 @@
+.
+ */
+
+declare(strict_types=1);
+
+namespace Tests\Unit\Import\Mapper;
+
+use FireflyIII\Import\Mapper\Tags;
+use FireflyIII\Models\Tag;
+use FireflyIII\Repositories\Tag\TagRepositoryInterface;
+use Illuminate\Support\Collection;
+use Tests\TestCase;
+
+/**
+ * Class TagsTest
+ */
+class TagsTest extends TestCase
+{
+ /**
+ * @covers \FireflyIII\Import\Mapper\Tags::getMap()
+ */
+ public function testGetMapBasic()
+ {
+ $one = new Tag;
+ $one->id = 12;
+ $one->tag = 'Something';
+ $two = new Tag;
+ $two->id = 14;
+ $two->tag = 'Else';
+ $collection = new Collection([$one, $two]);
+
+ $repository = $this->mock(TagRepositoryInterface::class);
+ $repository->shouldReceive('get')->andReturn($collection)->once();
+
+ $mapper = new Tags();
+ $mapping = $mapper->getMap();
+ $this->assertCount(3, $mapping);
+ // assert this is what the result looks like:
+ $result = [
+ 0 => strval(trans('import.map_do_not_map')),
+ 14 => 'Else',
+ 12 => 'Something',
+ ];
+ $this->assertEquals($result, $mapping);
+ }
+
+}
\ No newline at end of file
diff --git a/tests/Unit/Import/Mapper/TransactionCurrenciesTest.php b/tests/Unit/Import/Mapper/TransactionCurrenciesTest.php
new file mode 100644
index 0000000000..235cd165d4
--- /dev/null
+++ b/tests/Unit/Import/Mapper/TransactionCurrenciesTest.php
@@ -0,0 +1,68 @@
+.
+ */
+
+declare(strict_types=1);
+
+namespace Tests\Unit\Import\Mapper;
+
+use FireflyIII\Import\Mapper\TransactionCurrencies;
+use FireflyIII\Models\TransactionCurrency;
+use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
+use Illuminate\Support\Collection;
+use Tests\TestCase;
+
+/**
+ * Class TransactionCurrenciesTest
+ */
+class TransactionCurrenciesTest extends TestCase
+{
+ /**
+ * @covers \FireflyIII\Import\Mapper\TransactionCurrencies::getMap()
+ */
+ public function testGetMapBasic()
+ {
+ $one = new TransactionCurrency;
+ $one->id = 9;
+ $one->name = 'Something';
+ $one->code = 'ABC';
+ $two = new TransactionCurrency;
+ $two->id = 11;
+ $two->name = 'Else';
+ $two->code = 'DEF';
+ $collection = new Collection([$one, $two]);
+
+ $repository = $this->mock(CurrencyRepositoryInterface::class);
+ $repository->shouldReceive('get')->andReturn($collection)->once();
+
+ $mapper = new TransactionCurrencies();
+ $mapping = $mapper->getMap();
+ $this->assertCount(3, $mapping);
+ // assert this is what the result looks like:
+ $result = [
+ 0 => strval(trans('import.map_do_not_map')),
+ 11 => 'Else (DEF)',
+ 9 => 'Something (ABC)',
+
+ ];
+ $this->assertEquals($result, $mapping);
+ }
+
+}
\ No newline at end of file
diff --git a/tests/Unit/Import/MapperPreProcess/TagsCommaTest.php b/tests/Unit/Import/MapperPreProcess/TagsCommaTest.php
new file mode 100644
index 0000000000..c3deeb1516
--- /dev/null
+++ b/tests/Unit/Import/MapperPreProcess/TagsCommaTest.php
@@ -0,0 +1,49 @@
+.
+ */
+
+declare(strict_types=1);
+
+namespace Tests\Unit\Import\MapperPreProcess;
+
+use FireflyIII\Import\MapperPreProcess\TagsComma;
+use Tests\TestCase;
+
+/**
+ * Class TagsCommaTest
+ */
+class TagsCommaTest extends TestCase
+{
+
+ /**
+ * \FireflyIII\Import\MapperPreProcess\TagsComma::run
+ */
+ public function testBasic()
+ {
+ $input = 'some,tags, with, spaces ,and,without,,';
+ $output = ['some', 'tags', 'with', 'spaces', 'and', 'without'];
+ $mapper = new TagsComma();
+ $result = $mapper->run($input);
+
+ $this->assertEquals($output, $result);
+
+ }
+
+}
\ No newline at end of file
diff --git a/tests/Unit/Import/MapperPreProcess/TagsSpaceTest.php b/tests/Unit/Import/MapperPreProcess/TagsSpaceTest.php
new file mode 100644
index 0000000000..207b5151cb
--- /dev/null
+++ b/tests/Unit/Import/MapperPreProcess/TagsSpaceTest.php
@@ -0,0 +1,49 @@
+.
+ */
+
+declare(strict_types=1);
+
+namespace Tests\Unit\Import\MapperPreProcess;
+
+use FireflyIII\Import\MapperPreProcess\TagsComma;
+use FireflyIII\Import\MapperPreProcess\TagsSpace;
+use Tests\TestCase;
+
+/**
+ * Class TagsSpaceTest
+ */
+class TagsSpaceTest extends TestCase
+{
+
+ /**
+ * \FireflyIII\Import\MapperPreProcess\TagsSpace::run
+ */
+ public function testBasic()
+ {
+ $input = 'some tags with spaces,and without ';
+ $output = ['some', 'tags', 'with', 'spaces,and', 'without'];
+ $mapper = new TagsSpace();
+ $result = $mapper->run($input);
+
+ $this->assertEquals($output, $result);
+ }
+
+}
\ No newline at end of file
diff --git a/tests/Unit/Import/Object/ImportAccountTest.php b/tests/Unit/Import/Object/ImportAccountTest.php
new file mode 100644
index 0000000000..5de2216467
--- /dev/null
+++ b/tests/Unit/Import/Object/ImportAccountTest.php
@@ -0,0 +1,143 @@
+.
+ */
+
+declare(strict_types=1);
+
+namespace Tests\Unit\Import\Object;
+
+use FireflyIII\Import\Object\ImportAccount;
+use FireflyIII\Models\Account;
+use FireflyIII\Models\AccountType;
+use FireflyIII\Repositories\Account\AccountRepositoryInterface;
+use Illuminate\Support\Collection;
+use Mockery;
+use Tests\TestCase;
+
+/**
+ * Class ImportAccountTest
+ */
+class ImportAccountTest extends TestCase
+{
+
+ /**
+ * Should error because it requires a default asset account.
+ *
+ * @covers \FireflyIII\Import\Object\ImportAccount::__construct
+ * @covers \FireflyIII\Import\Object\ImportAccount::getAccount
+ * @covers \FireflyIII\Import\Object\ImportAccount::store
+ * @covers \FireflyIII\Import\Object\ImportAccount::findMappedObject
+ * @covers \FireflyIII\Import\Object\ImportAccount::findExistingObject
+ * @covers \FireflyIII\Import\Object\ImportAccount::getMappedObject
+ */
+ public function testBasic()
+ {
+ // mock stuff
+ $repository = $this->mock(AccountRepositoryInterface::class);
+ $accountType = AccountType::where('type', AccountType::ASSET)->first();
+ $account = Account::find(1);
+
+ // mock calls:
+ $repository->shouldReceive('setUser')->once()->withArgs([Mockery::any()]);
+ $repository->shouldReceive('getAccountType')->twice()->withArgs([AccountType::ASSET])->andReturn($accountType);
+ $repository->shouldReceive('getAccountsByType')->twice()->withArgs([[AccountType::ASSET]])->andReturn(new Collection());
+ $repository->shouldReceive('find')->once()->withArgs([1])->andReturn($account);
+
+ // create import account.
+ $importAccount = new ImportAccount;
+ $importAccount->setUser($this->user());
+ $importAccount->setDefaultAccountId(1);
+ $found = $importAccount->getAccount();
+ $this->assertEquals(1, $found->id);
+
+ }
+
+ /**
+ * Should error because it requires a default asset account.
+ *
+ * @covers \FireflyIII\Import\Object\ImportAccount::__construct
+ * @covers \FireflyIII\Import\Object\ImportAccount::getAccount
+ * @covers \FireflyIII\Import\Object\ImportAccount::store
+ * @covers \FireflyIII\Import\Object\ImportAccount::findMappedObject
+ * @covers \FireflyIII\Import\Object\ImportAccount::findExistingObject
+ * @covers \FireflyIII\Import\Object\ImportAccount::getMappedObject
+ */
+ public function testEmptyMappingAccountId()
+ {
+ // mock stuff
+ $repository = $this->mock(AccountRepositoryInterface::class);
+ $accountType = AccountType::where('type', AccountType::ASSET)->first();
+ $account = Account::find(1);
+
+ // mock calls:
+ $repository->shouldReceive('setUser')->once()->withArgs([Mockery::any()]);
+ $repository->shouldReceive('getAccountType')->once()->withArgs([AccountType::ASSET])->andReturn($accountType);
+ //$repository->shouldReceive('getAccountsByType')->once()->withArgs([[AccountType::ASSET]])->andReturn(new Collection());
+ //$repository->shouldReceive('find')->once()->withArgs([1])->andReturn($account);
+
+ // create import account.
+ $importAccount = new ImportAccount;
+ $importAccount->setUser($this->user());
+ $importAccount->setDefaultAccountId(1);
+
+ // add an account id:
+ $accountId = [
+ 'role' => 'account-id',
+ 'mapped' => null,
+ 'value' => 2,
+ ];
+ $importAccount->setAccountId($accountId);
+
+
+ $found = $importAccount->getAccount();
+ $this->assertEquals(2, $found->id);
+
+ }
+
+ /**
+ * @covers \FireflyIII\Import\Object\ImportAccount::__construct
+ * @covers \FireflyIII\Import\Object\ImportAccount::getAccount
+ * @covers \FireflyIII\Import\Object\ImportAccount::store
+ * @expectedException \FireflyIII\Exceptions\FireflyException
+ * @expectedExceptionMessage ImportAccount cannot continue without a default account to fall back on.
+ */
+ public function testNoAccount()
+ {
+ $repository = $this->mock(AccountRepositoryInterface::class);
+ $repository->shouldReceive('setUser')->once()->withArgs([Mockery::any()]);
+ $importAccount = new ImportAccount;
+ $importAccount->setUser($this->user());
+ $importAccount->getAccount();
+ }
+
+ /**
+ * @covers \FireflyIII\Import\Object\ImportAccount::__construct
+ * @covers \FireflyIII\Import\Object\ImportAccount::getAccount
+ * @covers \FireflyIII\Import\Object\ImportAccount::store
+ * @expectedException \FireflyIII\Exceptions\FireflyException
+ * @expectedExceptionMessage ImportAccount cannot continue without user.
+ */
+ public function testNoUser()
+ {
+ $this->mock(AccountRepositoryInterface::class);
+ $importAccount = new ImportAccount;
+ $importAccount->getAccount();
+ }
+}
\ No newline at end of file
|