rounding rules via admin screen, round begin when starting record (#1229)

This commit is contained in:
Kevin Papst
2019-11-10 13:57:05 +01:00
committed by GitHub
parent fa1c79e15c
commit c6c4098759
47 changed files with 1100 additions and 185 deletions

View File

@@ -10,11 +10,13 @@
namespace App\Tests\Timesheet\Calculator;
use App\Entity\Timesheet;
use App\Tests\Mocks\RoundingServiceFactory;
use App\Timesheet\Calculator\DurationCalculator;
use PHPUnit\Framework\TestCase;
/**
* @covers \App\Timesheet\Calculator\DurationCalculator
* @covers \App\Timesheet\RoundingService
*/
class DurationCalculatorTest extends TestCase
{
@@ -24,7 +26,7 @@ class DurationCalculatorTest extends TestCase
$record->setBegin(new \DateTime());
$this->assertEquals(0, $record->getDuration());
$sut = new DurationCalculator([]);
$sut = new DurationCalculator((new RoundingServiceFactory($this))->create());
$sut->calculate($record);
$this->assertEquals(0, $record->getDuration());
}
@@ -39,7 +41,7 @@ class DurationCalculatorTest extends TestCase
$record->setEnd($end);
$this->assertEquals(0, $record->getDuration());
$sut = new DurationCalculator($rules);
$sut = new DurationCalculator((new RoundingServiceFactory($this))->create($rules));
$sut->calculate($record);
$this->assertEquals($expectedDuration, $record->getDuration());
}
@@ -52,7 +54,7 @@ class DurationCalculatorTest extends TestCase
return [
[
[],
null,
$start,
(clone $start)->setTimestamp($start->getTimestamp() + 1837),
1837
@@ -60,7 +62,7 @@ class DurationCalculatorTest extends TestCase
[
[
'default' => [
'days' => [$day],
'days' => $day,
'begin' => 15,
'end' => 15,
'duration' => 0,
@@ -74,7 +76,7 @@ class DurationCalculatorTest extends TestCase
[
[
'default' => [
'days' => [$day],
'days' => $day,
'begin' => 0,
'end' => 0,
'duration' => 0,
@@ -88,7 +90,7 @@ class DurationCalculatorTest extends TestCase
[
[
'default' => [
'days' => [$day],
'days' => $day,
'begin' => 1,
'end' => 1,
'duration' => 0,
@@ -102,7 +104,7 @@ class DurationCalculatorTest extends TestCase
[
[
'default' => [
'days' => [$day],
'days' => $day,
'begin' => 0,
'end' => 0,
'duration' => 30,
@@ -116,14 +118,14 @@ class DurationCalculatorTest extends TestCase
[
[
'default' => [
'days' => [$day],
'days' => $day,
'begin' => 15,
'end' => 0,
'duration' => 0,
'mode' => 'default',
],
'weekdays' => [
'days' => ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'],
'foo' => [
'days' => 'monday,tuesday,wednesday,thursday,friday,saturday,sunday',
'begin' => 0,
'end' => 1,
'duration' => 30,
@@ -137,14 +139,14 @@ class DurationCalculatorTest extends TestCase
[
[
'default' => [
'days' => [$day],
'days' => $day,
'begin' => 15,
'end' => 0,
'duration' => 30,
'mode' => 'default',
],
'weekdays' => [
'days' => ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'],
'foo' => [
'days' => 'monday,tuesday,wednesday,thursday,friday,saturday,sunday',
'begin' => 0,
'end' => 1,
'duration' => 0,
@@ -158,14 +160,14 @@ class DurationCalculatorTest extends TestCase
[
[
'default' => [
'days' => [$day],
'days' => $day,
'begin' => 0,
'end' => 0,
'duration' => 1,
'mode' => 'default',
],
'weekdays' => [
'days' => ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'],
'foo' => [
'days' => 'monday,tuesday,wednesday,thursday,friday,saturday,sunday',
'begin' => 0,
'end' => 0,
'duration' => 1,
@@ -179,14 +181,14 @@ class DurationCalculatorTest extends TestCase
[
[
'default' => [
'days' => [$day],
'days' => $day,
'begin' => 1,
'end' => 1,
'duration' => 1,
'mode' => 'default',
],
'weekdays' => [
'days' => ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'],
'foo' => [
'days' => 'monday,tuesday,wednesday,thursday,friday,saturday,sunday',
'begin' => 1,
'end' => 1,
'duration' => 1,
@@ -200,14 +202,14 @@ class DurationCalculatorTest extends TestCase
[
[
'default' => [
'days' => [$day],
'days' => $day,
'begin' => 0,
'end' => 0,
'duration' => 0,
'mode' => 'default',
],
'weekdays' => [
'days' => ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'],
'foo' => [
'days' => 'monday,tuesday,wednesday,thursday,friday,saturday,sunday',
'begin' => 0,
'end' => 0,
'duration' => 0,

View File

@@ -215,7 +215,7 @@ class RateCalculatorTest extends TestCase
'days' => [$day],
'factor' => 2.0
],
'weekdays' => [
'foo' => [
'days' => ['MonDay', 'tUEsdAy', 'WEdnesday', 'THursday', 'friDay', 'SATURday', 'sunDAY'],
'factor' => 1.5
],

View File

@@ -31,6 +31,7 @@ class CeilRoundingTest extends TestCase
$record->setDuration($record->getEnd()->getTimestamp() - $record->getBegin()->getTimestamp());
$sut = new CeilRounding();
self::assertEquals('ceil', $sut->getId());
$sut->roundBegin($record, $roundBegin);
$sut->roundEnd($record, $roundEnd);
$record->setDuration($record->getEnd()->getTimestamp() - $record->getBegin()->getTimestamp());

View File

@@ -31,6 +31,7 @@ class ClosestRoundingTest extends TestCase
$record->setDuration($record->getEnd()->getTimestamp() - $record->getBegin()->getTimestamp());
$sut = new ClosestRounding();
self::assertEquals('closest', $sut->getId());
$sut->roundBegin($record, $roundBegin);
$sut->roundEnd($record, $roundEnd);
$record->setDuration($record->getEnd()->getTimestamp() - $record->getBegin()->getTimestamp());

View File

@@ -31,6 +31,7 @@ class DefaultRoundingTest extends TestCase
$record->setDuration($record->getEnd()->getTimestamp() - $record->getBegin()->getTimestamp());
$sut = new DefaultRounding();
self::assertEquals('default', $sut->getId());
$sut->roundBegin($record, $roundBegin);
$sut->roundEnd($record, $roundEnd);
$record->setDuration($record->getEnd()->getTimestamp() - $record->getBegin()->getTimestamp());

View File

@@ -31,6 +31,7 @@ class FloorRoundingTest extends TestCase
$record->setDuration($record->getEnd()->getTimestamp() - $record->getBegin()->getTimestamp());
$sut = new FloorRounding();
self::assertEquals('floor', $sut->getId());
$sut->roundBegin($record, $roundBegin);
$sut->roundEnd($record, $roundEnd);
$record->setDuration($record->getEnd()->getTimestamp() - $record->getBegin()->getTimestamp());

View File

@@ -0,0 +1,251 @@
<?php
/*
* This file is part of the Kimai time-tracking app.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Tests\Timesheet;
use App\Entity\Timesheet;
use App\Tests\Mocks\RoundingServiceFactory;
use PHPUnit\Framework\TestCase;
/**
* @covers \App\Timesheet\RoundingService
*/
class RoundingServiceTest extends TestCase
{
public function testCalculateWithEmptyEnd()
{
$record = new Timesheet();
$record->setBegin(new \DateTime());
$this->assertEquals(0, $record->getDuration());
$sut = (new RoundingServiceFactory($this))->create();
$sut->applyRoundings($record);
$this->assertEquals(0, $record->getDuration());
}
/**
* @dataProvider getTestData
*/
public function testCalculate($rules, $start, $end, $expectedStart, $expectedEnd, $expectedDuration)
{
$record = new Timesheet();
$record->setBegin($start);
$record->setEnd($end);
$this->assertEquals(0, $record->getDuration());
$sut = (new RoundingServiceFactory($this))->create($rules);
$sut->roundBegin($record);
$this->assertEquals($expectedStart, $record->getBegin());
$sut->roundEnd($record);
$this->assertEquals($expectedEnd, $record->getEnd());
// set the proper duration
$record->setDuration($record->getEnd()->getTimestamp() - $record->getBegin()->getTimestamp());
$sut->roundDuration($record);
$this->assertEquals($expectedDuration, $record->getDuration());
}
public function getTestData()
{
$start = new \DateTime();
$start->setTime(12, 0, 0);
$day = $start->format('l');
return [
[
null,
$start,
(clone $start)->setTimestamp($start->getTimestamp() + 1837),
$start,
(clone $start)->setTimestamp($start->getTimestamp() + 1837),
1837
],
[
[
'default' => [
'days' => $day,
'begin' => 15,
'end' => 15,
'duration' => 0,
'mode' => 'default',
],
],
(clone $start)->setTime(12, 17, 35),
(clone $start)->setTime(13, 32, 52),
(clone $start)->setTime(12, 15, 00),
(clone $start)->setTime(13, 45, 00),
5400
],
[
[
'default' => [
'days' => $day,
'begin' => 0,
'end' => 0,
'duration' => 0,
'mode' => 'default',
],
],
(clone $start)->setTime(12, 17, 35),
(clone $start)->setTime(13, 32, 52),
(clone $start)->setTime(12, 17, 35),
(clone $start)->setTime(13, 32, 52),
4517
],
[
[
'default' => [
'days' => $day,
'begin' => 1,
'end' => 1,
'duration' => 0,
'mode' => 'default',
],
],
(clone $start)->setTime(12, 17, 35),
(clone $start)->setTime(13, 32, 52),
(clone $start)->setTime(12, 17, 00),
(clone $start)->setTime(13, 33, 00),
4560
],
[
[
'default' => [
'days' => $day,
'begin' => 0,
'end' => 0,
'duration' => 30,
'mode' => 'default',
],
],
(clone $start)->setTime(12, 10, 51),
(clone $start)->setTime(14, 40, 52),
(clone $start)->setTime(12, 10, 51),
(clone $start)->setTime(14, 40, 52),
10800
],
[
[
'default' => [
'days' => $day,
'begin' => 15,
'end' => 0,
'duration' => 0,
'mode' => 'default',
],
'foo' => [
'days' => 'monday,tuesday,wednesday,thursday,friday,saturday,sunday',
'begin' => 0,
'end' => 1,
'duration' => 30,
'mode' => 'default',
],
],
(clone $start)->setTime(12, 27, 35), // 12:15
(clone $start)->setTime(14, 32, 52), // 14:33 => 2:18 => 2:30
(clone $start)->setTime(12, 15, 00), // 12:15
(clone $start)->setTime(14, 33, 00), // 14:33 => 2:18 => 2:30
9000
],
[
[
'default' => [
'days' => $day,
'begin' => 15,
'end' => 0,
'duration' => 30,
'mode' => 'default',
],
'foo' => [
'days' => 'monday,tuesday,wednesday,thursday,friday,saturday,sunday',
'begin' => 0,
'end' => 1,
'duration' => 0,
'mode' => 'default',
],
],
(clone $start)->setTime(12, 27, 35), // 12:15
(clone $start)->setTime(14, 32, 52), // 14:33 => 2:18 (second duration will not be rounded)
(clone $start)->setTime(12, 15, 00), // 12:15
(clone $start)->setTime(14, 33, 00), // 14:33 => 2:18 (second duration will not be rounded)
9000
],
[
[
'default' => [
'days' => $day,
'begin' => 0,
'end' => 0,
'duration' => 1,
'mode' => 'default',
],
'foo' => [
'days' => 'monday,tuesday,wednesday,thursday,friday,saturday,sunday',
'begin' => 0,
'end' => 0,
'duration' => 1,
'mode' => 'default',
],
],
(clone $start)->setTime(12, 27, 35), // no diff, to test ...
(clone $start)->setTime(12, 27, 35), // ... that no rounding is applied
(clone $start)->setTime(12, 27, 35), // no diff, to test ...
(clone $start)->setTime(12, 27, 35), // ... that no rounding is applied
0
],
[
[
'default' => [
'days' => $day,
'begin' => 1,
'end' => 1,
'duration' => 1,
'mode' => 'default',
],
'foo' => [
'days' => 'monday,tuesday,wednesday,thursday,friday,saturday,sunday',
'begin' => 1,
'end' => 1,
'duration' => 1,
'mode' => 'default',
],
],
(clone $start)->setTime(12, 27, 00), // no diff, to test ...
(clone $start)->setTime(12, 27, 00), // ... that no rounding is applied
(clone $start)->setTime(12, 27, 00), // no diff, to test ...
(clone $start)->setTime(12, 27, 00), // ... that no rounding is applied
0
],
[
[
'default' => [
'days' => $day,
'begin' => 0,
'end' => 0,
'duration' => 0,
'mode' => 'default',
],
'foo' => [
'days' => 'monday,tuesday,wednesday,thursday,friday,saturday,sunday',
'begin' => 0,
'end' => 0,
'duration' => 0,
'mode' => 'default',
],
],
(clone $start)->setTime(12, 27, 35), // no diff, to test ...
(clone $start)->setTime(12, 27, 35), // ... that no rounding is applied
(clone $start)->setTime(12, 27, 35), // no diff, to test ...
(clone $start)->setTime(12, 27, 35), // ... that no rounding is applied
0
],
];
}
}

View File

@@ -10,7 +10,9 @@
namespace App\Tests\Timesheet\TrackingMode;
use App\Configuration\TimesheetConfiguration;
use App\Entity\Timesheet;
use App\Tests\Configuration\TestConfigLoader;
use App\Tests\Mocks\RoundingServiceFactory;
use App\Tests\Mocks\Security\UserDateTimeFactoryFactory;
use App\Timesheet\TrackingMode\DefaultMode;
@@ -19,6 +21,12 @@ use App\Timesheet\TrackingMode\DefaultMode;
*/
class DefaultModeTest extends AbstractTrackingModeTest
{
protected function assertDefaultBegin(Timesheet $timesheet)
{
self::assertNotNull($timesheet->getBegin());
self::assertInstanceOf(\DateTime::class, $timesheet->getBegin());
}
/**
* @return DefaultMode
*/
@@ -28,7 +36,7 @@ class DefaultModeTest extends AbstractTrackingModeTest
$dateTime = (new UserDateTimeFactoryFactory($this))->create();
$configuration = new TimesheetConfiguration($loader, ['default_begin' => '13:47']);
return new DefaultMode($dateTime, $configuration);
return new DefaultMode($dateTime, $configuration, (new RoundingServiceFactory($this))->create());
}
public function testDefaultValues()

View File

@@ -10,6 +10,7 @@
namespace App\Tests\Timesheet\TrackingMode;
use App\Entity\Timesheet;
use App\Tests\Mocks\Security\UserDateTimeFactoryFactory;
use App\Timesheet\TrackingMode\PunchInOutMode;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
@@ -21,7 +22,8 @@ class PunchInOutModeTest extends TestCase
{
public function testDefaultValues()
{
$sut = new PunchInOutMode();
$dateTime = (new UserDateTimeFactoryFactory($this))->create();
$sut = new PunchInOutMode($dateTime);
self::assertFalse($sut->canEditBegin());
self::assertFalse($sut->canEditEnd());
@@ -33,13 +35,25 @@ class PunchInOutModeTest extends TestCase
public function testCreate()
{
$startingTime = new \DateTime('22:54');
$timesheet = new Timesheet();
$timesheet->setBegin(new \DateTime('22:54'));
$timesheet->setBegin($startingTime);
$request = new Request();
$timesheetNew = clone $timesheet;
$sut = new PunchInOutMode();
$dateTime = (new UserDateTimeFactoryFactory($this))->create();
$sut = new PunchInOutMode($dateTime);
$sut->create($timesheet, $request);
self::assertEquals($timesheet, $timesheetNew);
self::assertEquals($timesheet->getBegin(), $startingTime);
}
public function testCreateWithoutBegin()
{
$timesheet = new Timesheet();
$request = new Request();
$dateTime = (new UserDateTimeFactoryFactory($this))->create();
$sut = new PunchInOutMode($dateTime);
$sut->create($timesheet, $request);
self::assertInstanceOf(\DateTime::class, $timesheet->getBegin());
}
}

View File

@@ -9,11 +9,8 @@
namespace App\Tests\Timesheet;
use App\Configuration\TimesheetConfiguration;
use App\Tests\Configuration\TestConfigLoader;
use App\Tests\Mocks\Security\UserDateTimeFactoryFactory;
use App\Tests\Mocks\TrackingModeServiceFactory;
use App\Timesheet\TrackingMode\PunchInOutMode;
use App\Timesheet\TrackingModeService;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
@@ -24,11 +21,7 @@ class TrackingModeServiceTest extends TestCase
{
public function testDefaultTrackingModesAreRegistered()
{
$loader = new TestConfigLoader([]);
$dateTime = (new UserDateTimeFactoryFactory($this))->create();
$configuration = new TimesheetConfiguration($loader, ['mode' => 'punch']);
$sut = new TrackingModeService($dateTime, $configuration);
$sut = (new TrackingModeServiceFactory($this))->create('punch');
$modes = $sut->getModes();
self::assertGreaterThanOrEqual(4, $modes);
@@ -46,11 +39,7 @@ class TrackingModeServiceTest extends TestCase
public function testGetActiveMode()
{
$loader = new TestConfigLoader([]);
$dateTime = (new UserDateTimeFactoryFactory($this))->create();
$configuration = new TimesheetConfiguration($loader, ['mode' => 'punch']);
$sut = new TrackingModeService($dateTime, $configuration);
$sut = (new TrackingModeServiceFactory($this))->create('punch');
self::assertInstanceOf(PunchInOutMode::class, $sut->getActiveMode());
}
@@ -60,11 +49,7 @@ class TrackingModeServiceTest extends TestCase
$this->expectException(ServiceNotFoundException::class);
$this->expectExceptionMessage('You have requested a non-existent service "xxxxxx"');
$loader = new TestConfigLoader([]);
$dateTime = (new UserDateTimeFactoryFactory($this))->create();
$configuration = new TimesheetConfiguration($loader, ['mode' => 'xxxxxx']);
$sut = new TrackingModeService($dateTime, $configuration);
$sut = (new TrackingModeServiceFactory($this))->create('xxxxxx');
$sut->getActiveMode();
}