Repository navigation
Simplify the PlantUML import patterns - #521
Draft
alexanderlinne wants to merge 2 commits into
Draft
alexanderlinne wants to merge 2 commits into
alexanderlinne wants to merge 2 commits into
Conversation
Cover the error paths of PlantUmlParser: null arguments, a missing file and a stream that fails while reading. Pin the optional parts of the component and dependency patterns with characterization tests, so they can be rewritten safely: stereotypes with and without whitespace between them, quoted and unquoted aliases, surrounding whitespace, lines that are not components, and dependencies in both directions with and without brackets and descriptions. Signed-off-by: Alexander Linne <alexander.linne@tngtech.com>
Write each regex as one readable definition instead of assembling it from fields in a static constructor via Capture and AnythingBut. PlantUmlPatterns becomes a static class holding the shared stereotype fragment, and the matchers become parsed results: TryParse returns null (or nothing) for lines that don't match, so each component line is matched once, and the Match...() methods become properties. This removes FilterComponents, MatchComponent and the unreachable throw and null checks. In the parser, merge the two ReadLines overloads, drop a redundant Distinct() and stop building a regex for every line to filter comments. Stereotypes are now read from a named group of the component match instead of a second pass over the whole line. Before, a stereotype-like alias was read as a stereotype too, so `[A] <<Real.*>> as "<<Fake.*>>"` gave A the stereotypes Real.* and Fake.*, and `[A] as "<<Foo>>"` was accepted although it has no stereotype. Signed-off-by: Alexander Linne <alexander.linne@tngtech.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #521 +/- ##
==========================================
+ Coverage 86.55% 86.72% +0.17%
==========================================
Files 261 261
Lines 12648 12559 -89
Branches 1236 1231 -5
==========================================
- Hits 10947 10892 -55
+ Misses 1359 1330 -29
+ Partials 342 337 -5 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The next three PRs rewrite the component and dependency patterns, so this PR first makes them readable and pins what they match without changing it.
PlantUmlPatternswas hard to read and to change:static readonly stringfields, some set in a static constructor, throughCaptureandAnythingButhelpers, and anchored twice (\A(?:^ … )\z). To see what it matched, you had to put it together in your head.MatchStereoTypes()stepped a storedMatchforward, so a second call returned an empty set.FilterComponentsand again by thePlantUmlComponentMatcherconstructor, which threw if the line didn't match.PlantUmlPatternswas an object without state that the parser created withnew, and the "matchers" were really parsed results, read throughMatch…()methods.What changes
Tests first. The first commit adds tests through
PlantUmlParseronly, so that they survive the refactoring:Parse(null)for a file and a stream, a missing file, and a stream whoseReadthrows,: description, and lines that must not count as dependencies.All of them pass on
main.Patterns. Each regex is one readable definition.
PlantUmlPatternsbecomes a static class that holds the shared stereotype fragment, a named and repeatedstereotypegroup read throughCaptures.Matchers.
PlantUmlComponentMatcher.TryParsereturnsnullfor lines that aren't components, andPlantUmlDependencyMatcher.TryParsereplacesTryParseFromLeftToRightandTryParseFromRightToLeft. Each line is matched once, andName,Alias,Stereotypes,OriginandTargetare properties.FilterComponents,MatchComponent, the unreachable throw and the unreachable null checks go away. The matchers stay inPlantUmlPatterns.cs, so that the PRs on top rebase cleanly.Parser.
TryParsemethods directly, without thePlantUmlPatternsinstance.ReadLinesoverloads, which repeated the samecatch … whenfilter, become one.Distinct()before aHashSetis dropped.Main's way of splitting dependency lines stays as it is; #PR2 replaces it.
After this PR,
PlantUmlPatterns.csandPlantUmlParser.cshave 100% line and branch coverage.Behaviour change
Because stereotypes are now read from the component match, text that only looks like a stereotype is no longer read as one. Before,
[A] <<Real.*>> as "<<Fake.*>>"gaveAthe stereotypesReal.*andFake.*, and[A] as "<<Foo>>"was accepted although it has no stereotype. A regression test pins this. Apart from that, the import matches exactly what it matched before.