@@ -15,7 +15,7 @@ final class DokumentationsstrukturTest extends TestCase
|
||||
'Verbrauchskostenreport' => ['Verbrauchskostenreport', 'Status: Implementiert'],
|
||||
'Virtuelle Batterie' => ['Virtuelle-Batterie', 'Status: Diskussionsentwurf'],
|
||||
'CC100 Hardware' => ['CC100-Hardware', 'Status: Diskussionsentwurf'],
|
||||
'Energiediagramm' => ['Energiediagramm', 'Status: Diskussionsentwurf'],
|
||||
'Energiediagramm' => ['Energiediagramm', 'Status: Implementiert'],
|
||||
'VGT-Schnittstelle' => ['VGT-Schnittstelle', 'Status: Diskussionsentwurf'],
|
||||
'Shelly-Modul' => ['Shelly-Modul', 'Status: Implementiert'],
|
||||
];
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Belevo\EnelixUtils\Tests;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class EnergiediagrammModulstrukturTest extends TestCase
|
||||
{
|
||||
public function testModuleMetadataAndFormExposeRequiredConfiguration(): void
|
||||
{
|
||||
$module = json_decode(
|
||||
file_get_contents(__DIR__ . '/../Energiediagramm/module.json'),
|
||||
true,
|
||||
512,
|
||||
JSON_THROW_ON_ERROR
|
||||
);
|
||||
$form = json_decode(
|
||||
file_get_contents(__DIR__ . '/../Energiediagramm/form.json'),
|
||||
true,
|
||||
512,
|
||||
JSON_THROW_ON_ERROR
|
||||
);
|
||||
|
||||
self::assertSame('{F73B8F8D-5E36-4B23-B379-4632A517A1D6}', $module['id']);
|
||||
self::assertSame('Energiediagramm', $module['name']);
|
||||
self::assertSame('ENELIXENERGY', $module['prefix']);
|
||||
|
||||
$serialized = json_encode($form, JSON_THROW_ON_ERROR);
|
||||
foreach ([
|
||||
'ProduktionZaehlerID',
|
||||
'EinspeisungZaehlerID',
|
||||
'NetzbezugZaehlerID',
|
||||
'VerbrauchZaehlerID',
|
||||
'Standardzeitraum',
|
||||
'FarbeEigenverbrauch',
|
||||
'FarbeAutarkie',
|
||||
] as $property) {
|
||||
self::assertStringContainsString($property, $serialized);
|
||||
}
|
||||
self::assertSame(2, substr_count($serialized, 'SelectColor'));
|
||||
}
|
||||
|
||||
public function testHtmlStartsWithDataAndRespondsToAvailableWidth(): void
|
||||
{
|
||||
$html = file_get_contents(__DIR__ . '/../Energiediagramm/module.html');
|
||||
self::assertNotFalse($html);
|
||||
self::assertStringContainsString('__ENELIX_INITIAL_STATE__', $html);
|
||||
self::assertStringContainsString('ResizeObserver', $html);
|
||||
self::assertStringContainsString('grid-template-columns: minmax(0, 1fr)', $html);
|
||||
self::assertStringContainsString('SetCustomRange', $html);
|
||||
self::assertStringNotContainsString("addEventListener('load'", $html);
|
||||
}
|
||||
|
||||
public function testModuleEmbedsInitialPayloadForTileAndPopup(): void
|
||||
{
|
||||
$module = file_get_contents(__DIR__ . '/../Energiediagramm/module.php');
|
||||
self::assertNotFalse($module);
|
||||
self::assertStringContainsString(
|
||||
"str_replace('__ENELIX_INITIAL_STATE__'",
|
||||
$module
|
||||
);
|
||||
self::assertStringContainsString('GetVisualizationPopup', $module);
|
||||
self::assertStringContainsString('Standardzeitraum', $module);
|
||||
self::assertStringContainsString('CustomStart', $module);
|
||||
self::assertStringContainsString('CustomEnd', $module);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Belevo\EnelixUtils\Tests;
|
||||
|
||||
use Belevo\EnelixUtils\Energiediagramm\EnergyChartCalculator;
|
||||
use InvalidArgumentException;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
require_once __DIR__ . '/../Energiediagramm/libs/EnergyChartCalculator.php';
|
||||
|
||||
final class EnergiediagrammTest extends TestCase
|
||||
{
|
||||
private string $timezone;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->timezone = date_default_timezone_get();
|
||||
date_default_timezone_set('Europe/Zurich');
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
date_default_timezone_set($this->timezone);
|
||||
}
|
||||
|
||||
public function testCalendarRangesUseLocalBoundaries(): void
|
||||
{
|
||||
[$dayStart, $dayEnd] = EnergyChartCalculator::rangeBounds(
|
||||
'day',
|
||||
'2026-09-27',
|
||||
'2026-09-01',
|
||||
'2026-09-02'
|
||||
);
|
||||
self::assertSame('2026-09-27 00:00', date('Y-m-d H:i', $dayStart));
|
||||
self::assertSame('2026-09-28 00:00', date('Y-m-d H:i', $dayEnd));
|
||||
|
||||
[$weekStart, $weekEnd] = EnergyChartCalculator::rangeBounds(
|
||||
'week',
|
||||
'2026-09-27',
|
||||
'2026-09-01',
|
||||
'2026-09-02'
|
||||
);
|
||||
self::assertSame('2026-09-21', date('Y-m-d', $weekStart));
|
||||
self::assertSame('2026-09-28', date('Y-m-d', $weekEnd));
|
||||
|
||||
[$monthStart, $monthEnd] = EnergyChartCalculator::rangeBounds(
|
||||
'month',
|
||||
'2026-09-27',
|
||||
'2026-09-01',
|
||||
'2026-09-02'
|
||||
);
|
||||
self::assertSame('2026-09-01', date('Y-m-d', $monthStart));
|
||||
self::assertSame('2026-10-01', date('Y-m-d', $monthEnd));
|
||||
|
||||
[$yearStart, $yearEnd] = EnergyChartCalculator::rangeBounds(
|
||||
'year',
|
||||
'2026-09-27',
|
||||
'2026-09-01',
|
||||
'2026-09-02'
|
||||
);
|
||||
self::assertSame('2026-01-01', date('Y-m-d', $yearStart));
|
||||
self::assertSame('2027-01-01', date('Y-m-d', $yearEnd));
|
||||
}
|
||||
|
||||
public function testCustomRangeIncludesCompleteEndDateAcrossDstChange(): void
|
||||
{
|
||||
[$start, $end] = EnergyChartCalculator::rangeBounds(
|
||||
'custom',
|
||||
'2026-03-29',
|
||||
'2026-03-28',
|
||||
'2026-03-30'
|
||||
);
|
||||
|
||||
self::assertSame('2026-03-28 00:00', date('Y-m-d H:i', $start));
|
||||
self::assertSame('2026-03-31 00:00', date('Y-m-d H:i', $end));
|
||||
}
|
||||
|
||||
public function testInvalidCustomRangeIsRejected(): void
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
|
||||
EnergyChartCalculator::rangeBounds(
|
||||
'custom',
|
||||
'2026-09-27',
|
||||
'2026-09-28',
|
||||
'2026-09-27'
|
||||
);
|
||||
}
|
||||
|
||||
public function testMetricsUseDerivedOrExplicitConsumption(): void
|
||||
{
|
||||
$derived = EnergyChartCalculator::metrics(20.0, 5.0, 3.0);
|
||||
self::assertSame(18.0, $derived['Hausverbrauch']);
|
||||
self::assertSame(15.0, $derived['Eigenverbrauch']);
|
||||
self::assertSame(75.0, $derived['Eigenverbrauchsquote']);
|
||||
self::assertEqualsWithDelta(83.3333, $derived['Autarkiegrad'], 0.001);
|
||||
|
||||
$explicit = EnergyChartCalculator::metrics(20.0, 5.0, 3.0, 16.0);
|
||||
self::assertSame(16.0, $explicit['Hausverbrauch']);
|
||||
self::assertSame(13.0, $explicit['Eigenverbrauch']);
|
||||
self::assertSame(65.0, $explicit['Eigenverbrauchsquote']);
|
||||
self::assertSame(81.25, $explicit['Autarkiegrad']);
|
||||
}
|
||||
|
||||
public function testColorsAreValidatedAndNormalized(): void
|
||||
{
|
||||
self::assertSame(
|
||||
'#2F80ED',
|
||||
EnergyChartCalculator::normalizeColor('#2f80ed', '#000000')
|
||||
);
|
||||
self::assertSame(
|
||||
'#22A06B',
|
||||
EnergyChartCalculator::normalizeColor('transparent', '#22a06b')
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,12 @@
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'Energiediagramm' => [
|
||||
'file' => __DIR__ . '/modules/Energiediagramm.php',
|
||||
'paths' => [
|
||||
'Energiediagramm/*',
|
||||
],
|
||||
],
|
||||
'ShellyModul' => [
|
||||
'file' => __DIR__ . '/modules/ShellyModul.php',
|
||||
'paths' => [
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Belevo\EnelixUtils\SymconTest\TestContext;
|
||||
|
||||
return static function (TestContext $test): void {
|
||||
$productionId = $test->createVariable(2, 'Produktion', 1200.0);
|
||||
$feedInId = $test->createVariable(2, 'Einspeisung', 350.0);
|
||||
$gridId = $test->createVariable(2, 'Netzbezug', 180.0);
|
||||
|
||||
$moduleId = $test->createInstance(
|
||||
'{F73B8F8D-5E36-4B23-B379-4632A517A1D6}',
|
||||
'Energiediagramm',
|
||||
[
|
||||
'ProduktionZaehlerID' => $productionId,
|
||||
'EinspeisungZaehlerID' => $feedInId,
|
||||
'NetzbezugZaehlerID' => $gridId,
|
||||
'Standardzeitraum' => 'month',
|
||||
'FarbeEigenverbrauch' => '#1259A7',
|
||||
'FarbeAutarkie' => '#178A55',
|
||||
]
|
||||
);
|
||||
|
||||
$test->runCase('Instanz und Eigenschaften werden angelegt', static function (
|
||||
TestContext $test
|
||||
) use ($moduleId): void {
|
||||
$test->assertInstanceStatus($moduleId);
|
||||
$test->assertSame('month', IPS_GetProperty($moduleId, 'Standardzeitraum'));
|
||||
$test->assertSame('#1259A7', IPS_GetProperty($moduleId, 'FarbeEigenverbrauch'));
|
||||
$test->assertSame('#178A55', IPS_GetProperty($moduleId, 'FarbeAutarkie'));
|
||||
});
|
||||
|
||||
$test->runCase('Konfigurationsformular ist gültiges JSON', static function (
|
||||
TestContext $test
|
||||
) use ($moduleId): void {
|
||||
$form = json_decode(
|
||||
IPS_GetConfigurationForm($moduleId),
|
||||
true,
|
||||
512,
|
||||
JSON_THROW_ON_ERROR
|
||||
);
|
||||
$test->assertTrue(is_array($form));
|
||||
});
|
||||
|
||||
$test->runCase('Zeitraum und Datumsbereich werden angenommen', static function (
|
||||
TestContext $test
|
||||
) use ($moduleId): void {
|
||||
IPS_RequestAction($moduleId, 'SetRange', 'year');
|
||||
IPS_RequestAction(
|
||||
$moduleId,
|
||||
'SetCustomRange',
|
||||
json_encode(
|
||||
['start' => '2026-01-01', 'end' => '2026-01-31'],
|
||||
JSON_THROW_ON_ERROR
|
||||
)
|
||||
);
|
||||
IPS_RequestAction($moduleId, 'Refresh', true);
|
||||
$test->assertSame(102, (int) IPS_GetInstance($moduleId)['InstanceStatus']);
|
||||
});
|
||||
};
|
||||
@@ -58,7 +58,7 @@ final class SymconTestContractTest extends TestCase
|
||||
public function testAffectedModuleResolverSelectsAllModulesForFrameworkChanges(): void
|
||||
{
|
||||
self::assertSame(
|
||||
['ShellyModul', 'Verbrauchskostenreport'],
|
||||
['Energiediagramm', 'ShellyModul', 'Verbrauchskostenreport'],
|
||||
$this->resolveAffectedModules(['tests/Symcon/TestContext.php'])
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user