The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
# Before `make install' is performed this script should be runnable with
# `make test'. After `make install' it should work as `perl Device-Aurora.t'

#########################

use strict;
use warnings;

use Test::More tests => 29;
use Test::Device::SerialPort;

BEGIN { use_ok('Device::Inverter::Aurora') };

#########################

{
	no warnings 'once';
	# Patch on the fly - Test::Device::SerialPort is missing this method
	*Test::Device::SerialPort::datatype = sub {
		my ($self, $arg) = @_;
		$self->{datatype} = $arg if defined $arg;
		return $self->{datatye};
	};
	# Let Device::Inverter::Aurora know it's testing
	$Device::Inverter::Aurora::TEST = 1;
}

# Most tests can be summarised in a simple but large array.
my @tests = (
	['commCheck',              "\x02\x3a\x00\x20\x20\x20\x20\x20\xc9\x59", "\x00\x06\x49\x4b\x4e\x4e\x1f\x7b", 1],
	['getState',               "\x02\x32\x00\x20\x20\x20\x20\x20\x25\x87", "\x00\x06\x02\x07\x02\x00\xd4\x4a", {
		globalState       => [6, 'Run'],
		inverterState     => [2, 'Run'],
		channel1DCDCState => [7, 'Input Low'],
		channel2DCDCState => [2, 'MPPT'],
		alarmState        => [0, 'No Alarm']
	}],
	['getLastAlarms',          "\x02\x56\x00\x20\x20\x20\x20\x20\xd6\x4c", "\x00\x06\x00\x00\x00\x00\x17\xcc", [
		([0, 'No Alarm'])x4
	]],
	['getPartNumber',          "\x02\x34\x00\x20\x20\x20\x20\x20\xe8\xdf", "\x2d\x31\x32\x33\x34\x2d\xce\xaf", '-1234-'],
	['getSerialNumber',        "\x02\x3F\x00\x20\x20\x20\x20\x20\x6a\xa9", "\x31\x32\x33\x34\x35\x36\x72\xe6", '123456'],
	['getVersion',             "\x02\x3a\x00\x2e\x20\x20\x20\x20\x71\x38", "\x00\x06\x49\x4b\x4e\x4e\x1f\x7b", {
		model             => [73, 'Aurora 3.6 kW indoor'],
		regulation        => [75, 'AS 4777'],
		transformer       => [78, 'transformerless'],
		type              => [78, 'photovoltic'],
	}],
	['getManufactureDate',     "\x02\x41\x00\x20\x20\x20\x20\x20\x07\x3e", "\x00\x06\x30\x31\x31\x30\x6e\xc2", {
		year              => '10',
		month             => '01',
	}],
	['getFirmwareVersion',     "\x02\x48\x00\x20\x20\x20\x20\x20\x3e\x7f", "\x00\x06\x63\x31\x32\x33\x46\x2a", 'c.1.2.3'],
	['getConfiguration',       "\x02\x4d\x00\x20\x20\x20\x20\x20\x9d\x8f", "\x00\x06\x00\x00\x00\x00\x17\xcc", [
		0,
		'System operating with both strings.'
	]],
	['getDailyEnergy',         "\x02\x4e\x00\x00\x20\x20\x20\x20\x62\x47", "\x00\x06\x00\x00\x30\x39\xf7\xd6", '12345'],
	['getWeeklyEnergy',        "\x02\x4e\x01\x00\x20\x20\x20\x20\x49\x43", "\x00\x06\x00\x01\x51\x8f\x1b\x20", '86415'],
	['getMonthlyEnergy',       "\x02\x4e\x03\x00\x20\x20\x20\x20\x1f\x4b", "\x00\x06\x00\x05\xa6\xae\xf1\x42", '370350'],
	['getYearlyEnergy',        "\x02\x4e\x04\x00\x20\x20\x20\x20\xce\x57", "\x00\x06\x00\x44\xc1\x45\xdb\x6f", '4505925'],
	['getTotalEnergy',         "\x02\x4e\x05\x00\x20\x20\x20\x20\xe5\x53", "\x00\x06\x19\xc8\x87\x9e\xbe\x86", '432572318'],
	['getPartialEnergy',       "\x02\x4e\x06\x00\x20\x20\x20\x20\x98\x5f", "\x00\x06\x00\x52\x81\x86\x66\x8e", '5407110'],
	['getFrequency',           "\x02\x3b\x04\x00\x20\x20\x20\x20\x21\xb6", "\x00\x06\x42\x47\xf1\xab\xac\x17", '49.9860038757324'],
	['getGridVoltage',         "\x02\x3b\x01\x00\x20\x20\x20\x20\xa6\xa2", "\x00\x06\x43\x6a\xe0\xfd\xa9\x4c", '234.878860473633'],
	['getGridCurrent',         "\x02\x3b\x02\x00\x20\x20\x20\x20\xdb\xae", "\x00\x06\x3f\x6d\x5d\xad\x4e\xd5", '0.927210628986359'],
	['getGridPower',           "\x02\x3b\x03\x00\x20\x20\x20\x20\xf0\xaa", "\x00\x06\x42\x93\x61\xd8\x83\xa3", '73.6911010742188'],
	['getInput1Voltage',       "\x02\x3b\x17\x00\x20\x20\x20\x20\xec\xf8", "\x00\x06\x42\x81\xd2\xb0\xe6\x6c", '64.9114990234375'],
	['getInput1Current',       "\x02\x3b\x19\x00\x20\x20\x20\x20\x4e\xc1", "\x00\x06\x3c\x99\xba\x86\x96\x24", '0.0187656991183758'],
	['getInput2Voltage',       "\x02\x3b\x1a\x00\x20\x20\x20\x20\x33\xcd", "\x00\x06\x43\x89\xa4\xd7\x32\x05", '275.287811279297'],
	['getInput2Current',       "\x02\x3b\x1b\x00\x20\x20\x20\x20\x18\xc9", "\x00\x06\x3e\xc2\x09\x17\xa3\x22", '0.378975600004196'],
	['getInverterTemperature', "\x02\x3b\x15\x00\x20\x20\x20\x20\xba\xf0", "\x00\x06\x42\x7c\x0f\xde\x96\x7a", '63.015495300293'],
	['getBoosterTemperature',  "\x02\x3b\x16\x00\x20\x20\x20\x20\xc7\xfc", "\x00\x06\x42\x60\x74\xbb\x67\x7a", '56.1139945983887'],
);

