Skip to content

Commit 7d7d4ac

Browse files
committed
Consume one chunk on decoding errors if regex did not match
1 parent bc68773 commit 7d7d4ac

File tree

6 files changed

+94
-8
lines changed

6 files changed

+94
-8
lines changed

src/ChunkDecoder/MetarChunkDecoder.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,5 @@ public function consume($remaining_metar)
2727
'remaining' => $new_remaining_metar,
2828
);
2929
}
30+
3031
}

src/Exception/ChunkDecoderException.php

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,32 @@ public function getChunk()
3838
/**
3939
* Get remaining metar after the chunk decoder consumed it
4040
* In the cases where the exception is triggered because
41-
* chunk's regexp didn't match, it will be the same.
42-
* For other cases it won't, and having this information
43-
* will allow to continue decoding
41+
* chunk's regexp didn't match, one chunk will be eaten
42+
* with whitespace separator.
43+
* Having this information can allow the decoding to continue
44+
*/
45+
public function getFreshRemainingMetar()
46+
{
47+
if(trim($this->remaining_metar) == $this->metar_chunk){
48+
return $this->consumeOneChunk($this->remaining_metar);
49+
} else {
50+
return $this->remaining_metar;
51+
}
52+
}
53+
54+
55+
/**
56+
* Consume one chunk blindly, without looking for the specific pattern
57+
* (only whitespace)
4458
*/
45-
public function getRemainingMetar()
59+
private static function consumeOneChunk($remaining_metar)
4660
{
47-
return $this->remaining_metar;
61+
$next_space = strpos($remaining_metar, ' ');
62+
if($next_space > 0){
63+
return substr($remaining_metar, $next_space + 1);
64+
} else {
65+
return $remaining_metar;
66+
}
67+
4868
}
4969
}

src/MetarDecoder.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ class MetarDecoder
2626

2727
protected $global_strict_parsing = false;
2828

29+
protected $discard_faulty_part_on_error = true;
30+
2931
public function __construct()
3032
{
3133
$this->decoder_chain = array(
@@ -116,14 +118,16 @@ private function parseWithMode($raw_metar, $strict)
116118
// update remaining metar for next round
117119
$remaining_metar = $decoded['remaining_metar'];
118120
} catch (ChunkDecoderException $cde) {
119-
// log error in decoded metar and abort decoding if in strict mode
121+
// log error in decoded metar
120122
$decoded_metar->addDecodingException($cde);
123+
121124
// abort decoding if strict mode is activated, continue otherwise
122125
if ($strict) {
123126
break;
124127
}
128+
125129
// update remaining metar for next round
126-
$remaining_metar = $cde->getRemainingMetar();
130+
$remaining_metar = $cde->getFreshRemainingMetar();
127131
}
128132

129133
// hook for report status decoder, abort if nil, but decoded metar is valid though
@@ -141,4 +145,5 @@ private function parseWithMode($raw_metar, $strict)
141145

142146
return $decoded_metar;
143147
}
148+
144149
}

tests/ChunkDecoder/SurfaceWindChunkDecoderTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public function testEmptyInformationChunk()
7373
$this->decoder->parse('/////KT PPP');
7474
$this->fail('An exception should have been thrown here');
7575
} catch (ChunkDecoderException $cde) {
76-
$this->assertEquals('PPP', $cde->getRemainingMetar());
76+
$this->assertEquals('PPP', $cde->getFreshRemainingMetar());
7777
}
7878
}
7979

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
namespace MetarDecoder\Test\ChunkDecoder;
4+
5+
use MetarDecoder\ChunkDecoder\ReportStatusChunkDecoder;
6+
use MetarDecoder\Exception\ChunkDecoderException;
7+
8+
class ChunkDecoderExceptionTest extends \PHPUnit_Framework_TestCase
9+
{
10+
11+
/**
12+
* Test handling of remaining metar
13+
*/
14+
public function testFreshRemainingMetar()
15+
{
16+
$chunk_decoder = new ReportStatusChunkDecoder();
17+
18+
// with regex match
19+
$exception = new ChunkDecoderException("FAULTY_PART AAA BBB CC-D ", "BBB CC-D ", "This is an error message", $chunk_decoder);
20+
$this->assertEquals("BBB CC-D ", $exception->getFreshRemainingMetar());
21+
$this->assertEquals("ReportStatusChunkDecoder", $exception->getChunkDecoder());
22+
$this->assertEquals("FAULTY_PART AAA BBB CC-D", $exception->getChunk());
23+
24+
// no regex match, consume one chunk blindly
25+
$exception = new ChunkDecoderException("FAULTY_PART AAA BBB CC-D ", "FAULTY_PART AAA BBB CC-D ", "This is an error message", $chunk_decoder);
26+
$this->assertEquals("AAA BBB CC-D ", $exception->getFreshRemainingMetar());
27+
}
28+
29+
}

tests/MetarDecoderTest.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ public function testParseInvalid()
117117
{
118118
// launch decoding
119119
$d = $this->decoder->parseNotStrict('METAR LFPB 190730Z AUTOPP 17005KT 6000 OVC024 02/00 Q10032 ');
120+
// here ^ ^ and here
120121

121122
// compare results
122123
$this->assertFalse($d->isValid());
@@ -139,6 +140,36 @@ public function testParseInvalid()
139140
$this->assertEquals(2, $d->getAirTemperature()->getValue());
140141
$this->assertEquals(0, $d->getDewPointTemperature()->getValue());
141142
$this->assertNull($d->getPressure());
143+
144+
}
145+
146+
/**
147+
* Test parsing of an invalid METAR, where parsing can continue normally without strict option activated
148+
*/
149+
public function testParseInvalidPart()
150+
{
151+
// launch decoding
152+
$d = $this->decoder->parseNotStrict('METAR LFPB 190730Z AUTOP X17005KT 6000 OVC024 02/00 Q1032 ');
153+
// here ^ ^ and here
154+
155+
// compare results
156+
$this->assertFalse($d->isValid());
157+
$this->assertEquals(2, count($d->getDecodingExceptions()));
158+
$this->assertEquals('METAR', $d->getType());
159+
$this->assertEquals('LFPB', $d->getIcao());
160+
$this->assertEquals(19, $d->getDay());
161+
$this->assertEquals('07:30 UTC', $d->getTime());
162+
$this->assertNull($d->getStatus());
163+
$this->assertNull($d->getSurfaceWind());
164+
$v = $d->getVisibility();
165+
$this->assertEquals(6000, $v->getVisibility()->getValue());
166+
$cs = $d->getClouds();
167+
$c = $cs[0];
168+
$this->assertEquals('OVC', $c->getAmount());
169+
$this->assertEquals(2400, $c->getBaseHeight()->getValue());
170+
$this->assertEquals(2, $d->getAirTemperature()->getValue());
171+
$this->assertEquals(0, $d->getDewPointTemperature()->getValue());
172+
$this->assertEquals(1032, $d->getPressure()->getValue());
142173
}
143174

144175
/**

0 commit comments

Comments
 (0)