diff --git a/tdd_intro/demo/01_bob/test.cpp b/tdd_intro/demo/01_bob/test.cpp index dc9e42f..5840552 100644 --- a/tdd_intro/demo/01_bob/test.cpp +++ b/tdd_intro/demo/01_bob/test.cpp @@ -10,3 +10,45 @@ He answers 'Whatever.' to anything else. #include #include +const std::string g_tellBobAnswer = "Sure"; +const std::string g_yellBobAnswer = "Whoa, chill out!"; +const std::string g_emptyBobAnswer = "Fine. Be that way!"; +const std::string g_defaultBobAnswer = "Whatever."; + +std::string CallBob(const std::string& str) +{ + if (str.empty()) + { + return g_emptyBobAnswer; + } + if (str.back() == '!') + { + return g_yellBobAnswer; + } + else if (str.back() == '?') + { + return g_tellBobAnswer; + } + + return g_defaultBobAnswer; +} + +TEST(bob, AnswerSureOnQuestion) +{ + ASSERT_EQ(g_tellBobAnswer, CallBob("Are you ok?")); +} + +TEST(bob, AnswerChillOnYell) +{ + ASSERT_EQ(g_yellBobAnswer, CallBob("Yell!!!!")); +} + +TEST(bob, AnswerOnEmptyString) +{ + ASSERT_EQ(g_emptyBobAnswer, CallBob("")); +} + +TEST(bob, AnswerOnAnythingElse) +{ + ASSERT_EQ(g_defaultBobAnswer, CallBob("Anything else")); +} diff --git a/tdd_intro/demo/01_fizz_buzz/test.cpp b/tdd_intro/demo/01_fizz_buzz/test.cpp index 582ee51..49fa275 100644 --- a/tdd_intro/demo/01_fizz_buzz/test.cpp +++ b/tdd_intro/demo/01_fizz_buzz/test.cpp @@ -9,3 +9,64 @@ * a multiple of 15 = FizzBuzz * any other number = */ + +const std::string g_fizzString = "Fizz"; +const std::string g_buzzString = "Buzz"; +const std::string g_fizzBuzzString = "FizzBuzz"; + +std::string FizzBuzz(int num) +{ + std::string fizzBuzzStr; + + if (num % 3 == 0) + { + fizzBuzzStr = g_fizzString; + } + + if (num % 5 == 0) + { + fizzBuzzStr += g_buzzString; + } + + return fizzBuzzStr; +} + + +TEST(FizzBuzzTest, Fizz) +{ + EXPECT_EQ(g_fizzString, FizzBuzz(3)); +} + +TEST(FizzBuzzTest, Buzz) +{ + EXPECT_EQ(g_buzzString, FizzBuzz(5)); +} + +TEST(FizzBuzzTest, Fizz6) +{ + EXPECT_EQ(g_fizzString, FizzBuzz(6)); +} + +TEST(FizzBuzzTest, Buzz10) +{ + EXPECT_EQ(g_buzzString, FizzBuzz(10)); +} + +TEST(FizzBuzzTest, FizzBuzz) +{ + EXPECT_EQ(g_fizzBuzzString, FizzBuzz(15)); +} + +TEST(FizzBuzzTest, FizzBuzzEmpty) +{ + EXPECT_EQ("", FizzBuzz(1)); +} + +TEST(FizzBuzzTest, Acceptance) +{ + EXPECT_EQ(g_buzzString, FizzBuzz(35)); + EXPECT_EQ(g_fizzString, FizzBuzz(66)); + EXPECT_EQ(g_fizzBuzzString, FizzBuzz(45)); + EXPECT_EQ("", FizzBuzz(17)); + EXPECT_EQ("", FizzBuzz(-23)); +} diff --git a/tdd_intro/demo/02_anagram/test.cpp b/tdd_intro/demo/02_anagram/test.cpp index 4d65537..1c4d8e6 100644 --- a/tdd_intro/demo/02_anagram/test.cpp +++ b/tdd_intro/demo/02_anagram/test.cpp @@ -6,3 +6,76 @@ Given "listen" and a list of candidates like "enlists" "google" "inlets" "banana _from http://exercism.io/_ */ #include +typedef std::vector strings; + +bool IsAnagramPresent(std::string first, std::string second) +{ + std::sort(first.begin(), first.end()); + std::sort(second.begin(), second.end()); + + return first == second; +} + +strings ReturnAnagrams(std::string target, const strings& variants) +{ + strings anagrams; + for (std::string variant : variants) + { + if (IsAnagramPresent(target, variant)) + { + anagrams.push_back(variant); + } + } + + return anagrams; +} + +TEST (anagrams, emptyString) +{ + EXPECT_TRUE(IsAnagramPresent("", "")); +} + +TEST(anagrams, notEqualWords) +{ + EXPECT_FALSE(IsAnagramPresent("word", "lock")); +} + +TEST(anagrams, anagram) +{ + EXPECT_TRUE(IsAnagramPresent("listen", "inlets")); +} + +TEST(anagrams, returnEmptyString) +{ + EXPECT_EQ(strings(), ReturnAnagrams("", strings())); +} + +TEST(anagrams, singleAnagram) +{ + EXPECT_EQ( strings({"inlets"}), ReturnAnagrams("listen", strings({"inlets"}))); +} + +TEST(anagrams, otherSignleAnagram) +{ + EXPECT_EQ( strings({"letsin"}), ReturnAnagrams("listen", strings({"letsin"}))); +} + +TEST(anagrams, signleNotAnagram) +{ + EXPECT_EQ( strings(), ReturnAnagrams("listen", strings({"letiin"}))); +} + +TEST(anagrams, multipleWordsOnaAnagram) +{ + EXPECT_EQ(strings({"inlets"}), ReturnAnagrams("listen", strings({"inlets", "google"}))); +} + +TEST(anagrams, multipleAnagrams) +{ + EXPECT_EQ(strings({"inlets", "inelts"}), ReturnAnagrams("listen", strings({"inlets", "inelts"}))); +} + +TEST(anagrams, multipleAnagramsNotInOrder) +{ + EXPECT_EQ(strings({"inelts", "inlets"}), ReturnAnagrams("listen", strings({"inlets", "inelts"}))); +} diff --git a/tdd_intro/homework/02_ternary_numbers/test.cpp b/tdd_intro/homework/02_ternary_numbers/test.cpp index 1750302..e75a61a 100644 --- a/tdd_intro/homework/02_ternary_numbers/test.cpp +++ b/tdd_intro/homework/02_ternary_numbers/test.cpp @@ -16,3 +16,77 @@ The last place in a ternary number is the 1's place. The second to last is the 3 If your language provides a method in the standard library to perform the conversion, pretend it doesn't exist and implement it yourself. */ + +/* + * 1) 0 test + * 2) 1 test + * 3) 2 test + * 4) invalid digit test + * 5) Multiple digits tests + * 6) Invalid multiple digits tests + * 7) Acceptence test + */ + +bool TernaryNumber(int number) +{ + return number < 3; +} + +int ConvertTernaryNumbers(const std::string &number) +{ + int sum = 0; + for (int index = 0; index < number.size(); ++index) + { + int numberValue = std::stoi(std::string(1, number[number.size() - 1 - index])); + if (!TernaryNumber(numberValue)) + { + return 0; + } + sum += numberValue * std::pow(3, index); + } + + return sum; +} + +TEST(TernaryNumbers, ZeroTest) +{ + ASSERT_TRUE(TernaryNumber(0)); +} + +TEST(TernaryNumbers, CheckOne) +{ + ASSERT_TRUE(TernaryNumber(1)); +} + +TEST(TernaryNumbers, CheckTwo) +{ + ASSERT_TRUE(TernaryNumber(2)); +} + +TEST(TernaryNumbers, InvalidDigit) +{ + ASSERT_FALSE(TernaryNumber(3)); +} + +TEST(TernaryNumbers, MultipleDigits) +{ + ASSERT_EQ(0, ConvertTernaryNumbers("00")); +} + +TEST(TernaryNumbers, MultipleDigits111) +{ + ASSERT_EQ(13, ConvertTernaryNumbers("111")); +} + +TEST(TernaryNumbers, InvalidMultipleDigits) +{ + ASSERT_EQ(0, ConvertTernaryNumbers("113")); +} + +TEST(TernaryNumbers, Acceptance) +{ + ASSERT_EQ(0, ConvertTernaryNumbers("123")); + ASSERT_EQ(16, ConvertTernaryNumbers("121")); + ASSERT_EQ(439, ConvertTernaryNumbers("121021")); + ASSERT_EQ(597871, ConvertTernaryNumbers("1010101010101")); +} diff --git a/tdd_intro/homework/04_weather_client/test.cpp b/tdd_intro/homework/04_weather_client/test.cpp index 9fe711c..74cc453 100644 --- a/tdd_intro/homework/04_weather_client/test.cpp +++ b/tdd_intro/homework/04_weather_client/test.cpp @@ -44,5 +44,365 @@ 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 + +class Weather; + +using WeatherVector = std::vector; +using WeatherMap = std::map; +using TemperatureVector = std::vector; +using WindSpeedVector = std::vector; + +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 short GetMinimumTemperature(IWeatherServer& server, const std::string& date) = 0; + virtual short 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 WeatherMap 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 +{ +public: + double GetAverageTemperature(IWeatherServer& server, const std::string& date) + { + double result = 0; + + std::string response = server.GetWeather(date + ";03:00"); + result += ParseWeather(response).temperature; + response = server.GetWeather(date + ";09:00"); + result += ParseWeather(response).temperature; + response = server.GetWeather(date + ";15:00"); + result += ParseWeather(response).temperature; + response = server.GetWeather(date + ";21:00"); + result += ParseWeather(response).temperature; + + return result/4; + } + + short GetMinimumTemperature(IWeatherServer& server, const std::string& date) + { + TemperatureVector temps; + std::string response = server.GetWeather(date + ";03:00"); + temps.push_back(ParseWeather(response).temperature); + response = server.GetWeather(date + ";09:00"); + temps.push_back(ParseWeather(response).temperature); + response = server.GetWeather(date + ";15:00"); + temps.push_back(ParseWeather(response).temperature); + response = server.GetWeather(date + ";21:00"); + temps.push_back(ParseWeather(response).temperature); + + TemperatureVector::iterator result = std::min_element(std::begin(temps), std::end(temps)); + return *result; + } + + short GetMaximumTemperature(IWeatherServer& server, const std::string& date) + { + TemperatureVector temps; + std::string response = server.GetWeather(date + ";03:00"); + temps.push_back(ParseWeather(response).temperature); + response = server.GetWeather(date + ";09:00"); + temps.push_back(ParseWeather(response).temperature); + response = server.GetWeather(date + ";15:00"); + temps.push_back(ParseWeather(response).temperature); + response = server.GetWeather(date + ";21:00"); + temps.push_back(ParseWeather(response).temperature); + + TemperatureVector::iterator result = std::max_element(std::begin(temps), std::end(temps)); + return *result; + } + + double GetAverageWindDirection(IWeatherServer& server, const std::string& date) + { + unsigned short result = 0; + + std::string response = server.GetWeather(date + ";03:00"); + result += ParseWeather(response).windDirection; + response = server.GetWeather(date + ";09:00"); + result += ParseWeather(response).windDirection; + response = server.GetWeather(date + ";15:00"); + result += ParseWeather(response).windDirection; + response = server.GetWeather(date + ";21:00"); + result += ParseWeather(response).windDirection; + + return static_cast(result)/4; + } + + double GetMaximumWindSpeed(IWeatherServer& server, const std::string& date) + { + WindSpeedVector speeds; + + std::string response = server.GetWeather(date + ";03:00"); + speeds.push_back(ParseWeather(response).windSpeed); + response = server.GetWeather(date + ";09:00"); + speeds.push_back(ParseWeather(response).windSpeed); + response = server.GetWeather(date + ";15:00"); + speeds.push_back(ParseWeather(response).windSpeed); + response = server.GetWeather(date + ";21:00"); + speeds.push_back(ParseWeather(response).windSpeed); + + WindSpeedVector::iterator result = std::max_element(std::begin(speeds), std::end(speeds)); + return *result; + } +}; + +Weather ParseWeather(const std::string &data) +{ + if (data.empty()) + { + throw std::runtime_error(""); + } + + Weather weather; + std::istringstream stream(data); + + for (unsigned int operationIndex = 0; operationIndex < 3; ++operationIndex) + { + switch (operationIndex) + { + case 0: + stream >> weather.temperature; + break; + + case 1: + stream >> weather.windDirection; + break; + + case 2: + stream >> weather.windSpeed; + break; + + default: + break; + } + + if (stream.fail()) + { + throw std::runtime_error(""); + } + + stream.ignore(); + } + + return weather; +} + +WeatherVector ParseWeather(const std::vector &response) +{ + WeatherVector 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.0f; + + ASSERT_EQ(wether, ParseWeather("27;299;4.0")); +} + +TEST(WeatherClient, CheckParsingInvalidString) +{ + EXPECT_THROW(ParseWeather("asd;11;aaa"), std::runtime_error); +} + +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.1f; + + Weather wether1; + wether1.temperature = 23; + wether1.windDirection = 204; + wether1.windSpeed = 4.9f; + + Weather wether2; + wether2.temperature = 33; + wether2.windDirection = 193; + wether2.windSpeed = 4.3f; + + WeatherVector result = {wether0, wether1, wether2}; + ASSERT_EQ(result , ParseWeather(response)); +} + +TEST(WeatherClient, GetAverageTemperatureFor31_08_2018) +{ + WeatherServerStub server; + WeatherClient client; + + ASSERT_FLOAT_EQ(25.5f, client.GetAverageTemperature(server, "31.08.2018")); +} + +TEST(WeatherClient, GetAverageTemperatureAcceptence) +{ + WeatherServerStub server; + WeatherClient client; + + ASSERT_FLOAT_EQ(24.0f, client.GetAverageTemperature(server, "01.09.2018")); + ASSERT_FLOAT_EQ(26.75f, client.GetAverageTemperature(server, "02.09.2018")); + EXPECT_THROW(client.GetAverageTemperature(server, "sdsdfdf"), std::runtime_error); + EXPECT_ANY_THROW(client.GetAverageTemperature(server, "01.11.2018")); // Использовал этот метод, почему то 2 метода EXPECT_THROW не компилируются в одном методе... +} + +TEST(WeatherClient, GetMinimumTemperatureFor31_08_2018) +{ + WeatherServerStub server; + WeatherClient client; + + ASSERT_EQ(20, client.GetMinimumTemperature(server, "31.08.2018")); +} + +TEST(WeatherClient, GetMinimumTemperatureAcceptence) +{ + WeatherServerStub server; + WeatherClient client; + + ASSERT_EQ(19, client.GetMinimumTemperature(server, "01.09.2018")); + ASSERT_EQ(21, client.GetMinimumTemperature(server, "02.09.2018")); + EXPECT_THROW(client.GetMinimumTemperature(server, "sdsdfdf"), std::runtime_error); + EXPECT_ANY_THROW(client.GetMinimumTemperature(server, "01.11.2018")); // Использовал этот метод, почему то 2 метода EXPECT_THROW не компилируются в одном методе... +} + +TEST(WeatherClient, GetMaximumTemperatureFor31_08_2018) +{ + WeatherServerStub server; + WeatherClient client; + + ASSERT_EQ(33, client.GetMaximumTemperature(server, "31.08.2018")); +} + +TEST(WeatherClient, GetMaximumTemperatureAcceptence) +{ + WeatherServerStub server; + WeatherClient client; + + ASSERT_EQ(31, client.GetMaximumTemperature(server, "01.09.2018")); + ASSERT_EQ(34, client.GetMaximumTemperature(server, "02.09.2018")); + EXPECT_THROW(client.GetMaximumTemperature(server, "sdsdfdf"), std::runtime_error); + EXPECT_ANY_THROW(client.GetMaximumTemperature(server, "01.11.2018")); // Использовал этот метод, почему то 2 метода EXPECT_THROW не компилируются в одном методе... +} + +TEST(WeatherClient, GetAverageWindDirectionFor31_08_2018) +{ + WeatherServerStub server; + WeatherClient client; + + ASSERT_FLOAT_EQ(189.25, client.GetAverageWindDirection(server, "31.08.2018")); +} + +TEST(WeatherClient, GetAverageWindDirectionAcceptence) +{ + WeatherServerStub server; + WeatherClient client; + + ASSERT_FLOAT_EQ(135.75f, client.GetAverageWindDirection(server, "01.09.2018")); + ASSERT_FLOAT_EQ(229.0f, client.GetAverageWindDirection(server, "02.09.2018")); + EXPECT_THROW(client.GetAverageWindDirection(server, "sdsdfdf"), std::runtime_error); + EXPECT_ANY_THROW(client.GetAverageWindDirection(server, "01.11.2018")); // Использовал этот метод, почему то 2 метода EXPECT_THROW не компилируются в одном методе... +} + +TEST(WeatherClient, GetMaximumWindSpeedFor31_08_2018) +{ + WeatherServerStub server; + WeatherClient client; + + ASSERT_FLOAT_EQ(5.1f, client.GetMaximumWindSpeed(server, "31.08.2018")); +} + +TEST(WeatherClient, GetMaximumWindSpeedAcceptence) +{ + WeatherServerStub server; + WeatherClient client; + + ASSERT_FLOAT_EQ(4.2f, client.GetMaximumWindSpeed(server, "01.09.2018")); + ASSERT_FLOAT_EQ(4.0f, client.GetMaximumWindSpeed(server, "02.09.2018")); + EXPECT_THROW(client.GetMaximumWindSpeed(server, "sdsdfdf"), std::runtime_error); + EXPECT_ANY_THROW(client.GetMaximumWindSpeed(server, "01.11.2018")); // Использовал этот метод, почему то 2 метода EXPECT_THROW не компилируются в одном методе... +} diff --git a/tdd_intro/homework/homework.pro b/tdd_intro/homework/homework.pro index cf6c01b..07506ca 100644 --- a/tdd_intro/homework/homework.pro +++ b/tdd_intro/homework/homework.pro @@ -1,6 +1,7 @@ TEMPLATE = subdirs SUBDIRS += \ + 00_intro \ 01_leap_year \ 02_ternary_numbers \ 03_bank_ocr \