diff --git a/tdd_intro/homework/04_weather_client/test.cpp b/tdd_intro/homework/04_weather_client/test.cpp index 9fe711c..dcdd65c 100644 --- a/tdd_intro/homework/04_weather_client/test.cpp +++ b/tdd_intro/homework/04_weather_client/test.cpp @@ -44,5 +44,318 @@ Each line means "" : "": 2. Implement IWeatherClient using fake server. */ +/* + * - Empty string parsing + * - Valid data parsing + * - Invalid data parsing // TODO + * - Parse data list + * + * - Weather server stub + * - Test GetAverageTemperature for 31.08.2018 + * - Acceptance test for GetAverageTemperature + * - Test GetMinimumTemperature for 31.08.2018 + * - Acceptance test for GetMinimumTemperature + * - Test GetMaximumTemperature for 31.08.2018 + * - Acceptance test for GetMaximumTemperature + * - Test GetAverageWindDirection for 31.08.2018 + * - Acceptance test for GetAverageWindDirection + * - Test GetMaximumWindSpeed for 31.08.2018 + * - Acceptance test for GetMaximumWindSpeed + */ + #include #include + +struct Weather +{ + short temperature = 0; + unsigned short windDirection = 0; + double windSpeed = 0; + bool operator==(const Weather& right) const + { + return temperature == right.temperature && + windDirection == right.windDirection && + std::abs(windSpeed - right.windSpeed) < 0.01; + } +}; + +class IWeatherServer +{ +public: + virtual ~IWeatherServer() { } + // Returns raw response with weather for the given day and time in request + virtual std::string GetWeather(const std::string& request) = 0; +}; + +// Implement this interface +class IWeatherClient +{ +public: + virtual ~IWeatherClient() { } + virtual double GetAverageTemperature(IWeatherServer& server, const std::string& date) = 0; + virtual double GetMinimumTemperature(IWeatherServer& server, const std::string& date) = 0; + virtual double GetMaximumTemperature(IWeatherServer& server, const std::string& date) = 0; + virtual double GetAverageWindDirection(IWeatherServer& server, const std::string& date) = 0; + virtual double GetMaximumWindSpeed(IWeatherServer& server, const std::string& date) = 0; +}; + +class WeatherServerStub : public IWeatherServer +{ +public: + std::string GetWeather(const std::string& request) + { + static std::map weatherMap = {{"31.08.2018;03:00" , "20;181;5.1"}, + {"31.08.2018;09:00" , "23;204;4.9"}, + {"31.08.2018;15:00" , "33;193;4.3"}, + {"31.08.2018;21:00" , "26;179;4.5"}, + + {"01.09.2018;03:00" , "19;176;4.2"}, + {"01.09.2018;09:00" , "22;131;4.1"}, + {"01.09.2018;15:00" , "31;109;4.0"}, + {"01.09.2018;21:00" , "24;127;4.1"}, + + {"02.09.2018;03:00" , "21;158;3.8"}, + {"02.09.2018;09:00" , "25;201;3.5"}, + {"02.09.2018;15:00" , "34;258;3.7"}, + {"02.09.2018;21:00" , "27;299;4.0"}}; + auto result = weatherMap.find(request); + return result == weatherMap.end() ? "" : result->second; + } +}; + +Weather ParseWeather(const std::string &data); +class WeatherClient : public IWeatherClient +{ + template + double GetMaximum(IWeatherServer& server, const std::string& date, TAccessor accessor) + { + std::set results; + + results.insert(accessor(ParseWeather(server.GetWeather(date + ";03:00")))); + results.insert(accessor(ParseWeather(server.GetWeather(date + ";09:00")))); + results.insert(accessor(ParseWeather(server.GetWeather(date + ";15:00")))); + results.insert(accessor(ParseWeather(server.GetWeather(date + ";21:00")))); + + return *results.rbegin(); + } + + template + double GetMinimum(IWeatherServer& server, const std::string& date, TAccessor accessor) + { + std::set results; + + results.insert(accessor(ParseWeather(server.GetWeather(date + ";03:00")))); + results.insert(accessor(ParseWeather(server.GetWeather(date + ";09:00")))); + results.insert(accessor(ParseWeather(server.GetWeather(date + ";15:00")))); + results.insert(accessor(ParseWeather(server.GetWeather(date + ";21:00")))); + + return *results.begin(); + } + + template + double GetAverage(IWeatherServer& server, const std::string& date, TAccessor accessor) + { + double result = 0; + + std::string response = server.GetWeather(date + ";03:00"); + result += accessor(ParseWeather(response)); + response = server.GetWeather(date + ";09:00"); + result += accessor(ParseWeather(response)); + response = server.GetWeather(date + ";15:00"); + result += accessor(ParseWeather(response)); + response = server.GetWeather(date + ";21:00"); + result += accessor(ParseWeather(response)); + + return result/4; + } + +public: + double GetAverageTemperature(IWeatherServer& server, const std::string& date) + { + auto accessor = [](const Weather& weather)->double{ return weather.temperature; }; + return GetAverage(server, date, accessor); + } + + double GetMinimumTemperature(IWeatherServer& server, const std::string& date) + { + auto accessor = [](const Weather& weather)->double{ return weather.temperature; }; + return GetMinimum(server, date, accessor); + } + + double GetMaximumTemperature(IWeatherServer& server, const std::string& date) + { + auto accessor = [](const Weather& weather)->double{ return weather.temperature; }; + return GetMaximum(server, date, accessor); + } + + double GetAverageWindDirection(IWeatherServer& server, const std::string& date) + { + auto accessor = [](const Weather& weather)->double{ return weather.windDirection; }; + return GetAverage(server, date, accessor); + } + + double GetMaximumWindSpeed(IWeatherServer& server, const std::string& date) + { + auto accessor = [](const Weather& weather)->double{ return weather.windSpeed; }; + return GetMaximum(server, date, accessor); + } +}; + +Weather ParseWeather(const std::string &data) +{ + if (data.empty()) + { + throw std::runtime_error(""); + } + Weather weather; + std::istringstream stream(data); + + stream >> weather.temperature; + stream.ignore(); + stream >> weather.windDirection; + stream.ignore(); + stream >> weather.windSpeed; + + return weather; +} + +std::vector ParseWeather(const std::vector &response) +{ + std::vector result; + for (auto data : response) + { + Weather weather = ParseWeather(data); + result.push_back(weather); + } + + return result; +} + +TEST(WeatherClient, CheckParsingEmptyString) +{ + EXPECT_THROW(ParseWeather(""), std::runtime_error); +} + +TEST(WeatherClient, CheckParsingValidString) +{ + Weather wether; + wether.temperature = 27; + wether.windDirection = 299; + wether.windSpeed = 4.0; + + ASSERT_EQ(wether, ParseWeather("27;299;4.0")); +} + +TEST(WeatherClient, CheckParsingMultipleStrings) +{ + std::vector response = {"20;181;5.1", "23;204;4.9", "33;193;4.3"}; + + Weather wether0; + wether0.temperature = 20; + wether0.windDirection = 181; + wether0.windSpeed = 5.1; + + Weather wether1; + wether1.temperature = 23; + wether1.windDirection = 204; + wether1.windSpeed = 4.9; + + Weather wether2; + wether2.temperature = 33; + wether2.windDirection = 193; + wether2.windSpeed = 4.3; + + std::vector result = {wether0, wether1, wether2}; + ASSERT_EQ(result , ParseWeather(response)); +} + +TEST(WeatherClient, GetAverageTemperatureFor31_08_2018) +{ + WeatherServerStub server; + WeatherClient client; + + ASSERT_DOUBLE_EQ(25.5, client.GetAverageTemperature(server, "31.08.2018")); +} + +TEST(WeatherClient, AverageTemperatureAcceptance) +{ + WeatherServerStub server; + WeatherClient client; + + ASSERT_DOUBLE_EQ(25.5, client.GetAverageTemperature(server, "31.08.2018")); + ASSERT_DOUBLE_EQ(24.0, client.GetAverageTemperature(server, "01.09.2018")); + ASSERT_DOUBLE_EQ(26.75, client.GetAverageTemperature(server, "02.09.2018")); + EXPECT_THROW(client.GetAverageTemperature(server, "03.09.2018"), std::runtime_error); +} + +TEST(WeatherClient, GetMinimumTemperatureFor31_08_2018) +{ + WeatherServerStub server; + WeatherClient client; + + ASSERT_DOUBLE_EQ(20, client.GetMinimumTemperature(server, "31.08.2018")); +} + +TEST(WeatherClient, MinimumTempertureAcceptance) +{ + WeatherServerStub server; + WeatherClient client; + + ASSERT_DOUBLE_EQ(19, client.GetMinimumTemperature(server, "01.09.2018")); + ASSERT_DOUBLE_EQ(21, client.GetMinimumTemperature(server, "02.09.2018")); + EXPECT_THROW(client.GetMinimumTemperature(server, "03.09.2018"), std::runtime_error); +} + +TEST(WeatherClient, GetMaximumTemperatureFor31_08_2018) +{ + WeatherServerStub server; + WeatherClient client; + + ASSERT_DOUBLE_EQ(33, client.GetMaximumTemperature(server, "31.08.2018")); +} + +TEST(WeatherClient, MaximumTemperatureAcceptance) +{ + WeatherServerStub server; + WeatherClient client; + + ASSERT_DOUBLE_EQ(31, client.GetMaximumTemperature(server, "01.09.2018")); + ASSERT_DOUBLE_EQ(34, client.GetMaximumTemperature(server, "02.09.2018")); + EXPECT_THROW(client.GetMaximumTemperature(server, "03.09.2018"), std::runtime_error); +} + +TEST(WeatherClient, GetAverageWindDirectionFor31_08_2018) +{ + WeatherServerStub server; + WeatherClient client; + + ASSERT_DOUBLE_EQ(189.25, client.GetAverageWindDirection(server, "31.08.2018")); +} + +TEST(WeatherClient, AverageWindDirectionAcceptance) +{ + WeatherServerStub server; + WeatherClient client; + + ASSERT_DOUBLE_EQ(135.75, client.GetAverageWindDirection(server, "01.09.2018")); + ASSERT_DOUBLE_EQ(229, client.GetAverageWindDirection(server, "02.09.2018")); + EXPECT_THROW(client.GetAverageWindDirection(server, "03.09.2018"), std::runtime_error); +} + +TEST(WeatherClient, GetMaximumWindSpeedFor31_08_2018) +{ + WeatherServerStub server; + WeatherClient client; + + ASSERT_DOUBLE_EQ(5.1, client.GetMaximumWindSpeed(server, "31.08.2018")); +} + +TEST(WeatherClient, MaximumWindSpeedAcceptance) +{ + WeatherServerStub server; + WeatherClient client; + + ASSERT_DOUBLE_EQ(4.2, client.GetMaximumWindSpeed(server, "01.09.2018")); + ASSERT_DOUBLE_EQ(4.0, client.GetMaximumWindSpeed(server, "02.09.2018")); + EXPECT_THROW(client.GetMaximumWindSpeed(server, "03.09.2018"), std::runtime_error); +}