diff --git a/docs/en-us/MetarDecoder-Guide.md b/docs/en-us/MetarDecoder-Guide.md
new file mode 100644
index 0000000..69ddbd3
--- /dev/null
+++ b/docs/en-us/MetarDecoder-Guide.md
@@ -0,0 +1,274 @@
+# Metar.Decoder - Usage Guide (EN-US)
+
+## Overview
+
+**Metar.Decoder** is a .NET library for parsing METAR (Meteorological Aerodrome Report) strings into structured, strongly-typed objects. It supports multiple .NET frameworks: `.NET Standard 2.0`, `.NET 8.0`, `.NET 10.0`, and `.NET Framework 4.8`.
+
+**Version:** 1.0.9
+
+## Installation
+
+```bash
+dotnet add package Metar.Decoder
+```
+
+Or via NuGet Package Manager:
+
+```
+Install-Package Metar.Decoder
+```
+
+## Quick Start
+
+```csharp
+using Metar.Decoder;
+using Metar.Decoder.Entity;
+
+var decoder = new MetarDecoder();
+var metar = decoder.Parse("METAR SBGR 031000Z 35006KT 9999 FEW040 SCT100 27/18 Q1020");
+
+Console.WriteLine($"ICAO: {metar.ICAO}");
+Console.WriteLine($"Day: {metar.Day}");
+Console.WriteLine($"Time: {metar.Time}");
+Console.WriteLine($"Wind: {metar.SurfaceWind.MeanDirection.ActualValue} at {metar.SurfaceWind.MeanSpeed.ActualValue} {metar.SurfaceWind.MeanSpeed.ActualUnit}");
+Console.WriteLine($"Visibility: {metar.Visibility.PrevailingVisibility.ActualValue} {metar.Visibility.PrevailingVisibility.ActualUnit}");
+Console.WriteLine($"Temperature: {metar.AirTemperature.ActualValue} C");
+Console.WriteLine($"Dew Point: {metar.DewPointTemperature.ActualValue} C");
+Console.WriteLine($"Pressure: {metar.Pressure.ActualValue} {metar.Pressure.ActualUnit}");
+```
+
+## Parsing Modes
+
+### Default Parsing
+```csharp
+var metar = decoder.Parse("METAR LFPO 231027Z 24004KT 9999 FEW020 17/10 Q1009");
+```
+
+### Strict Parsing
+Stops at the first decoding error:
+```csharp
+var metar = decoder.ParseStrict("METAR LFPO 231027Z 24004KT 9999 FEW020 17/10 Q1009");
+```
+
+### Non-Strict Parsing
+Continues decoding even if errors are encountered:
+```csharp
+var metar = decoder.ParseNotStrict("METAR LFPO 231027Z 24004KT BADVALUE FEW020 17/10 Q1009");
+// metar.IsValid == false, but other fields are still decoded
+```
+
+### Static Parsing
+```csharp
+var metar = MetarDecoder.ParseWithMode("METAR LFPO 231027Z 24004KT 9999 FEW020 17/10 Q1009", isStrict: false);
+```
+
+## Decoded Fields
+
+### Report Type
+```csharp
+metar.Type // MetarType.METAR, MetarType.SPECI, MetarType.METAR_COR, MetarType.SPECI_COR
+```
+
+### ICAO Code
+```csharp
+metar.ICAO // "SBGR", "LFPO", "KJFK", etc.
+```
+
+### Date/Time
+```csharp
+metar.Day // Day of month (1-31)
+metar.Time // "10:00 UTC"
+metar.ObservationDateTime // DateTime object
+```
+
+### Report Status
+```csharp
+metar.Status // "AUTO", "NIL", or empty
+```
+
+### Surface Wind
+```csharp
+var wind = metar.SurfaceWind;
+wind.MeanDirection.ActualValue // Direction in degrees (0-360)
+wind.MeanSpeed.ActualValue // Speed value
+wind.MeanSpeed.ActualUnit // Unit.Knot, Unit.MeterPerSecond, Unit.KilometerPerHour
+wind.SpeedVariations?.ActualValue // Gust speed (if present)
+wind.VariableDirection // true if VRB
+wind.DirectionVariations // [min, max] direction variation values
+```
+
+### Visibility
+```csharp
+var vis = metar.Visibility;
+vis.PrevailingVisibility.ActualValue // Main visibility value
+vis.PrevailingVisibility.ActualUnit // Unit.Meter or Unit.StatuteMile
+vis.MinimumVisibility?.ActualValue // Minimum visibility (if present)
+vis.MinimumVisibilityDirection // "NW", "NE", "S", etc.
+vis.NDV // No Directional Variation flag
+metar.Cavok // CAVOK flag
+```
+
+### Runway Visual Range (RVR)
+```csharp
+foreach (var rvr in metar.RunwaysVisualRange)
+{
+ Console.WriteLine($"Runway: {rvr.Runway}");
+ Console.WriteLine($"Range: {rvr.VisualRange?.ActualValue}");
+ Console.WriteLine($"Variable: {rvr.Variable}");
+ if (rvr.Variable)
+ {
+ Console.WriteLine($"Min: {rvr.VisualRangeInterval[0].ActualValue}");
+ Console.WriteLine($"Max: {rvr.VisualRangeInterval[1].ActualValue}");
+ }
+ Console.WriteLine($"Tendency: {rvr.PastTendency}"); // U (up), D (down), N (no change)
+}
+```
+
+### Present Weather
+```csharp
+foreach (var pw in metar.PresentWeather)
+{
+ Console.WriteLine($"Intensity: {pw.IntensityProximity}"); // +, -, VC
+ Console.WriteLine($"Descriptor: {pw.Characteristics}"); // TS, FZ, SH, etc.
+ foreach (var type in pw.Types)
+ {
+ Console.WriteLine($"Phenomenon: {type}"); // RA, SN, FG, BR, etc.
+ }
+}
+```
+
+### Clouds
+```csharp
+foreach (var cloud in metar.Clouds)
+{
+ Console.WriteLine($"Amount: {cloud.Amount}"); // FEW, SCT, BKN, OVC, VV
+ Console.WriteLine($"Height: {cloud.BaseHeight?.ActualValue} feet");
+ Console.WriteLine($"Type: {cloud.Type}"); // CB, TCU, or NULL
+}
+```
+
+### Temperature
+```csharp
+metar.AirTemperature.ActualValue // Air temperature in Celsius
+metar.DewPointTemperature.ActualValue // Dew point in Celsius
+```
+
+### Pressure
+```csharp
+metar.Pressure.ActualValue // Pressure value
+metar.Pressure.ActualUnit // Unit.HectoPascal (Q) or Unit.MercuryInch (A)
+```
+
+### Recent Weather
+```csharp
+var rw = metar.RecentWeather;
+rw?.Characteristics // Weather descriptor
+rw?.Types // Weather phenomena list
+```
+
+### Wind Shear
+```csharp
+metar.WindshearAllRunways // true if WS ALL RWY
+metar.WindshearRunways // List of affected runways
+```
+
+### Trend Forecast (NOSIG/BECMG/TEMPO)
+```csharp
+metar.TrendType // "NOSIG", "BECMG", or "TEMPO"
+metar.TrendForecast // Raw trend content
+```
+
+### Remarks (RMK)
+```csharp
+metar.Remark // Raw remarks content
+metar.SeaLevelPressure // Parsed SLPnnn value (if present)
+```
+
+## Value Conversion
+
+The `Value` class supports unit conversion:
+
+```csharp
+var speed = metar.SurfaceWind.MeanSpeed;
+double knots = speed.GetConvertedValue(Value.Unit.Knot);
+double mps = speed.GetConvertedValue(Value.Unit.MeterPerSecond);
+double kph = speed.GetConvertedValue(Value.Unit.KilometerPerHour);
+```
+
+## Error Handling
+
+```csharp
+var metar = decoder.ParseNotStrict("METAR LFPO 231027Z BAD_DATA");
+
+if (!metar.IsValid)
+{
+ foreach (var ex in metar.DecodingExceptions)
+ {
+ Console.WriteLine($"Error in: {ex.ChunkDecoder.GetType().Name}");
+ Console.WriteLine($"Message: {ex.Message}");
+ Console.WriteLine($"Remaining: {ex.RemainingMetar}");
+ }
+}
+
+// Reset errors
+metar.ResetDecodingExceptions();
+```
+
+## Architecture
+
+The library follows Clean Architecture with SOLID principles:
+
+- **ChunkDecoder Pattern**: Chain of Responsibility - each decoder handles one METAR section
+- **Interface Segregation**: `IMetarChunkDecoder` defines the contract
+- **Single Responsibility**: Each decoder class handles exactly one METAR element
+- **Open/Closed**: New decoders can be added without modifying existing ones
+
+### Decoder Chain Order
+1. `ReportTypeChunkDecoder` - METAR/SPECI/COR
+2. `IcaoChunkDecoder` - Airport ICAO code
+3. `DatetimeChunkDecoder` - Day/time of observation
+4. `ReportStatusChunkDecoder` - AUTO/NIL status
+5. `SurfaceWindChunkDecoder` - Wind direction/speed/gusts
+6. `VisibilityChunkDecoder` - CAVOK or visibility values
+7. `RunwayVisualRangeChunkDecoder` - RVR for runways
+8. `PresentWeatherChunkDecoder` - Current weather phenomena
+9. `CloudChunkDecoder` - Cloud layers
+10. `TemperatureChunkDecoder` - Air/dew point temperatures
+11. `PressureChunkDecoder` - QNH/altimeter setting
+12. `RecentWeatherChunkDecoder` - Recent weather (RE)
+13. `WindShearChunkDecoder` - Wind shear information
+14. `TrendChunkDecoder` - Trend forecast (NOSIG/BECMG/TEMPO)
+15. `RemarkChunkDecoder` - Remarks section (RMK)
+
+## Supported METAR Elements
+
+| Element | Example | Supported |
+|---------|---------|-----------|
+| Report Type | METAR, SPECI, COR | Yes |
+| ICAO Code | SBGR, KJFK | Yes |
+| Date/Time | 231027Z | Yes |
+| Status | AUTO, NIL | Yes |
+| Surface Wind | 24004KT, VRB02MPS, 24015G25KT | Yes |
+| Direction Variation | 180V270 | Yes |
+| CAVOK | CAVOK | Yes |
+| Visibility (ICAO) | 9999, 2500 | Yes |
+| Visibility (US) | 3SM, 1 1/2SM | Yes |
+| Minimum Visibility | 1000NW | Yes |
+| NDV | 9999NDV | Yes |
+| RVR | R32/0400, R06L/0200V0600U | Yes |
+| Present Weather | +TSRA, -SN, FZFG, VCSH | Yes |
+| Clouds | FEW020, SCT030CB, OVC005 | Yes |
+| Vertical Visibility | VV003 | Yes |
+| Clear Sky | SKC, NSC, NCD, CLR | Yes |
+| Temperature | 17/10, M02/M05 | Yes |
+| Pressure (QNH) | Q1009 | Yes |
+| Pressure (Altimeter) | A2992 | Yes |
+| Recent Weather | REFZRA | Yes |
+| Wind Shear | WS R03, WS ALL RWY | Yes |
+| Trend Forecast | NOSIG, BECMG, TEMPO | Yes |
+| Remarks | RMK AO2 SLP013 | Yes |
+| Sea Level Pressure | SLPnnn (in RMK) | Yes |
+
+## License
+
+MIT License
diff --git a/docs/en-us/TafDecoder-Guide.md b/docs/en-us/TafDecoder-Guide.md
new file mode 100644
index 0000000..77b2059
--- /dev/null
+++ b/docs/en-us/TafDecoder-Guide.md
@@ -0,0 +1,278 @@
+# Taf.Decoder - Usage Guide (EN-US)
+
+## Overview
+
+**Taf.Decoder** is a .NET library for parsing TAF (Terminal Aerodrome Forecast) strings into structured, strongly-typed objects. It supports multiple .NET frameworks: `.NET Standard 2.0`, `.NET 8.0`, `.NET 10.0`, and `.NET Framework 4.8`.
+
+**Version:** 1.0.7
+
+## Installation
+
+```bash
+dotnet add package Taf.Decoder
+```
+
+Or via NuGet Package Manager:
+
+```
+Install-Package Taf.Decoder
+```
+
+## Quick Start
+
+```csharp
+using Taf.Decoder;
+using Taf.Decoder.Entity;
+
+var decoder = new TafDecoder();
+var taf = decoder.Parse("TAF SBGR 031100Z 0312/0418 35008KT 9999 FEW040 SCT100 TX30/0318Z TN20/0409Z");
+
+Console.WriteLine($"ICAO: {taf.Icao}");
+Console.WriteLine($"Day: {taf.Day}");
+Console.WriteLine($"Time: {taf.Time}");
+Console.WriteLine($"Forecast Period: {taf.ForecastPeriod.FromDay}/{taf.ForecastPeriod.FromHour} to {taf.ForecastPeriod.ToDay}/{taf.ForecastPeriod.ToHour}");
+Console.WriteLine($"Wind: {taf.SurfaceWind.MeanDirection.ActualValue} at {taf.SurfaceWind.MeanSpeed.ActualValue} {taf.SurfaceWind.MeanSpeed.ActualUnit}");
+Console.WriteLine($"Visibility: {taf.Visibility.ActualVisibility.ActualValue} {taf.Visibility.ActualVisibility.ActualUnit}");
+```
+
+## Parsing Modes
+
+### Default Parsing
+```csharp
+var taf = decoder.Parse("TAF LFPO 231100Z 2312/2418 24005KT 9999 FEW030");
+```
+
+### Strict Parsing
+Stops at the first decoding error:
+```csharp
+var taf = decoder.ParseStrict("TAF LFPO 231100Z 2312/2418 24005KT 9999 FEW030");
+```
+
+### Non-Strict Parsing
+Continues decoding even if errors are encountered:
+```csharp
+var taf = decoder.ParseNotStrict("TAF LFPO 231100Z 2312/2418 BADVALUE 9999 FEW030");
+```
+
+### Static Parsing
+```csharp
+var taf = TafDecoder.ParseWithMode("TAF LFPO 231100Z 2312/2418 24005KT 9999 FEW030", isStrict: false);
+```
+
+## Decoded Fields
+
+### Report Type
+```csharp
+taf.Type // TafType.TAF, TafType.TAFAMD, TafType.TAFCOR, TafType.RTD
+```
+
+### ICAO Code
+```csharp
+taf.Icao // "SBGR", "LFPO", "KJFK", etc.
+```
+
+### Date/Time
+```csharp
+taf.Day // Day of month (1-31)
+taf.Time // "11:00 UTC"
+taf.OriginDateTime // DateTime object
+```
+
+### Forecast Period
+```csharp
+var period = taf.ForecastPeriod;
+period.FromDay // Start day
+period.FromHour // Start hour
+period.ToDay // End day
+period.ToHour // End hour
+period.IsValid // Validity check
+```
+
+### Surface Wind
+```csharp
+var wind = taf.SurfaceWind;
+wind.MeanDirection.ActualValue // Direction in degrees (0-360)
+wind.MeanSpeed.ActualValue // Speed value
+wind.MeanSpeed.ActualUnit // Unit.Knot, Unit.MeterPerSecond, Unit.KilometerPerHour
+wind.SpeedVariations?.ActualValue // Gust speed (if present)
+wind.VariableDirection // true if VRB
+wind.DirectionVariations // [min, max] direction variation values
+```
+
+### Visibility
+```csharp
+var vis = taf.Visibility;
+vis.ActualVisibility.ActualValue // Visibility value
+vis.ActualVisibility.ActualUnit // Unit.Meter or Unit.StatuteMile
+vis.Greater // true if P (greater than) prefix
+taf.Cavok // CAVOK flag
+```
+
+### Weather Phenomena
+```csharp
+foreach (var wp in taf.WeatherPhenomenons)
+{
+ Console.WriteLine($"Intensity: {wp.IntensityProximity}"); // +, -, VC
+ Console.WriteLine($"Descriptor: {wp.Descriptor}"); // TS, FZ, SH, etc.
+ foreach (var p in wp.Phenomena)
+ {
+ Console.WriteLine($"Phenomenon: {p}"); // RA, SN, FG, BR, etc.
+ }
+}
+```
+
+### Clouds
+```csharp
+foreach (var cloud in taf.Clouds)
+{
+ Console.WriteLine($"Amount: {cloud.Amount}"); // FEW, SCT, BKN, OVC, VV
+ Console.WriteLine($"Height: {cloud.BaseHeight?.ActualValue} feet");
+ Console.WriteLine($"Type: {cloud.Type}"); // CB, TCU, or NULL
+}
+```
+
+### Temperature Forecast
+```csharp
+// Maximum temperature
+var maxTemp = taf.MaximumTemperature;
+if (maxTemp != null)
+{
+ Console.WriteLine($"Type: {maxTemp.Type}"); // "TX"
+ Console.WriteLine($"Value: {maxTemp.TemperatureValue.ActualValue} C");
+ Console.WriteLine($"Day: {maxTemp.Day}, Hour: {maxTemp.Hour}");
+}
+
+// Minimum temperature
+var minTemp = taf.MinimumTemperature;
+if (minTemp != null)
+{
+ Console.WriteLine($"Type: {minTemp.Type}"); // "TN"
+ Console.WriteLine($"Value: {minTemp.TemperatureValue.ActualValue} C");
+ Console.WriteLine($"Day: {minTemp.Day}, Hour: {minTemp.Hour}");
+}
+```
+
+## Weather Evolutions (TEMPO/BECMG/FM/PROB)
+
+TAF includes weather evolution sections that modify the base forecast. Evolutions are stored on each entity:
+
+```csharp
+// Check wind evolutions
+var windEvos = taf.SurfaceWind.Evolutions;
+foreach (var evo in windEvos)
+{
+ Console.WriteLine($"Type: {evo.Type}"); // "TEMPO", "BECMG", "FM"
+ Console.WriteLine($"From: Day {evo.FromDay} {evo.FromTime}");
+ Console.WriteLine($"To: Day {evo.ToDay} {evo.ToTime}");
+ Console.WriteLine($"Probability: {evo.Probability}"); // "PROB30", "PROB40", or null
+
+ var windEntity = evo.Entity as SurfaceWind;
+ if (windEntity != null)
+ {
+ Console.WriteLine($"New Wind: {windEntity.MeanDirection?.ActualValue} at {windEntity.MeanSpeed?.ActualValue}");
+ }
+}
+
+// Check visibility evolutions
+var visEvos = taf.Visibility?.Evolutions;
+// ... similar pattern
+
+// Check cloud evolutions
+foreach (var cloud in taf.Clouds)
+{
+ var cloudEvos = cloud.Evolutions;
+ // ... similar pattern
+}
+```
+
+### Evolution Types
+- **TEMPO**: Temporary fluctuation expected to last less than 1 hour
+- **BECMG**: Gradual change expected to occur during the specified period
+- **FM**: From a specific time, conditions replace the previous forecast
+- **PROB30/PROB40**: Probability of occurrence (30% or 40%)
+
+## Value Conversion
+
+The `Value` class supports unit conversion:
+
+```csharp
+var speed = taf.SurfaceWind.MeanSpeed;
+double knots = speed.GetConvertedValue(Value.Unit.Knot);
+double mps = speed.GetConvertedValue(Value.Unit.MeterPerSecond);
+double kph = speed.GetConvertedValue(Value.Unit.KilometerPerHour);
+```
+
+## Error Handling
+
+```csharp
+var taf = decoder.ParseNotStrict("TAF LFPO 231100Z 2312/2418 BAD_DATA");
+
+if (!taf.IsValid)
+{
+ foreach (var ex in taf.DecodingExceptions)
+ {
+ Console.WriteLine($"Error in: {ex.ChunkDecoder.GetType().Name}");
+ Console.WriteLine($"Message: {ex.Message}");
+ Console.WriteLine($"Remaining: {ex.RemainingTaf}");
+ }
+}
+
+// Reset errors
+taf.ResetDecodingExceptions();
+```
+
+## Architecture
+
+The library follows Clean Architecture with SOLID principles:
+
+- **ChunkDecoder Pattern**: Chain of Responsibility - each decoder handles one TAF section
+- **Interface Segregation**: `ITafChunkDecoder` defines the contract
+- **Single Responsibility**: Each decoder class handles exactly one TAF element
+- **Open/Closed**: New decoders can be added without modifying existing ones
+
+### Main Decoder Chain
+1. `ReportTypeChunkDecoder` - TAF/TAF AMD/TAF COR/RTD
+2. `IcaoChunkDecoder` - Airport ICAO code
+3. `DatetimeChunkDecoder` - Day/time of issue
+4. `ForecastPeriodChunkDecoder` - Valid period (e.g., 0312/0418)
+5. `SurfaceWindChunkDecoder` - Wind direction/speed/gusts
+6. `VisibilityChunkDecoder` - CAVOK or visibility values
+7. `WeatherChunkDecoder` - Weather phenomena
+8. `CloudChunkDecoder` - Cloud layers
+9. `TemperatureChunkDecoder` - TX/TN temperatures
+
+### Evolution Decoder
+After the main chain, `EvolutionChunkDecoder` processes:
+- `TEMPO` - Temporary changes
+- `BECMG` - Becoming changes
+- `FM` - From time changes
+- `PROB30/PROB40` - Probability groups
+
+## Supported TAF Elements
+
+| Element | Example | Supported |
+|---------|---------|-----------|
+| Report Type | TAF, TAF AMD, TAF COR, RTD | Yes |
+| ICAO Code | SBGR, KJFK | Yes |
+| Date/Time | 231100Z | Yes |
+| Forecast Period | 2312/2418 | Yes |
+| Surface Wind | 24005KT, VRB03MPS, 24015G25KT | Yes |
+| Direction Variation | 180V270 | Yes |
+| CAVOK | CAVOK | Yes |
+| Visibility (ICAO) | 9999, 2500 | Yes |
+| Visibility (US) | 3SM, 1 1/2SM, P6SM | Yes |
+| No Visibility Info | //// | Yes |
+| Weather Phenomena | -RA, +TSRA, FZFG | Yes |
+| Clouds | FEW020, SCT030CB, OVC005 | Yes |
+| Vertical Visibility | VV003 | Yes |
+| Clear Sky | SKC, NSC, NCD, CLR | Yes |
+| Temperature Max | TX25/0318Z | Yes |
+| Temperature Min | TNM03/0405Z | Yes |
+| TEMPO | TEMPO 0312/0315 ... | Yes |
+| BECMG | BECMG 0315/0317 ... | Yes |
+| FM | FM031500 ... | Yes |
+| PROB30/PROB40 | PROB40 TEMPO ... | Yes |
+
+## License
+
+MIT License
diff --git a/docs/pt-br/MetarDecoder-Guia.md b/docs/pt-br/MetarDecoder-Guia.md
new file mode 100644
index 0000000..83fe883
--- /dev/null
+++ b/docs/pt-br/MetarDecoder-Guia.md
@@ -0,0 +1,301 @@
+# Metar.Decoder - Guia de Uso (PT-BR)
+
+## Visao Geral
+
+**Metar.Decoder** e uma biblioteca .NET para decodificacao de strings METAR (Meteorological Aerodrome Report / Relatorio Meteorologico de Aerodromo) em objetos estruturados e fortemente tipados. Suporta multiplos frameworks: `.NET Standard 2.0`, `.NET 8.0`, `.NET 10.0` e `.NET Framework 4.8`.
+
+**Versao:** 1.0.9
+
+## Instalacao
+
+```bash
+dotnet add package Metar.Decoder
+```
+
+Ou pelo NuGet Package Manager:
+
+```
+Install-Package Metar.Decoder
+```
+
+## Inicio Rapido
+
+```csharp
+using Metar.Decoder;
+using Metar.Decoder.Entity;
+
+var decoder = new MetarDecoder();
+var metar = decoder.Parse("METAR SBGR 031000Z 35006KT 9999 FEW040 SCT100 27/18 Q1020");
+
+Console.WriteLine($"ICAO: {metar.ICAO}");
+Console.WriteLine($"Dia: {metar.Day}");
+Console.WriteLine($"Hora: {metar.Time}");
+Console.WriteLine($"Vento: {metar.SurfaceWind.MeanDirection.ActualValue} graus a {metar.SurfaceWind.MeanSpeed.ActualValue} {metar.SurfaceWind.MeanSpeed.ActualUnit}");
+Console.WriteLine($"Visibilidade: {metar.Visibility.PrevailingVisibility.ActualValue} {metar.Visibility.PrevailingVisibility.ActualUnit}");
+Console.WriteLine($"Temperatura: {metar.AirTemperature.ActualValue} C");
+Console.WriteLine($"Ponto de Orvalho: {metar.DewPointTemperature.ActualValue} C");
+Console.WriteLine($"Pressao: {metar.Pressure.ActualValue} {metar.Pressure.ActualUnit}");
+```
+
+## Modos de Decodificacao
+
+### Decodificacao Padrao
+```csharp
+var metar = decoder.Parse("METAR LFPO 231027Z 24004KT 9999 FEW020 17/10 Q1009");
+```
+
+### Decodificacao Estrita (Strict)
+Para na primeira falha de decodificacao:
+```csharp
+var metar = decoder.ParseStrict("METAR LFPO 231027Z 24004KT 9999 FEW020 17/10 Q1009");
+```
+
+### Decodificacao Nao-Estrita (Not Strict)
+Continua a decodificacao mesmo encontrando erros:
+```csharp
+var metar = decoder.ParseNotStrict("METAR LFPO 231027Z 24004KT INVALIDO FEW020 17/10 Q1009");
+// metar.IsValid == false, mas os demais campos sao decodificados normalmente
+```
+
+### Decodificacao Estatica
+```csharp
+var metar = MetarDecoder.ParseWithMode("METAR LFPO 231027Z 24004KT 9999 FEW020 17/10 Q1009", isStrict: false);
+```
+
+## Campos Decodificados
+
+### Tipo de Relatorio
+```csharp
+metar.Type // MetarType.METAR, MetarType.SPECI, MetarType.METAR_COR, MetarType.SPECI_COR
+```
+
+### Codigo ICAO
+```csharp
+metar.ICAO // "SBGR", "LFPO", "KJFK", etc.
+```
+
+### Data/Hora
+```csharp
+metar.Day // Dia do mes (1-31)
+metar.Time // "10:00 UTC"
+metar.ObservationDateTime // Objeto DateTime
+```
+
+### Status do Relatorio
+```csharp
+metar.Status // "AUTO", "NIL", ou vazio
+```
+
+### Vento de Superficie
+```csharp
+var vento = metar.SurfaceWind;
+vento.MeanDirection.ActualValue // Direcao em graus (0-360)
+vento.MeanSpeed.ActualValue // Valor da velocidade
+vento.MeanSpeed.ActualUnit // Unit.Knot, Unit.MeterPerSecond, Unit.KilometerPerHour
+vento.SpeedVariations?.ActualValue // Rajada (se presente)
+vento.VariableDirection // true se VRB (variavel)
+vento.DirectionVariations // [min, max] variacao de direcao
+```
+
+### Visibilidade
+```csharp
+var vis = metar.Visibility;
+vis.PrevailingVisibility.ActualValue // Valor da visibilidade predominante
+vis.PrevailingVisibility.ActualUnit // Unit.Meter ou Unit.StatuteMile
+vis.MinimumVisibility?.ActualValue // Visibilidade minima (se presente)
+vis.MinimumVisibilityDirection // "NW", "NE", "S", etc.
+vis.NDV // Sem Variacao Direcional
+metar.Cavok // CAVOK (teto e visibilidade OK)
+```
+
+### Alcance Visual de Pista (RVR)
+```csharp
+foreach (var rvr in metar.RunwaysVisualRange)
+{
+ Console.WriteLine($"Pista: {rvr.Runway}");
+ Console.WriteLine($"Alcance: {rvr.VisualRange?.ActualValue}");
+ Console.WriteLine($"Variavel: {rvr.Variable}");
+ if (rvr.Variable)
+ {
+ Console.WriteLine($"Min: {rvr.VisualRangeInterval[0].ActualValue}");
+ Console.WriteLine($"Max: {rvr.VisualRangeInterval[1].ActualValue}");
+ }
+ Console.WriteLine($"Tendencia: {rvr.PastTendency}"); // U (subindo), D (descendo), N (sem mudanca)
+}
+```
+
+### Tempo Presente
+```csharp
+foreach (var tp in metar.PresentWeather)
+{
+ Console.WriteLine($"Intensidade: {tp.IntensityProximity}"); // +, -, VC
+ Console.WriteLine($"Descritor: {tp.Characteristics}"); // TS, FZ, SH, etc.
+ foreach (var tipo in tp.Types)
+ {
+ Console.WriteLine($"Fenomeno: {tipo}"); // RA (chuva), SN (neve), FG (nevoeiro), etc.
+ }
+}
+```
+
+### Nuvens
+```csharp
+foreach (var nuvem in metar.Clouds)
+{
+ Console.WriteLine($"Quantidade: {nuvem.Amount}"); // FEW (poucas), SCT (esparsas), BKN (nublado), OVC (encoberto), VV (visib. vertical)
+ Console.WriteLine($"Altura: {nuvem.BaseHeight?.ActualValue} pes");
+ Console.WriteLine($"Tipo: {nuvem.Type}"); // CB (cumulonimbus), TCU (cumulus torre), ou NULL
+}
+```
+
+### Temperatura
+```csharp
+metar.AirTemperature.ActualValue // Temperatura do ar em Celsius
+metar.DewPointTemperature.ActualValue // Ponto de orvalho em Celsius
+```
+
+### Pressao
+```csharp
+metar.Pressure.ActualValue // Valor da pressao
+metar.Pressure.ActualUnit // Unit.HectoPascal (QNH) ou Unit.MercuryInch (altimetro)
+```
+
+### Tempo Recente
+```csharp
+var tr = metar.RecentWeather;
+tr?.Characteristics // Descritor do tempo
+tr?.Types // Lista de fenomenos
+```
+
+### Cisalhamento de Vento (Wind Shear)
+```csharp
+metar.WindshearAllRunways // true se WS ALL RWY (todas as pistas)
+metar.WindshearRunways // Lista de pistas afetadas
+```
+
+### Tendencia (NOSIG/BECMG/TEMPO)
+```csharp
+metar.TrendType // "NOSIG" (sem mudanca significativa), "BECMG" (tornando-se), ou "TEMPO" (temporario)
+metar.TrendForecast // Conteudo bruto da tendencia
+```
+
+### Observacoes (RMK)
+```csharp
+metar.Remark // Conteudo das observacoes
+metar.SeaLevelPressure // Pressao ao nivel do mar (SLPnnn)
+```
+
+## Conversao de Valores
+
+A classe `Value` suporta conversao de unidades:
+
+```csharp
+var velocidade = metar.SurfaceWind.MeanSpeed;
+double nos = velocidade.GetConvertedValue(Value.Unit.Knot);
+double mps = velocidade.GetConvertedValue(Value.Unit.MeterPerSecond);
+double kph = velocidade.GetConvertedValue(Value.Unit.KilometerPerHour);
+```
+
+## Tratamento de Erros
+
+```csharp
+var metar = decoder.ParseNotStrict("METAR LFPO 231027Z DADOS_INVALIDOS");
+
+if (!metar.IsValid)
+{
+ foreach (var ex in metar.DecodingExceptions)
+ {
+ Console.WriteLine($"Erro no decodificador: {ex.ChunkDecoder.GetType().Name}");
+ Console.WriteLine($"Mensagem: {ex.Message}");
+ Console.WriteLine($"METAR restante: {ex.RemainingMetar}");
+ }
+}
+
+// Limpar erros
+metar.ResetDecodingExceptions();
+```
+
+## Arquitetura
+
+A biblioteca segue os principios de Arquitetura Limpa (Clean Architecture) e SOLID:
+
+- **Padrao ChunkDecoder**: Cadeia de Responsabilidade - cada decodificador trata uma secao do METAR
+- **Segregacao de Interface**: `IMetarChunkDecoder` define o contrato
+- **Responsabilidade Unica**: Cada classe decodificadora trata exatamente um elemento do METAR
+- **Aberto/Fechado**: Novos decodificadores podem ser adicionados sem modificar os existentes
+
+### Ordem da Cadeia de Decodificacao
+1. `ReportTypeChunkDecoder` - METAR/SPECI/COR
+2. `IcaoChunkDecoder` - Codigo ICAO do aerodromo
+3. `DatetimeChunkDecoder` - Dia/hora da observacao
+4. `ReportStatusChunkDecoder` - Status AUTO/NIL
+5. `SurfaceWindChunkDecoder` - Direcao/velocidade/rajadas do vento
+6. `VisibilityChunkDecoder` - CAVOK ou valores de visibilidade
+7. `RunwayVisualRangeChunkDecoder` - RVR das pistas
+8. `PresentWeatherChunkDecoder` - Fenomenos meteorologicos atuais
+9. `CloudChunkDecoder` - Camadas de nuvens
+10. `TemperatureChunkDecoder` - Temperatura do ar/ponto de orvalho
+11. `PressureChunkDecoder` - Ajuste de altimetro (QNH)
+12. `RecentWeatherChunkDecoder` - Tempo recente (RE)
+13. `WindShearChunkDecoder` - Cisalhamento de vento
+14. `TrendChunkDecoder` - Tendencia (NOSIG/BECMG/TEMPO)
+15. `RemarkChunkDecoder` - Secao de observacoes (RMK)
+
+## Elementos METAR Suportados
+
+| Elemento | Exemplo | Suportado |
+|----------|---------|-----------|
+| Tipo de Relatorio | METAR, SPECI, COR | Sim |
+| Codigo ICAO | SBGR, KJFK | Sim |
+| Data/Hora | 231027Z | Sim |
+| Status | AUTO, NIL | Sim |
+| Vento de Superficie | 24004KT, VRB02MPS, 24015G25KT | Sim |
+| Variacao de Direcao | 180V270 | Sim |
+| CAVOK | CAVOK | Sim |
+| Visibilidade (ICAO) | 9999, 2500 | Sim |
+| Visibilidade (EUA) | 3SM, 1 1/2SM | Sim |
+| Visibilidade Minima | 1000NW | Sim |
+| NDV | 9999NDV | Sim |
+| RVR | R32/0400, R06L/0200V0600U | Sim |
+| Tempo Presente | +TSRA, -SN, FZFG, VCSH | Sim |
+| Nuvens | FEW020, SCT030CB, OVC005 | Sim |
+| Visibilidade Vertical | VV003 | Sim |
+| Ceu Claro | SKC, NSC, NCD, CLR | Sim |
+| Temperatura | 17/10, M02/M05 | Sim |
+| Pressao (QNH) | Q1009 | Sim |
+| Pressao (Altimetro) | A2992 | Sim |
+| Tempo Recente | REFZRA | Sim |
+| Cisalhamento de Vento | WS R03, WS ALL RWY | Sim |
+| Tendencia | NOSIG, BECMG, TEMPO | Sim |
+| Observacoes | RMK AO2 SLP013 | Sim |
+| Pressao ao Nivel do Mar | SLPnnn (no RMK) | Sim |
+
+## Glossario de Termos METAR
+
+| Codigo | Significado |
+|--------|-------------|
+| METAR | Relatorio Meteorologico de Aerodromo |
+| SPECI | Relatorio Especial |
+| CAVOK | Teto e Visibilidade OK (vis >10km, sem nuvens abaixo de 5000ft, sem tempo significativo) |
+| NOSIG | Sem Mudanca Significativa |
+| BECMG | Tornando-se (mudanca gradual esperada) |
+| TEMPO | Temporario (flutuacao temporaria) |
+| FEW | Poucas nuvens (1-2 oitavos) |
+| SCT | Esparsas (3-4 oitavos) |
+| BKN | Nublado (5-7 oitavos) |
+| OVC | Encoberto (8 oitavos) |
+| VV | Visibilidade Vertical |
+| CB | Cumulonimbus |
+| TCU | Cumulus em Torre |
+| RA | Chuva |
+| SN | Neve |
+| FG | Nevoeiro |
+| BR | Nevoa |
+| TS | Trovoada |
+| FZ | Congelante |
+| SH | Pancadas |
+| VRB | Variavel |
+| RVR | Alcance Visual de Pista |
+
+## Licenca
+
+MIT License
diff --git a/docs/pt-br/TafDecoder-Guia.md b/docs/pt-br/TafDecoder-Guia.md
new file mode 100644
index 0000000..0beed51
--- /dev/null
+++ b/docs/pt-br/TafDecoder-Guia.md
@@ -0,0 +1,309 @@
+# Taf.Decoder - Guia de Uso (PT-BR)
+
+## Visao Geral
+
+**Taf.Decoder** e uma biblioteca .NET para decodificacao de strings TAF (Terminal Aerodrome Forecast / Previsao de Aerodromo Terminal) em objetos estruturados e fortemente tipados. Suporta multiplos frameworks: `.NET Standard 2.0`, `.NET 8.0`, `.NET 10.0` e `.NET Framework 4.8`.
+
+**Versao:** 1.0.7
+
+## Instalacao
+
+```bash
+dotnet add package Taf.Decoder
+```
+
+Ou pelo NuGet Package Manager:
+
+```
+Install-Package Taf.Decoder
+```
+
+## Inicio Rapido
+
+```csharp
+using Taf.Decoder;
+using Taf.Decoder.Entity;
+
+var decoder = new TafDecoder();
+var taf = decoder.Parse("TAF SBGR 031100Z 0312/0418 35008KT 9999 FEW040 SCT100 TX30/0318Z TN20/0409Z");
+
+Console.WriteLine($"ICAO: {taf.Icao}");
+Console.WriteLine($"Dia: {taf.Day}");
+Console.WriteLine($"Hora: {taf.Time}");
+Console.WriteLine($"Periodo: {taf.ForecastPeriod.FromDay}/{taf.ForecastPeriod.FromHour} ate {taf.ForecastPeriod.ToDay}/{taf.ForecastPeriod.ToHour}");
+Console.WriteLine($"Vento: {taf.SurfaceWind.MeanDirection.ActualValue} graus a {taf.SurfaceWind.MeanSpeed.ActualValue} {taf.SurfaceWind.MeanSpeed.ActualUnit}");
+Console.WriteLine($"Visibilidade: {taf.Visibility.ActualVisibility.ActualValue} {taf.Visibility.ActualVisibility.ActualUnit}");
+```
+
+## Modos de Decodificacao
+
+### Decodificacao Padrao
+```csharp
+var taf = decoder.Parse("TAF LFPO 231100Z 2312/2418 24005KT 9999 FEW030");
+```
+
+### Decodificacao Estrita (Strict)
+Para na primeira falha de decodificacao:
+```csharp
+var taf = decoder.ParseStrict("TAF LFPO 231100Z 2312/2418 24005KT 9999 FEW030");
+```
+
+### Decodificacao Nao-Estrita (Not Strict)
+Continua a decodificacao mesmo encontrando erros:
+```csharp
+var taf = decoder.ParseNotStrict("TAF LFPO 231100Z 2312/2418 INVALIDO 9999 FEW030");
+```
+
+### Decodificacao Estatica
+```csharp
+var taf = TafDecoder.ParseWithMode("TAF LFPO 231100Z 2312/2418 24005KT 9999 FEW030", isStrict: false);
+```
+
+## Campos Decodificados
+
+### Tipo de Relatorio
+```csharp
+taf.Type // TafType.TAF, TafType.TAFAMD (emendado), TafType.TAFCOR (corrigido), TafType.RTD
+```
+
+### Codigo ICAO
+```csharp
+taf.Icao // "SBGR", "LFPO", "KJFK", etc.
+```
+
+### Data/Hora
+```csharp
+taf.Day // Dia do mes (1-31)
+taf.Time // "11:00 UTC"
+taf.OriginDateTime // Objeto DateTime
+```
+
+### Periodo de Previsao
+```csharp
+var periodo = taf.ForecastPeriod;
+periodo.FromDay // Dia inicial
+periodo.FromHour // Hora inicial
+periodo.ToDay // Dia final
+periodo.ToHour // Hora final
+periodo.IsValid // Verificacao de validade
+```
+
+### Vento de Superficie
+```csharp
+var vento = taf.SurfaceWind;
+vento.MeanDirection.ActualValue // Direcao em graus (0-360)
+vento.MeanSpeed.ActualValue // Valor da velocidade
+vento.MeanSpeed.ActualUnit // Unit.Knot, Unit.MeterPerSecond, Unit.KilometerPerHour
+vento.SpeedVariations?.ActualValue // Rajada (se presente)
+vento.VariableDirection // true se VRB (variavel)
+vento.DirectionVariations // [min, max] variacao de direcao
+```
+
+### Visibilidade
+```csharp
+var vis = taf.Visibility;
+vis.ActualVisibility.ActualValue // Valor da visibilidade
+vis.ActualVisibility.ActualUnit // Unit.Meter ou Unit.StatuteMile
+vis.Greater // true se prefixo P (maior que)
+taf.Cavok // CAVOK (teto e visibilidade OK)
+```
+
+### Fenomenos Meteorologicos
+```csharp
+foreach (var fm in taf.WeatherPhenomenons)
+{
+ Console.WriteLine($"Intensidade: {fm.IntensityProximity}"); // +, -, VC
+ Console.WriteLine($"Descritor: {fm.Descriptor}"); // TS, FZ, SH, etc.
+ foreach (var p in fm.Phenomena)
+ {
+ Console.WriteLine($"Fenomeno: {p}"); // RA (chuva), SN (neve), FG (nevoeiro), etc.
+ }
+}
+```
+
+### Nuvens
+```csharp
+foreach (var nuvem in taf.Clouds)
+{
+ Console.WriteLine($"Quantidade: {nuvem.Amount}"); // FEW, SCT, BKN, OVC, VV
+ Console.WriteLine($"Altura: {nuvem.BaseHeight?.ActualValue} pes");
+ Console.WriteLine($"Tipo: {nuvem.Type}"); // CB, TCU, ou NULL
+}
+```
+
+### Previsao de Temperatura
+```csharp
+// Temperatura maxima
+var tempMax = taf.MaximumTemperature;
+if (tempMax != null)
+{
+ Console.WriteLine($"Tipo: {tempMax.Type}"); // "TX"
+ Console.WriteLine($"Valor: {tempMax.TemperatureValue.ActualValue} C");
+ Console.WriteLine($"Dia: {tempMax.Day}, Hora: {tempMax.Hour}");
+}
+
+// Temperatura minima
+var tempMin = taf.MinimumTemperature;
+if (tempMin != null)
+{
+ Console.WriteLine($"Tipo: {tempMin.Type}"); // "TN"
+ Console.WriteLine($"Valor: {tempMin.TemperatureValue.ActualValue} C");
+ Console.WriteLine($"Dia: {tempMin.Day}, Hora: {tempMin.Hour}");
+}
+```
+
+## Evolucoes Meteorologicas (TEMPO/BECMG/FM/PROB)
+
+O TAF inclui secoes de evolucao meteorologica que modificam a previsao base. As evolucoes sao armazenadas em cada entidade:
+
+```csharp
+// Verificar evolucoes de vento
+var evoVento = taf.SurfaceWind.Evolutions;
+foreach (var evo in evoVento)
+{
+ Console.WriteLine($"Tipo: {evo.Type}"); // "TEMPO", "BECMG", "FM"
+ Console.WriteLine($"De: Dia {evo.FromDay} {evo.FromTime}");
+ Console.WriteLine($"Ate: Dia {evo.ToDay} {evo.ToTime}");
+ Console.WriteLine($"Probabilidade: {evo.Probability}"); // "PROB30", "PROB40", ou null
+
+ var ventoEvo = evo.Entity as SurfaceWind;
+ if (ventoEvo != null)
+ {
+ Console.WriteLine($"Novo Vento: {ventoEvo.MeanDirection?.ActualValue} a {ventoEvo.MeanSpeed?.ActualValue}");
+ }
+}
+
+// Verificar evolucoes de visibilidade
+var evoVis = taf.Visibility?.Evolutions;
+// ... mesmo padrao
+
+// Verificar evolucoes de nuvens
+foreach (var nuvem in taf.Clouds)
+{
+ var evoNuvem = nuvem.Evolutions;
+ // ... mesmo padrao
+}
+```
+
+### Tipos de Evolucao
+- **TEMPO**: Flutuacao temporaria com duracao esperada inferior a 1 hora
+- **BECMG**: Mudanca gradual esperada durante o periodo especificado
+- **FM**: A partir de um horario especifico, as condicoes substituem a previsao anterior
+- **PROB30/PROB40**: Probabilidade de ocorrencia (30% ou 40%)
+
+## Conversao de Valores
+
+A classe `Value` suporta conversao de unidades:
+
+```csharp
+var velocidade = taf.SurfaceWind.MeanSpeed;
+double nos = velocidade.GetConvertedValue(Value.Unit.Knot);
+double mps = velocidade.GetConvertedValue(Value.Unit.MeterPerSecond);
+double kph = velocidade.GetConvertedValue(Value.Unit.KilometerPerHour);
+```
+
+## Tratamento de Erros
+
+```csharp
+var taf = decoder.ParseNotStrict("TAF LFPO 231100Z 2312/2418 DADOS_INVALIDOS");
+
+if (!taf.IsValid)
+{
+ foreach (var ex in taf.DecodingExceptions)
+ {
+ Console.WriteLine($"Erro no decodificador: {ex.ChunkDecoder.GetType().Name}");
+ Console.WriteLine($"Mensagem: {ex.Message}");
+ Console.WriteLine($"TAF restante: {ex.RemainingTaf}");
+ }
+}
+
+// Limpar erros
+taf.ResetDecodingExceptions();
+```
+
+## Arquitetura
+
+A biblioteca segue os principios de Arquitetura Limpa (Clean Architecture) e SOLID:
+
+- **Padrao ChunkDecoder**: Cadeia de Responsabilidade - cada decodificador trata uma secao do TAF
+- **Segregacao de Interface**: `ITafChunkDecoder` define o contrato
+- **Responsabilidade Unica**: Cada classe decodificadora trata exatamente um elemento do TAF
+- **Aberto/Fechado**: Novos decodificadores podem ser adicionados sem modificar os existentes
+
+### Cadeia Principal de Decodificacao
+1. `ReportTypeChunkDecoder` - TAF/TAF AMD/TAF COR/RTD
+2. `IcaoChunkDecoder` - Codigo ICAO do aerodromo
+3. `DatetimeChunkDecoder` - Dia/hora de emissao
+4. `ForecastPeriodChunkDecoder` - Periodo de validade (ex: 0312/0418)
+5. `SurfaceWindChunkDecoder` - Direcao/velocidade/rajadas do vento
+6. `VisibilityChunkDecoder` - CAVOK ou valores de visibilidade
+7. `WeatherChunkDecoder` - Fenomenos meteorologicos
+8. `CloudChunkDecoder` - Camadas de nuvens
+9. `TemperatureChunkDecoder` - Temperaturas TX/TN
+
+### Decodificador de Evolucao
+Apos a cadeia principal, `EvolutionChunkDecoder` processa:
+- `TEMPO` - Mudancas temporarias
+- `BECMG` - Mudancas graduais (tornando-se)
+- `FM` - A partir de determinado horario
+- `PROB30/PROB40` - Grupos de probabilidade
+
+## Elementos TAF Suportados
+
+| Elemento | Exemplo | Suportado |
+|----------|---------|-----------|
+| Tipo de Relatorio | TAF, TAF AMD, TAF COR, RTD | Sim |
+| Codigo ICAO | SBGR, KJFK | Sim |
+| Data/Hora | 231100Z | Sim |
+| Periodo de Previsao | 2312/2418 | Sim |
+| Vento de Superficie | 24005KT, VRB03MPS, 24015G25KT | Sim |
+| Variacao de Direcao | 180V270 | Sim |
+| CAVOK | CAVOK | Sim |
+| Visibilidade (ICAO) | 9999, 2500 | Sim |
+| Visibilidade (EUA) | 3SM, 1 1/2SM, P6SM | Sim |
+| Sem Info Visibilidade | //// | Sim |
+| Fenomenos Meteorologicos | -RA, +TSRA, FZFG | Sim |
+| Nuvens | FEW020, SCT030CB, OVC005 | Sim |
+| Visibilidade Vertical | VV003 | Sim |
+| Ceu Claro | SKC, NSC, NCD, CLR | Sim |
+| Temperatura Maxima | TX25/0318Z | Sim |
+| Temperatura Minima | TNM03/0405Z | Sim |
+| TEMPO | TEMPO 0312/0315 ... | Sim |
+| BECMG | BECMG 0315/0317 ... | Sim |
+| FM | FM031500 ... | Sim |
+| PROB30/PROB40 | PROB40 TEMPO ... | Sim |
+
+## Glossario de Termos TAF
+
+| Codigo | Significado |
+|--------|-------------|
+| TAF | Previsao de Aerodromo Terminal |
+| AMD | Emenda (forecast emendado) |
+| COR | Correcao (forecast corrigido) |
+| RTD | Retardado (forecast atrasado) |
+| CAVOK | Teto e Visibilidade OK |
+| TEMPO | Temporario (flutuacao temporaria) |
+| BECMG | Tornando-se (mudanca gradual) |
+| FM | A partir de (mudanca completa) |
+| PROB | Probabilidade |
+| FEW | Poucas nuvens (1-2 oitavos) |
+| SCT | Esparsas (3-4 oitavos) |
+| BKN | Nublado (5-7 oitavos) |
+| OVC | Encoberto (8 oitavos) |
+| VV | Visibilidade Vertical |
+| CB | Cumulonimbus |
+| TCU | Cumulus em Torre |
+| TX | Temperatura Maxima |
+| TN | Temperatura Minima |
+| RA | Chuva |
+| SN | Neve |
+| FG | Nevoeiro |
+| BR | Nevoa |
+| TS | Trovoada |
+| FZ | Congelante |
+| SH | Pancadas |
+| VRB | Variavel |
+
+## Licenca
+
+MIT License
diff --git a/src/Metar.Decoder/ChunkDecoder/Abstract/IMetarChunkDecoder.cs b/src/Metar.Decoder/ChunkDecoder/Abstract/IMetarChunkDecoder.cs
index 7a32ee3..51c9f14 100644
--- a/src/Metar.Decoder/ChunkDecoder/Abstract/IMetarChunkDecoder.cs
+++ b/src/Metar.Decoder/ChunkDecoder/Abstract/IMetarChunkDecoder.cs
@@ -1,6 +1,6 @@
using System.Collections.Generic;
-namespace Metar.Decoder.Chunkdecoder
+namespace Metar.Decoder.ChunkDecoder
{
public interface IMetarChunkDecoder
{
diff --git a/src/Metar.Decoder/ChunkDecoder/Abstract/MetarChunkDecoder.cs b/src/Metar.Decoder/ChunkDecoder/Abstract/MetarChunkDecoder.cs
index f4cacef..ca39ad4 100644
--- a/src/Metar.Decoder/ChunkDecoder/Abstract/MetarChunkDecoder.cs
+++ b/src/Metar.Decoder/ChunkDecoder/Abstract/MetarChunkDecoder.cs
@@ -3,7 +3,7 @@
using System.Linq;
using System.Text.RegularExpressions;
-namespace Metar.Decoder.Chunkdecoder
+namespace Metar.Decoder.ChunkDecoder
{
public abstract class MetarChunkDecoder : IMetarChunkDecoder
{
diff --git a/src/Metar.Decoder/ChunkDecoder/CloudChunkDecoder.cs b/src/Metar.Decoder/ChunkDecoder/CloudChunkDecoder.cs
index e132ed2..1a57abb 100644
--- a/src/Metar.Decoder/ChunkDecoder/CloudChunkDecoder.cs
+++ b/src/Metar.Decoder/ChunkDecoder/CloudChunkDecoder.cs
@@ -1,7 +1,7 @@
using Metar.Decoder.Entity;
using System.Collections.Generic;
-namespace Metar.Decoder.Chunkdecoder
+namespace Metar.Decoder.ChunkDecoder
{
public sealed class CloudChunkDecoder : MetarChunkDecoder
{
diff --git a/src/Metar.Decoder/ChunkDecoder/DatetimeChunkDecoder.cs b/src/Metar.Decoder/ChunkDecoder/DatetimeChunkDecoder.cs
index f2ff3b5..f4953a8 100644
--- a/src/Metar.Decoder/ChunkDecoder/DatetimeChunkDecoder.cs
+++ b/src/Metar.Decoder/ChunkDecoder/DatetimeChunkDecoder.cs
@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
-namespace Metar.Decoder.Chunkdecoder
+namespace Metar.Decoder.ChunkDecoder
{
public sealed class DatetimeChunkDecoder : MetarChunkDecoder
{
diff --git a/src/Metar.Decoder/ChunkDecoder/IcaoChunkDecoder.cs b/src/Metar.Decoder/ChunkDecoder/IcaoChunkDecoder.cs
index 9c8930a..5021c18 100644
--- a/src/Metar.Decoder/ChunkDecoder/IcaoChunkDecoder.cs
+++ b/src/Metar.Decoder/ChunkDecoder/IcaoChunkDecoder.cs
@@ -1,6 +1,6 @@
using System.Collections.Generic;
-namespace Metar.Decoder.Chunkdecoder
+namespace Metar.Decoder.ChunkDecoder
{
public sealed class IcaoChunkDecoder : MetarChunkDecoder
{
diff --git a/src/Metar.Decoder/ChunkDecoder/PresentWeatherChunkDecoder.cs b/src/Metar.Decoder/ChunkDecoder/PresentWeatherChunkDecoder.cs
index e20b090..1854552 100644
--- a/src/Metar.Decoder/ChunkDecoder/PresentWeatherChunkDecoder.cs
+++ b/src/Metar.Decoder/ChunkDecoder/PresentWeatherChunkDecoder.cs
@@ -1,7 +1,7 @@
using Metar.Decoder.Entity;
using System.Collections.Generic;
-namespace Metar.Decoder.Chunkdecoder
+namespace Metar.Decoder.ChunkDecoder
{
public sealed class PresentWeatherChunkDecoder : MetarChunkDecoder
{
diff --git a/src/Metar.Decoder/ChunkDecoder/PressureChunkDecoder.cs b/src/Metar.Decoder/ChunkDecoder/PressureChunkDecoder.cs
index 5fb693e..cca9b2a 100644
--- a/src/Metar.Decoder/ChunkDecoder/PressureChunkDecoder.cs
+++ b/src/Metar.Decoder/ChunkDecoder/PressureChunkDecoder.cs
@@ -2,7 +2,7 @@
using System.Collections.Generic;
using static Metar.Decoder.Entity.Value;
-namespace Metar.Decoder.Chunkdecoder
+namespace Metar.Decoder.ChunkDecoder
{
///
/// Chunk decoder for atmospheric pressure section.
diff --git a/src/Metar.Decoder/ChunkDecoder/RecentWeatherChunkDecoder.cs b/src/Metar.Decoder/ChunkDecoder/RecentWeatherChunkDecoder.cs
index ebd4127..eda0293 100644
--- a/src/Metar.Decoder/ChunkDecoder/RecentWeatherChunkDecoder.cs
+++ b/src/Metar.Decoder/ChunkDecoder/RecentWeatherChunkDecoder.cs
@@ -1,7 +1,7 @@
using Metar.Decoder.Entity;
using System.Collections.Generic;
-namespace Metar.Decoder.Chunkdecoder
+namespace Metar.Decoder.ChunkDecoder
{
public sealed class RecentWeatherChunkDecoder : MetarChunkDecoder
{
diff --git a/src/Metar.Decoder/ChunkDecoder/RemarkChunkDecoder.cs b/src/Metar.Decoder/ChunkDecoder/RemarkChunkDecoder.cs
new file mode 100644
index 0000000..9732749
--- /dev/null
+++ b/src/Metar.Decoder/ChunkDecoder/RemarkChunkDecoder.cs
@@ -0,0 +1,49 @@
+using System.Collections.Generic;
+
+namespace Metar.Decoder.ChunkDecoder
+{
+ ///
+ /// Chunk decoder for METAR remarks section (RMK).
+ /// Per ICAO Annex 3, the remarks section contains supplementary information
+ /// including sea-level pressure (SLPnnn), hourly precipitation, etc.
+ ///
+ public sealed class RemarkChunkDecoder : MetarChunkDecoder
+ {
+ public const string RemarkParameterName = "Remark";
+ public const string SeaLevelPressureParameterName = "SeaLevelPressure";
+
+ public override string GetRegex()
+ {
+ return @"^RMK (.*)";
+ }
+
+ public override Dictionary Parse(string remainingMetar, bool withCavok = false)
+ {
+ var consumed = Consume(remainingMetar);
+ var found = consumed.Value;
+ var newRemainingMetar = consumed.Key;
+ var result = new Dictionary();
+
+ if (found.Count > 1)
+ {
+ var remarkContent = found[1].Value.Trim();
+ result.Add(RemarkParameterName, remarkContent);
+
+ // Try to extract sea-level pressure (SLPnnn)
+ var slpMatch = System.Text.RegularExpressions.Regex.Match(
+ remarkContent,
+ @"SLP(\d{3})",
+ System.Text.RegularExpressions.RegexOptions.None,
+ System.TimeSpan.FromMilliseconds(500));
+ if (slpMatch.Success)
+ {
+ var slpValue = int.Parse(slpMatch.Groups[1].Value);
+ double pressureHpa = slpValue >= 500 ? (900.0 + slpValue / 10.0) : (1000.0 + slpValue / 10.0);
+ result.Add(SeaLevelPressureParameterName, new Entity.Value(pressureHpa, Entity.Value.Unit.HectoPascal));
+ }
+ }
+
+ return GetResults(newRemainingMetar, result);
+ }
+ }
+}
diff --git a/src/Metar.Decoder/ChunkDecoder/ReportStatusChunkDecoder.cs b/src/Metar.Decoder/ChunkDecoder/ReportStatusChunkDecoder.cs
index f04fca5..a3d4208 100644
--- a/src/Metar.Decoder/ChunkDecoder/ReportStatusChunkDecoder.cs
+++ b/src/Metar.Decoder/ChunkDecoder/ReportStatusChunkDecoder.cs
@@ -1,6 +1,6 @@
using System.Collections.Generic;
-namespace Metar.Decoder.Chunkdecoder
+namespace Metar.Decoder.ChunkDecoder
{
public sealed class ReportStatusChunkDecoder : MetarChunkDecoder
{
diff --git a/src/Metar.Decoder/ChunkDecoder/ReportTypeChunkDecoder.cs b/src/Metar.Decoder/ChunkDecoder/ReportTypeChunkDecoder.cs
index ca0cc76..194cd7b 100644
--- a/src/Metar.Decoder/ChunkDecoder/ReportTypeChunkDecoder.cs
+++ b/src/Metar.Decoder/ChunkDecoder/ReportTypeChunkDecoder.cs
@@ -1,7 +1,7 @@
using System.Collections.Generic;
using static Metar.Decoder.Entity.DecodedMetar;
-namespace Metar.Decoder.Chunkdecoder
+namespace Metar.Decoder.ChunkDecoder
{
public sealed class ReportTypeChunkDecoder : MetarChunkDecoder
{
diff --git a/src/Metar.Decoder/ChunkDecoder/RunwayVisualRangeChunkDecoder.cs b/src/Metar.Decoder/ChunkDecoder/RunwayVisualRangeChunkDecoder.cs
index dd5f490..b3fd5c3 100644
--- a/src/Metar.Decoder/ChunkDecoder/RunwayVisualRangeChunkDecoder.cs
+++ b/src/Metar.Decoder/ChunkDecoder/RunwayVisualRangeChunkDecoder.cs
@@ -2,7 +2,7 @@
using System.Collections.Generic;
using static Metar.Decoder.Entity.RunwayVisualRange;
-namespace Metar.Decoder.Chunkdecoder
+namespace Metar.Decoder.ChunkDecoder
{
public sealed class RunwayVisualRangeChunkDecoder : MetarChunkDecoder
{
diff --git a/src/Metar.Decoder/ChunkDecoder/SurfaceWindChunkDecoder.cs b/src/Metar.Decoder/ChunkDecoder/SurfaceWindChunkDecoder.cs
index 0c376ea..dbd5344 100644
--- a/src/Metar.Decoder/ChunkDecoder/SurfaceWindChunkDecoder.cs
+++ b/src/Metar.Decoder/ChunkDecoder/SurfaceWindChunkDecoder.cs
@@ -1,7 +1,7 @@
using Metar.Decoder.Entity;
using System.Collections.Generic;
-namespace Metar.Decoder.Chunkdecoder
+namespace Metar.Decoder.ChunkDecoder
{
public sealed class SurfaceWindChunkDecoder : MetarChunkDecoder
{
diff --git a/src/Metar.Decoder/ChunkDecoder/TemperatureChunkDecoder.cs b/src/Metar.Decoder/ChunkDecoder/TemperatureChunkDecoder.cs
index dbc38ca..a5268c9 100644
--- a/src/Metar.Decoder/ChunkDecoder/TemperatureChunkDecoder.cs
+++ b/src/Metar.Decoder/ChunkDecoder/TemperatureChunkDecoder.cs
@@ -1,7 +1,7 @@
using Metar.Decoder.Entity;
using System.Collections.Generic;
-namespace Metar.Decoder.Chunkdecoder
+namespace Metar.Decoder.ChunkDecoder
{
public sealed class TemperatureChunkDecoder : MetarChunkDecoder
{
diff --git a/src/Metar.Decoder/ChunkDecoder/TrendChunkDecoder.cs b/src/Metar.Decoder/ChunkDecoder/TrendChunkDecoder.cs
new file mode 100644
index 0000000..9867dd6
--- /dev/null
+++ b/src/Metar.Decoder/ChunkDecoder/TrendChunkDecoder.cs
@@ -0,0 +1,52 @@
+using Metar.Decoder.Entity;
+using System.Collections.Generic;
+
+namespace Metar.Decoder.ChunkDecoder
+{
+ ///
+ /// Chunk decoder for METAR trend forecast section (NOSIG, BECMG, TEMPO).
+ /// Per ICAO Annex 3, METAR can include a trend forecast indicating expected changes.
+ ///
+ public sealed class TrendChunkDecoder : MetarChunkDecoder
+ {
+ public const string TrendForecastParameterName = "TrendForecast";
+ public const string TrendTypeParameterName = "TrendType";
+
+ public override string GetRegex()
+ {
+ return @"^(NOSIG|BECMG\s+.*|TEMPO\s+.*)( )";
+ }
+
+ public override Dictionary Parse(string remainingMetar, bool withCavok = false)
+ {
+ var consumed = Consume(remainingMetar);
+ var found = consumed.Value;
+ var newRemainingMetar = consumed.Key;
+ var result = new Dictionary();
+
+ if (found.Count > 1)
+ {
+ var trendRaw = found[1].Value.Trim();
+ string trendType;
+
+ if (trendRaw.StartsWith("NOSIG"))
+ {
+ trendType = "NOSIG";
+ }
+ else if (trendRaw.StartsWith("BECMG"))
+ {
+ trendType = "BECMG";
+ }
+ else
+ {
+ trendType = "TEMPO";
+ }
+
+ result.Add(TrendTypeParameterName, trendType);
+ result.Add(TrendForecastParameterName, trendRaw);
+ }
+
+ return GetResults(newRemainingMetar, result);
+ }
+ }
+}
diff --git a/src/Metar.Decoder/ChunkDecoder/VisibilityChunkDecoder.cs b/src/Metar.Decoder/ChunkDecoder/VisibilityChunkDecoder.cs
index 1d5adcd..d6b9a32 100644
--- a/src/Metar.Decoder/ChunkDecoder/VisibilityChunkDecoder.cs
+++ b/src/Metar.Decoder/ChunkDecoder/VisibilityChunkDecoder.cs
@@ -2,7 +2,7 @@
using System;
using System.Collections.Generic;
-namespace Metar.Decoder.Chunkdecoder
+namespace Metar.Decoder.ChunkDecoder
{
public sealed class VisibilityChunkDecoder : MetarChunkDecoder
{
diff --git a/src/Metar.Decoder/ChunkDecoder/WindShearChunkDecoder.cs b/src/Metar.Decoder/ChunkDecoder/WindShearChunkDecoder.cs
index e1f12ad..dbd3da3 100644
--- a/src/Metar.Decoder/ChunkDecoder/WindShearChunkDecoder.cs
+++ b/src/Metar.Decoder/ChunkDecoder/WindShearChunkDecoder.cs
@@ -1,7 +1,7 @@
using Metar.Decoder.Entity;
using System.Collections.Generic;
-namespace Metar.Decoder.Chunkdecoder
+namespace Metar.Decoder.ChunkDecoder
{
public sealed class WindShearChunkDecoder : MetarChunkDecoder
{
diff --git a/src/Metar.Decoder/Entity/DecodedMetar.cs b/src/Metar.Decoder/Entity/DecodedMetar.cs
index 039fe02..ac0b2c7 100644
--- a/src/Metar.Decoder/Entity/DecodedMetar.cs
+++ b/src/Metar.Decoder/Entity/DecodedMetar.cs
@@ -150,7 +150,27 @@ public ReadOnlyCollection DecodingExceptions
///
public List WindshearRunways { get; set; }
- internal DecodedMetar(string rawMetar = "")
+ ///
+ /// Trend forecast type (NOSIG, BECMG, TEMPO)
+ ///
+ public string TrendType { get; set; } = string.Empty;
+
+ ///
+ /// Trend forecast raw content
+ ///
+ public string TrendForecast { get; set; } = string.Empty;
+
+ ///
+ /// Remarks section raw content (after RMK)
+ ///
+ public string Remark { get; set; } = string.Empty;
+
+ ///
+ /// Sea-level pressure extracted from remarks (SLPnnn)
+ ///
+ public Value SeaLevelPressure { get; set; }
+
+ public DecodedMetar(string rawMetar = "")
{
RawMetar = rawMetar;
}
diff --git a/src/Metar.Decoder/Exception/MetarChunkDecoderException.cs b/src/Metar.Decoder/Exception/MetarChunkDecoderException.cs
index acd5f81..9f4fb86 100644
--- a/src/Metar.Decoder/Exception/MetarChunkDecoderException.cs
+++ b/src/Metar.Decoder/Exception/MetarChunkDecoderException.cs
@@ -1,4 +1,4 @@
-using Metar.Decoder.Chunkdecoder;
+using Metar.Decoder.ChunkDecoder;
using System;
using System.Runtime.Serialization;
using System.Security.Permissions;
diff --git a/src/Metar.Decoder/Metar.Decoder.csproj b/src/Metar.Decoder/Metar.Decoder.csproj
index d02a51e..4238839 100644
--- a/src/Metar.Decoder/Metar.Decoder.csproj
+++ b/src/Metar.Decoder/Metar.Decoder.csproj
@@ -1,7 +1,7 @@
netstandard2.0;net8.0;net10.0;net48
- 1.0.8
+ 1.0.9
$(NoWarn);CS1591;SYSLIB0001;SYSLIB0002;SYSLIB0003
https://github.com/afonsoft/metar-decoder
git
diff --git a/src/Metar.Decoder/MetarDecoder.cs b/src/Metar.Decoder/MetarDecoder.cs
index f690466..d394800 100644
--- a/src/Metar.Decoder/MetarDecoder.cs
+++ b/src/Metar.Decoder/MetarDecoder.cs
@@ -1,4 +1,4 @@
-using Metar.Decoder.Chunkdecoder;
+using Metar.Decoder.ChunkDecoder;
using Metar.Decoder.Entity;
using System;
using System.Collections.Generic;
@@ -40,6 +40,8 @@ public MetarDecoder()
new PressureChunkDecoder(),
new RecentWeatherChunkDecoder(),
new WindShearChunkDecoder(),
+ new TrendChunkDecoder(),
+ new RemarkChunkDecoder(),
});
private bool _globalStrictParsing = false;
diff --git a/src/Taf.Decoder/ChunkDecoder/Abstract/ITafChunkDecoder.cs b/src/Taf.Decoder/ChunkDecoder/Abstract/ITafChunkDecoder.cs
index a6cfdec..60cd53b 100644
--- a/src/Taf.Decoder/ChunkDecoder/Abstract/ITafChunkDecoder.cs
+++ b/src/Taf.Decoder/ChunkDecoder/Abstract/ITafChunkDecoder.cs
@@ -1,6 +1,6 @@
using System.Collections.Generic;
-namespace Taf.Decoder.chunkdecoder
+namespace Taf.Decoder.ChunkDecoder
{
public interface ITafChunkDecoder
{
diff --git a/src/Taf.Decoder/ChunkDecoder/Abstract/TafChunkDecoder.cs b/src/Taf.Decoder/ChunkDecoder/Abstract/TafChunkDecoder.cs
index b1b9e35..99d268a 100644
--- a/src/Taf.Decoder/ChunkDecoder/Abstract/TafChunkDecoder.cs
+++ b/src/Taf.Decoder/ChunkDecoder/Abstract/TafChunkDecoder.cs
@@ -3,7 +3,7 @@
using System.Linq;
using System.Text.RegularExpressions;
-namespace Taf.Decoder.chunkdecoder
+namespace Taf.Decoder.ChunkDecoder
{
public abstract class TafChunkDecoder : ITafChunkDecoder
{
diff --git a/src/Taf.Decoder/ChunkDecoder/CloudChunkDecoder.cs b/src/Taf.Decoder/ChunkDecoder/CloudChunkDecoder.cs
index 4e14127..9fc0031 100644
--- a/src/Taf.Decoder/ChunkDecoder/CloudChunkDecoder.cs
+++ b/src/Taf.Decoder/ChunkDecoder/CloudChunkDecoder.cs
@@ -1,7 +1,7 @@
using System.Collections.Generic;
-using Taf.Decoder.entity;
+using Taf.Decoder.Entity;
-namespace Taf.Decoder.chunkdecoder
+namespace Taf.Decoder.ChunkDecoder
{
public sealed class CloudChunkDecoder : TafChunkDecoder
{
diff --git a/src/Taf.Decoder/ChunkDecoder/DatetimeChunkDecoder.cs b/src/Taf.Decoder/ChunkDecoder/DatetimeChunkDecoder.cs
index cb93602..747e226 100644
--- a/src/Taf.Decoder/ChunkDecoder/DatetimeChunkDecoder.cs
+++ b/src/Taf.Decoder/ChunkDecoder/DatetimeChunkDecoder.cs
@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
-namespace Taf.Decoder.chunkdecoder
+namespace Taf.Decoder.ChunkDecoder
{
public sealed class DatetimeChunkDecoder : TafChunkDecoder
{
@@ -31,7 +31,7 @@ public override Dictionary Parse(string remainingTaf, bool withC
var hour = Convert.ToInt32(found[2].Value);
var minute = Convert.ToInt32(found[3].Value);
- if (!checkValidity(day, hour, minute))
+ if (!CheckValidity(day, hour, minute))
{
throw new TafChunkDecoderException(remainingTaf, newRemainingTaf, TafChunkDecoderException.Messages.InvalidDayHourMinuteRanges, this);
}
@@ -70,7 +70,7 @@ public override Dictionary Parse(string remainingTaf, bool withC
///
///
///
- private bool checkValidity(int day, int hour, int minute)
+ private bool CheckValidity(int day, int hour, int minute)
{
// check value range
if (day < 1 || day > 31)
diff --git a/src/Taf.Decoder/ChunkDecoder/EvolutionChunkDecoder.cs b/src/Taf.Decoder/ChunkDecoder/EvolutionChunkDecoder.cs
index f7afacc..075f8d2 100644
--- a/src/Taf.Decoder/ChunkDecoder/EvolutionChunkDecoder.cs
+++ b/src/Taf.Decoder/ChunkDecoder/EvolutionChunkDecoder.cs
@@ -3,9 +3,9 @@
using System.Collections.ObjectModel;
using System.Linq;
using System.Text.RegularExpressions;
-using Taf.Decoder.entity;
+using Taf.Decoder.Entity;
-namespace Taf.Decoder.chunkdecoder
+namespace Taf.Decoder.ChunkDecoder
{
public sealed class EvolutionChunkDecoder : TafChunkDecoder
{
diff --git a/src/Taf.Decoder/ChunkDecoder/ForecastPeriodChunkDecoder.cs b/src/Taf.Decoder/ChunkDecoder/ForecastPeriodChunkDecoder.cs
index 1967a00..cacb1f7 100644
--- a/src/Taf.Decoder/ChunkDecoder/ForecastPeriodChunkDecoder.cs
+++ b/src/Taf.Decoder/ChunkDecoder/ForecastPeriodChunkDecoder.cs
@@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
-using Taf.Decoder.entity;
+using Taf.Decoder.Entity;
-namespace Taf.Decoder.chunkdecoder
+namespace Taf.Decoder.ChunkDecoder
{
public class ForecastPeriodChunkDecoder : TafChunkDecoder
{
diff --git a/src/Taf.Decoder/ChunkDecoder/IcaoChunkDecoder.cs b/src/Taf.Decoder/ChunkDecoder/IcaoChunkDecoder.cs
index 7479b90..fecd876 100644
--- a/src/Taf.Decoder/ChunkDecoder/IcaoChunkDecoder.cs
+++ b/src/Taf.Decoder/ChunkDecoder/IcaoChunkDecoder.cs
@@ -1,6 +1,6 @@
using System.Collections.Generic;
-namespace Taf.Decoder.chunkdecoder
+namespace Taf.Decoder.ChunkDecoder
{
public sealed class IcaoChunkDecoder : TafChunkDecoder
{
diff --git a/src/Taf.Decoder/ChunkDecoder/ReportTypeChunkDecoder.cs b/src/Taf.Decoder/ChunkDecoder/ReportTypeChunkDecoder.cs
index 063d92e..73e6289 100644
--- a/src/Taf.Decoder/ChunkDecoder/ReportTypeChunkDecoder.cs
+++ b/src/Taf.Decoder/ChunkDecoder/ReportTypeChunkDecoder.cs
@@ -1,7 +1,8 @@
using System;
using System.Collections.Generic;
+using Taf.Decoder.Entity;
-namespace Taf.Decoder.chunkdecoder
+namespace Taf.Decoder.ChunkDecoder
{
public sealed class ReportTypeChunkDecoder : TafChunkDecoder
{
@@ -21,13 +22,13 @@ public override Dictionary Parse(string remainingTaf, bool withC
// handle the case where nothing has been found
if (found.Count <= 1)
{
- result.Add(TypeParameterName, entity.DecodedTaf.TafType.NULL);
+ result.Add(TypeParameterName, DecodedTaf.TafType.NULL);
}
else
{
// retrieve found params
// 'TAF' sometimes happens to be duplicated
- result.Add(TypeParameterName, (entity.DecodedTaf.TafType)Enum.Parse(typeof(entity.DecodedTaf.TafType), found[1].Value.Replace("TAF TAF", "TAF").Replace(" ", string.Empty)));
+ result.Add(TypeParameterName, (DecodedTaf.TafType)Enum.Parse(typeof(DecodedTaf.TafType), found[1].Value.Replace("TAF TAF", "TAF").Replace(" ", string.Empty)));
}
return GetResults(newRemainingTaf, result);
diff --git a/src/Taf.Decoder/ChunkDecoder/SurfaceWindChunkDecoder.cs b/src/Taf.Decoder/ChunkDecoder/SurfaceWindChunkDecoder.cs
index 267bb62..557a388 100644
--- a/src/Taf.Decoder/ChunkDecoder/SurfaceWindChunkDecoder.cs
+++ b/src/Taf.Decoder/ChunkDecoder/SurfaceWindChunkDecoder.cs
@@ -1,7 +1,7 @@
using System.Collections.Generic;
-using Taf.Decoder.entity;
+using Taf.Decoder.Entity;
-namespace Taf.Decoder.chunkdecoder
+namespace Taf.Decoder.ChunkDecoder
{
public sealed class SurfaceWindChunkDecoder : TafChunkDecoder
{
diff --git a/src/Taf.Decoder/ChunkDecoder/TemperatureChunkDecoder.cs b/src/Taf.Decoder/ChunkDecoder/TemperatureChunkDecoder.cs
index d0d4302..aef6ba6 100644
--- a/src/Taf.Decoder/ChunkDecoder/TemperatureChunkDecoder.cs
+++ b/src/Taf.Decoder/ChunkDecoder/TemperatureChunkDecoder.cs
@@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
-using Taf.Decoder.entity;
+using Taf.Decoder.Entity;
-namespace Taf.Decoder.chunkdecoder
+namespace Taf.Decoder.ChunkDecoder
{
public sealed class TemperatureChunkDecoder : TafChunkDecoder
{
diff --git a/src/Taf.Decoder/ChunkDecoder/VisibilityChunkDecoder.cs b/src/Taf.Decoder/ChunkDecoder/VisibilityChunkDecoder.cs
index 4ff9a4c..45dd0ab 100644
--- a/src/Taf.Decoder/ChunkDecoder/VisibilityChunkDecoder.cs
+++ b/src/Taf.Decoder/ChunkDecoder/VisibilityChunkDecoder.cs
@@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
-using Taf.Decoder.entity;
+using Taf.Decoder.Entity;
-namespace Taf.Decoder.chunkdecoder
+namespace Taf.Decoder.ChunkDecoder
{
public sealed class VisibilityChunkDecoder : TafChunkDecoder
{
diff --git a/src/Taf.Decoder/ChunkDecoder/WeatherChunkDecoder.cs b/src/Taf.Decoder/ChunkDecoder/WeatherChunkDecoder.cs
index 404d4ed..6a55ba1 100644
--- a/src/Taf.Decoder/ChunkDecoder/WeatherChunkDecoder.cs
+++ b/src/Taf.Decoder/ChunkDecoder/WeatherChunkDecoder.cs
@@ -1,7 +1,7 @@
using System.Collections.Generic;
-using Taf.Decoder.entity;
+using Taf.Decoder.Entity;
-namespace Taf.Decoder.chunkdecoder
+namespace Taf.Decoder.ChunkDecoder
{
public sealed class WeatherChunkDecoder : TafChunkDecoder
{
diff --git a/src/Taf.Decoder/Entity/BaseEntity.cs b/src/Taf.Decoder/Entity/AbstractEntity.cs
similarity index 91%
rename from src/Taf.Decoder/Entity/BaseEntity.cs
rename to src/Taf.Decoder/Entity/AbstractEntity.cs
index 8eeaa64..3da6088 100644
--- a/src/Taf.Decoder/Entity/BaseEntity.cs
+++ b/src/Taf.Decoder/Entity/AbstractEntity.cs
@@ -1,6 +1,6 @@
using System.Collections.Generic;
-namespace Taf.Decoder.entity
+namespace Taf.Decoder.Entity
{
public class AbstractEntity
{
diff --git a/src/Taf.Decoder/Entity/CloudLayer.cs b/src/Taf.Decoder/Entity/CloudLayer.cs
index 551e76a..40e9cd6 100644
--- a/src/Taf.Decoder/Entity/CloudLayer.cs
+++ b/src/Taf.Decoder/Entity/CloudLayer.cs
@@ -1,6 +1,6 @@
using System.ComponentModel;
-namespace Taf.Decoder.entity
+namespace Taf.Decoder.Entity
{
public sealed class CloudLayer : AbstractEntity
{
diff --git a/src/Taf.Decoder/Entity/DecodedTaf.cs b/src/Taf.Decoder/Entity/DecodedTaf.cs
index 9fed6b9..24f21c8 100644
--- a/src/Taf.Decoder/Entity/DecodedTaf.cs
+++ b/src/Taf.Decoder/Entity/DecodedTaf.cs
@@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
-namespace Taf.Decoder.entity
+namespace Taf.Decoder.Entity
{
public sealed class DecodedTaf : AbstractEntity
{
@@ -117,7 +117,7 @@ public ReadOnlyCollection DecodingExceptions
///
public Temperature MaximumTemperature { get; set; }
- internal DecodedTaf(string rawTaf = "")
+ public DecodedTaf(string rawTaf = "")
{
RawTaf = rawTaf;
}
diff --git a/src/Taf.Decoder/Entity/Evolution.cs b/src/Taf.Decoder/Entity/Evolution.cs
index ccd84f3..81a9ce4 100644
--- a/src/Taf.Decoder/Entity/Evolution.cs
+++ b/src/Taf.Decoder/Entity/Evolution.cs
@@ -1,6 +1,6 @@
using System;
-namespace Taf.Decoder.entity
+namespace Taf.Decoder.Entity
{
public class Evolution : AbstractEntity, ICloneable
{
diff --git a/src/Taf.Decoder/Entity/ForecastPeriod.cs b/src/Taf.Decoder/Entity/ForecastPeriod.cs
index ca9bf7a..33fe2d3 100644
--- a/src/Taf.Decoder/Entity/ForecastPeriod.cs
+++ b/src/Taf.Decoder/Entity/ForecastPeriod.cs
@@ -1,4 +1,4 @@
-namespace Taf.Decoder.entity
+namespace Taf.Decoder.Entity
{
public sealed class ForecastPeriod
{
diff --git a/src/Taf.Decoder/Entity/SurfaceWind.cs b/src/Taf.Decoder/Entity/SurfaceWind.cs
index db3f6d5..42a8ec3 100644
--- a/src/Taf.Decoder/Entity/SurfaceWind.cs
+++ b/src/Taf.Decoder/Entity/SurfaceWind.cs
@@ -1,4 +1,4 @@
-namespace Taf.Decoder.entity
+namespace Taf.Decoder.Entity
{
public sealed class SurfaceWind : AbstractEntity
{
diff --git a/src/Taf.Decoder/Entity/Temperature.cs b/src/Taf.Decoder/Entity/Temperature.cs
index bf978e2..41454b0 100644
--- a/src/Taf.Decoder/Entity/Temperature.cs
+++ b/src/Taf.Decoder/Entity/Temperature.cs
@@ -1,4 +1,4 @@
-namespace Taf.Decoder.entity
+namespace Taf.Decoder.Entity
{
public class Temperature : AbstractEntity
{
diff --git a/src/Taf.Decoder/Entity/Value.cs b/src/Taf.Decoder/Entity/Value.cs
index 2611d5a..654dc9f 100644
--- a/src/Taf.Decoder/Entity/Value.cs
+++ b/src/Taf.Decoder/Entity/Value.cs
@@ -4,7 +4,7 @@
using System.Diagnostics;
using System.Text.RegularExpressions;
-namespace Taf.Decoder.entity
+namespace Taf.Decoder.Entity
{
[DebuggerDisplay("{ActualValue} {ActualUnit}")]
public sealed class Value
diff --git a/src/Taf.Decoder/Entity/Visibility.cs b/src/Taf.Decoder/Entity/Visibility.cs
index fc3937e..1b34234 100644
--- a/src/Taf.Decoder/Entity/Visibility.cs
+++ b/src/Taf.Decoder/Entity/Visibility.cs
@@ -1,4 +1,4 @@
-namespace Taf.Decoder.entity
+namespace Taf.Decoder.Entity
{
public sealed class Visibility : AbstractEntity
{
diff --git a/src/Taf.Decoder/Entity/WeatherPhenomenon.cs b/src/Taf.Decoder/Entity/WeatherPhenomenon.cs
index a8e0ddb..01b352b 100644
--- a/src/Taf.Decoder/Entity/WeatherPhenomenon.cs
+++ b/src/Taf.Decoder/Entity/WeatherPhenomenon.cs
@@ -1,6 +1,6 @@
using System.Collections.Generic;
-namespace Taf.Decoder.entity
+namespace Taf.Decoder.Entity
{
public sealed class WeatherPhenomenon : AbstractEntity
{
diff --git a/src/Taf.Decoder/Exception/TafChunkDecoderException.cs b/src/Taf.Decoder/Exception/TafChunkDecoderException.cs
index aea1852..93e5126 100644
--- a/src/Taf.Decoder/Exception/TafChunkDecoderException.cs
+++ b/src/Taf.Decoder/Exception/TafChunkDecoderException.cs
@@ -1,7 +1,7 @@
using System;
using System.Runtime.Serialization;
using System.Security.Permissions;
-using Taf.Decoder.chunkdecoder;
+using Taf.Decoder.ChunkDecoder;
namespace Taf.Decoder
{
diff --git a/src/Taf.Decoder/Taf.Decoder.csproj b/src/Taf.Decoder/Taf.Decoder.csproj
index 5d46017..afa3d91 100644
--- a/src/Taf.Decoder/Taf.Decoder.csproj
+++ b/src/Taf.Decoder/Taf.Decoder.csproj
@@ -1,7 +1,7 @@
netstandard2.0;net8.0;net10.0;net48
- 1.0.6
+ 1.0.7
$(NoWarn);CS1591;SYSLIB0001;SYSLIB0002;SYSLIB0003
https://github.com/afonsoft/metar-decoder
git
diff --git a/src/Taf.Decoder/TafDecoder.cs b/src/Taf.Decoder/TafDecoder.cs
index bbb67bf..7409080 100644
--- a/src/Taf.Decoder/TafDecoder.cs
+++ b/src/Taf.Decoder/TafDecoder.cs
@@ -2,8 +2,8 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text.RegularExpressions;
-using Taf.Decoder.chunkdecoder;
-using Taf.Decoder.entity;
+using Taf.Decoder.ChunkDecoder;
+using Taf.Decoder.Entity;
namespace Taf.Decoder
{
diff --git a/tests/Metar.Decoder.Tests/BasicTest.cs b/tests/Metar.Decoder.Tests/BasicTest.cs
index bd1ce26..255197d 100644
--- a/tests/Metar.Decoder.Tests/BasicTest.cs
+++ b/tests/Metar.Decoder.Tests/BasicTest.cs
@@ -1,5 +1,5 @@
using Metar.Decoder;
-using Metar.Decoder.Chunkdecoder;
+using Metar.Decoder.ChunkDecoder;
using Metar.Decoder.Entity;
using NUnit.Framework;
using NUnit.Framework.Legacy;
@@ -7,7 +7,7 @@
using System.Collections.ObjectModel;
using System.Linq;
-namespace Metar.Decoder_tests
+namespace Metar.Decoder.Tests
{
///
/// BasicTest
diff --git a/tests/Metar.Decoder.Tests/ChunkDecoder/CloudChunkDecoderTest.cs b/tests/Metar.Decoder.Tests/ChunkDecoder/CloudChunkDecoderTest.cs
index 90606d3..f193f44 100644
--- a/tests/Metar.Decoder.Tests/ChunkDecoder/CloudChunkDecoderTest.cs
+++ b/tests/Metar.Decoder.Tests/ChunkDecoder/CloudChunkDecoderTest.cs
@@ -1,12 +1,12 @@
using Metar.Decoder;
-using Metar.Decoder.Chunkdecoder;
+using Metar.Decoder.ChunkDecoder;
using Metar.Decoder.Entity;
using NUnit.Framework;
using NUnit.Framework.Legacy;
using System.Collections.Generic;
using static Metar.Decoder.Entity.CloudLayer;
-namespace Metar.Decoder_tests.chunkdecoder
+namespace Metar.Decoder.Tests.ChunkDecoder
{
///
/// CloudChunkDecoderTest
diff --git a/tests/Metar.Decoder.Tests/ChunkDecoder/DatetimeChunkDecoderTest.cs b/tests/Metar.Decoder.Tests/ChunkDecoder/DatetimeChunkDecoderTest.cs
index 82a5347..06037bc 100644
--- a/tests/Metar.Decoder.Tests/ChunkDecoder/DatetimeChunkDecoderTest.cs
+++ b/tests/Metar.Decoder.Tests/ChunkDecoder/DatetimeChunkDecoderTest.cs
@@ -1,11 +1,11 @@
using Metar.Decoder;
-using Metar.Decoder.Chunkdecoder;
+using Metar.Decoder.ChunkDecoder;
using NUnit.Framework;
using NUnit.Framework.Legacy;
using System;
using System.Collections.Generic;
-namespace Metar.Decoder_tests.chunkdecoder
+namespace Metar.Decoder.Tests.ChunkDecoder
{
[TestFixture, Category("DatetimeChunkDecoder")]
public class DatetimeChunkDecoderTest
diff --git a/tests/Metar.Decoder.Tests/ChunkDecoder/IcaoChunkDecoderTest.cs b/tests/Metar.Decoder.Tests/ChunkDecoder/IcaoChunkDecoderTest.cs
index bb10927..788f225 100644
--- a/tests/Metar.Decoder.Tests/ChunkDecoder/IcaoChunkDecoderTest.cs
+++ b/tests/Metar.Decoder.Tests/ChunkDecoder/IcaoChunkDecoderTest.cs
@@ -1,11 +1,11 @@
using Metar.Decoder;
-using Metar.Decoder.Chunkdecoder;
+using Metar.Decoder.ChunkDecoder;
using NUnit.Framework;
using NUnit.Framework.Legacy;
using System;
using System.Collections.Generic;
-namespace Metar.Decoder_tests.chunkdecoder
+namespace Metar.Decoder.Tests.ChunkDecoder
{
///
/// IcaoChunkDecoderTest
diff --git a/tests/Metar.Decoder.Tests/ChunkDecoder/PresentWeatherChunkDecoderTest.cs b/tests/Metar.Decoder.Tests/ChunkDecoder/PresentWeatherChunkDecoderTest.cs
index 0accae8..84cbc41 100644
--- a/tests/Metar.Decoder.Tests/ChunkDecoder/PresentWeatherChunkDecoderTest.cs
+++ b/tests/Metar.Decoder.Tests/ChunkDecoder/PresentWeatherChunkDecoderTest.cs
@@ -1,11 +1,11 @@
using Metar.Decoder;
-using Metar.Decoder.Chunkdecoder;
+using Metar.Decoder.ChunkDecoder;
using Metar.Decoder.Entity;
using NUnit.Framework;
using NUnit.Framework.Legacy;
using System.Collections.Generic;
-namespace Metar.Decoder_tests.chunkdecoder
+namespace Metar.Decoder.Tests.ChunkDecoder
{
[TestFixture, Category("PresentWeatherChunkDecoder")]
public class PresentWeatherChunkDecoderTest
diff --git a/tests/Metar.Decoder.Tests/ChunkDecoder/PressureChunkDecoderTest.cs b/tests/Metar.Decoder.Tests/ChunkDecoder/PressureChunkDecoderTest.cs
index eaeb5f3..67a785f 100644
--- a/tests/Metar.Decoder.Tests/ChunkDecoder/PressureChunkDecoderTest.cs
+++ b/tests/Metar.Decoder.Tests/ChunkDecoder/PressureChunkDecoderTest.cs
@@ -1,5 +1,5 @@
using Metar.Decoder;
-using Metar.Decoder.Chunkdecoder;
+using Metar.Decoder.ChunkDecoder;
using Metar.Decoder.Entity;
using NUnit.Framework;
using NUnit.Framework.Legacy;
@@ -7,7 +7,7 @@
using System.Collections.Generic;
using static Metar.Decoder.Entity.Value;
-namespace Metar.Decoder_tests.chunkdecoder
+namespace Metar.Decoder.Tests.ChunkDecoder
{
[TestFixture, Category("PressureChunkDecoder")]
public class PressureChunkDecoderTest
diff --git a/tests/Metar.Decoder.Tests/ChunkDecoder/RecentWeatherChunkDecoderTest.cs b/tests/Metar.Decoder.Tests/ChunkDecoder/RecentWeatherChunkDecoderTest.cs
index d71c6e9..60bb8f5 100644
--- a/tests/Metar.Decoder.Tests/ChunkDecoder/RecentWeatherChunkDecoderTest.cs
+++ b/tests/Metar.Decoder.Tests/ChunkDecoder/RecentWeatherChunkDecoderTest.cs
@@ -1,12 +1,12 @@
using Metar.Decoder;
-using Metar.Decoder.Chunkdecoder;
+using Metar.Decoder.ChunkDecoder;
using Metar.Decoder.Entity;
using NUnit.Framework;
using NUnit.Framework.Legacy;
using System;
using System.Collections.Generic;
-namespace Metar.Decoder_tests.chunkdecoder
+namespace Metar.Decoder.Tests.ChunkDecoder
{
[TestFixture, Category("RecentWeatherChunkDecoder")]
public class RecentWeatherChunkDecoderTest
diff --git a/tests/Metar.Decoder.Tests/ChunkDecoder/RemarkChunkDecoderTest.cs b/tests/Metar.Decoder.Tests/ChunkDecoder/RemarkChunkDecoderTest.cs
new file mode 100644
index 0000000..bbf281d
--- /dev/null
+++ b/tests/Metar.Decoder.Tests/ChunkDecoder/RemarkChunkDecoderTest.cs
@@ -0,0 +1,57 @@
+using Metar.Decoder.ChunkDecoder;
+using Metar.Decoder.Entity;
+using NUnit.Framework;
+using NUnit.Framework.Legacy;
+using System.Collections.Generic;
+
+namespace Metar.Decoder.Tests.ChunkDecoder
+{
+ [TestFixture, Category("RemarkChunkDecoder")]
+ public class RemarkChunkDecoderTest
+ {
+ private RemarkChunkDecoder decoder;
+
+ [SetUp]
+ public void Setup()
+ {
+ decoder = new RemarkChunkDecoder();
+ }
+
+ [Test]
+ public void TestParseRemark()
+ {
+ var result = decoder.Parse("RMK AO2 SLP013 T00720044 ");
+ var decoded = result[MetarDecoder.ResultKey] as Dictionary;
+ ClassicAssert.IsTrue(decoded.ContainsKey(RemarkChunkDecoder.RemarkParameterName));
+ ClassicAssert.IsTrue(((string)decoded[RemarkChunkDecoder.RemarkParameterName]).Contains("AO2"));
+ }
+
+ [Test]
+ public void TestParseSeaLevelPressure()
+ {
+ var result = decoder.Parse("RMK AO2 SLP013 T00720044 ");
+ var decoded = result[MetarDecoder.ResultKey] as Dictionary;
+ ClassicAssert.IsTrue(decoded.ContainsKey(RemarkChunkDecoder.SeaLevelPressureParameterName));
+ var slp = (Value)decoded[RemarkChunkDecoder.SeaLevelPressureParameterName];
+ ClassicAssert.AreEqual(1001.3, slp.ActualValue, 0.01);
+ ClassicAssert.AreEqual(Value.Unit.HectoPascal, slp.ActualUnit);
+ }
+
+ [Test]
+ public void TestParseSeaLevelPressureHigh()
+ {
+ var result = decoder.Parse("RMK SLP982 ");
+ var decoded = result[MetarDecoder.ResultKey] as Dictionary;
+ var slp = (Value)decoded[RemarkChunkDecoder.SeaLevelPressureParameterName];
+ ClassicAssert.AreEqual(998.2, slp.ActualValue, 0.01);
+ }
+
+ [Test]
+ public void TestParseNoRemark()
+ {
+ var result = decoder.Parse("SOMETHING ");
+ var decoded = result[MetarDecoder.ResultKey] as Dictionary;
+ ClassicAssert.IsFalse(decoded.ContainsKey(RemarkChunkDecoder.RemarkParameterName));
+ }
+ }
+}
diff --git a/tests/Metar.Decoder.Tests/ChunkDecoder/ReportStatusChunkDecoderTest.cs b/tests/Metar.Decoder.Tests/ChunkDecoder/ReportStatusChunkDecoderTest.cs
index 5bab3ef..0b60b9c 100644
--- a/tests/Metar.Decoder.Tests/ChunkDecoder/ReportStatusChunkDecoderTest.cs
+++ b/tests/Metar.Decoder.Tests/ChunkDecoder/ReportStatusChunkDecoderTest.cs
@@ -1,11 +1,11 @@
using Metar.Decoder;
-using Metar.Decoder.Chunkdecoder;
+using Metar.Decoder.ChunkDecoder;
using NUnit.Framework;
using NUnit.Framework.Legacy;
using System;
using System.Collections.Generic;
-namespace Metar.Decoder_tests.chunkdecoder
+namespace Metar.Decoder.Tests.ChunkDecoder
{
[TestFixture, Category("ReportStatusChunkDecoder")]
public class ReportStatusChunkDecoderTest
diff --git a/tests/Metar.Decoder.Tests/ChunkDecoder/ReportTypeChunkDecoderTest.cs b/tests/Metar.Decoder.Tests/ChunkDecoder/ReportTypeChunkDecoderTest.cs
index 6afd7d2..1dd66d7 100644
--- a/tests/Metar.Decoder.Tests/ChunkDecoder/ReportTypeChunkDecoderTest.cs
+++ b/tests/Metar.Decoder.Tests/ChunkDecoder/ReportTypeChunkDecoderTest.cs
@@ -1,12 +1,12 @@
using Metar.Decoder;
-using Metar.Decoder.Chunkdecoder;
+using Metar.Decoder.ChunkDecoder;
using NUnit.Framework;
using NUnit.Framework.Legacy;
using System;
using System.Collections.Generic;
using static Metar.Decoder.Entity.DecodedMetar;
-namespace Metar.Decoder_tests.chunkdecoder
+namespace Metar.Decoder.Tests.ChunkDecoder
{
[TestFixture, Category("ReportTypeChunkDecoder")]
public class ReportTypeChunkDecoderTest
diff --git a/tests/Metar.Decoder.Tests/ChunkDecoder/RunwayVisualRangeChunkDecoderTest.cs b/tests/Metar.Decoder.Tests/ChunkDecoder/RunwayVisualRangeChunkDecoderTest.cs
index 6f940ed..6f6c749 100644
--- a/tests/Metar.Decoder.Tests/ChunkDecoder/RunwayVisualRangeChunkDecoderTest.cs
+++ b/tests/Metar.Decoder.Tests/ChunkDecoder/RunwayVisualRangeChunkDecoderTest.cs
@@ -1,11 +1,11 @@
using Metar.Decoder;
-using Metar.Decoder.Chunkdecoder;
+using Metar.Decoder.ChunkDecoder;
using Metar.Decoder.Entity;
using NUnit.Framework;
using NUnit.Framework.Legacy;
using System.Collections.Generic;
-namespace Metar.Decoder_tests.chunkdecoder
+namespace Metar.Decoder.Tests.ChunkDecoder
{
[TestFixture, Category("RunwayVisualRangeChunkDecoder")]
public class RunwayVisualRangeChunkDecoderTest
diff --git a/tests/Metar.Decoder.Tests/ChunkDecoder/SurfaceWindChunkDecoderTest.cs b/tests/Metar.Decoder.Tests/ChunkDecoder/SurfaceWindChunkDecoderTest.cs
index 4a7186c..61096d6 100644
--- a/tests/Metar.Decoder.Tests/ChunkDecoder/SurfaceWindChunkDecoderTest.cs
+++ b/tests/Metar.Decoder.Tests/ChunkDecoder/SurfaceWindChunkDecoderTest.cs
@@ -1,11 +1,11 @@
using Metar.Decoder;
-using Metar.Decoder.Chunkdecoder;
+using Metar.Decoder.ChunkDecoder;
using Metar.Decoder.Entity;
using NUnit.Framework;
using NUnit.Framework.Legacy;
using System.Collections.Generic;
-namespace Metar.Decoder_tests.chunkdecoder
+namespace Metar.Decoder.Tests.ChunkDecoder
{
[TestFixture, Category("SurfaceWindChunkDecoder")]
public class SurfaceWindChunkDecoderTest
diff --git a/tests/Metar.Decoder.Tests/ChunkDecoder/TemperatureChunkDecoderTest.cs b/tests/Metar.Decoder.Tests/ChunkDecoder/TemperatureChunkDecoderTest.cs
index db425fe..2d6203c 100644
--- a/tests/Metar.Decoder.Tests/ChunkDecoder/TemperatureChunkDecoderTest.cs
+++ b/tests/Metar.Decoder.Tests/ChunkDecoder/TemperatureChunkDecoderTest.cs
@@ -1,11 +1,11 @@
using Metar.Decoder;
-using Metar.Decoder.Chunkdecoder;
+using Metar.Decoder.ChunkDecoder;
using Metar.Decoder.Entity;
using NUnit.Framework;
using NUnit.Framework.Legacy;
using System.Collections.Generic;
-namespace Metar.Decoder_tests.chunkdecoder
+namespace Metar.Decoder.Tests.ChunkDecoder
{
[TestFixture, Category("TemperatureChunkDecoder")]
public class TemperatureChunkDecoderTest
diff --git a/tests/Metar.Decoder.Tests/ChunkDecoder/TrendChunkDecoderTest.cs b/tests/Metar.Decoder.Tests/ChunkDecoder/TrendChunkDecoderTest.cs
new file mode 100644
index 0000000..c65a0ae
--- /dev/null
+++ b/tests/Metar.Decoder.Tests/ChunkDecoder/TrendChunkDecoderTest.cs
@@ -0,0 +1,52 @@
+using Metar.Decoder.ChunkDecoder;
+using NUnit.Framework;
+using NUnit.Framework.Legacy;
+using System.Collections.Generic;
+
+namespace Metar.Decoder.Tests.ChunkDecoder
+{
+ [TestFixture, Category("TrendChunkDecoder")]
+ public class TrendChunkDecoderTest
+ {
+ private TrendChunkDecoder decoder;
+
+ [SetUp]
+ public void Setup()
+ {
+ decoder = new TrendChunkDecoder();
+ }
+
+ [Test]
+ public void TestParseNosig()
+ {
+ var result = decoder.Parse("NOSIG ");
+ var decoded = result[MetarDecoder.ResultKey] as Dictionary;
+ ClassicAssert.AreEqual("NOSIG", decoded[TrendChunkDecoder.TrendTypeParameterName]);
+ ClassicAssert.AreEqual("NOSIG", decoded[TrendChunkDecoder.TrendForecastParameterName]);
+ }
+
+ [Test]
+ public void TestParseBecmg()
+ {
+ var result = decoder.Parse("BECMG 24010KT ");
+ var decoded = result[MetarDecoder.ResultKey] as Dictionary;
+ ClassicAssert.AreEqual("BECMG", decoded[TrendChunkDecoder.TrendTypeParameterName]);
+ }
+
+ [Test]
+ public void TestParseTempo()
+ {
+ var result = decoder.Parse("TEMPO 3000 BR ");
+ var decoded = result[MetarDecoder.ResultKey] as Dictionary;
+ ClassicAssert.AreEqual("TEMPO", decoded[TrendChunkDecoder.TrendTypeParameterName]);
+ }
+
+ [Test]
+ public void TestParseNoTrend()
+ {
+ var result = decoder.Parse("SOMETHING ");
+ var decoded = result[MetarDecoder.ResultKey] as Dictionary;
+ ClassicAssert.IsFalse(decoded.ContainsKey(TrendChunkDecoder.TrendTypeParameterName));
+ }
+ }
+}
diff --git a/tests/Metar.Decoder.Tests/ChunkDecoder/VisibilityChunkDecoderTest.cs b/tests/Metar.Decoder.Tests/ChunkDecoder/VisibilityChunkDecoderTest.cs
index ff604db..8485f23 100644
--- a/tests/Metar.Decoder.Tests/ChunkDecoder/VisibilityChunkDecoderTest.cs
+++ b/tests/Metar.Decoder.Tests/ChunkDecoder/VisibilityChunkDecoderTest.cs
@@ -1,11 +1,11 @@
using Metar.Decoder;
-using Metar.Decoder.Chunkdecoder;
+using Metar.Decoder.ChunkDecoder;
using Metar.Decoder.Entity;
using NUnit.Framework;
using NUnit.Framework.Legacy;
using System.Collections.Generic;
-namespace Metar.Decoder_tests.chunkdecoder
+namespace Metar.Decoder.Tests.ChunkDecoder
{
[TestFixture, Category("VisibilityChunkDecoder")]
public class VisibilityChunkDecoderTest
diff --git a/tests/Metar.Decoder.Tests/ChunkDecoder/WindShearChunkDecoderTest.cs b/tests/Metar.Decoder.Tests/ChunkDecoder/WindShearChunkDecoderTest.cs
index e1edcd4..f28a252 100644
--- a/tests/Metar.Decoder.Tests/ChunkDecoder/WindShearChunkDecoderTest.cs
+++ b/tests/Metar.Decoder.Tests/ChunkDecoder/WindShearChunkDecoderTest.cs
@@ -1,10 +1,10 @@
using Metar.Decoder;
-using Metar.Decoder.Chunkdecoder;
+using Metar.Decoder.ChunkDecoder;
using NUnit.Framework;
using NUnit.Framework.Legacy;
using System.Collections.Generic;
-namespace Metar.Decoder_tests.chunkdecoder
+namespace Metar.Decoder.Tests.ChunkDecoder
{
[TestFixture, Category("WindShearChunkDecoder")]
public class WindShearChunkDecoderTest
diff --git a/tests/Metar.Decoder.Tests/Integration.cs b/tests/Metar.Decoder.Tests/Integration.cs
index 0279aad..247da54 100644
--- a/tests/Metar.Decoder.Tests/Integration.cs
+++ b/tests/Metar.Decoder.Tests/Integration.cs
@@ -8,7 +8,7 @@
using static Metar.Decoder.Entity.CloudLayer;
using static Metar.Decoder.Entity.DecodedMetar;
-namespace Metar.Decoder_tests
+namespace Metar.Decoder.Tests
{
///
/// Integration
diff --git a/tests/Metar.Decoder.Tests/MetarChunkDecoderExceptionTest.cs b/tests/Metar.Decoder.Tests/MetarChunkDecoderExceptionTest.cs
index 9b24c16..10cc5af 100644
--- a/tests/Metar.Decoder.Tests/MetarChunkDecoderExceptionTest.cs
+++ b/tests/Metar.Decoder.Tests/MetarChunkDecoderExceptionTest.cs
@@ -6,7 +6,7 @@
using System.Text.Json;
using System.Xml.Serialization;
-namespace Metar.Decoder_tests
+namespace Metar.Decoder.Tests
{
///
/// MetarChunkDecoderExceptionTest
diff --git a/tests/Metar.Decoder.Tests/MetarDecoderComprehensiveTest.cs b/tests/Metar.Decoder.Tests/MetarDecoderComprehensiveTest.cs
new file mode 100644
index 0000000..ba8209e
--- /dev/null
+++ b/tests/Metar.Decoder.Tests/MetarDecoderComprehensiveTest.cs
@@ -0,0 +1,403 @@
+using Metar.Decoder;
+using Metar.Decoder.Entity;
+using NUnit.Framework;
+using NUnit.Framework.Legacy;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using static Metar.Decoder.Entity.CloudLayer;
+using static Metar.Decoder.Entity.DecodedMetar;
+using static Metar.Decoder.Entity.RunwayVisualRange;
+using static Metar.Decoder.Entity.Value;
+
+namespace Metar.Decoder.Tests
+{
+ [TestFixture, Category("MetarDecoderComprehensiveTest")]
+ public class MetarDecoderComprehensiveTest
+ {
+ private MetarDecoder decoder;
+
+ [SetUp]
+ public void Setup()
+ {
+ decoder = new MetarDecoder();
+ }
+
+ [Test]
+ public void TestParseMetarWithCavok()
+ {
+ var d = decoder.ParseNotStrict("METAR LFPO 231027Z 24004KT CAVOK 17/10 Q1009 ");
+ ClassicAssert.IsTrue(d.Cavok);
+ ClassicAssert.AreEqual(MetarType.METAR, d.Type);
+ ClassicAssert.AreEqual("LFPO", d.ICAO);
+ }
+
+ [Test]
+ public void TestParseMetarWithVariableWind()
+ {
+ var d = decoder.ParseNotStrict("METAR LFPO 231027Z VRB02KT 9999 FEW020 17/10 Q1009 ");
+ ClassicAssert.IsTrue(d.SurfaceWind.VariableDirection);
+ ClassicAssert.IsNull(d.SurfaceWind.MeanDirection);
+ ClassicAssert.AreEqual(2, d.SurfaceWind.MeanSpeed.ActualValue);
+ }
+
+ [Test]
+ public void TestParseMetarWithGust()
+ {
+ var d = decoder.ParseNotStrict("METAR LFPO 231027Z 24015G25KT 9999 FEW020 17/10 Q1009 ");
+ ClassicAssert.AreEqual(240, d.SurfaceWind.MeanDirection.ActualValue);
+ ClassicAssert.AreEqual(15, d.SurfaceWind.MeanSpeed.ActualValue);
+ ClassicAssert.AreEqual(25, d.SurfaceWind.SpeedVariations.ActualValue);
+ ClassicAssert.AreEqual(Unit.Knot, d.SurfaceWind.MeanSpeed.ActualUnit);
+ }
+
+ [Test]
+ public void TestParseMetarWithDirectionVariation()
+ {
+ var d = decoder.ParseNotStrict("METAR LFPO 231027Z 24004KT 180V270 9999 FEW020 17/10 Q1009 ");
+ ClassicAssert.IsNotNull(d.SurfaceWind.DirectionVariations);
+ ClassicAssert.AreEqual(180, d.SurfaceWind.DirectionVariations[0].ActualValue);
+ ClassicAssert.AreEqual(270, d.SurfaceWind.DirectionVariations[1].ActualValue);
+ }
+
+ [Test]
+ public void TestParseMetarWithNilStatus()
+ {
+ var d = decoder.ParseNotStrict("METAR LFPO 231027Z NIL ");
+ ClassicAssert.AreEqual("NIL", d.Status);
+ }
+
+ [Test]
+ public void TestParseMetarWithMultipleClouds()
+ {
+ var d = decoder.ParseNotStrict("METAR LFPO 231027Z 24004KT 9999 FEW020 SCT030 BKN060 17/10 Q1009 ");
+ ClassicAssert.AreEqual(3, d.Clouds.Count);
+ ClassicAssert.AreEqual(CloudAmount.FEW, d.Clouds[0].Amount);
+ ClassicAssert.AreEqual(2000, d.Clouds[0].BaseHeight.ActualValue);
+ ClassicAssert.AreEqual(CloudAmount.SCT, d.Clouds[1].Amount);
+ ClassicAssert.AreEqual(3000, d.Clouds[1].BaseHeight.ActualValue);
+ ClassicAssert.AreEqual(CloudAmount.BKN, d.Clouds[2].Amount);
+ ClassicAssert.AreEqual(6000, d.Clouds[2].BaseHeight.ActualValue);
+ }
+
+ [Test]
+ public void TestParseMetarWithCB()
+ {
+ var d = decoder.ParseNotStrict("METAR LFPO 231027Z 24004KT 9999 SCT025CB 17/10 Q1009 ");
+ ClassicAssert.AreEqual(1, d.Clouds.Count);
+ ClassicAssert.AreEqual(CloudType.CB, d.Clouds[0].Type);
+ }
+
+ [Test]
+ public void TestParseMetarWithTCU()
+ {
+ var d = decoder.ParseNotStrict("METAR LFPO 231027Z 24004KT 9999 BKN035TCU 17/10 Q1009 ");
+ ClassicAssert.AreEqual(CloudType.TCU, d.Clouds[0].Type);
+ }
+
+ [Test]
+ public void TestParseMetarWithClearSky()
+ {
+ var d = decoder.ParseNotStrict("METAR LFPO 231027Z 24004KT 9999 SKC 17/10 Q1009 ");
+ ClassicAssert.AreEqual(0, d.Clouds.Count);
+ }
+
+ [Test]
+ public void TestParseMetarWithNSC()
+ {
+ var d = decoder.ParseNotStrict("METAR LFPO 231027Z 24004KT 9999 NSC 17/10 Q1009 ");
+ ClassicAssert.AreEqual(0, d.Clouds.Count);
+ }
+
+ [Test]
+ public void TestParseMetarWithVerticalVisibility()
+ {
+ var d = decoder.ParseNotStrict("METAR LFPO 231027Z 24004KT 0500 VV003 17/10 Q1009 ");
+ ClassicAssert.AreEqual(1, d.Clouds.Count);
+ ClassicAssert.AreEqual(CloudAmount.VV, d.Clouds[0].Amount);
+ ClassicAssert.AreEqual(300, d.Clouds[0].BaseHeight.ActualValue);
+ }
+
+ [Test]
+ public void TestParseMetarWithUSVisibility()
+ {
+ var d = decoder.ParseNotStrict("METAR KJFK 231027Z 24004KT 1 1/2SM FEW020 17/10 A2992 ");
+ ClassicAssert.AreEqual(1.5, d.Visibility.PrevailingVisibility.ActualValue);
+ ClassicAssert.AreEqual(Unit.StatuteMile, d.Visibility.PrevailingVisibility.ActualUnit);
+ }
+
+ [Test]
+ public void TestParseMetarWithMercuryPressure()
+ {
+ var d = decoder.ParseNotStrict("METAR KJFK 231027Z 24004KT 9999 FEW020 17/10 A2992 ");
+ ClassicAssert.AreEqual(29.92, d.Pressure.ActualValue);
+ ClassicAssert.AreEqual(Unit.MercuryInch, d.Pressure.ActualUnit);
+ }
+
+ [Test]
+ public void TestParseMetarWithNegativeTemperature()
+ {
+ var d = decoder.ParseNotStrict("METAR LFPO 231027Z 24004KT 9999 FEW020 M02/M05 Q1009 ");
+ ClassicAssert.AreEqual(-2, d.AirTemperature.ActualValue);
+ ClassicAssert.AreEqual(-5, d.DewPointTemperature.ActualValue);
+ }
+
+ [Test]
+ public void TestParseMetarWithWindShearAllRunways()
+ {
+ var d = decoder.ParseNotStrict("METAR LFPO 231027Z 24004KT 9999 FEW020 17/10 Q1009 WS ALL RWY ");
+ ClassicAssert.IsTrue(d.WindshearAllRunways.Value);
+ }
+
+ [Test]
+ public void TestParseMetarWithMultipleRunwayVisualRange()
+ {
+ var d = decoder.ParseNotStrict("METAR LFPO 231027Z 24004KT 0800 R06L/0600U R24/0400D FEW020 17/10 Q1009 ");
+ ClassicAssert.AreEqual(2, d.RunwaysVisualRange.Count);
+ ClassicAssert.AreEqual("06L", d.RunwaysVisualRange[0].Runway);
+ ClassicAssert.AreEqual(Tendency.U, d.RunwaysVisualRange[0].PastTendency);
+ ClassicAssert.AreEqual("24", d.RunwaysVisualRange[1].Runway);
+ ClassicAssert.AreEqual(Tendency.D, d.RunwaysVisualRange[1].PastTendency);
+ }
+
+ [Test]
+ public void TestParseMetarWithVariableRVR()
+ {
+ var d = decoder.ParseNotStrict("METAR LFPO 231027Z 24004KT 0800 R06L/0200V0600U FEW020 17/10 Q1009 ");
+ ClassicAssert.IsTrue(d.RunwaysVisualRange[0].Variable);
+ ClassicAssert.AreEqual(200, d.RunwaysVisualRange[0].VisualRangeInterval[0].ActualValue);
+ ClassicAssert.AreEqual(600, d.RunwaysVisualRange[0].VisualRangeInterval[1].ActualValue);
+ }
+
+ [Test]
+ public void TestParseMetarWithMultipleWeatherPhenomena()
+ {
+ var d = decoder.ParseNotStrict("METAR LFPO 231027Z 24004KT 2000 +TSRA FZDZ FEW020 17/10 Q1009 ");
+ ClassicAssert.AreEqual(2, d.PresentWeather.Count);
+ ClassicAssert.AreEqual("+", d.PresentWeather[0].IntensityProximity);
+ ClassicAssert.AreEqual("TS", d.PresentWeather[0].Characteristics);
+ }
+
+ [Test]
+ public void TestParseMetarNotStrictWithErrors()
+ {
+ var d = decoder.ParseNotStrict("METAR LFPO 231027Z 24004KT INVALID_VISIBILITY FEW020 17/10 Q1009 ");
+ ClassicAssert.IsFalse(d.IsValid);
+ ClassicAssert.IsTrue(d.DecodingExceptions.Count > 0);
+ }
+
+ [Test]
+ public void TestParseMetarStrictWithErrors()
+ {
+ var d = decoder.ParseStrict("METAR LFPO 231027Z 24004KT INVALID_VISIBILITY FEW020 17/10 Q1009 ");
+ ClassicAssert.IsFalse(d.IsValid);
+ }
+
+ [Test]
+ public void TestParseSpeciMetar()
+ {
+ var d = decoder.ParseNotStrict("SPECI LFPO 231027Z 24004KT 9999 FEW020 17/10 Q1009 ");
+ ClassicAssert.AreEqual(MetarType.SPECI, d.Type);
+ }
+
+ [Test]
+ public void TestParseSpeciCorMetar()
+ {
+ var d = decoder.ParseNotStrict("SPECI COR LFPO 231027Z 24004KT 9999 FEW020 17/10 Q1009 ");
+ ClassicAssert.AreEqual(MetarType.SPECI_COR, d.Type);
+ }
+
+ [Test]
+ public void TestParseMetarCor()
+ {
+ var d = decoder.ParseNotStrict("METAR COR LFPO 231027Z 24004KT 9999 FEW020 17/10 Q1009 ");
+ ClassicAssert.AreEqual(MetarType.METAR_COR, d.Type);
+ }
+
+ [Test]
+ public void TestParseMetarWithNDV()
+ {
+ var d = decoder.ParseNotStrict("METAR LFPO 231027Z 24004KT 9999NDV FEW020 17/10 Q1009 ");
+ ClassicAssert.IsTrue(d.Visibility.NDV);
+ }
+
+ [Test]
+ public void TestParseMetarWithMinimumVisibility()
+ {
+ var d = decoder.ParseNotStrict("METAR LFPO 231027Z 24004KT 5000 2000NE FEW020 17/10 Q1009 ");
+ ClassicAssert.AreEqual(5000, d.Visibility.PrevailingVisibility.ActualValue);
+ ClassicAssert.AreEqual(2000, d.Visibility.MinimumVisibility.ActualValue);
+ ClassicAssert.AreEqual("NE", d.Visibility.MinimumVisibilityDirection);
+ }
+
+ [Test]
+ public void TestParseMetarWithNoVisibilityInfo()
+ {
+ var d = decoder.ParseNotStrict("METAR LFPO 231027Z 24004KT //// FEW020 17/10 Q1009 ");
+ ClassicAssert.IsNull(d.Visibility);
+ ClassicAssert.IsFalse(d.Cavok);
+ }
+
+ [Test]
+ public void TestParseMetarWithNosig()
+ {
+ var d = decoder.ParseNotStrict("METAR LFPO 231027Z 24004KT 9999 FEW020 17/10 Q1009 NOSIG ");
+ ClassicAssert.AreEqual("NOSIG", d.TrendType);
+ }
+
+ [Test]
+ public void TestParseMetarWithRecentWeather()
+ {
+ var d = decoder.ParseNotStrict("METAR LFPO 231027Z 24004KT 9999 FEW020 17/10 Q1009 RERA ");
+ ClassicAssert.IsNotNull(d.RecentWeather);
+ ClassicAssert.AreEqual("RA", d.RecentWeather.Types[0]);
+ }
+
+ [Test]
+ public void TestParseMetarWithKPH()
+ {
+ var d = decoder.ParseNotStrict("METAR LFPO 231027Z 24010KPH 9999 FEW020 17/10 Q1009 ");
+ ClassicAssert.AreEqual(Unit.KilometerPerHour, d.SurfaceWind.MeanSpeed.ActualUnit);
+ }
+
+ [Test]
+ public void TestParseMetarWithNoPressureValue()
+ {
+ var d = decoder.ParseNotStrict("METAR LFPO 231027Z 24004KT 9999 FEW020 17/10 Q//// ");
+ ClassicAssert.IsNull(d.Pressure);
+ }
+
+ [Test]
+ public void TestParseMetarMissingType()
+ {
+ var d = decoder.ParseNotStrict("LFPO 231027Z 24004KT 9999 FEW020 17/10 Q1009 ");
+ ClassicAssert.AreEqual(MetarType.NULL, d.Type);
+ ClassicAssert.AreEqual("LFPO", d.ICAO);
+ }
+
+ [Test]
+ public void TestSetStrictParsing()
+ {
+ decoder.SetStrictParsing(true);
+ var d = decoder.Parse("METAR LFPO 231027Z 24004KT 9999 FEW020 17/10 Q1009 ");
+ ClassicAssert.IsTrue(d.IsValid);
+ }
+
+ [Test]
+ public void TestDecodedMetarResetExceptions()
+ {
+ var d = decoder.ParseNotStrict("METAR LFPO 231027Z 24004KT INVALID_VIS FEW020 17/10 Q1009 ");
+ ClassicAssert.IsFalse(d.IsValid);
+ d.ResetDecodingExceptions();
+ ClassicAssert.IsTrue(d.IsValid);
+ }
+
+ [Test]
+ public void TestParseMetarWithRVRFeetUnit()
+ {
+ var d = decoder.ParseNotStrict("METAR KJFK 231027Z 24004KT 0800 R04R/2000FT FEW020 17/10 A2992 ");
+ if (d.RunwaysVisualRange.Count > 0)
+ {
+ ClassicAssert.AreEqual(Unit.Feet, d.RunwaysVisualRange[0].VisualRange.ActualUnit);
+ }
+ }
+
+ [Test]
+ public void TestParseMetarWithOVCClouds()
+ {
+ var d = decoder.ParseNotStrict("METAR LFPO 231027Z 24004KT 3000 OVC005 17/10 Q1009 ");
+ ClassicAssert.AreEqual(1, d.Clouds.Count);
+ ClassicAssert.AreEqual(CloudAmount.OVC, d.Clouds[0].Amount);
+ ClassicAssert.AreEqual(500, d.Clouds[0].BaseHeight.ActualValue);
+ }
+
+ [Test]
+ public void TestParseMetarWithAutoStatus()
+ {
+ var d = decoder.ParseNotStrict("METAR LFPO 231027Z AUTO 24004KT 9999 FEW020 17/10 Q1009 ");
+ ClassicAssert.AreEqual("AUTO", d.Status);
+ }
+
+ [Test]
+ public void TestParseMetarWithFractionalUSVisibility()
+ {
+ var d = decoder.ParseNotStrict("METAR KJFK 231027Z 24004KT 3/4SM FEW020 17/10 A2992 ");
+ ClassicAssert.AreEqual(0.75, d.Visibility.PrevailingVisibility.ActualValue, 0.001);
+ ClassicAssert.AreEqual(Unit.StatuteMile, d.Visibility.PrevailingVisibility.ActualUnit);
+ }
+
+ [Test]
+ public void TestParseRealWorldMetar()
+ {
+ var d = decoder.ParseNotStrict("METAR SBGR 031000Z 35006KT 9999 FEW040 SCT100 27/18 Q1020 ");
+ ClassicAssert.IsTrue(d.IsValid);
+ ClassicAssert.AreEqual("SBGR", d.ICAO);
+ ClassicAssert.AreEqual(3, d.Day);
+ ClassicAssert.AreEqual("10:00 UTC", d.Time);
+ ClassicAssert.AreEqual(350, d.SurfaceWind.MeanDirection.ActualValue);
+ ClassicAssert.AreEqual(6, d.SurfaceWind.MeanSpeed.ActualValue);
+ ClassicAssert.AreEqual(9999, d.Visibility.PrevailingVisibility.ActualValue);
+ ClassicAssert.AreEqual(2, d.Clouds.Count);
+ ClassicAssert.AreEqual(27, d.AirTemperature.ActualValue);
+ ClassicAssert.AreEqual(18, d.DewPointTemperature.ActualValue);
+ ClassicAssert.AreEqual(1020, d.Pressure.ActualValue);
+ }
+
+ [Test]
+ public void TestParseRealWorldMetarWithPhenomena()
+ {
+ var d = decoder.ParseNotStrict("METAR SBSP 031200Z 09005KT 4000 -RA BR BKN010 OVC020 18/17 Q1019 ");
+ ClassicAssert.IsTrue(d.IsValid);
+ ClassicAssert.AreEqual("SBSP", d.ICAO);
+ ClassicAssert.AreEqual(4000, d.Visibility.PrevailingVisibility.ActualValue);
+ ClassicAssert.IsTrue(d.PresentWeather.Count >= 1);
+ }
+
+ [Test]
+ public void TestParseMetarWithWindshearMultipleRunways()
+ {
+ var d = decoder.ParseNotStrict("METAR LFPO 231027Z 24004KT 9999 FEW020 17/10 Q1009 WS R03 WS R21 ");
+ if (d.WindshearRunways != null)
+ {
+ ClassicAssert.IsTrue(d.WindshearRunways.Count >= 1);
+ }
+ }
+
+ [Test]
+ public void TestValueConversion()
+ {
+ var v = new Value(10, Unit.MeterPerSecond);
+ var ktValue = v.GetConvertedValue(Unit.Knot);
+ ClassicAssert.IsTrue(ktValue > 0);
+ }
+
+ [Test]
+ public void TestValueToString()
+ {
+ var v = new Value(15, Unit.Knot);
+ ClassicAssert.AreEqual("15 Knot", v.ToString());
+ }
+
+ [Test]
+ public void TestValueToInt()
+ {
+ ClassicAssert.AreEqual(10, Value.ToInt("10"));
+ ClassicAssert.AreEqual(-10, Value.ToInt("M10"));
+ ClassicAssert.IsNull(Value.ToInt("///"));
+ }
+
+ [Test]
+ public void TestParseMetarWithMPS()
+ {
+ var d = decoder.ParseNotStrict("METAR UUEE 231027Z 24004MPS 9999 FEW020 17/10 Q1009 ");
+ ClassicAssert.AreEqual(Unit.MeterPerSecond, d.SurfaceWind.MeanSpeed.ActualUnit);
+ ClassicAssert.AreEqual(4, d.SurfaceWind.MeanSpeed.ActualValue);
+ }
+
+ [Test]
+ public void TestParseMetarLowercaseInput()
+ {
+ var d = decoder.ParseNotStrict("metar lfpo 231027z 24004kt 9999 few020 17/10 q1009 ");
+ ClassicAssert.AreEqual("LFPO", d.ICAO);
+ }
+ }
+}
diff --git a/tests/Metar.Decoder.Tests/MetarDecoderTest.cs b/tests/Metar.Decoder.Tests/MetarDecoderTest.cs
index 11c35a3..b2ea675 100644
--- a/tests/Metar.Decoder.Tests/MetarDecoderTest.cs
+++ b/tests/Metar.Decoder.Tests/MetarDecoderTest.cs
@@ -10,7 +10,7 @@
using static Metar.Decoder.Entity.RunwayVisualRange;
using static Metar.Decoder.Entity.Value;
-namespace Metar.Decoder_tests
+namespace Metar.Decoder.Tests
{
///
/// MetarDecoderTest
diff --git a/tests/Metar.Decoder.Tests/ValueTest.cs b/tests/Metar.Decoder.Tests/ValueTest.cs
index 70a8d02..f206636 100644
--- a/tests/Metar.Decoder.Tests/ValueTest.cs
+++ b/tests/Metar.Decoder.Tests/ValueTest.cs
@@ -4,7 +4,7 @@
using System;
using System.Collections.Generic;
-namespace Metar.Decoder_tests
+namespace Metar.Decoder.Tests
{
///
/// ValueTest
diff --git a/tests/Taf.Decoder.Tests/BasicTest.cs b/tests/Taf.Decoder.Tests/BasicTest.cs
index 1ba0281..7e04713 100644
--- a/tests/Taf.Decoder.Tests/BasicTest.cs
+++ b/tests/Taf.Decoder.Tests/BasicTest.cs
@@ -4,9 +4,9 @@
using System.Collections.ObjectModel;
using System.Linq;
using Taf.Decoder;
-using Taf.Decoder.entity;
+using Taf.Decoder.Entity;
-namespace Taf.Decoder_tests
+namespace Taf.Decoder.Tests
{
[TestFixture]
public class BasicTest
diff --git a/tests/Taf.Decoder.Tests/ChunkDecoder/CloudChunkDecoderTest.cs b/tests/Taf.Decoder.Tests/ChunkDecoder/CloudChunkDecoderTest.cs
index 9ed1d9c..ae7ba67 100644
--- a/tests/Taf.Decoder.Tests/ChunkDecoder/CloudChunkDecoderTest.cs
+++ b/tests/Taf.Decoder.Tests/ChunkDecoder/CloudChunkDecoderTest.cs
@@ -3,10 +3,10 @@
using System;
using System.Collections.Generic;
using Taf.Decoder;
-using Taf.Decoder.chunkdecoder;
-using Taf.Decoder.entity;
+using Taf.Decoder.ChunkDecoder;
+using Taf.Decoder.Entity;
-namespace Taf.Decoder_tests.ChunkDecoder
+namespace Taf.Decoder.Tests.ChunkDecoder
{
[TestFixture, Category("CloudChunkDecoder")]
public class CloudChunkDecoderTest
diff --git a/tests/Taf.Decoder.Tests/ChunkDecoder/DatetimeChunkDecoderTest.cs b/tests/Taf.Decoder.Tests/ChunkDecoder/DatetimeChunkDecoderTest.cs
index 8c9e272..cfe520b 100644
--- a/tests/Taf.Decoder.Tests/ChunkDecoder/DatetimeChunkDecoderTest.cs
+++ b/tests/Taf.Decoder.Tests/ChunkDecoder/DatetimeChunkDecoderTest.cs
@@ -3,9 +3,9 @@
using System;
using System.Collections.Generic;
using Taf.Decoder;
-using Taf.Decoder.chunkdecoder;
+using Taf.Decoder.ChunkDecoder;
-namespace Taf.Decoder_tests.ChunkDecoder
+namespace Taf.Decoder.Tests.ChunkDecoder
{
[TestFixture, Category("DatetimeChunkDecoder")]
public class DatetimeChunkDecoderTest
diff --git a/tests/Taf.Decoder.Tests/ChunkDecoder/EvolutionChunkDecoderTest.cs b/tests/Taf.Decoder.Tests/ChunkDecoder/EvolutionChunkDecoderTest.cs
index 24f21cb..1d1f747 100644
--- a/tests/Taf.Decoder.Tests/ChunkDecoder/EvolutionChunkDecoderTest.cs
+++ b/tests/Taf.Decoder.Tests/ChunkDecoder/EvolutionChunkDecoderTest.cs
@@ -2,10 +2,10 @@
using NUnit.Framework.Legacy;
using System.Collections.Generic;
using Taf.Decoder;
-using Taf.Decoder.chunkdecoder;
-using Taf.Decoder.entity;
+using Taf.Decoder.ChunkDecoder;
+using Taf.Decoder.Entity;
-namespace Taf.Decoder_tests.ChunkDecoder
+namespace Taf.Decoder.Tests.ChunkDecoder
{
[TestFixture, Category("EvolutionChunkDecoder")]
public class EvolutionChunkDecoderTest
diff --git a/tests/Taf.Decoder.Tests/ChunkDecoder/ForecastPeriodChunkDecoderTest.cs b/tests/Taf.Decoder.Tests/ChunkDecoder/ForecastPeriodChunkDecoderTest.cs
index 775070d..5908268 100644
--- a/tests/Taf.Decoder.Tests/ChunkDecoder/ForecastPeriodChunkDecoderTest.cs
+++ b/tests/Taf.Decoder.Tests/ChunkDecoder/ForecastPeriodChunkDecoderTest.cs
@@ -3,10 +3,10 @@
using System;
using System.Collections.Generic;
using Taf.Decoder;
-using Taf.Decoder.chunkdecoder;
-using Taf.Decoder.entity;
+using Taf.Decoder.ChunkDecoder;
+using Taf.Decoder.Entity;
-namespace Taf.Decoder_tests.ChunkDecoder
+namespace Taf.Decoder.Tests.ChunkDecoder
{
[TestFixture, Category("ForecastPeriodChunkDecoder")]
public class ForecastPeriodChunkDecoderTest
diff --git a/tests/Taf.Decoder.Tests/ChunkDecoder/IcaoChunkDecoderTest.cs b/tests/Taf.Decoder.Tests/ChunkDecoder/IcaoChunkDecoderTest.cs
index d780677..fcc2771 100644
--- a/tests/Taf.Decoder.Tests/ChunkDecoder/IcaoChunkDecoderTest.cs
+++ b/tests/Taf.Decoder.Tests/ChunkDecoder/IcaoChunkDecoderTest.cs
@@ -3,9 +3,9 @@
using System;
using System.Collections.Generic;
using Taf.Decoder;
-using Taf.Decoder.chunkdecoder;
+using Taf.Decoder.ChunkDecoder;
-namespace Taf.Decoder_tests.ChunkDecoder
+namespace Taf.Decoder.Tests.ChunkDecoder
{
[TestFixture, Category("IcaoChunkDecoder")]
public class IcaoChunkDecoderTest
diff --git a/tests/Taf.Decoder.Tests/ChunkDecoder/ReportTypeChunkDecoderTest.cs b/tests/Taf.Decoder.Tests/ChunkDecoder/ReportTypeChunkDecoderTest.cs
index 3164ad5..5826d5d 100644
--- a/tests/Taf.Decoder.Tests/ChunkDecoder/ReportTypeChunkDecoderTest.cs
+++ b/tests/Taf.Decoder.Tests/ChunkDecoder/ReportTypeChunkDecoderTest.cs
@@ -3,9 +3,9 @@
using System;
using System.Collections.Generic;
using Taf.Decoder;
-using Taf.Decoder.chunkdecoder;
+using Taf.Decoder.ChunkDecoder;
-namespace Taf.Decoder_tests.ChunkDecoder
+namespace Taf.Decoder.Tests.ChunkDecoder
{
[TestFixture, Category("ReportTypeChunkDecoder")]
public class ReportTypeChunkDecoderTest
@@ -13,22 +13,22 @@ public class ReportTypeChunkDecoderTest
private static readonly ReportTypeChunkDecoder chunkDecoder = new ReportTypeChunkDecoder();
[Test, TestCaseSource("ValidChunks")]
- public void TestParse(Tuple chunk)
+ public void TestParse(Tuple chunk)
{
var decoded = chunkDecoder.Parse(chunk.Item1);
ClassicAssert.AreEqual(chunk.Item2, (decoded[TafDecoder.ResultKey] as Dictionary)[ReportTypeChunkDecoder.TypeParameterName]);
ClassicAssert.AreEqual(chunk.Item3, decoded[TafDecoder.RemainingTafKey]);
}
- public static List> ValidChunks => new List>()
+ public static List> ValidChunks => new List>()
{
- new Tuple("TAF LFPG", Taf.Decoder.entity.DecodedTaf.TafType.TAF, "LFPG"),
- new Tuple("TAF TAF LFPG", Taf.Decoder.entity.DecodedTaf.TafType.TAF, "LFPG"),
- new Tuple("TAF AMD LFPO", Taf.Decoder.entity.DecodedTaf.TafType.TAFAMD, "LFPO"),
- new Tuple("TA LFPG", Taf.Decoder.entity.DecodedTaf.TafType.NULL, "TA LFPG"),
- new Tuple("123 LFPO", Taf.Decoder.entity.DecodedTaf.TafType.NULL, "123 LFPO"),
- new Tuple("TAF COR LFPO", Taf.Decoder.entity.DecodedTaf.TafType.TAFCOR, "LFPO"),
- new Tuple("RTD EKEB", Taf.Decoder.entity.DecodedTaf.TafType.RTD, "EKEB"),
+ new Tuple("TAF LFPG", Taf.Decoder.Entity.DecodedTaf.TafType.TAF, "LFPG"),
+ new Tuple("TAF TAF LFPG", Taf.Decoder.Entity.DecodedTaf.TafType.TAF, "LFPG"),
+ new Tuple("TAF AMD LFPO", Taf.Decoder.Entity.DecodedTaf.TafType.TAFAMD, "LFPO"),
+ new Tuple("TA LFPG", Taf.Decoder.Entity.DecodedTaf.TafType.NULL, "TA LFPG"),
+ new Tuple("123 LFPO", Taf.Decoder.Entity.DecodedTaf.TafType.NULL, "123 LFPO"),
+ new Tuple("TAF COR LFPO", Taf.Decoder.Entity.DecodedTaf.TafType.TAFCOR, "LFPO"),
+ new Tuple("RTD EKEB", Taf.Decoder.Entity.DecodedTaf.TafType.RTD, "EKEB"),
};
}
}
\ No newline at end of file
diff --git a/tests/Taf.Decoder.Tests/ChunkDecoder/SurfaceWindChunkDecoderTest.cs b/tests/Taf.Decoder.Tests/ChunkDecoder/SurfaceWindChunkDecoderTest.cs
index 7a5c152..3265b29 100644
--- a/tests/Taf.Decoder.Tests/ChunkDecoder/SurfaceWindChunkDecoderTest.cs
+++ b/tests/Taf.Decoder.Tests/ChunkDecoder/SurfaceWindChunkDecoderTest.cs
@@ -3,11 +3,11 @@
using System;
using System.Collections.Generic;
using Taf.Decoder;
-using Taf.Decoder.chunkdecoder;
-using Taf.Decoder.entity;
-using static Taf.Decoder.entity.Value;
+using Taf.Decoder.ChunkDecoder;
+using Taf.Decoder.Entity;
+using static Taf.Decoder.Entity.Value;
-namespace Taf.Decoder_tests.ChunkDecoder
+namespace Taf.Decoder.Tests.ChunkDecoder
{
[TestFixture, Category("SurfaceWindChunkDecoder")]
public class SurfaceWindChunkDecoderTest
diff --git a/tests/Taf.Decoder.Tests/ChunkDecoder/TemperatureChunkDecoderTest.cs b/tests/Taf.Decoder.Tests/ChunkDecoder/TemperatureChunkDecoderTest.cs
index d13cf82..c4bd9a3 100644
--- a/tests/Taf.Decoder.Tests/ChunkDecoder/TemperatureChunkDecoderTest.cs
+++ b/tests/Taf.Decoder.Tests/ChunkDecoder/TemperatureChunkDecoderTest.cs
@@ -3,10 +3,10 @@
using System;
using System.Collections.Generic;
using Taf.Decoder;
-using Taf.Decoder.chunkdecoder;
-using Taf.Decoder.entity;
+using Taf.Decoder.ChunkDecoder;
+using Taf.Decoder.Entity;
-namespace Taf.Decoder_tests.ChunkDecoder
+namespace Taf.Decoder.Tests.ChunkDecoder
{
[TestFixture, Category("TemperatureChunkDecoder")]
public class TemperatureChunkDecoderTest
diff --git a/tests/Taf.Decoder.Tests/ChunkDecoder/VisibilityChunkDecoderTest.cs b/tests/Taf.Decoder.Tests/ChunkDecoder/VisibilityChunkDecoderTest.cs
index 32a117f..0449e64 100644
--- a/tests/Taf.Decoder.Tests/ChunkDecoder/VisibilityChunkDecoderTest.cs
+++ b/tests/Taf.Decoder.Tests/ChunkDecoder/VisibilityChunkDecoderTest.cs
@@ -3,10 +3,10 @@
using System;
using System.Collections.Generic;
using Taf.Decoder;
-using Taf.Decoder.chunkdecoder;
-using Taf.Decoder.entity;
+using Taf.Decoder.ChunkDecoder;
+using Taf.Decoder.Entity;
-namespace Taf.Decoder_tests.ChunkDecoder
+namespace Taf.Decoder.Tests.ChunkDecoder
{
[TestFixture, Category("VisibilityChunkDecoder")]
public class VisibilityChunkDecoderTest
diff --git a/tests/Taf.Decoder.Tests/ChunkDecoder/WeatherPhenomenonDecoderTest.cs b/tests/Taf.Decoder.Tests/ChunkDecoder/WeatherPhenomenonDecoderTest.cs
index f4c6a03..dfa3698 100644
--- a/tests/Taf.Decoder.Tests/ChunkDecoder/WeatherPhenomenonDecoderTest.cs
+++ b/tests/Taf.Decoder.Tests/ChunkDecoder/WeatherPhenomenonDecoderTest.cs
@@ -3,10 +3,10 @@
using System;
using System.Collections.Generic;
using Taf.Decoder;
-using Taf.Decoder.chunkdecoder;
-using Taf.Decoder.entity;
+using Taf.Decoder.ChunkDecoder;
+using Taf.Decoder.Entity;
-namespace Taf.Decoder_tests.ChunkDecoder
+namespace Taf.Decoder.Tests.ChunkDecoder
{
[TestFixture, Category("WeatherPhenomenon")]
public class WeatherPhenomenonDecoderTest
diff --git a/tests/Taf.Decoder.Tests/RtdIntegrationTest.cs b/tests/Taf.Decoder.Tests/RtdIntegrationTest.cs
index 0afbbf9..967017d 100644
--- a/tests/Taf.Decoder.Tests/RtdIntegrationTest.cs
+++ b/tests/Taf.Decoder.Tests/RtdIntegrationTest.cs
@@ -1,6 +1,7 @@
using NUnit.Framework;
using NUnit.Framework.Legacy;
using Taf.Decoder;
+using Taf.Decoder.Entity;
namespace Taf.Decoder.Tests
{
@@ -18,7 +19,7 @@ public void TestParseRtdTaf()
var result = decoder.Parse(rtdTaf);
// Assert - Most important: RTD type is recognized
- ClassicAssert.AreEqual(entity.DecodedTaf.TafType.RTD, result.Type);
+ ClassicAssert.AreEqual(DecodedTaf.TafType.RTD, result.Type);
ClassicAssert.AreEqual("EKEB", result.Icao);
ClassicAssert.AreEqual(19, result.Day);
ClassicAssert.AreEqual(rtdTaf, result.RawTaf);
@@ -41,7 +42,7 @@ public void TestParseRtdTafNotStrict()
// Assert
ClassicAssert.IsTrue(result.IsValid);
- ClassicAssert.AreEqual(entity.DecodedTaf.TafType.RTD, result.Type);
+ ClassicAssert.AreEqual(DecodedTaf.TafType.RTD, result.Type);
ClassicAssert.AreEqual("EKEB", result.Icao);
}
}
diff --git a/tests/Taf.Decoder.Tests/TafDecoderComprehensiveTest.cs b/tests/Taf.Decoder.Tests/TafDecoderComprehensiveTest.cs
new file mode 100644
index 0000000..9d47ca7
--- /dev/null
+++ b/tests/Taf.Decoder.Tests/TafDecoderComprehensiveTest.cs
@@ -0,0 +1,411 @@
+using NUnit.Framework;
+using NUnit.Framework.Legacy;
+using Taf.Decoder;
+using Taf.Decoder.Entity;
+using static Taf.Decoder.Entity.CloudLayer;
+using static Taf.Decoder.Entity.DecodedTaf;
+using static Taf.Decoder.Entity.Value;
+
+namespace Taf.Decoder.Tests
+{
+ [TestFixture, Category("TafDecoderComprehensiveTest")]
+ public class TafDecoderComprehensiveTest
+ {
+ private TafDecoder decoder;
+
+ [SetUp]
+ public void Setup()
+ {
+ decoder = new TafDecoder();
+ }
+
+ [Test]
+ public void TestParseTafBasic()
+ {
+ var d = decoder.ParseNotStrict("TAF LFPO 231100Z 2312/2418 24005KT 9999 FEW030 ");
+ ClassicAssert.AreEqual(TafType.TAF, d.Type);
+ ClassicAssert.AreEqual("LFPO", d.Icao);
+ ClassicAssert.AreEqual(23, d.Day);
+ ClassicAssert.AreEqual("11:00 UTC", d.Time);
+ }
+
+ [Test]
+ public void TestParseTafWithCavok()
+ {
+ var d = decoder.ParseNotStrict("TAF LFPO 231100Z 2312/2418 24005KT CAVOK ");
+ ClassicAssert.IsTrue(d.Cavok);
+ ClassicAssert.AreEqual("LFPO", d.Icao);
+ }
+
+ [Test]
+ public void TestParseTafWithVariableWind()
+ {
+ var d = decoder.ParseNotStrict("TAF LFPO 231100Z 2312/2418 VRB03KT 9999 FEW030 ");
+ ClassicAssert.IsTrue(d.SurfaceWind.VariableDirection);
+ ClassicAssert.IsNull(d.SurfaceWind.MeanDirection);
+ ClassicAssert.AreEqual(3, d.SurfaceWind.MeanSpeed.ActualValue);
+ }
+
+ [Test]
+ public void TestParseTafWithGust()
+ {
+ var d = decoder.ParseNotStrict("TAF LFPO 231100Z 2312/2418 24015G25KT 9999 FEW030 ");
+ ClassicAssert.AreEqual(15, d.SurfaceWind.MeanSpeed.ActualValue);
+ ClassicAssert.AreEqual(25, d.SurfaceWind.SpeedVariations.ActualValue);
+ ClassicAssert.AreEqual(Unit.Knot, d.SurfaceWind.MeanSpeed.ActualUnit);
+ }
+
+ [Test]
+ public void TestParseTafWithMultipleClouds()
+ {
+ var d = decoder.ParseNotStrict("TAF LFPO 231100Z 2312/2418 24005KT 9999 FEW020 SCT030 BKN060 ");
+ ClassicAssert.AreEqual(3, d.Clouds.Count);
+ ClassicAssert.AreEqual(CloudAmount.FEW, d.Clouds[0].Amount);
+ ClassicAssert.AreEqual(2000, d.Clouds[0].BaseHeight.ActualValue);
+ ClassicAssert.AreEqual(CloudAmount.SCT, d.Clouds[1].Amount);
+ ClassicAssert.AreEqual(CloudAmount.BKN, d.Clouds[2].Amount);
+ }
+
+ [Test]
+ public void TestParseTafWithCB()
+ {
+ var d = decoder.ParseNotStrict("TAF LFPO 231100Z 2312/2418 24005KT 9999 SCT025CB ");
+ ClassicAssert.AreEqual(1, d.Clouds.Count);
+ ClassicAssert.AreEqual(CloudType.CB, d.Clouds[0].Type);
+ }
+
+ [Test]
+ public void TestParseTafWithTCU()
+ {
+ var d = decoder.ParseNotStrict("TAF LFPO 231100Z 2312/2418 24005KT 9999 BKN035TCU ");
+ ClassicAssert.AreEqual(CloudType.TCU, d.Clouds[0].Type);
+ }
+
+ [Test]
+ public void TestParseTafWithNSC()
+ {
+ var d = decoder.ParseNotStrict("TAF LFPO 231100Z 2312/2418 24005KT 9999 NSC ");
+ ClassicAssert.AreEqual(0, d.Clouds.Count);
+ }
+
+ [Test]
+ public void TestParseTafWithVerticalVisibility()
+ {
+ var d = decoder.ParseNotStrict("TAF LFPO 231100Z 2312/2418 24005KT 0500 VV003 ");
+ ClassicAssert.AreEqual(1, d.Clouds.Count);
+ ClassicAssert.AreEqual(CloudAmount.VV, d.Clouds[0].Amount);
+ ClassicAssert.AreEqual(300, d.Clouds[0].BaseHeight.ActualValue);
+ }
+
+ [Test]
+ public void TestParseTafWithWeatherPhenomena()
+ {
+ var d = decoder.ParseNotStrict("TAF LFPO 231100Z 2312/2418 24005KT 3000 -RA BKN010 ");
+ ClassicAssert.IsTrue(d.WeatherPhenomenons.Count >= 1);
+ }
+
+ [Test]
+ public void TestParseTafWithFZRA()
+ {
+ var d = decoder.ParseNotStrict("TAF LFPO 231100Z 2312/2418 24005KT 2000 FZRA BKN010 ");
+ ClassicAssert.IsTrue(d.WeatherPhenomenons.Count >= 1);
+ }
+
+ [Test]
+ public void TestParseTafWithUSVisibility()
+ {
+ var d = decoder.ParseNotStrict("TAF KJFK 231100Z 2312/2418 24005KT 3SM FEW030 ");
+ ClassicAssert.AreEqual(3, d.Visibility.ActualVisibility.ActualValue);
+ ClassicAssert.AreEqual(Unit.StatuteMile, d.Visibility.ActualVisibility.ActualUnit);
+ }
+
+ [Test]
+ public void TestParseTafWithFractionalUSVisibility()
+ {
+ var d = decoder.ParseNotStrict("TAF KJFK 231100Z 2312/2418 24005KT 1 1/2SM FEW030 ");
+ ClassicAssert.AreEqual(1.5, d.Visibility.ActualVisibility.ActualValue, 0.01);
+ }
+
+ [Test]
+ public void TestParseTafWithEvolutions()
+ {
+ var d = decoder.ParseNotStrict("TAF LFPO 231100Z 2312/2418 24005KT 9999 FEW030 TEMPO 2312/2315 24010KT 3000 -RA BKN010 ");
+ // Evolutions are stored on each entity (SurfaceWind, Visibility, etc.), not on DecodedTaf directly
+ ClassicAssert.IsNotNull(d.SurfaceWind);
+ ClassicAssert.IsTrue(d.SurfaceWind.Evolutions.Count >= 1);
+ }
+
+ [Test]
+ public void TestParseTafWithBECMG()
+ {
+ var d = decoder.ParseNotStrict("TAF LFPO 231100Z 2312/2418 24005KT 9999 FEW030 BECMG 2315/2318 18010KT 9999 SCT020 ");
+ ClassicAssert.IsNotNull(d.SurfaceWind);
+ ClassicAssert.IsTrue(d.SurfaceWind.Evolutions.Count >= 1);
+ ClassicAssert.AreEqual("BECMG", d.SurfaceWind.Evolutions[0].Type);
+ }
+
+ [Test]
+ public void TestParseTafWithFM()
+ {
+ var d = decoder.ParseNotStrict("TAF LFPO 231100Z 2312/2418 24005KT 9999 FEW030 FM231500 18010KT 9999 SCT020 ");
+ ClassicAssert.IsNotNull(d.SurfaceWind);
+ ClassicAssert.IsTrue(d.SurfaceWind.Evolutions.Count >= 1);
+ ClassicAssert.AreEqual("FM", d.SurfaceWind.Evolutions[0].Type);
+ }
+
+ [Test]
+ public void TestParseTafWithPROB()
+ {
+ var d = decoder.ParseNotStrict("TAF LFPO 231100Z 2312/2418 24005KT 9999 FEW030 PROB40 TEMPO 2318/2320 24010KT 2000 TSRA BKN010 ");
+ // PROB evolutions are stored on the entities
+ ClassicAssert.IsNotNull(d.SurfaceWind);
+ }
+
+ [Test]
+ public void TestParseTafWithTemperature()
+ {
+ var d = decoder.ParseNotStrict("TAF LFPO 231100Z 2312/2418 24005KT 9999 FEW030 TX25/2314Z TN15/2405Z ");
+ if (d.MaximumTemperature != null)
+ {
+ ClassicAssert.AreEqual("TX", d.MaximumTemperature.Type);
+ }
+ if (d.MinimumTemperature != null)
+ {
+ ClassicAssert.AreEqual("TN", d.MinimumTemperature.Type);
+ }
+ }
+
+ [Test]
+ public void TestParseTafWithMPS()
+ {
+ var d = decoder.ParseNotStrict("TAF UUEE 231100Z 2312/2418 24005MPS 9999 FEW030 ");
+ ClassicAssert.AreEqual(Unit.MeterPerSecond, d.SurfaceWind.MeanSpeed.ActualUnit);
+ }
+
+ [Test]
+ public void TestParseTafWithKPH()
+ {
+ var d = decoder.ParseNotStrict("TAF LFPO 231100Z 2312/2418 24010KPH 9999 FEW030 ");
+ ClassicAssert.AreEqual(Unit.KilometerPerHour, d.SurfaceWind.MeanSpeed.ActualUnit);
+ }
+
+ [Test]
+ public void TestParseTafAMD()
+ {
+ var d = decoder.ParseNotStrict("TAF AMD LFPO 231100Z 2312/2418 24005KT 9999 FEW030 ");
+ ClassicAssert.AreEqual(TafType.TAFAMD, d.Type);
+ }
+
+ [Test]
+ public void TestParseTafCOR()
+ {
+ var d = decoder.ParseNotStrict("TAF COR LFPO 231100Z 2312/2418 24005KT 9999 FEW030 ");
+ ClassicAssert.AreEqual(TafType.TAFCOR, d.Type);
+ }
+
+ [Test]
+ public void TestParseTafStrictWithErrors()
+ {
+ var d = decoder.ParseStrict("TAF LFPO 231100Z 2312/2418 INVALID_WIND 9999 FEW030 ");
+ ClassicAssert.IsFalse(d.IsValid);
+ }
+
+ [Test]
+ public void TestParseTafNotStrictWithErrors()
+ {
+ var d = decoder.ParseNotStrict("TAF LFPO 231100Z 2312/2418 INVALID_WIND 9999 FEW030 ");
+ ClassicAssert.IsFalse(d.IsValid);
+ ClassicAssert.IsTrue(d.DecodingExceptions.Count > 0);
+ }
+
+ [Test]
+ public void TestParseTafMissingType()
+ {
+ var d = decoder.ParseNotStrict("LFPO 231100Z 2312/2418 24005KT 9999 FEW030 ");
+ ClassicAssert.AreEqual(TafType.NULL, d.Type);
+ ClassicAssert.AreEqual("LFPO", d.Icao);
+ }
+
+ [Test]
+ public void TestParseTafForecastPeriod()
+ {
+ var d = decoder.ParseNotStrict("TAF LFPO 231100Z 2312/2418 24005KT 9999 FEW030 ");
+ ClassicAssert.IsNotNull(d.ForecastPeriod);
+ ClassicAssert.AreEqual(23, d.ForecastPeriod.FromDay);
+ ClassicAssert.AreEqual(12, d.ForecastPeriod.FromHour);
+ ClassicAssert.AreEqual(24, d.ForecastPeriod.ToDay);
+ ClassicAssert.AreEqual(18, d.ForecastPeriod.ToHour);
+ }
+
+ [Test]
+ public void TestParseTafWithOVC()
+ {
+ var d = decoder.ParseNotStrict("TAF LFPO 231100Z 2312/2418 24005KT 3000 OVC005 ");
+ ClassicAssert.AreEqual(1, d.Clouds.Count);
+ ClassicAssert.AreEqual(CloudAmount.OVC, d.Clouds[0].Amount);
+ ClassicAssert.AreEqual(500, d.Clouds[0].BaseHeight.ActualValue);
+ }
+
+ [Test]
+ public void TestParseTafResetExceptions()
+ {
+ var d = decoder.ParseNotStrict("TAF LFPO 231100Z 2312/2418 INVALID 9999 FEW030 ");
+ ClassicAssert.IsFalse(d.IsValid);
+ d.ResetDecodingExceptions();
+ ClassicAssert.IsTrue(d.IsValid);
+ }
+
+ [Test]
+ public void TestParseTafLowercaseInput()
+ {
+ var d = decoder.ParseNotStrict("taf lfpo 231100z 2312/2418 24005kt 9999 few030 ");
+ ClassicAssert.AreEqual("LFPO", d.Icao);
+ }
+
+ [Test]
+ public void TestParseTafWithDirectionVariation()
+ {
+ var d = decoder.ParseNotStrict("TAF LFPO 231100Z 2312/2418 24005KT 180V270 9999 FEW030 ");
+ if (d.SurfaceWind.DirectionVariations != null)
+ {
+ ClassicAssert.AreEqual(180, d.SurfaceWind.DirectionVariations[0].ActualValue);
+ ClassicAssert.AreEqual(270, d.SurfaceWind.DirectionVariations[1].ActualValue);
+ }
+ }
+
+ [Test]
+ public void TestParseTafNoVisibilityInfo()
+ {
+ var d = decoder.ParseNotStrict("TAF LFPO 231100Z 2312/2418 24005KT //// FEW030 ");
+ ClassicAssert.IsNull(d.Visibility);
+ }
+
+ [Test]
+ public void TestParseTafWithNegativeTemperature()
+ {
+ var d = decoder.ParseNotStrict("TAF LFPO 231100Z 2312/2418 24005KT 9999 FEW030 TX02/2314Z TNM10/2405Z ");
+ if (d.MaximumTemperature != null)
+ {
+ ClassicAssert.AreEqual("TX", d.MaximumTemperature.Type);
+ }
+ if (d.MinimumTemperature != null)
+ {
+ ClassicAssert.AreEqual(-10, d.MinimumTemperature.TemperatureValue.ActualValue);
+ }
+ }
+
+ [Test]
+ public void TestParseRealWorldTaf()
+ {
+ var d = decoder.ParseNotStrict("TAF SBGR 031100Z 0312/0418 35008KT 9999 FEW040 SCT100 TX30/0318Z TN20/0409Z ");
+ ClassicAssert.AreEqual("SBGR", d.Icao);
+ ClassicAssert.AreEqual(3, d.Day);
+ ClassicAssert.IsNotNull(d.SurfaceWind);
+ ClassicAssert.IsNotNull(d.Visibility);
+ ClassicAssert.IsTrue(d.Clouds.Count >= 1);
+ }
+
+ [Test]
+ public void TestParseRealWorldTafWithEvolutions()
+ {
+ var d = decoder.ParseNotStrict("TAF SBSP 031200Z 0312/0418 09005KT 9999 FEW025 TEMPO 0312/0315 09010KT 4000 -RA BKN010 BECMG 0315/0317 18010KT 9999 SCT020 ");
+ ClassicAssert.AreEqual("SBSP", d.Icao);
+ // Evolutions are stored on each entity
+ ClassicAssert.IsNotNull(d.SurfaceWind);
+ ClassicAssert.IsTrue(d.SurfaceWind.Evolutions.Count >= 1);
+ }
+
+ [Test]
+ public void TestParseTafWithMultipleEvolutions()
+ {
+ var d = decoder.ParseNotStrict("TAF LFPO 231100Z 2312/2418 24005KT 9999 FEW030 TEMPO 2312/2315 24010KT 3000 -RA BKN010 BECMG 2315/2318 18010KT 9999 SCT020 FM231800 27015G25KT 9999 SCT025 ");
+ ClassicAssert.IsNotNull(d.SurfaceWind);
+ // Multiple evolutions are stored on the wind entity
+ ClassicAssert.IsTrue(d.SurfaceWind.Evolutions.Count >= 1);
+ }
+
+ [Test]
+ public void TestSetStrictParsing()
+ {
+ decoder.SetStrictParsing(true);
+ var d = decoder.Parse("TAF LFPO 231100Z 2312/2418 24005KT 9999 FEW030 ");
+ ClassicAssert.IsTrue(d.IsValid);
+ }
+
+ [Test]
+ public void TestParseTafRTD()
+ {
+ var d = decoder.ParseNotStrict("RTD EKEB 190416Z 1905/1912 13006KT 0200 FZFG BKN001 ");
+ ClassicAssert.AreEqual(TafType.RTD, d.Type);
+ ClassicAssert.AreEqual("EKEB", d.Icao);
+ }
+
+ [Test]
+ public void TestParseTafWithSKC()
+ {
+ var d = decoder.ParseNotStrict("TAF LFPO 231100Z 2312/2418 24005KT 9999 SKC ");
+ ClassicAssert.AreEqual(0, d.Clouds.Count);
+ }
+
+ [Test]
+ public void TestParseTafWithCLR()
+ {
+ var d = decoder.ParseNotStrict("TAF LFPO 231100Z 2312/2418 24005KT 9999 CLR ");
+ ClassicAssert.AreEqual(0, d.Clouds.Count);
+ }
+
+ [Test]
+ public void TestTafValueConversions()
+ {
+ var v = new Value(10, Unit.MeterPerSecond);
+ var ktValue = v.GetConvertedValue(Unit.Knot);
+ ClassicAssert.IsTrue(ktValue > 0);
+ }
+
+ [Test]
+ public void TestTafValueToString()
+ {
+ var v = new Value(15, Unit.Knot);
+ ClassicAssert.AreEqual("15 Knot", v.ToString());
+ }
+
+ [Test]
+ public void TestTafValueToInt()
+ {
+ ClassicAssert.AreEqual(10, Value.ToInt("10"));
+ ClassicAssert.AreEqual(-10, Value.ToInt("M10"));
+ ClassicAssert.IsNull(Value.ToInt("///"));
+ }
+
+ [Test]
+ public void TestParseTafWithWindDirectionVariation()
+ {
+ var d = decoder.ParseNotStrict("TAF LFPO 231100Z 2312/2418 24005KT 200V280 9999 FEW030 ");
+ if (d.SurfaceWind.DirectionVariations != null)
+ {
+ ClassicAssert.AreEqual(2, d.SurfaceWind.DirectionVariations.Length);
+ }
+ }
+
+ [Test]
+ public void TestParseTafWithPROB30TEMPO()
+ {
+ var d = decoder.ParseNotStrict("TAF LFPO 231100Z 2312/2418 24005KT 9999 FEW030 PROB30 TEMPO 2318/2320 24010KT 2000 TSRA BKN010 ");
+ ClassicAssert.IsNotNull(d.SurfaceWind);
+ }
+
+ [Test]
+ public void TestParseTafWithEndMarker()
+ {
+ var d = decoder.ParseNotStrict("TAF LFPO 231100Z 2312/2418 24005KT 9999 FEW030=");
+ ClassicAssert.AreEqual("LFPO", d.Icao);
+ }
+
+ [Test]
+ public void TestParseTafWithExtraSpaces()
+ {
+ var d = decoder.ParseNotStrict("TAF LFPO 231100Z 2312/2418 24005KT 9999 FEW030 ");
+ ClassicAssert.AreEqual("LFPO", d.Icao);
+ }
+ }
+}
diff --git a/tests/Taf.Decoder.Tests/TafDecoderTest.cs b/tests/Taf.Decoder.Tests/TafDecoderTest.cs
index 76e1ba0..7174f6a 100644
--- a/tests/Taf.Decoder.Tests/TafDecoderTest.cs
+++ b/tests/Taf.Decoder.Tests/TafDecoderTest.cs
@@ -4,11 +4,11 @@
using System.Collections.Generic;
using System.Linq;
using Taf.Decoder;
-using Taf.Decoder.chunkdecoder;
-using Taf.Decoder.entity;
-using static Taf.Decoder.entity.DecodedTaf;
+using Taf.Decoder.ChunkDecoder;
+using Taf.Decoder.Entity;
+using static Taf.Decoder.Entity.DecodedTaf;
-namespace Taf.Decoder_tests
+namespace Taf.Decoder.Tests
{
[TestFixture, Category("TafDecoder")]
public class TafDecoderTest
diff --git a/tests/Taf.Decoder.Tests/ValueTest.cs b/tests/Taf.Decoder.Tests/ValueTest.cs
index e18df74..9f072a0 100644
--- a/tests/Taf.Decoder.Tests/ValueTest.cs
+++ b/tests/Taf.Decoder.Tests/ValueTest.cs
@@ -2,9 +2,9 @@
using NUnit.Framework.Legacy;
using System;
using System.Collections.Generic;
-using Taf.Decoder.entity;
+using Taf.Decoder.Entity;
-namespace Taf.Decoder_tests
+namespace Taf.Decoder.Tests
{
[TestFixture, Category("Entity")]
public class ValueTest