diff --git a/Tests/UtilityBeltxUnitTests/WeatherForecastTests.cs b/Tests/UtilityBeltxUnitTests/WeatherForecastTests.cs new file mode 100644 index 0000000..65ca8eb --- /dev/null +++ b/Tests/UtilityBeltxUnitTests/WeatherForecastTests.cs @@ -0,0 +1,94 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using System; +using System.Net; +using System.Text.Json; +using UtilityBelt; +using UtilityBelt.Interfaces; +using UtilityBelt.Models; +using UtilityBelt.Utilities; +using Xunit; + +namespace UtilityBeltxUnitTests +{ + public class WeatherForecastTests + { + private readonly IServiceProvider services; + private readonly IOptions options; + private readonly Mock webClient = new Mock(); + + public WeatherForecastTests() + { + this.services = ServiceProviderBuilder.GetServiceProvider(new string[] { "" }); + this.options = services.GetRequiredService>(); + } + + [Fact] + public void WeatherForecastReturnsForeCast() + { + var mockWeatherRootResult = getWeatherRootObject(); + var jsonresult = JsonSerializer.Serialize(mockWeatherRootResult); + this.webClient.Setup(x => x.DownloadString(It.IsAny())).Returns(jsonresult); + var weatherForecastClient = new TestableWeatherForecast(webClient.Object); + + weatherForecastClient.Configure(this.options); + weatherForecastClient.Run("atlanta"); + + this.webClient.Verify(x => x.DownloadString(It.IsAny()), Times.Once); + } + + [Fact] + public void WeatherForecastDoesNotThrowsIfNoKey() + { + this.webClient.Setup(x => x.DownloadString(It.IsAny())).Returns(""); + + var weatherForecastClient = new TestableWeatherForecast(webClient.Object); + //omitting configure so that the API key isn't set + weatherForecastClient.Run(); + + //webclient shouldn't be called if the key isn't set + this.webClient.Verify(x => x.DownloadString(It.IsAny()), Times.Never); + } + + [Fact] + public void WeatherForecastDoesNotThrowsIfNoResult() + { + this.webClient.Setup(x => x.DownloadString(It.IsAny())).Returns(""); + + var weatherForecastClient = new TestableWeatherForecast(webClient.Object); + weatherForecastClient.Configure(this.options); + weatherForecastClient.Run("atlanta"); + + //assert...nothing to do, just shouldnt error + } + + private WeatherRoot getWeatherRootObject() + { + var mockSyst = new Sys { Country = "Bolivia", Id = 123456, Sunrise = DateTimeOffset.UtcNow.AddHours(-8).ToUnixTimeSeconds(), Sunset = DateTimeOffset.UtcNow.AddHours(4).ToUnixTimeSeconds() }; + var mockMain = new Main { Pressure = 40, FeelsLike = 27, Humidity = 33, Temperature = 24, TempMax = 29, TempMin = 22 }; + var mockWind = new Wind { Degrees = 231, Speed = 22 }; + var mockWeatherRoot = new WeatherRoot + { + Main = mockMain, + Sys = mockSyst, + Wind = mockWind + }; + + return mockWeatherRoot; + } + + private class TestableWeatherForecast : WeatherForecastUtility + { + public IWebClient webClient { get; set; } + + public TestableWeatherForecast(IWebClient webClient) : base() + { + this.webClient = webClient; + } + + protected override IWebClient GetWebClient() => this.webClient; + } + } +} \ No newline at end of file diff --git a/Utilities/WeatherForecast.cs b/Utilities/WeatherForecast.cs index fd078d4..c303fea 100644 --- a/Utilities/WeatherForecast.cs +++ b/Utilities/WeatherForecast.cs @@ -4,14 +4,15 @@ using System.Composition; using System.Net; using System.Text.Json; +using UtilityBelt.Interfaces; using UtilityBelt.Models; namespace UtilityBelt.Utilities { [Export(typeof(IUtility))] - internal class WeatherForecastUtility : IUtility + public class WeatherForecastUtility : IUtility { - public IList Commands => new List { "weather", "weather forecast"}; + public IList Commands => new List { "weather", "weather forecast" }; public string Name => "Weather forecast"; @@ -19,46 +20,63 @@ internal class WeatherForecastUtility : IUtility public void Configure(IOptions options) { - _openWeatherMapKey = options.Value.OpenWeatherMapApiKey; + _openWeatherMapKey = options.Value.OpenWeatherMapApiKey; } - public void Run() + public void Run() => Run(null); + + public void Run(string townParm = null) { - if (String.IsNullOrEmpty(_openWeatherMapKey)) + if (String.IsNullOrEmpty(_openWeatherMapKey)) + { + Console.WriteLine("Whoops! API key is not defined."); + Console.WriteLine("Get an API key from https://home.openweathermap.org/api_keys then.."); + Console.WriteLine("run dotnet user-secrets set \"SecretsModel: OpenWeatherMapApiKey\" \"12345\" to specify your key"); + return; + } + + Console.Write("Enter your town name:"); + string town = (String.IsNullOrEmpty(townParm)) ? Console.ReadLine() : townParm; + string resp = ""; + WeatherRoot wr = new WeatherRoot(); + try + { + using (var wc = GetWebClient()) { - Console.WriteLine("Whoops! API key is not defined."); - return; + resp = wc.DownloadString($"http://api.openweathermap.org/data/2.5/weather?q={town}&appid={_openWeatherMapKey}"); } + wr = JsonSerializer.Deserialize(resp); + } + catch + { + Console.WriteLine("Got no result or couldn't convert to Weather object"); + return; + } - Console.Write("Enter your town name:"); - string town = Console.ReadLine(); - - string resp = ""; + Console.WriteLine(); + Console.WriteLine("Temperature: " + Weather.KtoF(wr.Main.Temperature) + "°F or " + Weather.KtoC(wr.Main.Temperature) + "°C. Feels like: " + Weather.KtoF(wr.Main.Temperature) + "°F or " + Weather.KtoC(wr.Main.Temperature) + "°C"); + Console.WriteLine("Wind speed: " + wr.Wind.Speed + " m/s. Air pressure is " + wr.Main.Pressure + "mmHg or " + Math.Round(wr.Main.Pressure * 133.322, 1) + " Pascals."); - using (var wc = new WebClient()) - { - resp = wc.DownloadString($"http://api.openweathermap.org/data/2.5/weather?q={town}&appid={_openWeatherMapKey}"); - } - WeatherRoot wr = JsonSerializer.Deserialize(resp); + long currentTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); + bool SunWhat = currentTime > wr.Sys.Sunrise; + long whatNext = SunWhat ? wr.Sys.Sunset : wr.Sys.Sunrise; + long diff = whatNext - currentTime; + var dto = DateTimeOffset.FromUnixTimeSeconds(diff); - Console.WriteLine(); - Console.WriteLine("Temperature: " + Weather.KtoF(wr.Main.Temperature) + "°F or " + Weather.KtoC(wr.Main.Temperature) + "°C. Feels like: " + Weather.KtoF(wr.Main.Temperature) + "°F or " + Weather.KtoC(wr.Main.Temperature) + "°C"); - Console.WriteLine("Wind speed: " + wr.Wind.Speed + " m/s. Air pressure is " + wr.Main.Pressure + "mmHg or " + Math.Round(wr.Main.Pressure * 133.322, 1) + " Pascals."); - - long currentTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); - bool SunWhat = currentTime > wr.Sys.Sunrise; - long whatNext = SunWhat ? wr.Sys.Sunset : wr.Sys.Sunrise; - long diff = whatNext - currentTime; - var dto = DateTimeOffset.FromUnixTimeSeconds(diff); + if (SunWhat) //If sun should be setting... + { + Console.WriteLine("It's day right now. The sun will set in " + dto.ToString("HH:mm:ss")); + } + else + { + Console.WriteLine("It's night right now. The sun will rise in " + dto.ToString("HH:mm:ss")); + } + } - if (SunWhat) //If sun should be setting... - { - Console.WriteLine("It's day right now. The sun will set in " + dto.ToString("HH:mm:ss")); - } - else - { - Console.WriteLine("It's night right now. The sun will rise in " + dto.ToString("HH:mm:ss")); - } + protected virtual IWebClient GetWebClient() + { + var factory = new SystemWebClientFactory(); + return factory.Create(); } } } \ No newline at end of file