test: aumenta cobertura para 99,8%#104
Conversation
…llow-up fix: torna DictionaryExtensions public e remove using redundante
…yDecodedData) Co-Authored-By: Afonso Dutra Nogueira Filho <[email protected]>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
|
Qodana Community for .NET27 new problems were found
💡 Qodana analysis was run in the pull request mode: only the changed files were checked View the detailed Qodana reportTo be able to view the detailed Qodana report, you can either:
To get - name: 'Qodana Scan'
uses: JetBrains/[email protected]
with:
upload-result: trueContact Qodana teamContact us at [email protected]
|
| public void TestAddEvolutionThrowsForUnknownEntity() | ||
| { | ||
| var method = typeof(EvolutionChunkDecoder).GetMethod("AddEvolution", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); | ||
| var decoder = new EvolutionChunkDecoder(true, false); | ||
| var decodedTaf = new DecodedTaf("TAF KJFK 080500Z 0806/0910 23010KT"); | ||
| var evolution = new Evolution(); | ||
| var result = new Dictionary<string, object> { { "Type", new object() } }; | ||
|
|
||
| var ex = ClassicAssert.Throws<System.Reflection.TargetInvocationException>(() => | ||
| { | ||
| method.Invoke(decoder, new object[] { decodedTaf, evolution, result, "Type" }); | ||
| }); | ||
|
|
||
| ClassicAssert.That(ex.InnerException, Is.InstanceOf<TafChunkDecoderException>()); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Test HandleDecodeFailure in strict mode throws. | ||
| /// </summary> | ||
| [Test] | ||
| public void TestHandleDecodeFailureStrictThrows() | ||
| { | ||
| var method = typeof(EvolutionChunkDecoder).GetMethod("HandleDecodeFailure", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); | ||
| var decoder = new EvolutionChunkDecoder(true, true); | ||
| var remaining = "AAA"; | ||
| var ex = ClassicAssert.Throws<System.Reflection.TargetInvocationException>(() => | ||
| { | ||
| method.Invoke(decoder, new object[] { "BAD", remaining }); | ||
| }); | ||
| ClassicAssert.That(ex.InnerException, Is.InstanceOf<TafChunkDecoderException>()); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Test HandleDecodeFailure in non-strict mode consumes one chunk. | ||
| /// </summary> | ||
| [Test] | ||
| public void TestHandleDecodeFailureNonStrictConsumesChunk() | ||
| { | ||
| var method = typeof(EvolutionChunkDecoder).GetMethod("HandleDecodeFailure", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); | ||
| var decoder = new EvolutionChunkDecoder(false, false); | ||
| var parameters = new object[] { "BAD", "BAD REMAINING" }; | ||
| method.Invoke(decoder, parameters); | ||
| ClassicAssert.That(parameters[1], Is.EqualTo("REMAINING")); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Test ApplyDecodedChunk throws when result is not a dictionary. | ||
| /// </summary> | ||
| [Test] | ||
| public void TestApplyDecodedChunkThrowsForInvalidResult() | ||
| { | ||
| var method = typeof(EvolutionChunkDecoder).GetMethod("ApplyDecodedChunk", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); | ||
| var decoder = new EvolutionChunkDecoder(true, false); | ||
| var decodedTaf = new DecodedTaf("TAF KJFK 080500Z 0806/0910 23010KT"); | ||
| var evolution = new Evolution(); | ||
| var decoded = new Dictionary<string, object> { { TafDecoder.ResultKey, "not a dictionary" }, { TafDecoder.RemainingTafKey, "AAA" } }; | ||
|
|
||
| var ex = ClassicAssert.Throws<System.Reflection.TargetInvocationException>(() => | ||
| { | ||
| method.Invoke(decoder, new object[] { evolution, "AAA", decodedTaf, decoded }); | ||
| }); | ||
|
|
||
| ClassicAssert.That(ex.InnerException, Is.InstanceOf<TafChunkDecoderException>()); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Test ApplyDecodedChunk throws when entity is null and not visibility. | ||
| /// </summary> | ||
| [Test] | ||
| public void TestApplyDecodedChunkThrowsForNullEntity() | ||
| { | ||
| var method = typeof(EvolutionChunkDecoder).GetMethod("ApplyDecodedChunk", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); | ||
| var decoder = new EvolutionChunkDecoder(true, false); | ||
| var decodedTaf = new DecodedTaf("TAF KJFK 080500Z 0806/0910 23010KT"); | ||
| var evolution = new Evolution(); | ||
| var result = new Dictionary<string, object> { { SurfaceWindChunkDecoder.SurfaceWindParameterName, null } }; | ||
| var decoded = new Dictionary<string, object> { { TafDecoder.ResultKey, result }, { TafDecoder.RemainingTafKey, "AAA" } }; | ||
|
|
||
| var ex = ClassicAssert.Throws<System.Reflection.TargetInvocationException>(() => | ||
| { | ||
| method.Invoke(decoder, new object[] { evolution, "AAA", decodedTaf, decoded }); | ||
| }); | ||
|
|
||
| ClassicAssert.That(ex.InnerException, Is.InstanceOf<TafChunkDecoderException>()); | ||
| } |
There was a problem hiding this comment.
📝 Info: Tests use reflection to access private methods, creating coupling to implementation details
All new tests in this PR use System.Reflection.BindingFlags.NonPublic to invoke private/static methods directly (e.g., RunwayVisualRangeChunkDecoder.ToValue, MetarDecoder.ApplyDecodedData, EvolutionChunkDecoder.HandleDecodeFailure). While this achieves the coverage goal, these tests will break silently (at runtime, not compile time) if any of these methods are renamed, have their signatures changed, or are refactored. Consider whether some of these error paths could be tested through the public API instead, which would be more resilient to refactoring.
Was this helpful? React with 👍 or 👎 to provide feedback.
| public void TestHandleDecodeFailureNonStrictConsumesChunk() | ||
| { | ||
| var method = typeof(EvolutionChunkDecoder).GetMethod("HandleDecodeFailure", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); | ||
| var decoder = new EvolutionChunkDecoder(false, false); | ||
| var parameters = new object[] { "BAD", "BAD REMAINING" }; | ||
| method.Invoke(decoder, parameters); | ||
| ClassicAssert.That(parameters[1], Is.EqualTo("REMAINING")); | ||
| } |
There was a problem hiding this comment.
📝 Info: Reflection-based ref parameter test relies on subtle .NET behavior
The test at line 346-348 relies on the fact that when invoking a method with a ref parameter via MethodInfo.Invoke, the parameters array is modified in-place to reflect the updated value. This is correct .NET behavior but is non-obvious. The HandleDecodeFailure method signature is (string chunk, ref string remainingEvolutions) at src/Taf.Decoder/ChunkDecoder/EvolutionChunkDecoder.cs:173, and ConsumeOneChunk("BAD REMAINING") correctly returns "REMAINING" by splitting on the first space.
Was this helpful? React with 👍 or 👎 to provide feedback.
| public void TestAddEvolutionThrowsForUnknownEntity() | ||
| { | ||
| var method = typeof(EvolutionChunkDecoder).GetMethod("AddEvolution", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); | ||
| var decoder = new EvolutionChunkDecoder(true, false); |
| public void TestHandleDecodeFailureStrictThrows() | ||
| { | ||
| var method = typeof(EvolutionChunkDecoder).GetMethod("HandleDecodeFailure", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); | ||
| var decoder = new EvolutionChunkDecoder(true, true); |
| public void TestHandleDecodeFailureNonStrictConsumesChunk() | ||
| { | ||
| var method = typeof(EvolutionChunkDecoder).GetMethod("HandleDecodeFailure", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); | ||
| var decoder = new EvolutionChunkDecoder(false, false); |
| public void TestApplyDecodedChunkThrowsForInvalidResult() | ||
| { | ||
| var method = typeof(EvolutionChunkDecoder).GetMethod("ApplyDecodedChunk", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); | ||
| var decoder = new EvolutionChunkDecoder(true, false); |
| public void TestApplyDecodedChunkThrowsForNullEntity() | ||
| { | ||
| var method = typeof(EvolutionChunkDecoder).GetMethod("ApplyDecodedChunk", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); | ||
| var decoder = new EvolutionChunkDecoder(true, false); |



All Submissions:
New Feature Submissions:
Changes to Core Features:
Summary
Aumenta a cobertura de testes para 99,8% line e 99,5% branch.
Novos testes:
Value.ToInt(null)/Value.ToInt("")retornanull(METAR e TAF)RunwayVisualRangeChunkDecoder.ToValuecom string vazia e string inválidaEvolutionChunkDecoder:AddEvolutioncom entidade desconhecidaHandleDecodeFailureem modo estrito e não-estritoApplyDecodedChunkcom resultado inválido e entidade nulaMetarDecoder.ApplyDecodedDatacom propriedade desconhecidaTafDecoder.ApplyDecodedDatacom propriedade desconhecidaValidação
dotnet test tests/Metar.Decoder.Tests/net8.0/net10.0 — 244/244 passandodotnet test tests/Taf.Decoder.Tests/net8.0/net10.0 — 200/200 passandoObservações
As 2 linhas restantes sem cobertura em
EvolutionChunkDecodersão caminhos defensivos/inacessíveis (defaultdoswitchdeAddEvolutionnão é alcançado porqueInstantiateEntityjá lança para entidades desconhecidas).Link to Devin session: https://app.devin.ai/sessions/94a258020ea4488c8eecc672035d0da1
Requested by: @afonsoft