diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index d2ccc67..f8fcf34 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -10,7 +10,12 @@ jobs: steps: - uses: actions/checkout@v4 - uses: dart-lang/setup-dart@v1 + - run: sudo apt-get install lcov -y + - run: mkdir -p ./build/coverage - run: dart pub get - run: dart format --output=none --set-exit-if-changed . - run: dart analyze - - run: dart test + - run: dart pub global activate coverage + - run: dart test test/main.dart --coverage=./build/coverage + - run: dart pub global run coverage:format_coverage --lcov --check-ignore --in=./build/coverage --out=./build/lcov.info --packages=./.dart_tool/package_config.json --report-on=lib + - run: "sudo genhtml ./build/lcov.info --output=.build/coverage/html | grep 'lines.*: 100.0%'" diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f7291a..cbf6ef5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,23 +1,28 @@ -## 1.0.5 +# 2.0.0 +- If a element of map of a list is not JSON serializable it'll be ignore but the subsequence elements will be added to the resulting `Json` - `Json` and `JsonPayload` equal operator override to handle comparison by instance or by value -## 1.0.4 +## Breaking changes +- `ofType`, `listOf` and `mapOf` will wrap the element in a `Json` when calling `builder` instead of the raw value +- When expecting a single type when raw value is heterogeneous list and maps, matching type element will remain and the rest will be discarded instead of returning empty list/map + +# 1.0.4 - `Json` and `JsonPayload` are json encodable, meaning they can be use with `darat:convert jsonEncode` -## 1.0.3 +# 1.0.3 - Fixed `JsonPayload` nested assignment -## 1.0.2 +# 1.0.2 - Fixed `JsonPayload` nested assignment -## 1.0.1 +# 1.0.1 - `.float` returns a value when actual value is an integer -## 1.0.0 +# 1.0.0 - Initial version. diff --git a/Makefile b/Makefile index 922e6bf..624fe55 100644 --- a/Makefile +++ b/Makefile @@ -2,4 +2,4 @@ test_with_coverage: dart pub global activate coverage dart test test/main.dart --coverage=./build/coverage dart pub global run coverage:format_coverage --lcov --check-ignore --in=./build/coverage --out=./build/lcov.info --packages=./.dart_tool/package_config.json --report-on=lib - genhtml ./build/lcov.info --output=./build/coverage/html \ No newline at end of file + genhtml ./build/lcov.info --output=./build/coverage/html diff --git a/amber.png b/amber.png new file mode 100644 index 0000000..2cab170 Binary files /dev/null and b/amber.png differ diff --git a/cmd_line b/cmd_line new file mode 100644 index 0000000..4335b72 --- /dev/null +++ b/cmd_line @@ -0,0 +1 @@ +genhtml ./build/lcov.info diff --git a/emerald.png b/emerald.png new file mode 100644 index 0000000..38ad4f4 Binary files /dev/null and b/emerald.png differ diff --git a/gcov.css b/gcov.css new file mode 100644 index 0000000..6c23ba9 --- /dev/null +++ b/gcov.css @@ -0,0 +1,1101 @@ +/* All views: initial background and text color */ +body +{ + color: #000000; + background-color: #ffffff; +} + +/* All views: standard link format*/ +a:link +{ + color: #284fa8; + text-decoration: underline; +} + +/* All views: standard link - visited format */ +a:visited +{ + color: #00cb40; + text-decoration: underline; +} + +/* All views: standard link - activated format */ +a:active +{ + color: #ff0040; + text-decoration: underline; +} + +/* All views: main title format */ +td.title +{ + text-align: center; + padding-bottom: 10px; + font-family: sans-serif; + font-size: 20pt; + font-style: italic; + font-weight: bold; +} +/* "Line coverage date bins" leader */ +td.subTableHeader +{ + text-align: center; + padding-bottom: 6px; + font-family: sans-serif; + font-weight: bold; + vertical-align: center; +} + +/* All views: header item format */ +td.headerItem +{ + text-align: right; + padding-right: 6px; + font-family: sans-serif; + font-weight: bold; + vertical-align: top; + white-space: nowrap; +} + +/* All views: header item value format */ +td.headerValue +{ + text-align: left; + color: #284fa8; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; +} + +/* All views: header item coverage table heading */ +td.headerCovTableHead +{ + text-align: center; + padding-right: 6px; + padding-left: 6px; + padding-bottom: 0px; + font-family: sans-serif; + white-space: nowrap; +} + +/* All views: header item coverage table entry */ +td.headerCovTableEntry +{ + text-align: right; + color: #284fa8; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; + padding-left: 12px; + padding-right: 4px; + background-color: #dae7fe; +} + +/* All views: header item coverage table entry for high coverage rate */ +td.headerCovTableEntryHi +{ + text-align: right; + color: #000000; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; + padding-left: 12px; + padding-right: 4px; + background-color: #a7fc9d; +} + +/* All views: header item coverage table entry for medium coverage rate */ +td.headerCovTableEntryMed +{ + text-align: right; + color: #000000; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; + padding-left: 12px; + padding-right: 4px; + background-color: #ffea20; +} + +/* All views: header item coverage table entry for ow coverage rate */ +td.headerCovTableEntryLo +{ + text-align: right; + color: #000000; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; + padding-left: 12px; + padding-right: 4px; + background-color: #ff0000; +} + +/* All views: header legend value for legend entry */ +td.headerValueLeg +{ + text-align: left; + color: #000000; + font-family: sans-serif; + font-size: 80%; + white-space: nowrap; + padding-top: 4px; +} + +/* All views: color of horizontal ruler */ +td.ruler +{ + background-color: #6688d4; +} + +/* All views: version string format */ +td.versionInfo +{ + text-align: center; + padding-top: 2px; + font-family: sans-serif; + font-style: italic; +} + +/* Directory view/File view (all)/Test case descriptions: + table headline format */ +td.tableHead +{ + text-align: center; + color: #ffffff; + background-color: #6688d4; + font-family: sans-serif; + font-size: 120%; + font-weight: bold; + white-space: nowrap; + padding-left: 4px; + padding-right: 4px; +} + +span.tableHeadSort +{ + padding-right: 4px; +} + +/* Directory view/File view (all): filename entry format */ +td.coverFile +{ + text-align: left; + padding-left: 10px; + padding-right: 20px; + color: #284fa8; + background-color: #dae7fe; + font-family: monospace; +} + +/* Directory view/File view (all): directory name entry format */ +td.coverDirectory +{ + text-align: left; + padding-left: 10px; + padding-right: 20px; + color: #284fa8; + background-color: #b8d0ff; + font-family: monospace; +} + +/* Directory view/File view (all): filename entry format */ +td.overallOwner +{ + text-align: center; + font-weight: bold; + font-family: sans-serif; + background-color: #dae7fe; + padding-right: 10px; + padding-left: 10px; +} + +/* Directory view/File view (all): filename entry format */ +td.ownerName +{ + text-align: right; + font-style: italic; + font-family: sans-serif; + background-color: #E5DBDB; + padding-right: 10px; + padding-left: 20px; +} + +/* Directory view/File view (all): bar-graph entry format*/ +td.coverBar +{ + padding-left: 10px; + padding-right: 10px; + background-color: #dae7fe; +} + +/* Directory view/File view (all): bar-graph entry format*/ +td.owner_coverBar +{ + padding-left: 10px; + padding-right: 10px; + background-color: #E5DBDB; +} + +/* Directory view/File view (all): bar-graph outline color */ +td.coverBarOutline +{ + background-color: #000000; +} + +/* Directory view/File view (all): percentage entry for files with + high coverage rate */ +td.coverPerHi +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #a7fc9d; + font-weight: bold; + font-family: sans-serif; +} + +/* 'owner' entry: slightly lighter color than 'coverPerHi' */ +td.owner_coverPerHi +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #82E0AA; + font-weight: bold; + font-family: sans-serif; +} + +/* Directory view/File view (all): line count entry */ +td.coverNumDflt +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #dae7fe; + white-space: nowrap; + font-family: sans-serif; +} + +/* td background color and font for the 'owner' section of the table */ +td.ownerTla +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #E5DBDB; + white-space: nowrap; + font-family: sans-serif; + font-style: italic; +} + +/* Directory view/File view (all): line count entry for files with + high coverage rate */ +td.coverNumHi +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #a7fc9d; + white-space: nowrap; + font-family: sans-serif; +} + +td.owner_coverNumHi +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #82E0AA; + white-space: nowrap; + font-family: sans-serif; +} + +/* Directory view/File view (all): percentage entry for files with + medium coverage rate */ +td.coverPerMed +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #ffea20; + font-weight: bold; + font-family: sans-serif; +} + +td.owner_coverPerMed +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #F9E79F; + font-weight: bold; + font-family: sans-serif; +} + +/* Directory view/File view (all): line count entry for files with + medium coverage rate */ +td.coverNumMed +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #ffea20; + white-space: nowrap; + font-family: sans-serif; +} + +td.owner_coverNumMed +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #F9E79F; + white-space: nowrap; + font-family: sans-serif; +} + +/* Directory view/File view (all): percentage entry for files with + low coverage rate */ +td.coverPerLo +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #ff0000; + font-weight: bold; + font-family: sans-serif; +} + +td.owner_coverPerLo +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #EC7063; + font-weight: bold; + font-family: sans-serif; +} + +/* Directory view/File view (all): line count entry for files with + low coverage rate */ +td.coverNumLo +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #ff0000; + white-space: nowrap; + font-family: sans-serif; +} + +td.owner_coverNumLo +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #EC7063; + white-space: nowrap; + font-family: sans-serif; +} + +/* File view (all): "show/hide details" link format */ +a.detail:link +{ + color: #b8d0ff; + font-size:80%; +} + +/* File view (all): "show/hide details" link - visited format */ +a.detail:visited +{ + color: #b8d0ff; + font-size:80%; +} + +/* File view (all): "show/hide details" link - activated format */ +a.detail:active +{ + color: #ffffff; + font-size:80%; +} + +/* File view (detail): test name entry */ +td.testName +{ + text-align: right; + padding-right: 10px; + background-color: #dae7fe; + font-family: sans-serif; +} + +/* File view (detail): test percentage entry */ +td.testPer +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #dae7fe; + font-family: sans-serif; +} + +/* File view (detail): test lines count entry */ +td.testNum +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #dae7fe; + font-family: sans-serif; +} + +/* Test case descriptions: test name format*/ +dt +{ + font-family: sans-serif; + font-weight: bold; +} + +/* Test case descriptions: description table body */ +td.testDescription +{ + padding-top: 10px; + padding-left: 30px; + padding-bottom: 10px; + padding-right: 30px; + background-color: #dae7fe; +} + +/* Source code view: function entry */ +td.coverFn +{ + text-align: left; + padding-left: 10px; + padding-right: 20px; + color: #284fa8; + background-color: #dae7fe; + font-family: monospace; +} + +/* Source code view: function entry zero count*/ +td.coverFnLo +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #ff0000; + font-weight: bold; + font-family: sans-serif; +} + +/* Source code view: function entry nonzero count*/ +td.coverFnHi +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #dae7fe; + font-weight: bold; + font-family: sans-serif; +} + +td.coverFnAlias +{ + text-align: right; + padding-left: 10px; + padding-right: 20px; + color: #284fa8; + /* make this a slightly different color than the leader - otherwise, + otherwise the alias is hard to distinguish in the table */ + background-color: #E5DBDB; /* very light pale grey/blue */ + font-family: monospace; +} + +/* Source code view: function entry zero count*/ +td.coverFnAliasLo +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #EC7063; /* lighter red */ + font-family: sans-serif; +} + +/* Source code view: function entry nonzero count*/ +td.coverFnAliasHi +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #dae7fe; + font-weight: bold; + font-family: sans-serif; +} + +/* Source code view: source code format */ +pre.source +{ + font-family: monospace; + white-space: pre; + margin-top: 2px; +} + +/* elided/removed code */ +span.elidedSource +{ + font-family: sans-serif; + /*font-size: 8pt; */ + font-style: italic; + background-color: lightgrey; +} + +/* Source code view: line number format */ +span.lineNum +{ + background-color: #efe383; +} + +/* Source code view: line number format when there are deleted + lines in the corresponding location */ +span.lineNumWithDelete +{ + foreground-color: #efe383; + background-color: lightgrey; +} + +/* Source code view: format for Cov legend */ +span.coverLegendCov +{ + padding-left: 10px; + padding-right: 10px; + padding-bottom: 2px; + background-color: #cad7fe; +} + +/* Source code view: format for NoCov legend */ +span.coverLegendNoCov +{ + padding-left: 10px; + padding-right: 10px; + padding-bottom: 2px; + background-color: #ff6230; +} + +/* Source code view: format for the source code heading line */ +pre.sourceHeading +{ + white-space: pre; + font-family: monospace; + font-weight: bold; + margin: 0px; +} + +/* All views: header legend value for low rate */ +td.headerValueLegL +{ + font-family: sans-serif; + text-align: center; + white-space: nowrap; + padding-left: 4px; + padding-right: 2px; + background-color: #ff0000; + font-size: 80%; +} + +/* All views: header legend value for med rate */ +td.headerValueLegM +{ + font-family: sans-serif; + text-align: center; + white-space: nowrap; + padding-left: 2px; + padding-right: 2px; + background-color: #ffea20; + font-size: 80%; +} + +/* All views: header legend value for hi rate */ +td.headerValueLegH +{ + font-family: sans-serif; + text-align: center; + white-space: nowrap; + padding-left: 2px; + padding-right: 4px; + background-color: #a7fc9d; + font-size: 80%; +} + +/* All views except source code view: legend format for low coverage */ +span.coverLegendCovLo +{ + padding-left: 10px; + padding-right: 10px; + padding-top: 2px; + background-color: #ff0000; +} + +/* All views except source code view: legend format for med coverage */ +span.coverLegendCovMed +{ + padding-left: 10px; + padding-right: 10px; + padding-top: 2px; + background-color: #ffea20; +} + +/* All views except source code view: legend format for hi coverage */ +span.coverLegendCovHi +{ + padding-left: 10px; + padding-right: 10px; + padding-top: 2px; + background-color: #a7fc9d; +} + +a.branchTla:link +{ + color: #000000; +} + +a.branchTla:visited +{ + color: #000000; +} + +/* Source code view/table entry background: format for lines classified as "Uncovered New Code (+ => 0): +Newly added code is not tested" */ +td.tlaUNC +{ + text-align: right; + background-color: #FF6230; +} +td.tlaBgUNC { + background-color: #FF6230; +} + +/* Source code view/table entry background: format for lines classified as "Uncovered New Code (+ => 0): +Newly added code is not tested" */ +span.tlaUNC +{ + text-align: left; + background-color: #FF6230; +} +span.tlaBgUNC { + background-color: #FF6230; +} +a.tlaBgUNC { + background-color: #FF6230; + color: #000000; +} + +td.headerCovTableHeadUNC { + text-align: center; + padding-right: 6px; + padding-left: 6px; + padding-bottom: 0px; + font-family: sans-serif; + white-space: nowrap; + background-color: #FF6230; +} + +/* Source code view/table entry background: format for lines classified as "Lost Baseline Coverage (1 => 0): +Unchanged code is no longer tested" */ +td.tlaLBC +{ + text-align: right; + background-color: #FF6230; +} +td.tlaBgLBC { + background-color: #FF6230; +} + +/* Source code view/table entry background: format for lines classified as "Lost Baseline Coverage (1 => 0): +Unchanged code is no longer tested" */ +span.tlaLBC +{ + text-align: left; + background-color: #FF6230; +} +span.tlaBgLBC { + background-color: #FF6230; +} +a.tlaBgLBC { + background-color: #FF6230; + color: #000000; +} + +td.headerCovTableHeadLBC { + text-align: center; + padding-right: 6px; + padding-left: 6px; + padding-bottom: 0px; + font-family: sans-serif; + white-space: nowrap; + background-color: #FF6230; +} + +/* Source code view/table entry background: format for lines classified as "Uncovered Included Code (# => 0): +Previously unused code is untested" */ +td.tlaUIC +{ + text-align: right; + background-color: #FF6230; +} +td.tlaBgUIC { + background-color: #FF6230; +} + +/* Source code view/table entry background: format for lines classified as "Uncovered Included Code (# => 0): +Previously unused code is untested" */ +span.tlaUIC +{ + text-align: left; + background-color: #FF6230; +} +span.tlaBgUIC { + background-color: #FF6230; +} +a.tlaBgUIC { + background-color: #FF6230; + color: #000000; +} + +td.headerCovTableHeadUIC { + text-align: center; + padding-right: 6px; + padding-left: 6px; + padding-bottom: 0px; + font-family: sans-serif; + white-space: nowrap; + background-color: #FF6230; +} + +/* Source code view/table entry background: format for lines classified as "Uncovered Baseline Code (0 => 0): +Unchanged code was untested before, is untested now" */ +td.tlaUBC +{ + text-align: right; + background-color: #FF6230; +} +td.tlaBgUBC { + background-color: #FF6230; +} + +/* Source code view/table entry background: format for lines classified as "Uncovered Baseline Code (0 => 0): +Unchanged code was untested before, is untested now" */ +span.tlaUBC +{ + text-align: left; + background-color: #FF6230; +} +span.tlaBgUBC { + background-color: #FF6230; +} +a.tlaBgUBC { + background-color: #FF6230; + color: #000000; +} + +td.headerCovTableHeadUBC { + text-align: center; + padding-right: 6px; + padding-left: 6px; + padding-bottom: 0px; + font-family: sans-serif; + white-space: nowrap; + background-color: #FF6230; +} + +/* Source code view/table entry background: format for lines classified as "Gained Baseline Coverage (0 => 1): +Unchanged code is tested now" */ +td.tlaGBC +{ + text-align: right; + background-color: #CAD7FE; +} +td.tlaBgGBC { + background-color: #CAD7FE; +} + +/* Source code view/table entry background: format for lines classified as "Gained Baseline Coverage (0 => 1): +Unchanged code is tested now" */ +span.tlaGBC +{ + text-align: left; + background-color: #CAD7FE; +} +span.tlaBgGBC { + background-color: #CAD7FE; +} +a.tlaBgGBC { + background-color: #CAD7FE; + color: #000000; +} + +td.headerCovTableHeadGBC { + text-align: center; + padding-right: 6px; + padding-left: 6px; + padding-bottom: 0px; + font-family: sans-serif; + white-space: nowrap; + background-color: #CAD7FE; +} + +/* Source code view/table entry background: format for lines classified as "Gained Included Coverage (# => 1): +Previously unused code is tested now" */ +td.tlaGIC +{ + text-align: right; + background-color: #CAD7FE; +} +td.tlaBgGIC { + background-color: #CAD7FE; +} + +/* Source code view/table entry background: format for lines classified as "Gained Included Coverage (# => 1): +Previously unused code is tested now" */ +span.tlaGIC +{ + text-align: left; + background-color: #CAD7FE; +} +span.tlaBgGIC { + background-color: #CAD7FE; +} +a.tlaBgGIC { + background-color: #CAD7FE; + color: #000000; +} + +td.headerCovTableHeadGIC { + text-align: center; + padding-right: 6px; + padding-left: 6px; + padding-bottom: 0px; + font-family: sans-serif; + white-space: nowrap; + background-color: #CAD7FE; +} + +/* Source code view/table entry background: format for lines classified as "Gained New Coverage (+ => 1): +Newly added code is tested" */ +td.tlaGNC +{ + text-align: right; + background-color: #CAD7FE; +} +td.tlaBgGNC { + background-color: #CAD7FE; +} + +/* Source code view/table entry background: format for lines classified as "Gained New Coverage (+ => 1): +Newly added code is tested" */ +span.tlaGNC +{ + text-align: left; + background-color: #CAD7FE; +} +span.tlaBgGNC { + background-color: #CAD7FE; +} +a.tlaBgGNC { + background-color: #CAD7FE; + color: #000000; +} + +td.headerCovTableHeadGNC { + text-align: center; + padding-right: 6px; + padding-left: 6px; + padding-bottom: 0px; + font-family: sans-serif; + white-space: nowrap; + background-color: #CAD7FE; +} + +/* Source code view/table entry background: format for lines classified as "Covered Baseline Code (1 => 1): +Unchanged code was tested before and is still tested" */ +td.tlaCBC +{ + text-align: right; + background-color: #CAD7FE; +} +td.tlaBgCBC { + background-color: #CAD7FE; +} + +/* Source code view/table entry background: format for lines classified as "Covered Baseline Code (1 => 1): +Unchanged code was tested before and is still tested" */ +span.tlaCBC +{ + text-align: left; + background-color: #CAD7FE; +} +span.tlaBgCBC { + background-color: #CAD7FE; +} +a.tlaBgCBC { + background-color: #CAD7FE; + color: #000000; +} + +td.headerCovTableHeadCBC { + text-align: center; + padding-right: 6px; + padding-left: 6px; + padding-bottom: 0px; + font-family: sans-serif; + white-space: nowrap; + background-color: #CAD7FE; +} + +/* Source code view/table entry background: format for lines classified as "Excluded Uncovered Baseline (0 => #): +Previously untested code is unused now" */ +td.tlaEUB +{ + text-align: right; + background-color: #FFFFFF; +} +td.tlaBgEUB { + background-color: #FFFFFF; +} + +/* Source code view/table entry background: format for lines classified as "Excluded Uncovered Baseline (0 => #): +Previously untested code is unused now" */ +span.tlaEUB +{ + text-align: left; + background-color: #FFFFFF; +} +span.tlaBgEUB { + background-color: #FFFFFF; +} +a.tlaBgEUB { + background-color: #FFFFFF; + color: #000000; +} + +td.headerCovTableHeadEUB { + text-align: center; + padding-right: 6px; + padding-left: 6px; + padding-bottom: 0px; + font-family: sans-serif; + white-space: nowrap; + background-color: #FFFFFF; +} + +/* Source code view/table entry background: format for lines classified as "Excluded Covered Baseline (1 => #): +Previously tested code is unused now" */ +td.tlaECB +{ + text-align: right; + background-color: #FFFFFF; +} +td.tlaBgECB { + background-color: #FFFFFF; +} + +/* Source code view/table entry background: format for lines classified as "Excluded Covered Baseline (1 => #): +Previously tested code is unused now" */ +span.tlaECB +{ + text-align: left; + background-color: #FFFFFF; +} +span.tlaBgECB { + background-color: #FFFFFF; +} +a.tlaBgECB { + background-color: #FFFFFF; + color: #000000; +} + +td.headerCovTableHeadECB { + text-align: center; + padding-right: 6px; + padding-left: 6px; + padding-bottom: 0px; + font-family: sans-serif; + white-space: nowrap; + background-color: #FFFFFF; +} + +/* Source code view/table entry background: format for lines classified as "Deleted Uncovered Baseline (0 => -): +Previously untested code has been deleted" */ +td.tlaDUB +{ + text-align: right; + background-color: #FFFFFF; +} +td.tlaBgDUB { + background-color: #FFFFFF; +} + +/* Source code view/table entry background: format for lines classified as "Deleted Uncovered Baseline (0 => -): +Previously untested code has been deleted" */ +span.tlaDUB +{ + text-align: left; + background-color: #FFFFFF; +} +span.tlaBgDUB { + background-color: #FFFFFF; +} +a.tlaBgDUB { + background-color: #FFFFFF; + color: #000000; +} + +td.headerCovTableHeadDUB { + text-align: center; + padding-right: 6px; + padding-left: 6px; + padding-bottom: 0px; + font-family: sans-serif; + white-space: nowrap; + background-color: #FFFFFF; +} + +/* Source code view/table entry background: format for lines classified as "Deleted Covered Baseline (1 => -): +Previously tested code has been deleted" */ +td.tlaDCB +{ + text-align: right; + background-color: #FFFFFF; +} +td.tlaBgDCB { + background-color: #FFFFFF; +} + +/* Source code view/table entry background: format for lines classified as "Deleted Covered Baseline (1 => -): +Previously tested code has been deleted" */ +span.tlaDCB +{ + text-align: left; + background-color: #FFFFFF; +} +span.tlaBgDCB { + background-color: #FFFFFF; +} +a.tlaBgDCB { + background-color: #FFFFFF; + color: #000000; +} + +td.headerCovTableHeadDCB { + text-align: center; + padding-right: 6px; + padding-left: 6px; + padding-bottom: 0px; + font-family: sans-serif; + white-space: nowrap; + background-color: #FFFFFF; +} + +/* Source code view: format for date/owner bin that is not hit */ +span.missBins +{ + background-color: #ff0000 /* red */ +} diff --git a/glass.png b/glass.png new file mode 100644 index 0000000..e1abc00 Binary files /dev/null and b/glass.png differ diff --git a/index-sort-f.html b/index-sort-f.html new file mode 100644 index 0000000..c17f4be --- /dev/null +++ b/index-sort-f.html @@ -0,0 +1,105 @@ + + + + +
+ +| LCOV - code coverage report | ||||||||||||||||||||||
+
|
+ ||||||||||||||||||||||
| + | + | + | + | + | + | + | ||
| Directory |
+ Line Coverage |
+ Function Coverage |
+ ||||||
| Rate | +Total | +Hit | +Rate | +Total | +Hit | +|||
| src/ | +
+ |
+ 99.6 % | +253 | +252 | +- | ++ | + | |
| Generated by: LCOV version 2.1-1 |
| LCOV - code coverage report | ||||||||||||||||||||||
+
|
+ ||||||||||||||||||||||
| + | + | + | + | + | + | + | ||
| Directory |
+ Line Coverage |
+ Function Coverage |
+ ||||||
| Rate | +Total | +Hit | +Rate | +Total | +Hit | +|||
| src/ | +
+ |
+ 99.6 % | +253 | +252 | +- | ++ | + | |
| Generated by: LCOV version 2.1-1 |
| LCOV - code coverage report | ||||||||||||||||||||||
+
|
+ ||||||||||||||||||||||
| + | + | + | + | + | + | + | ||
| Directory |
+ Line Coverage |
+ Function Coverage |
+ ||||||
| Rate | +Total | +Hit | +Rate | +Total | +Hit | +|||
| src/ | +
+ |
+ 99.6 % | +253 | +252 | +- | ++ | + | |
| Generated by: LCOV version 2.1-1 |
| LCOV - code coverage report | ||||||||||||||||||||||
+
|
+ ||||||||||||||||||||||
| + | + | + | + | + | + | + | ||
| File |
+ Line Coverage |
+ Function Coverage |
+ ||||||
| Rate | +Total | +Hit | +Rate | +Total | +Hit | +|||
| json.dart | +
+ |
+ 99.6 % | +253 | +252 | +- | ++ | + | |
| Generated by: LCOV version 2.1-1 |
| LCOV - code coverage report | ||||||||||||||||||||||
+
|
+ ||||||||||||||||||||||
| + | + | + | + | + | + | + | ||
| File |
+ Line Coverage |
+ Function Coverage |
+ ||||||
| Rate | +Total | +Hit | +Rate | +Total | +Hit | +|||
| json.dart | +
+ |
+ 99.6 % | +253 | +252 | +- | ++ | + | |
| Generated by: LCOV version 2.1-1 |
| LCOV - code coverage report | ||||||||||||||||||||||
+
|
+ ||||||||||||||||||||||
| + | + | + | + | + | + | + | ||
| File |
+ Line Coverage |
+ Function Coverage |
+ ||||||
| Rate | +Total | +Hit | +Rate | +Total | +Hit | +|||
| json.dart | +
+ |
+ 99.6 % | +253 | +252 | +- | ++ | + | |
| Generated by: LCOV version 2.1-1 |
| LCOV - code coverage report | ||||||||||||||||||||||
+
|
+ ||||||||||||||||||||||
| Function Name |
+
+ Hit count |
+
+
+
| Generated by: LCOV version 2.1-1 |
| LCOV - code coverage report | ||||||||||||||||||||||
+
|
+ ||||||||||||||||||||||
| Function Name |
+
+ Hit count |
+
+
+
| Generated by: LCOV version 2.1-1 |
| LCOV - code coverage report | ||||||||||||||||||||||
+
|
+ ||||||||||||||||||||||
+Line data Source code+ + 1 : import 'dart:convert'; + 2 : + 3 : typedef Any = Object?; + 4 : + 5 : /// Wraps Json decoded data + 6 : class Json { + 7 : static const decoder = JsonDecoder(); + 8 : + 9 : Any _rawValue; + 10 : + 11 : /// Actual value + 12 2 : Any get rawValue => _rawValue; + 13 : + 14 : /// Exceptions are never thrown, instead they are silently stored in the [Json] instance + 15 : JsonException? exception; + 16 : + 17 : /// Empty [Json] + 18 1 : Json(); + 19 : + 20 : /// Decodes the string with [JsonDecoder] and wraps it with [Json] + 21 2 : Json.fromString(String json) : _rawValue = Json.decoder.convert(json); + 22 : + 23 : /// Create a [Json] instance from any value + 24 1 : Json.fromDynamic(this._rawValue, {bool initial = true}) { + 25 : if (!initial) { + 26 : // Type checking has already been done + 27 : return; + 28 : } + 29 : + 30 2 : final asMap = tryCast<Map<String, Any>>(_rawValue); + 31 2 : final asIterable = tryCast<Iterable<Any>>(_rawValue); + 32 : + 33 : if (asMap != null) { + 34 2 : _rawValue = <String, Any>{}; + 35 2 : asMap.forEach((String key, Any value) { + 36 : try { + 37 1 : _set(key, value); + 38 1 : } on JsonException catch (error) { + 39 2 : exception = exception ?? error; + 40 : } + 41 : }); + 42 : } else if (asIterable != null) { + 43 2 : _rawValue = <Any>[]; + 44 : int i = 0; + 45 2 : for (final item in asIterable) { + 46 : try { + 47 2 : _set(i++, item); + 48 1 : } on JsonException catch (error) { + 49 2 : exception = exception ?? error; + 50 1 : i--; + 51 : } + 52 : } + 53 2 : } else if (_rawValue is! int && + 54 2 : _rawValue is! double && + 55 2 : _rawValue is! String && + 56 1 : _rawValue != null && + 57 2 : _rawValue is! bool) { + 58 3 : exception = exception ?? JsonException(JsonError.unsupportedType); + 59 1 : _rawValue = null; + 60 : } + 61 : } + 62 : + 63 : /// Create [Json] from a [Map] + 64 1 : Json.fromMap(Map<String, Any> map) { + 65 2 : _rawValue = <String, Any>{}; + 66 : + 67 2 : map.forEach((String key, Any value) { + 68 : try { + 69 1 : _set(key, value); + 70 1 : } on JsonException catch (error) { + 71 2 : exception = exception ?? error; + 72 : } + 73 : }); + 74 : } + 75 : + 76 : /// Create [Json] from a [List] + 77 1 : Json.fromList(List<Any> list) { + 78 2 : _rawValue = <Any>[]; + 79 : + 80 : int i = 0; + 81 2 : for (var item in list) { + 82 : try { + 83 2 : _set(i++, item); + 84 1 : } on JsonException catch (error) { + 85 2 : exception = exception ?? error; + 86 1 : i--; + 87 : } + 88 : } + 89 : } + 90 : + 91 : /// Create [Json] from another + 92 1 : Json.from(Json other, {bool initial = true}) { + 93 : if (!initial) { + 94 2 : _rawValue = other._rawValue; + 95 : return; + 96 : } + 97 : + 98 3 : assert(other._rawValue is int || + 99 2 : other._rawValue is double || + 100 2 : other._rawValue is bool || + 101 2 : other._rawValue is String || + 102 1 : other._rawValue == null || + 103 2 : other._rawValue is Map || + 104 2 : other._rawValue is List); + 105 : + 106 2 : if (other._rawValue is int || + 107 2 : other._rawValue is double || + 108 2 : other._rawValue is bool || + 109 2 : other._rawValue is String || + 110 1 : other._rawValue == null) { + 111 2 : _rawValue = other._rawValue; + 112 2 : } else if (other._rawValue is Map) { + 113 3 : _rawValue = Map<String, Any>.from(other._rawValue as Map); + 114 2 : } else if (other._rawValue is List) { + 115 3 : _rawValue = List<Any>.from(other._rawValue as List); + 116 : } + 117 : + 118 2 : exception = other.exception; + 119 : } + 120 : + 121 : /// Create a [Json] with a [null] [rawValue] + 122 2 : Json get jsonNull => Json.fromDynamic(null); + 123 : + 124 : /// Returns actual Json + 125 1 : @override + 126 2 : String toString() => jsonEncode(_rawValue); + 127 : + 128 : /// Compare [Json] by instance or by value + 129 1 : @override + 130 : bool operator ==(Object other) => + 131 4 : identical(this, other) || other is Json && toString() == other.toString(); + 132 : + 133 1 : @override + 134 2 : int get hashCode => toString().hashCode; + 135 : + 136 1 : void _set(Any key, Any value) { + 137 : // If not a json encodable type fail + 138 1 : if (value is! String && + 139 1 : value is! int && + 140 1 : value is! double && + 141 1 : value is! bool && + 142 1 : value is! List && + 143 1 : value is! Map && + 144 : value != null) { + 145 1 : throw JsonException(JsonError.unsupportedType); + 146 : } + 147 : + 148 : if (key == null) return; + 149 : + 150 2 : final rawMap = tryCast<Map<Any, Any>>(_rawValue); + 151 2 : final rawList = tryCast<List<Any>>(_rawValue); + 152 : if (rawList != null) { + 153 3 : int? index = (key is String) ? int.tryParse(key) : tryCast<int>(key); + 154 : if (index == null) { + 155 1 : throw JsonException( + 156 : JsonError.wrongType, + 157 2 : userReason: 'JSON Error: index must be int, ${key.runtimeType} given', + 158 : ); + 159 : } + 160 : + 161 3 : if (index < 0 || index > rawList.length) { + 162 1 : throw JsonException( + 163 : JsonError.indexOutOfBounds, + 164 1 : userReason: 'JSON Error: index `$index` is out of bounds', + 165 : ); + 166 2 : } else if (index == rawList.length) { + 167 1 : rawList.add(value); + 168 : } else { + 169 1 : rawList[index] = value; + 170 : } + 171 : } else if (rawMap != null) { + 172 2 : rawMap[key.toString()] = value; + 173 : } + 174 : } + 175 : + 176 : /// Returns a [Json] wrapping the data under [key]. If [key] does not exist, returns a empty [Json] instance with an [exception] + 177 1 : Json operator [](Object key) { + 178 2 : if ((key is! String && key is! int) || + 179 4 : (_rawValue is! List && _rawValue is! Map)) { + 180 1 : var result = jsonNull; + 181 3 : result.exception = exception ?? JsonException(JsonError.wrongType); + 182 : return result; + 183 : } + 184 : + 185 2 : final rawList = tryCast<List<Any>>(_rawValue); + 186 2 : final rawMap = tryCast<Map<Any, Any>>(_rawValue); + 187 : + 188 : if (rawList != null) { + 189 3 : int? index = key is String ? int.tryParse(key) : tryCast<int>(key); + 190 : + 191 : if (index == null) { + 192 1 : var result = jsonNull; + 193 2 : result.exception = exception ?? + 194 1 : JsonException( + 195 : JsonError.wrongType, + 196 : userReason: + 197 2 : 'JSON Error: index must be int, ${key.runtimeType} given', + 198 : ); + 199 : return result; + 200 : } + 201 : + 202 3 : if (index < 0 || index >= rawList.length) { + 203 1 : var result = jsonNull; + 204 2 : result.exception = exception ?? + 205 1 : JsonException( + 206 : JsonError.indexOutOfBounds, + 207 1 : userReason: 'JSON Error: index `$index` is out of bounds', + 208 : ); + 209 : return result; + 210 : } + 211 : + 212 2 : return Json.fromDynamic(rawList.elementAtOrNull(index), initial: false); + 213 : } + 214 : + 215 1 : assert(rawMap != null); + 216 : + 217 1 : final index = key.toString(); + 218 2 : final result = Json.fromDynamic(rawMap![index], initial: false); + 219 1 : if (!rawMap.containsKey(index)) { + 220 2 : result.exception = exception ?? + 221 1 : JsonException( + 222 : JsonError.notExist, + 223 1 : userReason: 'JSON Error: key `$index` does not exists', + 224 : ); + 225 : } + 226 : + 227 : return result; + 228 : } + 229 : + 230 : /// Returns [true] if [exception] is [null] + 231 1 : bool exists([Any key]) { + 232 : return key != null + 233 4 : ? this[key].exception == null && this[key].rawValue != null + 234 2 : : exception == null && rawValue != null; + 235 : } + 236 : + 237 : /// Returns a [String] or [null] if [rawValue] is not a [String] + 238 4 : String? get string => (_rawValue is String) ? _rawValue as String : null; + 239 : + 240 : /// Returns a [String] or an empty [String] if [rawValue] is not a [String] + 241 3 : String get stringValue => _rawValue is String || + 242 2 : _rawValue is bool || + 243 2 : _rawValue is int || + 244 2 : _rawValue is double + 245 2 : ? _rawValue?.toString() ?? '' + 246 : : ''; + 247 : + 248 : /// Returns a [bool] or [null] if [rawValue] is not a [bool] + 249 4 : bool? get boolean => (_rawValue is bool) ? _rawValue as bool : null; + 250 : + 251 : /// Returns a [bool] or [false] if [rawValue] is not thruthy + 252 1 : bool get booleanValue { + 253 2 : if (_rawValue is bool) { + 254 1 : return _rawValue as bool; + 255 4 : } else if (_rawValue is int || _rawValue is double) { + 256 2 : return _rawValue == 1; + 257 2 : } else if (_rawValue is String) { + 258 1 : return ['true', 'y', 't', 'yes', '1'] + 259 3 : .contains((_rawValue as String).toLowerCase()); + 260 : } + 261 : + 262 : return false; + 263 : } + 264 : + 265 : /// Returns a [int] or [null] if [rawValue] is not a [int] + 266 4 : int? get integer => (_rawValue is int) ? _rawValue as int : null; + 267 : + 268 : /// Returns a [int] or 0 if [rawValue] is not a [int] + 269 1 : int get integerValue { + 270 2 : if (_rawValue is int) { + 271 1 : return _rawValue as int; + 272 2 : } else if (_rawValue is bool) { + 273 1 : return _rawValue as bool ? 1 : 0; + 274 2 : } else if (_rawValue is double) { + 275 2 : return (_rawValue as double).toInt(); + 276 2 : } else if (_rawValue is String) { + 277 : try { + 278 2 : return int.parse(_rawValue as String); + 279 : } catch (error) { + 280 : return 0; + 281 : } + 282 : } + 283 : + 284 : return 0; + 285 : } + 286 : + 287 1 : double? get float => + 288 4 : (_rawValue is num) ? (_rawValue as num).toDouble() : null; + 289 : + 290 : /// Returns a [double] 0 if [rawValue] is not a [double] + 291 1 : double get floatValue { + 292 2 : if (_rawValue is double) { + 293 1 : return _rawValue as double; + 294 2 : } else if (_rawValue is int) { + 295 2 : return (_rawValue as int).toDouble(); + 296 2 : } else if (_rawValue is bool) { + 297 1 : return _rawValue as bool ? 1 : 0; + 298 2 : } else if (_rawValue is String) { + 299 : try { + 300 2 : return double.parse(_rawValue as String); + 301 : } catch (error) { + 302 : return 0; + 303 : } + 304 : } + 305 : + 306 : return 0; + 307 : } + 308 : + 309 : /// Returns a [T] or [null] if [rawValue] is not a [T] + 310 : /// If actual data is not [T], calls [builder] to get one + 311 1 : T? ofType<T>([T? Function(Json)? builder]) { + 312 2 : if (_rawValue is T) { + 313 1 : return _rawValue as T; + 314 : } else if (builder != null) { + 315 1 : return builder(this); + 316 : } + 317 : + 318 : return null; + 319 : } + 320 : + 321 : /// Returns a [T] or [defaultValue] if [rawValue] is not a [T] + 322 : /// If actual data is not [T], calls [builder] to get one + 323 1 : T ofTypeValue<T>(T defaultValue, [T? Function(Json)? builder]) { + 324 2 : if (_rawValue is T) { + 325 1 : return _rawValue as T; + 326 : } else if (builder != null) { + 327 1 : T? built = builder(this); + 328 : + 329 : if (built != null) { + 330 : return built; + 331 : } + 332 : } + 333 : + 334 : return defaultValue; + 335 : } + 336 : + 337 : /// Returns a [List] or [null] if [rawValue] is not a [List] + 338 : /// Each element of the list is wrapped in a [Json] instance + 339 3 : List<Json>? get list => (_rawValue is List) + 340 5 : ? (_rawValue as List).map<Json>((Any e) => Json.fromDynamic(e)).toList() + 341 : : null; + 342 : + 343 : /// Returns a [List] or an empty [List] if [rawValue] is not a [List] + 344 : /// Each element of the list is wrapped in a [Json] instance + 345 3 : List<Json> get listValue => (_rawValue is List) + 346 5 : ? (_rawValue as List).map<Json>((Any e) => Json.fromDynamic(e)).toList() + 347 0 : : []; + 348 : + 349 : /// Returns a [List] or [null] if [rawValue] is not a [List] + 350 : /// Leaves list items untouched + 351 4 : List<Any>? get listObject => (_rawValue is List) ? _rawValue as List : null; + 352 : + 353 : /// Returns a [List] or an empty [List] if [rawValue] is not a [List] + 354 : /// Leaves list items untouched + 355 5 : List<Any> get listObjectValue => (_rawValue is List) ? _rawValue as List : []; + 356 : + 357 : /// Returns a [List] of [T] or empty list if [rawValue] is not a [List] of [T] + 358 : /// If actual data is not a [List] of [T], calls [builder] to get one + 359 1 : List<T>? listOf<T>([T? Function(Json)? builder]) { + 360 2 : if (_rawValue is List) { + 361 1 : return (_rawValue as List) + 362 2 : .map<T?>((Any e) { + 363 1 : if (e is T) { + 364 : return e; + 365 : } else if (builder != null) { + 366 2 : return builder(Json.fromDynamic(e)); + 367 : } + 368 : + 369 : return null; + 370 : }) + 371 1 : .whereType<T>() + 372 1 : .toList(); + 373 : } + 374 : + 375 : return null; + 376 : } + 377 : + 378 : /// Returns a [List] of [T] or an empty [List] if [rawValue] is not a [List] of [T] + 379 : /// If actual data is not a [List] of [T], calls [builder] to get one + 380 1 : List<T> listOfValue<T>([T? Function(Json)? builder]) { + 381 1 : return listOf(builder) ?? []; + 382 : } + 383 : + 384 : /// Returns a [Map] or [null] if [rawValue] is not a [Map] + 385 : /// Each value of the map is wrapped in a [Json] + 386 3 : Map<String, Json>? get map => (_rawValue is Map) + 387 2 : ? (_rawValue as Map).map( + 388 4 : (Any key, Any value) => MapEntry('$key', Json.fromDynamic(value)), + 389 : ) + 390 : : null; + 391 : + 392 : /// Returns a [Map] or an empty [Map] if [rawValue] is not a [Map] + 393 : /// Each value of the map is wrapped in a [Json] + 394 3 : Map<String, Json> get mapValue => (_rawValue is Map) + 395 2 : ? (_rawValue as Map).map( + 396 4 : (Any key, Any value) => MapEntry('$key', Json.fromDynamic(value)), + 397 : ) + 398 1 : : {}; + 399 : + 400 : /// Returns a [Map] or [null] if [rawValue] is not a [Map] + 401 : /// Leaves map values untouched + 402 1 : Map<String, Any>? get mapObject => + 403 3 : (_rawValue is Map) ? _rawValue as Map<String, Any> : null; + 404 : + 405 : /// Returns a [Map] of [T] or empty [Map] if [rawValue] is not a [Map] of [T] + 406 : /// Leaves map values untouched + 407 1 : Map<String, Any> get mapObjectValue => + 408 4 : (_rawValue is Map) ? _rawValue as Map<String, Any> : {}; + 409 : + 410 : /// Returns a [Map] of [T] or [null] if [rawValue] is not a [Map] of [T] + 411 : /// If actual data is not a [Map] of [T], calls [builder] to get one + 412 1 : Map<String, T>? mapOf<T>([T? Function(Json)? builder]) { + 413 2 : if (_rawValue is Map) { + 414 2 : return <String, T>{}..addEntries( + 415 1 : (_rawValue as Map) + 416 1 : .entries + 417 2 : .map<MapEntry<String, T>?>((entry) { + 418 2 : if (entry.key is! String) { + 419 : return null; + 420 2 : } else if (entry.value is T) { + 421 1 : return MapEntry<String, T>( + 422 2 : entry.key as String, entry.value as T); + 423 : } else if (builder != null) { + 424 3 : final element = builder(Json.fromDynamic(entry.value)); + 425 : if (element != null) { + 426 2 : return MapEntry(entry.key as String, element); + 427 : } + 428 : } + 429 : + 430 : return null; + 431 : }) + 432 1 : .whereType<MapEntry<String, T>>() + 433 1 : .toList(), + 434 : ); + 435 : } + 436 : + 437 : return null; + 438 : } + 439 : + 440 : /// Returns a [List] of [T] or empty [Map] if [rawValue] is not a [List] of [T] + 441 : /// If actual data is not a [List] of [T], calls [builder] to get one + 442 1 : Map<String, T> mapOfValue<T>([T? Function(Json)? builder]) { + 443 1 : return mapOf(builder) ?? {}; + 444 : } + 445 : } + 446 : + 447 : /// A mutable Json payload that enforce it'll always be able to json encode it's content + 448 : class JsonPayload extends Json { + 449 1 : JsonPayload(); + 450 2 : JsonPayload.fromString(super.json) : super.fromString(); + 451 1 : JsonPayload.fromDynamic(super.rawValue, {super.initial}) + 452 1 : : super.fromDynamic(); + 453 2 : JsonPayload.fromMap(super.map) : super.fromMap(); + 454 2 : JsonPayload.fromList(super.list) : super.fromList(); + 455 2 : JsonPayload.from(super.other, {super.initial}) : super.from(); + 456 : + 457 1 : set rawValue(Any newValue) { + 458 1 : _rawValue = newValue; + 459 : } + 460 : + 461 1 : void operator []=(Any key, Any value) { + 462 4 : if (_rawValue is! List && _rawValue is! Map) { + 463 1 : throw JsonException(JsonError.wrongType, + 464 : userReason: 'Underlying value is neither a map or a list'); + 465 : } + 466 : + 467 1 : _set(key, value); + 468 : } + 469 : + 470 1 : @override + 471 1 : JsonPayload get jsonNull => JsonPayload.fromDynamic(null); + 472 : + 473 1 : @override + 474 : JsonPayload operator [](Object key) => + 475 2 : JsonPayload.from(super[key], initial: false); + 476 : + 477 1 : @override + 478 2 : List<JsonPayload>? get list => (_rawValue is List) + 479 1 : ? (_rawValue as List) + 480 3 : .map<JsonPayload>((Any e) => JsonPayload.fromDynamic(e)) + 481 1 : .toList() + 482 : : null; + 483 : + 484 1 : @override + 485 1 : List<JsonPayload> get listValue => list ?? []; + 486 : + 487 1 : @override + 488 2 : Map<String, JsonPayload>? get map => (_rawValue is Map) + 489 3 : ? (_rawValue as Map).map((Any key, Any value) => + 490 3 : MapEntry('$key', JsonPayload.fromDynamic(value))) + 491 : : null; + 492 : + 493 1 : @override + 494 1 : Map<String, JsonPayload> get mapValue => map ?? {}; + 495 : + 496 : /// Remove element under [key] + 497 1 : void removeElementWithKey(Any key) { + 498 2 : if (_rawValue is List) { + 499 1 : final rawList = _rawValue as List; + 500 : late int index; + 501 : + 502 1 : if (key is String) { + 503 : try { + 504 1 : index = int.parse(key); + 505 : } catch (_, trace) { + 506 1 : Error.throwWithStackTrace( + 507 1 : JsonException( + 508 : JsonError.wrongType, + 509 : userReason: + 510 2 : 'JSON Error: index must be int, ${key.runtimeType} given', + 511 : ), + 512 : trace, + 513 : ); + 514 : } + 515 : } else { + 516 : index = key as int; + 517 : } + 518 : + 519 3 : if (index < 0 || index > rawList.length) { + 520 1 : throw JsonException( + 521 : JsonError.indexOutOfBounds, + 522 1 : userReason: 'JSON Error: index `$index` is out of bounds', + 523 : ); + 524 : } + 525 : + 526 1 : rawList.removeAt(index); + 527 2 : } else if (_rawValue is Map) { + 528 1 : final rawMap = _rawValue as Map; + 529 : late String index; + 530 : + 531 1 : if (key is String) { + 532 : index = key; + 533 : } else { + 534 1 : index = '$key'; + 535 : } + 536 : + 537 1 : rawMap.remove(index); + 538 : } else { + 539 1 : throw throw JsonException( + 540 : JsonError.wrongType, + 541 : userReason: '_rawValue is not a List or a Map', + 542 : ); + 543 : } + 544 : } + 545 : } + 546 : + 547 2 : T? tryCast<T>(Any object) => object is T ? object : null; + 548 : + 549 : /// Json error types + 550 : enum JsonError { + 551 : /// Type is not json encodable + 552 : unsupportedType(reason: 'JSON Error: not a valid JSON value'), + 553 : + 554 : /// Out of bound access to list + 555 : indexOutOfBounds(reason: 'JSON Error: index out of bounds'), + 556 : + 557 : /// Unexpected type + 558 : wrongType( + 559 : reason: + 560 : 'JSON Error: either key is not a index type or value is not indexable', + 561 : ), + 562 : + 563 : /// Entry does not exists + 564 : notExist(reason: 'JSON Error: key does\'t not exists'); + 565 : + 566 : final String reason; + 567 : + 568 : const JsonError({required this.reason}); + 569 : } + 570 : + 571 : /// Exceptions are never thrown, instead they are silently stored in the [Json] instance + 572 : class JsonException implements Exception { + 573 : /// What error is this + 574 : final JsonError error; + 575 : + 576 : /// Error message + 577 : final String reason; + 578 : + 579 1 : JsonException(this.error, {String? userReason}) + 580 1 : : reason = userReason ?? error.reason; + 581 : + 582 1 : @override + 583 3 : String toString() => 'JsonException{error: $error, reason: $reason}'; + 584 : } ++ |
+
| Generated by: LCOV version 2.1-1 |