# Lets test what we can and can't do
can_ok('Device::Inverter::Aurora', 'crc', map {$_->[0]} @tests);

my $obj = new Device::Inverter::Aurora();
isa_ok $obj, 'Device::Inverter::Aurora';

isa_ok $obj->{port}, 'Test::Device::SerialPort';
$obj->{port}->set_test_mode_active(1);
$obj->{port}->{_no_random_data} = 1;

for my $test (@tests) {
	my $func = $test->[0];
	my $result;

	subtest "Test function $func" => sub {
		plan tests => 3;

		# Inject the reply into the port
		$obj->{port}->lookclear($test->[2]);

		# Execute the function
		ok $result = $obj->$func(), "Function called";

		# Compare the tx buffer on the port with the expected value
		cmp_ok $obj->{port}->{_tx_buf}, 'eq', $test->[1], 'Expected TX';
		$obj->{port}->{_tx_buf} = '';

		# Compare the result of the function with expected results
		if (ref $test->[3] || $test->[3] =~ /^c/ || $test->[3] !~ /\./) {
			# For everything that isn't a float
			is_deeply $result, $test->[3], 'Expected return';
		}
		else {
			#Floats
			cmp_ok sprintf('%0.8f', $result), 'eq', sprintf('%0.8f', $test->[3]), 'Expected return';
		}
	}
}