From bbf974c648d1b1d9781557789277f6dfabc067e1 Mon Sep 17 00:00:00 2001 From: Jean-Kevin KPADEY Date: Tue, 21 Jul 2026 22:15:24 +0200 Subject: [PATCH 1/2] feat(parser): add structured token-level error metadata to ParseException Add ParseErrorType enum and enrich ParseException with type, offendingToken, and position fields. Guard five failure points in TAFParser and MetarParser that previously leaked unchecked exceptions or carried no structured context: - TAFParser.parseTemperature: validate with TEMPERATURE_REGEX, throw TEMPERATURE on mismatch - AbstractWeatherCodeParser.parseDeliveryTime: wrap parseInt/substring calls, throw DELIVERY_TIME on failure - TAFParser.parse validity: guard with VALIDITY_REGEX before parseValidity, throw VALIDITY on mismatch - MetarParser.parse station: add ICAO format guard, throw STATION - TAFParser.processLines: guard short tokens and null factory results, throw TREND All existing valid-message tests remain green. --- .../mivek/exception/ParseErrorType.java | 19 +++++++ .../mivek/exception/ParseException.java | 44 ++++++++++++++- .../parser/AbstractWeatherCodeParser.java | 35 +++++++----- .../io/github/mivek/parser/MetarParser.java | 22 +++++++- .../io/github/mivek/parser/TAFParser.java | 48 ++++++++++++---- .../github/mivek/parser/MetarParserTest.java | 22 ++++++++ .../io/github/mivek/parser/TAFParserTest.java | 56 +++++++++++++++++-- 7 files changed, 213 insertions(+), 33 deletions(-) create mode 100644 metarParser-parsers/src/main/java/io/github/mivek/exception/ParseErrorType.java diff --git a/metarParser-parsers/src/main/java/io/github/mivek/exception/ParseErrorType.java b/metarParser-parsers/src/main/java/io/github/mivek/exception/ParseErrorType.java new file mode 100644 index 00000000..a8fd789b --- /dev/null +++ b/metarParser-parsers/src/main/java/io/github/mivek/exception/ParseErrorType.java @@ -0,0 +1,19 @@ +package io.github.mivek.exception; + +/** + * @author mivek + */ +public enum ParseErrorType { + /** Station parse error. */ + STATION, + /** Delivery time parse error. */ + DELIVERY_TIME, + /** Validity parse error. */ + VALIDITY, + /** Temperature parse error. */ + TEMPERATURE, + /** Trend header parse error. */ + TREND, + /** Generic / unknown parse error. */ + INVALID_MESSAGE +} diff --git a/metarParser-parsers/src/main/java/io/github/mivek/exception/ParseException.java b/metarParser-parsers/src/main/java/io/github/mivek/exception/ParseException.java index e695976a..6e1d3065 100644 --- a/metarParser-parsers/src/main/java/io/github/mivek/exception/ParseException.java +++ b/metarParser-parsers/src/main/java/io/github/mivek/exception/ParseException.java @@ -11,6 +11,12 @@ public class ParseException extends Exception { private static final long serialVersionUID = -9022781702124062628L; /** The error code. */ private final ErrorCodes codes; + /** The error type, may be null. */ + private final ParseErrorType type; + /** The offending token, may be null. */ + private final String offendingToken; + /** The token index in the tokenized input. */ + private final int position; /** * Constructor with error code. @@ -18,8 +24,23 @@ public class ParseException extends Exception { * @param code the error code. */ public ParseException(final ErrorCodes code) { - super(code.toString()); + this(code, null, null, -1); + } + + /** + * Constructor with error code and structured metadata. + * + * @param code the error code. + * @param type the parse error type. + * @param offendingToken the token that caused the failure. + * @param position the token index in the tokenized input. + */ + public ParseException(final ErrorCodes code, final ParseErrorType type, final String offendingToken, final int position) { + super(offendingToken == null ? code.toString() : code.toString() + " [" + offendingToken + "]"); this.codes = code; + this.type = type; + this.offendingToken = offendingToken; + this.position = position; } /** @@ -28,4 +49,25 @@ public ParseException(final ErrorCodes code) { public ErrorCodes getErrorCode() { return codes; } + + /** + * @return the error type, or null if not set. + */ + public ParseErrorType getType() { + return type; + } + + /** + * @return the offending token, or null if not set. + */ + public String getOffendingToken() { + return offendingToken; + } + + /** + * @return the token index in the tokenized input. + */ + public int getPosition() { + return position; + } } diff --git a/metarParser-parsers/src/main/java/io/github/mivek/parser/AbstractWeatherCodeParser.java b/metarParser-parsers/src/main/java/io/github/mivek/parser/AbstractWeatherCodeParser.java index 4ee1231c..4053a5d7 100644 --- a/metarParser-parsers/src/main/java/io/github/mivek/parser/AbstractWeatherCodeParser.java +++ b/metarParser-parsers/src/main/java/io/github/mivek/parser/AbstractWeatherCodeParser.java @@ -3,6 +3,9 @@ import io.github.mivek.command.AirportSupplier; import io.github.mivek.command.common.CommonCommandSupplier; import io.github.mivek.enums.Flag; +import io.github.mivek.exception.ErrorCodes; +import io.github.mivek.exception.ParseErrorType; +import io.github.mivek.exception.ParseException; import io.github.mivek.model.AbstractWeatherCode; import java.time.LocalTime; import java.util.Objects; @@ -46,21 +49,27 @@ public abstract class AbstractWeatherCodeParser e * * @param weatherCode The weather code. * @param time the string to parse. + * @param position the token index in the tokenized input. * @return true if the token was a real delivery time, false if it was a validity time. + * @throws ParseException if the time token is malformed. */ - boolean parseDeliveryTime(final AbstractWeatherCode weatherCode, final String time) { - weatherCode.setDay(Integer.parseInt(time.substring(0, 2))); - int hours = Integer.parseInt(time.substring(2, 4)); - LocalTime t; - if (time.length() > 6 && time.contains("/")) { - t = LocalTime.of(hours, 0); - weatherCode.setTime(t); - return false; - } else { - int minutes = Integer.parseInt(time.substring(4, 6)); - t = LocalTime.of(hours, minutes); - weatherCode.setTime(t); - return true; + boolean parseDeliveryTime(final AbstractWeatherCode weatherCode, final String time, final int position) throws ParseException { + try { + weatherCode.setDay(Integer.parseInt(time.substring(0, 2))); + int hours = Integer.parseInt(time.substring(2, 4)); + LocalTime t; + if (time.length() > 6 && time.contains("/")) { + t = LocalTime.of(hours, 0); + weatherCode.setTime(t); + return false; + } else { + int minutes = Integer.parseInt(time.substring(4, 6)); + t = LocalTime.of(hours, minutes); + weatherCode.setTime(t); + return true; + } + } catch (NumberFormatException | StringIndexOutOfBoundsException e) { + throw new ParseException(ErrorCodes.ERROR_CODE_INVALID_MESSAGE, ParseErrorType.DELIVERY_TIME, time, position); } } diff --git a/metarParser-parsers/src/main/java/io/github/mivek/parser/MetarParser.java b/metarParser-parsers/src/main/java/io/github/mivek/parser/MetarParser.java index 70c3b287..09f18535 100644 --- a/metarParser-parsers/src/main/java/io/github/mivek/parser/MetarParser.java +++ b/metarParser-parsers/src/main/java/io/github/mivek/parser/MetarParser.java @@ -5,6 +5,8 @@ import io.github.mivek.command.metar.Command; import io.github.mivek.command.metar.MetarCommandSupplier; import io.github.mivek.enums.WeatherChangeType; +import io.github.mivek.exception.ErrorCodes; +import io.github.mivek.exception.ParseErrorType; import io.github.mivek.exception.ParseException; import io.github.mivek.factory.FactoryProvider; import io.github.mivek.model.Airport; @@ -12,7 +14,9 @@ import io.github.mivek.model.trend.MetarTrend; import io.github.mivek.model.trend.validity.AbstractMetarTrendTime; import io.github.mivek.utils.Converter; +import io.github.mivek.utils.Regex; import java.util.Objects; +import java.util.regex.Pattern; /** * This controller contains methods that parse the metar code. This class is a @@ -21,6 +25,8 @@ * @author mivek */ public final class MetarParser extends AbstractWeatherCodeParser { + /** Station ICAO pattern. */ + private static final Pattern STATION_PATTERN = Pattern.compile("^[A-Z]{4}$"); /** The command supplier. */ private final MetarCommandSupplier supplier; @@ -69,11 +75,21 @@ public Metar parse(final String code) throws ParseException { } } - Airport airport = getAirportSupplier().get(metarTab[startIndex]); - m.setStation(metarTab[startIndex]); + if (startIndex >= metarTab.length) { + throw new ParseException(ErrorCodes.ERROR_CODE_INVALID_MESSAGE, ParseErrorType.STATION, null, startIndex); + } + String stationToken = metarTab[startIndex]; + if (!Regex.match(STATION_PATTERN, stationToken)) { + throw new ParseException(ErrorCodes.ERROR_CODE_INVALID_MESSAGE, ParseErrorType.STATION, stationToken, startIndex); + } + Airport airport = getAirportSupplier().get(stationToken); + m.setStation(stationToken); m.setAirport(airport); m.setMessage(code); - parseDeliveryTime(m, metarTab[startIndex + 1]); + if (startIndex + 1 >= metarTab.length) { + throw new ParseException(ErrorCodes.ERROR_CODE_INVALID_MESSAGE, ParseErrorType.DELIVERY_TIME, null, startIndex + 1); + } + parseDeliveryTime(m, metarTab[startIndex + 1], startIndex + 1); int metarTabLength = metarTab.length; int i = startIndex + 2; while (i < metarTabLength) { diff --git a/metarParser-parsers/src/main/java/io/github/mivek/parser/TAFParser.java b/metarParser-parsers/src/main/java/io/github/mivek/parser/TAFParser.java index 8c6ca805..c6deeaad 100644 --- a/metarParser-parsers/src/main/java/io/github/mivek/parser/TAFParser.java +++ b/metarParser-parsers/src/main/java/io/github/mivek/parser/TAFParser.java @@ -5,6 +5,7 @@ import io.github.mivek.command.taf.Command; import io.github.mivek.command.taf.TAFCommandSupplier; import io.github.mivek.exception.ErrorCodes; +import io.github.mivek.exception.ParseErrorType; import io.github.mivek.exception.ParseException; import io.github.mivek.factory.FactoryProvider; import io.github.mivek.model.Airport; @@ -13,8 +14,10 @@ import io.github.mivek.model.trend.AbstractTafTrend; import io.github.mivek.model.trend.validity.AbstractValidity; import io.github.mivek.utils.Converter; +import io.github.mivek.utils.Regex; import java.util.Arrays; import java.util.List; +import java.util.regex.Pattern; import java.util.stream.Stream; /** @@ -27,6 +30,8 @@ public final class TAFParser extends AbstractWeatherCodeParser { private static final String TX = "TX"; /** Temperature Minimum Constant. */ private static final String TN = "TN"; + /** Temperature regex pattern. */ + private static final Pattern TEMPERATURE_REGEX = Pattern.compile("^(TX|TN)M?\\d{2}/\\d{4}Z$"); /** TAF command supplier. */ private final TAFCommandSupplier supplier; @@ -75,11 +80,15 @@ public TAF parse(final String code) throws ParseException { taf.setAirport(airport); taf.setMessage(code); // Day and time - if(parseDeliveryTime(taf, line1parts[i])) { + if(parseDeliveryTime(taf, line1parts[i], i)) { i++; } // Validity Time - taf.setValidity(parseValidity(line1parts[i])); + String validityToken = line1parts[i]; + if (!Regex.match(VALIDITY_REGEX, validityToken)) { + throw new ParseException(ErrorCodes.ERROR_CODE_INVALID_MESSAGE, ParseErrorType.VALIDITY, validityToken, i); + } + taf.setValidity(parseValidity(validityToken)); // Handle rest of second line. for (int j = i + 1; j < line1parts.length; j++) { @@ -88,9 +97,9 @@ public TAF parse(final String code) throws ParseException { parseRMK(taf, line1parts, j); break; } else if (part.startsWith(TX)) { - taf.setMaxTemperature(parseTemperature(part)); + taf.setMaxTemperature(parseTemperature(part, j)); } else if (part.startsWith(TN)) { - taf.setMinTemperature(parseTemperature(part)); + taf.setMinTemperature(parseTemperature(part, j)); } else { executeCommand(taf, part); } @@ -149,8 +158,14 @@ private String[][] extractLineTokens(final String tafCode) { * @param taf the TAF object to build * @param parts the token of the line */ - private void processLines(final TAF taf, final String[] parts) throws ParseException { + void processLines(final TAF taf, final String[] parts) throws ParseException { + if (parts[0].length() < 2) { + throw new ParseException(ErrorCodes.ERROR_CODE_INVALID_MESSAGE, ParseErrorType.TREND, parts[0], 0); + } AbstractTAFTrendParser trendParser = FactoryProvider.getTrendParser().create(parts[0].substring(0, 2)); + if (trendParser == null) { + throw new ParseException(ErrorCodes.ERROR_CODE_INVALID_MESSAGE, ParseErrorType.TREND, parts[0], 0); + } AbstractTafTrend trend = trendParser.parse(parts); taf.addTrend(trend); } @@ -159,15 +174,24 @@ private void processLines(final TAF taf, final String[] parts) throws ParseExcep * Parse the temperature. * * @param tempPart the string to parse. + * @param position the token index. * @return a temperature with its date. + * @throws ParseException if the temperature token is malformed. */ - TemperatureDated parseTemperature(final String tempPart) { - TemperatureDated temperature = new TemperatureDated(); - String[] parts = tempPart.split("/"); - temperature.setTemperature(Converter.convertTemperature(parts[0].substring(2))); - temperature.setDay(Integer.parseInt(parts[1].substring(0, 2))); - temperature.setHour(Integer.parseInt(parts[1].substring(2, 4))); - return temperature; + TemperatureDated parseTemperature(final String tempPart, final int position) throws ParseException { + if (!Regex.match(TEMPERATURE_REGEX, tempPart)) { + throw new ParseException(ErrorCodes.ERROR_CODE_INVALID_MESSAGE, ParseErrorType.TEMPERATURE, tempPart, position); + } + try { + TemperatureDated temperature = new TemperatureDated(); + String[] parts = tempPart.split("/"); + temperature.setTemperature(Converter.convertTemperature(parts[0].substring(2))); + temperature.setDay(Integer.parseInt(parts[1].substring(0, 2))); + temperature.setHour(Integer.parseInt(parts[1].substring(2, 4))); + return temperature; + } catch (NumberFormatException | StringIndexOutOfBoundsException e) { + throw new ParseException(ErrorCodes.ERROR_CODE_INVALID_MESSAGE, ParseErrorType.TEMPERATURE, tempPart, position); + } } } diff --git a/metarParser-parsers/src/test/java/io/github/mivek/parser/MetarParserTest.java b/metarParser-parsers/src/test/java/io/github/mivek/parser/MetarParserTest.java index 6f8cae64..17e4f082 100644 --- a/metarParser-parsers/src/test/java/io/github/mivek/parser/MetarParserTest.java +++ b/metarParser-parsers/src/test/java/io/github/mivek/parser/MetarParserTest.java @@ -1,6 +1,8 @@ package io.github.mivek.parser; import io.github.mivek.enums.*; +import io.github.mivek.exception.ErrorCodes; +import io.github.mivek.exception.ParseErrorType; import io.github.mivek.exception.ParseException; import io.github.mivek.internationalization.Messages; import io.github.mivek.model.*; @@ -485,4 +487,24 @@ void testParseWithRecentRain() throws ParseException { assertEquals(Phenomenon.RAIN, m.getWeatherConditions().get(0).getPhenomenons().get(0)); } + @Test + void testParseInvalidStation() { + ParseException e = assertThrows(ParseException.class, () -> parser.parse("METAR 12 150500Z 17005KT 6000")); + assertEquals(ParseErrorType.STATION, e.getType()); + assertEquals("12", e.getOffendingToken()); + assertEquals(1, e.getPosition()); + } + + @Test + void testParseEmptyMessageThrowsStationError() { + ParseException e = assertThrows(ParseException.class, () -> parser.parse("METAR")); + assertEquals(ParseErrorType.STATION, e.getType()); + } + + @Test + void testParseWithoutDeliveryTimeThrowsDeliveryTimeError() { + ParseException e = assertThrows(ParseException.class, () -> parser.parse("LFPG")); + assertEquals(ParseErrorType.DELIVERY_TIME, e.getType()); + } + } diff --git a/metarParser-parsers/src/test/java/io/github/mivek/parser/TAFParserTest.java b/metarParser-parsers/src/test/java/io/github/mivek/parser/TAFParserTest.java index e1d1c69c..bf455249 100644 --- a/metarParser-parsers/src/test/java/io/github/mivek/parser/TAFParserTest.java +++ b/metarParser-parsers/src/test/java/io/github/mivek/parser/TAFParserTest.java @@ -2,6 +2,7 @@ import io.github.mivek.enums.*; import io.github.mivek.exception.ErrorCodes; +import io.github.mivek.exception.ParseErrorType; import io.github.mivek.exception.ParseException; import io.github.mivek.internationalization.Messages; import io.github.mivek.model.TAF; @@ -95,9 +96,9 @@ void testParseValidity() { } @Test - void testParseTemperatureMax() { + void testParseTemperatureMax() throws ParseException { String tempString = "TX15/0612Z"; - TemperatureDated res = parser.parseTemperature(tempString); + TemperatureDated res = parser.parseTemperature(tempString, 6); assertThat(res.getTemperature(), is(15)); assertThat(res.getDay(), is(6)); @@ -105,9 +106,9 @@ void testParseTemperatureMax() { } @Test - void testParseTemperatureMinus() { + void testParseTemperatureMinus() throws ParseException { String tempString = "TNM02/0612Z"; - TemperatureDated res = parser.parseTemperature(tempString); + TemperatureDated res = parser.parseTemperature(tempString, 7); assertThat(res.getTemperature(), is(-2)); assertThat(res.getDay(), is(6)); @@ -959,4 +960,51 @@ void testParseWithoutDeliveryTime() throws ParseException { assertEquals(3, taf.getValidity().getEndHour()); } + @Test + void testParseInvalidTemperature() { + ParseException e = assertThrows(ParseException.class, () -> parser.parse("TAF LFPG 150500Z 1506/1612 17005KT 6000 TX/34 2112Z")); + assertEquals(ParseErrorType.TEMPERATURE, e.getType()); + assertEquals("TX/34", e.getOffendingToken()); + } + + @Test + void testParseInvalidValidity() { + ParseException e = assertThrows(ParseException.class, () -> parser.parse("TAF LFPG 150500Z 2018l/2020 17005KT 6000")); + assertEquals(ParseErrorType.VALIDITY, e.getType()); + assertEquals("2018l/2020", e.getOffendingToken()); + } + + @Test + void testParseInvalidDeliveryTime() { + ParseException e = assertThrows(ParseException.class, () -> parser.parse("TAF LFPG 2007XXZ 1506/1612 17005KT 6000")); + assertEquals(ParseErrorType.DELIVERY_TIME, e.getType()); + assertEquals("2007XXZ", e.getOffendingToken()); + } + + @Test + void testProcessLinesWithShortToken() { + TAF taf = new TAF(); + String[] parts = {"X"}; + ParseException e = assertThrows(ParseException.class, () -> parser.processLines(taf, parts)); + assertEquals(ParseErrorType.TREND, e.getType()); + assertEquals("X", e.getOffendingToken()); + } + + @Test + void testProcessLinesWithUnknownTrendPrefix() { + TAF taf = new TAF(); + String[] parts = {"XX", "1506/1508"}; + ParseException e = assertThrows(ParseException.class, () -> parser.processLines(taf, parts)); + assertEquals(ParseErrorType.TREND, e.getType()); + assertEquals("XX", e.getOffendingToken()); + } + + @Test + void testParseInvalidTemperatureWithPosition() throws ParseException { + ParseException e = assertThrows(ParseException.class, () -> parser.parseTemperature("TX/34", 7)); + assertEquals(ParseErrorType.TEMPERATURE, e.getType()); + assertEquals("TX/34", e.getOffendingToken()); + assertEquals(7, e.getPosition()); + } + } From 7e843216069714818f82ec7c0947c3f7d8e7906f Mon Sep 17 00:00:00 2001 From: Jean-Kevin KPADEY Date: Wed, 22 Jul 2026 10:50:47 +0200 Subject: [PATCH 2/2] refactor: reduce MetarParser.parse cognitive complexity and drop dead throws - Extract report-type/station/delivery-time parsing from parse() into parseIdentification() helper, lowering parse() complexity below 15. - Remove unthrowable ParseException from testParseInvalidTemperature- WithPosition() signature since the call is inside assertThrows. --- .../io/github/mivek/parser/MetarParser.java | 59 +++++++++++-------- .../io/github/mivek/parser/TAFParserTest.java | 2 +- 2 files changed, 34 insertions(+), 27 deletions(-) diff --git a/metarParser-parsers/src/main/java/io/github/mivek/parser/MetarParser.java b/metarParser-parsers/src/main/java/io/github/mivek/parser/MetarParser.java index 09f18535..d055ecdb 100644 --- a/metarParser-parsers/src/main/java/io/github/mivek/parser/MetarParser.java +++ b/metarParser-parsers/src/main/java/io/github/mivek/parser/MetarParser.java @@ -9,7 +9,6 @@ import io.github.mivek.exception.ParseErrorType; import io.github.mivek.exception.ParseException; import io.github.mivek.factory.FactoryProvider; -import io.github.mivek.model.Airport; import io.github.mivek.model.Metar; import io.github.mivek.model.trend.MetarTrend; import io.github.mivek.model.trend.validity.AbstractMetarTrendTime; @@ -62,9 +61,38 @@ public MetarParser(final CommonCommandSupplier commonCommandSupplier, final Rema public Metar parse(final String code) throws ParseException { Metar m = new Metar(); String[] metarTab = tokenize(code); - int startIndex = 0; + int index = parseIdentification(m, metarTab, code); + while (index < metarTab.length) { + if (!generalParse(m, metarTab[index]) && !parseFlags(m, metarTab[index])) { + if ("NOSIG".equals(metarTab[index])) { + m.setNosig(true); + } else if (RMK.equals(metarTab[index])) { + parseRMK(m, metarTab, index); + break; + } else if (metarTab[index].equals(TEMPO) || metarTab[index].equals(BECMG)) { + MetarTrend trend = new MetarTrend(WeatherChangeType.valueOf(metarTab[index])); + index = parseTrend(index, trend, metarTab); + m.addTrend(trend); + } else { + executeCommand(m, metarTab[index]); + } + } + index++; + } + return m; + } - // Check for METAR/SPECI prefix + /** + * Parses the report-type prefix, station and delivery time. + * + * @param m the metar being built. + * @param metarTab the tokenized message. + * @param code the raw message. + * @return the index of the first body token. + * @throws ParseException if the station or delivery time is missing or malformed. + */ + private int parseIdentification(final Metar m, final String[] metarTab, final String code) throws ParseException { + int startIndex = 0; if (metarTab.length > 0) { if ("METAR".equals(metarTab[0])) { m.setReportType(io.github.mivek.enums.ReportType.METAR); @@ -74,7 +102,6 @@ public Metar parse(final String code) throws ParseException { startIndex = 1; } } - if (startIndex >= metarTab.length) { throw new ParseException(ErrorCodes.ERROR_CODE_INVALID_MESSAGE, ParseErrorType.STATION, null, startIndex); } @@ -82,34 +109,14 @@ public Metar parse(final String code) throws ParseException { if (!Regex.match(STATION_PATTERN, stationToken)) { throw new ParseException(ErrorCodes.ERROR_CODE_INVALID_MESSAGE, ParseErrorType.STATION, stationToken, startIndex); } - Airport airport = getAirportSupplier().get(stationToken); m.setStation(stationToken); - m.setAirport(airport); + m.setAirport(getAirportSupplier().get(stationToken)); m.setMessage(code); if (startIndex + 1 >= metarTab.length) { throw new ParseException(ErrorCodes.ERROR_CODE_INVALID_MESSAGE, ParseErrorType.DELIVERY_TIME, null, startIndex + 1); } parseDeliveryTime(m, metarTab[startIndex + 1], startIndex + 1); - int metarTabLength = metarTab.length; - int i = startIndex + 2; - while (i < metarTabLength) { - if (!generalParse(m, metarTab[i]) && !parseFlags(m, metarTab[i])) { - if ("NOSIG".equals(metarTab[i])) { - m.setNosig(true); - } else if (RMK.equals(metarTab[i])) { - parseRMK(m, metarTab, i); - break; - } else if (metarTab[i].equals(TEMPO) || metarTab[i].equals(BECMG)) { - MetarTrend trend = new MetarTrend(WeatherChangeType.valueOf(metarTab[i])); - i = parseTrend(i, trend, metarTab); - m.addTrend(trend); - } else { - executeCommand(m, metarTab[i]); - } - } - i++; - } - return m; + return startIndex + 2; } /** diff --git a/metarParser-parsers/src/test/java/io/github/mivek/parser/TAFParserTest.java b/metarParser-parsers/src/test/java/io/github/mivek/parser/TAFParserTest.java index bf455249..42ba60f9 100644 --- a/metarParser-parsers/src/test/java/io/github/mivek/parser/TAFParserTest.java +++ b/metarParser-parsers/src/test/java/io/github/mivek/parser/TAFParserTest.java @@ -1000,7 +1000,7 @@ void testProcessLinesWithUnknownTrendPrefix() { } @Test - void testParseInvalidTemperatureWithPosition() throws ParseException { + void testParseInvalidTemperatureWithPosition() { ParseException e = assertThrows(ParseException.class, () -> parser.parseTemperature("TX/34", 7)); assertEquals(ParseErrorType.TEMPERATURE, e.getType()); assertEquals("TX/34", e.getOffendingToken());