< Summary

Information
Class: NtpServiceLibrary.RegistryKeyWrapper
Assembly: NtpServiceLibrary
File(s): D:\a\ntp-service\ntp-service\NtpServiceLibrary\RegistrySettingsProvider.cs
Line coverage
81%
Covered lines: 9
Uncovered lines: 2
Coverable lines: 11
Total lines: 141
Line coverage: 81.8%
Branch coverage
50%
Covered branches: 1
Total branches: 2
Branch coverage: 50%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
GetValue(...)100%210%
GetValueKind(...)100%210%
OpenSubKey(...)50%22100%
GetValueNames()100%11100%

File(s)

D:\a\ntp-service\ntp-service\NtpServiceLibrary\RegistrySettingsProvider.cs

#LineLine coverage
 1using Microsoft.Win32;
 2
 3namespace NtpServiceLibrary
 4{
 5    /// <summary>
 6    /// Provides a wrapper around the Windows Registry key to implement the IKey interface.
 7    /// </summary>
 8    internal class RegistryKeyWrapper : IKey
 9    {
 10        private readonly RegistryKey _registryKey;
 411        public RegistryKeyWrapper(RegistryKey registryKey)
 412        {
 413            _registryKey = registryKey;
 414        }
 015        public object GetValue(string name) => _registryKey.GetValue(name);
 016        public RegistryValueKind GetValueKind(string name) => _registryKey.GetValueKind(name);
 17        public IKey OpenSubKey(string name)
 218        {
 219            var subkey = _registryKey.OpenSubKey(name);
 220            return subkey != null ? new RegistryKeyWrapper(subkey) : null;
 221        }
 222        public string[] GetValueNames() => _registryKey.GetValueNames();
 23    }
 24
 25    /// <summary>
 26    /// Provides a settings provider that reads NTP service configuration from the Windows Registry.
 27    /// </summary>
 28    public class RegistrySettingsProvider : ISettingsProvider
 29    {
 30        private readonly ILogger _logger;
 31        private readonly string[] _subKeys;
 32        private readonly Settings _settings;
 33        private readonly IKey _registryKey;
 34
 35
 36        /// <summary>
 37        /// Initializes a new instance of the <see cref="RegistrySettingsProvider"/> class.
 38        /// </summary>
 39        /// <param name="serviceName">The name of the service whose settings are to be read.</param>
 40        /// <param name="logger">Logger instance for logging events and errors.</param>
 41        /// <param name="registryKey">Root node of registry do use, or null if the Windows default (HKLM) is to be used.
 42        public RegistrySettingsProvider(string serviceName, ILogger logger, IKey registryKey = null)
 43        {
 44            _subKeys = new string[] { "SYSTEM", "CurrentControlSet", "Services", serviceName, "Parameters" };
 45            _logger = logger;
 46            _settings = new Settings();
 47            _registryKey = registryKey ?? new RegistryKeyWrapper(Registry.LocalMachine);
 48        }
 49
 50        /// <summary>
 51        /// Converts a <see cref="RegistryValueKind"/> to its string representation.
 52        /// </summary>
 53        /// <param name="valueKind">The registry value kind.</param>
 54        /// <returns>String representation of the registry value kind.</returns>
 55        private string RegistryValueKindToString(RegistryValueKind valueKind)
 56        {
 57            switch (valueKind)
 58            {
 59                case RegistryValueKind.String:
 60                    return "string";
 61                case RegistryValueKind.DWord:
 62                    return "dword";
 63                default:
 64                    return "<unsupported>";
 65            }
 66        }
 67
 68        /// <summary>
 69        /// Reads a value from the registry and assigns it to the specified <see cref="SettingsValue{T}"/>.
 70        /// Logs a message if the value type does not match the expected type.
 71        /// </summary>
 72        /// <typeparam name="T">The type of the setting value.</typeparam>
 73        /// <param name="settingsValue">Reference to the settings value to assign.</param>
 74        /// <param name="registryKey">The registry key containing the value.</param>
 75        /// <param name="registryValue">The name of the registry value.</param>
 76        /// <param name="expectedType">The expected registry value type.</param>
 77        /// <param name="message">Additional message for logging.</param>
 78        /// <returns>Updated log message.</returns>
 79        private string ReadValue<T>(ref SettingsValue<T> settingsValue, IKey registryKey, string registryValue,
 80            RegistryValueKind expectedType, string message)
 81        {
 82            var value = registryKey.GetValue(registryValue);
 83            var actualType = registryKey.GetValueKind(registryValue);
 84            if (actualType != expectedType)
 85            {
 86                return string.Format("{0}Invalid data type for key '{1}'. Expected: '{2}', actual: '{3}'. Falling back t
 87                    message, registryValue, RegistryValueKindToString(expectedType), RegistryValueKindToString(actualTyp
 88            }
 89            settingsValue.Set((T)value, "registry");
 90            return message;
 91        }
 92
 93        /// <summary>
 94        /// Reads the NTP service settings from the Windows Registry.
 95        /// If the registry key or values are missing, default values are used.
 96        /// </summary>
 97        /// <returns>A <see cref="Settings"/> object containing the loaded or default settings.</returns>
 98        public Settings Read()
 99        {
 100            IKey registryKey = _registryKey;
 101            foreach (var key in _subKeys)
 102            {
 103                registryKey = registryKey.OpenSubKey(key);
 104                if (registryKey == null)
 105                {
 106                    _logger.Write("No settings found in registry, using default values:\n{0}: {1}\n{2}: {3}\n{4}: {5}",
 107                        "Server", (string)_settings.NTPServer,
 108                        "Port", (int)_settings.NTPPort,
 109                        "PollIntervalHours", (int)_settings.NTPPollIntervalHours
 110                        );
 111                    return _settings;
 112                }
 113            }
 114            string additionalMessage = "";
 115
 116            foreach (var registryValue in registryKey.GetValueNames())
 117            {
 118                switch (registryValue)
 119                {
 120                    case "Server":
 121                        additionalMessage = ReadValue(ref _settings.NTPServer, registryKey, registryValue,
 122                            RegistryValueKind.String, additionalMessage);
 123                        break;
 124                    case "Port":
 125                        additionalMessage = ReadValue(ref _settings.NTPPort, registryKey, registryValue,
 126                            RegistryValueKind.DWord, additionalMessage);
 127                        break;
 128                    case "PollIntervalHours":
 129                        additionalMessage = ReadValue(ref _settings.NTPPollIntervalHours, registryKey, registryValue,
 130                            RegistryValueKind.DWord, additionalMessage);
 131                        break;
 132                    default:
 133                        additionalMessage += string.Format("Unexpected parameter '{0}', ignoring\n", registryValue);
 134                        break;
 135                }
 136            }
 137            _logger.Write("Service settings:\n{0}{1}", _settings.ToString(), additionalMessage);
 138            return _settings;
 139        }
 140    }
 141}