LCOV - code coverage report
Current view: top level - src/formats - roman.dart (source / functions) Coverage Total Hit
Test: lcov.info Lines: 100.0 % 14 14
Test Date: 2026-06-16 03:31:00 Functions: - 0 0
Legend: Lines: hit not hit

            Line data    Source code
       1              : // Copyright 2026 The Authors
       2              : //
       3              : // Licensed under the Apache License, Version 2.0 (the "License");
       4              : // you may not use this file except in compliance with the License.
       5              : // You may obtain a copy of the License at
       6              : //
       7              : //      https://www.apache.org/licenses/LICENSE-2.0
       8              : //
       9              : // Unless required by applicable law or agreed to in writing, software
      10              : // distributed under the License is distributed on an "AS IS" BASIS,
      11              : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12              : // See the License for the specific language governing permissions and
      13              : // limitations under the License.
      14              : 
      15              : import 'package:characters/characters.dart';
      16              : 
      17              : const romanDigits = <String, int>{
      18              :   'i': 1,
      19              :   'v': 5,
      20              :   'x': 10,
      21              :   'l': 50,
      22              :   'c': 100,
      23              :   'd': 500,
      24              :   'm': 1000,
      25              :   'I': 1,
      26              :   'V': 5,
      27              :   'X': 10,
      28              :   'L': 50,
      29              :   'C': 100,
      30              :   'D': 500,
      31              :   'M': 1000,
      32              : };
      33              : 
      34              : /// Represents a basic Roman numeral-based number
      35              : ///
      36              : /// This is a simplistic rendition of handling Roman numerals.
      37              : ///
      38              : /// The apostrophus and the vinculum are not supported. Fractions are not
      39              : /// supported.
      40              : ///
      41              : /// See also: [Wikipedia: Roman numerals](https://en.wikipedia.org/wiki/Roman_numerals)
      42              : class RomanNumerals {
      43              :   final String value;
      44              : 
      45            1 :   RomanNumerals._(this.value);
      46              : 
      47              :   /// Creates a new instance
      48              :   ///
      49              :   /// Only a basic check of [input] is performed - namely that it is
      50              :   /// not empty and contains only valid Roman numerals (as defined in
      51              :   /// [romanDigits]).
      52            1 :   static RomanNumerals? tryParse(String input) {
      53              :     // Check for empty string
      54            1 :     if (input.isEmpty) {
      55              :       return null;
      56              :     }
      57              : 
      58            2 :     for (final c in input.characters) {
      59            1 :       if (!romanDigits.containsKey(c)) {
      60              :         return null;
      61              :       }
      62              :     }
      63            1 :     return RomanNumerals._(input);
      64              :   }
      65              : 
      66              :   /// Attempts to evaluate a Roman numeral as an integer
      67              :   ///
      68              :   /// Evaluates a Roman numeral string as an integer.
      69              :   ///
      70              :   /// Returns the integer value, or `null` if [value] is empty or contains
      71              :   /// any character that is not a recognised Roman numeral digit.
      72              :   ///
      73              :   /// Allows additive repetition (e.g. `"IIII"` is accepted as 4, even though
      74              :   /// the canonical form is `"IV"`).
      75            1 :   int? toInt() {
      76              :     // go backwards through the digits
      77              :     var total = 0;
      78              :     var prevDigit = 0;
      79            4 :     final reversed = value.characters.toList().reversed;
      80              : 
      81            2 :     for (final c in reversed) {
      82            1 :       var n = romanDigits[c];
      83              : 
      84              :       if (n == null) {
      85              :         return null;
      86              :       }
      87              : 
      88            1 :       if (n < prevDigit) {
      89              :         // e.g. ix
      90            1 :         total -= n;
      91              :       } else {
      92            1 :         total += n;
      93              :       }
      94              :       prevDigit = n;
      95              :     }
      96              :     return total;
      97              :   }
      98              : 
      99            2 :   static bool isValid(String value) => tryParse(value) != null;
     100              : }
        

Generated by: LCOV version 2.0-1