/* * AndFHEM - Open Source Android application to control a FHEM home automation * server. * * Copyright (c) 2011, Matthias Klass or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. All third-party contributions are * distributed under license by Red Hat Inc. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU GENERAL PUBLIC LICENSE, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU GENERAL PUBLIC LICENSE * for more details. * * You should have received a copy of the GNU GENERAL PUBLIC LICENSE * along with this distribution; if not, write to: * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ package li.klass.fhem.service.graph.gplot; import com.google.common.base.Charsets; import com.google.common.collect.Range; import com.google.common.io.Resources; import com.tngtech.java.junit.dataprovider.DataProvider; import com.tngtech.java.junit.dataprovider.DataProviderRunner; import com.tngtech.java.junit.dataprovider.UseDataProvider; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; import li.klass.fhem.testutil.MockitoRule; import static li.klass.fhem.service.graph.gplot.GPlotSeries.Axis; import static li.klass.fhem.service.graph.gplot.GPlotSeries.Builder; import static li.klass.fhem.service.graph.gplot.GPlotSeries.LineType; import static li.klass.fhem.service.graph.gplot.GPlotSeries.SeriesColor; import static li.klass.fhem.service.graph.gplot.GPlotSeries.SeriesType; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.guava.api.Assertions.assertThat; @RunWith(DataProviderRunner.class) public class GPlotParserTest { @Rule public MockitoRule mockitoRule = new MockitoRule(); @InjectMocks GPlotParser gPlotParser; @Test public void should_parse_standard_GPlot_File() throws Exception { // given String content = readGPlot("fht.gplot"); // when GPlotDefinition definition = gPlotParser.parse(content); // then GPlotAxis leftAxis = definition.getLeftAxis(); assertThat(leftAxis.getLabel()).isEqualTo("Actuator (%)"); assertThat(leftAxis.getSeries()).containsExactly(new Builder() .withTitle("Actuator (%)") .withColor(SeriesColor.GREEN) .withLineType(LineType.LINES) .withLogDef("4:actuator.*[0-9]+%:0:int") .withAxis(Axis.LEFT) .build() ); GPlotAxis rightAxis = definition.getRightAxis(); assertThat(rightAxis.getLabel()).isEqualTo("Temperature in C"); assertThat(rightAxis.getSeries()).containsExactly(new Builder() .withTitle("Measured temperature") .withLineType(LineType.LINES) .withLogDef("4:measured:0:") .withAxis(Axis.RIGHT) .withColor(SeriesColor.RED) .build() ); } @Test public void should_parse_GPlot_File_without_using() throws Exception { // given String content = readGPlot("ks550_all.gplot"); // when GPlotDefinition definition = gPlotParser.parse(content); // then GPlotAxis leftAxis = definition.getLeftAxis(); assertThat(leftAxis.getLabel()).isEqualTo("<L1>"); assertThat(leftAxis.getSeries()).containsExactly( new Builder() .withTitle("T") .withLineType(LineType.LINES) .withLogDef("4:::") .withAxis(Axis.LEFT) .withColor(SeriesColor.RED) .build(), new Builder() .withTitle("H") .withLineType(LineType.LINES) .withLogDef("6:::") .withAxis(Axis.LEFT) .withColor(SeriesColor.GREEN) .build(), new Builder() .withTitle("W") .withLineType(LineType.LINES) .withLogDef("8:::") .withAxis(Axis.LEFT) .withColor(SeriesColor.BLUE) .build(), new Builder() .withTitle("R/h") .withLineType(LineType.LINES) .withLogDef("10::0:delta-h") .withAxis(Axis.LEFT) .withColor(SeriesColor.MAGENTA) .build(), new Builder() .withTitle("R/d") .withLineType(LineType.LINES) .withLogDef("10::0:delta-d") .withAxis(Axis.LEFT) .withColor(SeriesColor.BROWN) .build(), new Builder() .withTitle("IR") .withLineType(LineType.LINES) .withLogDef("12::0:$fld[11]=~\"32768\"?1:0") .withAxis(Axis.LEFT) .withColor(SeriesColor.WHITE) .build(), new Builder() .withTitle("WD") .withLineType(LineType.LINES) .withLogDef("14::0:") .withAxis(Axis.LEFT) .withColor(SeriesColor.OLIVE) .build(), new Builder() .withTitle("WDR") .withLineType(LineType.LINES) .withLogDef("16::0:") .withAxis(Axis.LEFT) .withColor(SeriesColor.GRAY) .build(), new Builder() .withTitle("S") .withLineType(LineType.LINES) .withLogDef("18::0:delta-h") .withAxis(Axis.LEFT) .withColor(SeriesColor.YELLOW) .build(), new Builder() .withTitle("B") .withLineType(LineType.LINES) .withLogDef("20::0:") .withAxis(Axis.LEFT) .withColor(SeriesColor.RED) .build() ); GPlotAxis rightAxis = definition.getRightAxis(); assertThat(rightAxis.getLabel()).isEqualTo("<L2>"); assertThat(rightAxis.getSeries()).isEmpty(); } @Test public void should_parse_oneline_GPlot_File() throws Exception { // given String content = readGPlot("power4.gplot"); // when GPlotDefinition definition = gPlotParser.parse(content); // then GPlotAxis leftAxis = definition.getLeftAxis(); assertThat(leftAxis.getLabel()).isEqualTo("Power (KW)"); assertThat(leftAxis.getSeries()).containsExactly( new Builder() .withTitle("") .withLineType(LineType.LINES) .withLogDef("4::0:") .withAxis(Axis.LEFT) .withColor(SeriesColor.RED) .build() ); GPlotAxis rightAxis = definition.getRightAxis(); assertThat(rightAxis.getLabel()).isEqualTo("Power (KW)"); assertThat(rightAxis.getSeries()).isEmpty(); } @Test public void should_parse_yrange_GPlot_File() throws Exception { // given String content = readGPlot("fht80tf.gplot"); // when GPlotDefinition definition = gPlotParser.parse(content); // then GPlotAxis leftAxis = definition.getLeftAxis(); assertThat(leftAxis.getLabel()).isEmpty(); assertThat(leftAxis.getSeries()).containsExactly( new Builder() .withTitle("Open/Closed") .withLineType(LineType.LINES) .withColor(SeriesColor.RED) .withLogDef("4:Window:0:$fld[3]=~\"Open\"?1:0") .withAxis(Axis.LEFT) .build() ); assertThat(leftAxis.getRange().get()).isEqualTo(Range.closed(-0.2, 1.2)); GPlotAxis rightAxis = definition.getRightAxis(); assertThat(rightAxis.getSeries()).isEmpty(); } @Test public void should_parse_yrange_upper_open_GPlot_File() throws Exception { // given String content = readGPlot("esa2000.gplot"); // when GPlotDefinition definition = gPlotParser.parse(content); // then assertThat(definition.getLeftAxis().getRange().get()).isEqualTo(Range.atLeast(0.0)); assertThat(definition.getRightAxis().getRange().get()).isEqualTo(Range.atLeast(0.0)); } @Test public void should_parse_dblog_GPlot_File() throws Exception { // given String content = readGPlot("SM_DB_Network_eth0.gplot"); // when GPlotDefinition definition = gPlotParser.parse(content); // then GPlotAxis leftAxis = definition.getLeftAxis(); assertThat(leftAxis.getLabel()).isEqualTo("Traffic RX / TX"); assertThat(leftAxis.getSeries()).containsExactly( new Builder() .withTitle("RX") .withLineType(LineType.LINES) .withLogDef("<SPEC1>:eth0_diff:::$val=~s/^RX..([\\d.]*).*/$1/eg") .withAxis(Axis.LEFT) .withColor(SeriesColor.RED) .build(), new Builder() .withTitle("TX") .withLineType(LineType.LINES) .withLogDef("<SPEC1>:eth0_diff:::$val=~s/.*TX..([\\d.]*).*/$1/eg") .withColor(SeriesColor.GREEN) .withAxis(Axis.LEFT) .build() ); GPlotAxis rightAxis = definition.getRightAxis(); assertThat(rightAxis.getLabel()).isEqualTo("Traffic Total"); assertThat(rightAxis.getSeries()).containsExactly( new Builder() .withTitle("Total") .withLineType(LineType.LINES) .withLogDef("<SPEC1>:eth0_diff:::$val=~s/.*Total..([\\d.]*).*/$1/eg") .withAxis(Axis.RIGHT) .withColor(SeriesColor.BLUE) .build() ); } @Test public void should_parse_series_types() throws Exception { // given String content = readGPlot("temp4rain10.gplot"); // when GPlotDefinition definition = gPlotParser.parse(content); // then GPlotAxis leftAxis = definition.getLeftAxis(); assertThat(leftAxis.getLabel()).isEqualTo("Rain (l/m2)"); assertThat(leftAxis.getSeries()).containsExactly( new Builder() .withTitle("Rain/h") .withLineType(LineType.HISTEPS) .withLogDef("10:IR\\x3a:0:delta-h") .withColor(SeriesColor.GREEN) .withSeriesType(SeriesType.FILL) .withAxis(Axis.LEFT) .build(), new Builder() .withTitle("Rain/day") .withLineType(LineType.HISTEPS) .withLogDef("10:IR\\x3a:0:delta-d") .withColor(SeriesColor.BLUE) .withSeriesType(SeriesType.DEFAULT) .withAxis(Axis.LEFT) .build() ); GPlotAxis rightAxis = definition.getRightAxis(); assertThat(rightAxis.getLabel()).isEqualTo("Temperature in C"); assertThat(rightAxis.getSeries()).containsExactly( new Builder() .withTitle("Temperature") .withLineType(LineType.LINES) .withLogDef("4:IR\\x3a:0:") .withColor(SeriesColor.RED) .withSeriesType(SeriesType.DEFAULT) .withAxis(Axis.RIGHT) .build() ); } @Test public void should_parse_line_width() throws Exception { // given String content = readGPlot("co20.gplot"); // when GPlotDefinition definition = gPlotParser.parse(content); // then GPlotAxis axis = definition.getRightAxis(); assertThat(axis.getSeries()).contains( new Builder() .withTitle("Air quality (ppm)") .withLineType(LineType.LINES) .withLogDef("4:voc::") .withColor(SeriesColor.WHITE) .withSeriesType(SeriesType.DEFAULT) .withAxis(Axis.RIGHT) .withLineWith(0.2f) .build() ); } @DataProvider public static Object[][] allGplotFilesProvider() throws Exception { File resourceDirectory = new File(GPlotParser.class.getResource(".").toURI()); File[] files = resourceDirectory.listFiles(new FilenameFilter() { @Override public boolean accept(File dir, String filename) { return filename != null && filename.endsWith(".gplot"); } }); Object[][] out = new Object[files.length][]; for (int i = 0; i < files.length; i++) { out[i] = new Object[]{files[i]}; } return out; } @Test @UseDataProvider("allGplotFilesProvider") public void should_find_at_least_one_series_in_GPlot_Files(File file) throws Exception { // given String content = Resources.toString(file.toURI().toURL(), Charsets.UTF_8); // when GPlotDefinition definition = gPlotParser.parse(content); // then boolean containsSeries = !definition.getLeftAxis().getSeries().isEmpty(); containsSeries = !definition.getRightAxis().getSeries().isEmpty() | containsSeries; assertThat(containsSeries).isTrue(); } @Test public void should_parse_user_specified_power8ttt_gplot() throws Exception { // given String content = readGPlot("power8ttt.gplot"); // when GPlotDefinition definition = gPlotParser.parse(content); // then GPlotAxis leftAxis = definition.getLeftAxis(); assertThat(leftAxis.getLabel()).isEqualTo("Power (KWh)"); assertThat(leftAxis.getRange().isPresent()).isFalse(); GPlotAxis rightAxis = definition.getRightAxis(); assertThat(rightAxis.getLabel()).isEqualTo("Power (KWh)"); assertThat(rightAxis.getRange().isPresent()).isFalse(); assertThat(rightAxis.getSeries()).containsOnly( new Builder() .withTitle("Stromzähler") .withLineType(LineType.LINES) .withLogDef("4:CUL_EM_22.Summe\\x3a:0:") .withColor(SeriesColor.RED) .withSeriesType(SeriesType.FILL) .withAxis(Axis.RIGHT) .withLineWith(1) .build()); } @Test public void should_parse_temp4hum4_gplot() throws Exception { // given String content = readGPlot("temp4hum4.gplot"); // when GPlotDefinition definition = gPlotParser.parse(content); // then GPlotAxis leftAxis = definition.getLeftAxis(); assertThat(leftAxis.getLabel()).isEqualTo("Humidity (%)"); assertThat(leftAxis.getRange().isPresent()).isFalse(); GPlotAxis rightAxis = definition.getRightAxis(); assertThat(rightAxis.getLabel()).isEqualTo("Temperature in C"); assertThat(rightAxis.getRange().isPresent()).isFalse(); assertThat(rightAxis.getSeries()).containsOnly( new Builder() .withTitle("Measured temperature") .withLineType(LineType.LINES) .withLogDef("4:temperature:10:") .withColor(SeriesColor.RED) .withSeriesType(SeriesType.DEFAULT) .withAxis(Axis.RIGHT) .withLineWith(1) .build()); assertThat(leftAxis.getSeries()).containsOnly( new Builder() .withTitle("Humidity (%)") .withLineType(LineType.LINES) .withLogDef("4:humidity:50:") .withColor(SeriesColor.GREEN) .withSeriesType(SeriesType.DEFAULT) .withAxis(Axis.LEFT) .withLineWith(1) .build()); } @Test public void should_parse_egrep_files() throws Exception { // given String content = readGPlot("egrep.gplot"); // when GPlotDefinition definition = gPlotParser.parse(content); // then GPlotAxis leftAxis = definition.getLeftAxis(); assertThat(leftAxis.getLabel()).isEqualTo("Signal in %"); assertThat(leftAxis.getRange().isPresent()).isFalse(); GPlotAxis rightAxis = definition.getRightAxis(); assertThat(rightAxis.getLabel()).isEqualTo("Temperatur in Grad Celsius"); assertThat(rightAxis.getRange().isPresent()).isFalse(); assertThat(rightAxis.getSeries()).containsOnly( new Builder() .withTitle("Soll-Temperatur (C)") .withLineType(LineType.LINES) .withLogDef("4:desiredTemperature:0:") .withColor(SeriesColor.RED) .withSeriesType(SeriesType.DEFAULT) .withAxis(Axis.RIGHT) .withLineWith(2) .build(), new Builder() .withTitle("Ist-Temperatur(ungenau)(C)") .withLineType(LineType.LINES) .withLogDef("4:temperature:0:") .withColor(SeriesColor.GREEN) .withSeriesType(SeriesType.DEFAULT) .withAxis(Axis.RIGHT) .withLineWith(2) .build()); assertThat(leftAxis.getSeries()).containsOnly( new Builder() .withTitle("Ventil (%)") .withLineType(LineType.LINES) .withLogDef("4:valveposition:0:") .withColor(SeriesColor.BLUE) .withSeriesType(SeriesType.DEFAULT) .withAxis(Axis.LEFT) .withLineWith(2) .build()); } @Test public void should_parse_custom_gplot_file() throws Exception { // given String content = readGPlot("custom.gplot"); // when GPlotDefinition definition = gPlotParser.parse(content); // then GPlotAxis leftAxis = definition.getLeftAxis(); assertThat(leftAxis.getLabel()).isEqualTo("Anwesenheit"); assertThat(leftAxis.getRange()).contains(Range.closed(0d, 100d)); GPlotAxis rightAxis = definition.getRightAxis(); assertThat(rightAxis.getLabel()).isEqualTo("Tür/Fenster"); assertThat(rightAxis.getRange()).contains(Range.closed(0d, 1d)); assertThat(leftAxis.getSeries()).containsOnly( new Builder() .withTitle("Handy1") .withLineType(LineType.STEPS) .withLogDef("Handy1:state:::$val=($val=~'present'?50:0)") .withColor(SeriesColor.GREEN) .withSeriesType(SeriesType.FILL) .withAxis(Axis.LEFT) .withLineWith(1.5f) .build(), new Builder() .withTitle("Handy2") .withLineType(LineType.STEPS) .withLogDef("Handy2:state:::$val=($val=~'present'?50:0)") .withColor(SeriesColor.MAGENTA) .withSeriesType(SeriesType.FILL) .withAxis(Axis.LEFT) .withLineWith(1.5f) .build()); assertThat(rightAxis.getSeries()).containsOnly( new Builder() .withTitle("Tür") .withLineType(LineType.STEPS) .withLogDef("whg_tuer:onoff") .withColor(SeriesColor.BLUE) .withSeriesType(SeriesType.DEFAULT) .withAxis(Axis.RIGHT) .withLineWith(2) .build(), new Builder() .withTitle("Fenster Küche") .withLineType(LineType.POINTS) .withLogDef("k_fenster:opened:::$val=($val=~'opened'?1:0)") .withColor(SeriesColor.RED) .withSeriesType(SeriesType.DEFAULT) .withAxis(Axis.RIGHT) .withLineWith(1) .build(), new Builder() .withTitle("Fenster Schlafzimmer") .withLineType(LineType.POINTS) .withLogDef("sz_fenster:opened:::$val=($val=~'opened'?1:0)") .withColor(SeriesColor.WHITE) .withSeriesType(SeriesType.DEFAULT) .withAxis(Axis.RIGHT) .withLineWith(1) .build()); } private String readGPlot(String fileName) throws IOException { return Resources.toString(Resources.getResource(GPlotParser.class, fileName), Charsets.UTF_8); } }