mirror of
https://github.com/ysoftdevs/Theatrical-Players-Refactoring-Kata.git
synced 2026-04-25 02:09:10 +02:00
2
cpp/.gitignore
vendored
Normal file
2
cpp/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
.idea/
|
||||||
|
cmake-build-*/
|
||||||
6
cpp/CMakeLists.txt
Normal file
6
cpp/CMakeLists.txt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.4)
|
||||||
|
project(theatrical_players_refactoring_kata)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 11)
|
||||||
|
|
||||||
|
add_subdirectory(tests)
|
||||||
14
cpp/README.md
Normal file
14
cpp/README.md
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
Theatrical Players Refactoring Kata - C++ version
|
||||||
|
========================================================
|
||||||
|
|
||||||
|
See the [top level readme](https://github.com/emilybache/Theatrical-Players-Refactoring-Kata) for general information about this exercise.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
The tests use the following header-only projects, which are in the `third_party` sub-directory:
|
||||||
|
|
||||||
|
| Project | Licence |
|
||||||
|
| --- | --- |
|
||||||
|
| [doctest test framework](https://github.com/onqtam/doctest) | [MIT](https://github.com/onqtam/doctest/blob/master/LICENSE.txt) |
|
||||||
|
| [ApprovalTests.cpp](https://github.com/approvals/ApprovalTests.cpp) | [Apache 2.0](https://github.com/approvals/ApprovalTests.cpp/blob/master/LICENSE) |
|
||||||
|
| [JSON for Modern C++](https://github.com/nlohmann/json) | [MIT](https://github.com/nlohmann/json/blob/develop/LICENSE.MIT) |
|
||||||
95
cpp/statement.cpp
Normal file
95
cpp/statement.cpp
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
#include "statement.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
|
// https://stackoverflow.com/a/7277333/104370
|
||||||
|
class comma_numpunct : public std::numpunct<char>
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
virtual char do_thousands_sep() const override
|
||||||
|
{
|
||||||
|
return ',';
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string do_grouping() const override
|
||||||
|
{
|
||||||
|
return "\03";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string format_as_dollars(float amount)
|
||||||
|
{
|
||||||
|
// this creates a new locale based on the current application default
|
||||||
|
// (which is either the one given on startup, but can be overriden with
|
||||||
|
// std::locale::global) - then extends it with an extra facet that
|
||||||
|
// controls numeric output.
|
||||||
|
const std::locale comma_locale(std::locale(), new comma_numpunct());
|
||||||
|
|
||||||
|
std::ostringstream out;
|
||||||
|
// tell stream to use our new locale.
|
||||||
|
out.imbue(comma_locale);
|
||||||
|
out.precision(2);
|
||||||
|
out << "$" << std::fixed << amount;
|
||||||
|
return out.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string statement(
|
||||||
|
const nlohmann::json& invoice,
|
||||||
|
const nlohmann::json& plays)
|
||||||
|
{
|
||||||
|
float total_amount = 0;
|
||||||
|
int volume_credits = 0;
|
||||||
|
|
||||||
|
std::stringstream result;
|
||||||
|
result << "Statement for " << invoice["customer"].get<std::string>() << '\n';
|
||||||
|
|
||||||
|
for( const auto& perf : invoice["performances"])
|
||||||
|
{
|
||||||
|
float this_amount = 0;
|
||||||
|
auto play = plays[perf["playID"].get<std::string>()];
|
||||||
|
if (play["type"] == "tragedy")
|
||||||
|
{
|
||||||
|
this_amount = 40000;
|
||||||
|
if (perf["audience"] > 30)
|
||||||
|
{
|
||||||
|
this_amount += 1000 * (perf["audience"].get<int>() - 30);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (play["type"] == "comedy")
|
||||||
|
{
|
||||||
|
this_amount = 30000;
|
||||||
|
if (perf["audience"] > 20)
|
||||||
|
{
|
||||||
|
this_amount += 10000 + 500 * (perf["audience"].get<int>() - 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
this_amount += 300 * perf["audience"].get<int>();
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::domain_error("unknown type: " + play["type"].get<std::string>());
|
||||||
|
}
|
||||||
|
|
||||||
|
// add volume credits
|
||||||
|
volume_credits += std::max(perf["audience"].get<int>() - 30, 0);
|
||||||
|
|
||||||
|
// add extra credit for every ten comedy attendees
|
||||||
|
if ("comedy" == play["type"])
|
||||||
|
{
|
||||||
|
volume_credits += perf["audience"].get<int>() / 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// print line for this order
|
||||||
|
result << " " << play["name"].get<std::string>() << ": " << format_as_dollars(this_amount/100) <<
|
||||||
|
" (" << perf["audience"] << " seats)\n";
|
||||||
|
total_amount += this_amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
result << "Amount owed is " << format_as_dollars(total_amount/100.0f) << "\n";
|
||||||
|
result << "You earned " << volume_credits << " credits";
|
||||||
|
return result.str();
|
||||||
|
}
|
||||||
7
cpp/statement.h
Normal file
7
cpp/statement.h
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
// TODO Include Guard
|
||||||
|
|
||||||
|
#include "json.hpp"
|
||||||
|
|
||||||
|
std::string statement(
|
||||||
|
const nlohmann::json& invoice,
|
||||||
|
const nlohmann::json& plays);
|
||||||
15
cpp/tests/CMakeLists.txt
Normal file
15
cpp/tests/CMakeLists.txt
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
project(tests)
|
||||||
|
|
||||||
|
add_executable(${PROJECT_NAME}
|
||||||
|
../statement.cpp
|
||||||
|
../statement.h
|
||||||
|
test_statement.cpp
|
||||||
|
main.cpp)
|
||||||
|
|
||||||
|
target_include_directories(
|
||||||
|
${PROJECT_NAME}
|
||||||
|
PUBLIC
|
||||||
|
../third_party ..)
|
||||||
|
|
||||||
|
enable_testing()
|
||||||
|
add_test(NAME ${PROJECT_NAME}_test COMMAND ${PROJECT_NAME})
|
||||||
17
cpp/tests/invoice.json
Normal file
17
cpp/tests/invoice.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"customer": "BigCo",
|
||||||
|
"performances": [
|
||||||
|
{
|
||||||
|
"playID": "hamlet",
|
||||||
|
"audience": 55
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playID": "as-like",
|
||||||
|
"audience": 35
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playID": "othello",
|
||||||
|
"audience": 40
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
13
cpp/tests/invoice_new_plays.json
Normal file
13
cpp/tests/invoice_new_plays.json
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"customer": "BigCoII",
|
||||||
|
"performances": [
|
||||||
|
{
|
||||||
|
"playID": "henry-v",
|
||||||
|
"audience": 53
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playID": "as-like",
|
||||||
|
"audience": 55
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
2
cpp/tests/main.cpp
Normal file
2
cpp/tests/main.cpp
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#define APPROVALS_DOCTEST
|
||||||
|
#include "ApprovalTests.hpp"
|
||||||
4
cpp/tests/new_plays.json
Normal file
4
cpp/tests/new_plays.json
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"henry-v": {"name": "Henry V", "type": "history"},
|
||||||
|
"as-like": {"name": "As You Like It", "type": "pastoral"}
|
||||||
|
}
|
||||||
5
cpp/tests/plays.json
Normal file
5
cpp/tests/plays.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"hamlet": {"name": "Hamlet", "type": "tragedy"},
|
||||||
|
"as-like": {"name": "As You Like It", "type": "comedy"},
|
||||||
|
"othello": {"name": "Othello", "type": "tragedy"}
|
||||||
|
}
|
||||||
43
cpp/tests/test_statement.cpp
Normal file
43
cpp/tests/test_statement.cpp
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#include "statement.h"
|
||||||
|
|
||||||
|
#include "json.hpp"
|
||||||
|
#include "doctest.h"
|
||||||
|
#include "ApprovalTests.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
std::string get_adjacent_file(const std::string& filename)
|
||||||
|
{
|
||||||
|
return ApprovalTestNamer().getDirectory() + filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
nlohmann::json read_json_file(const std::string& filename)
|
||||||
|
{
|
||||||
|
std::ifstream invoice_stream(filename);
|
||||||
|
if ( ! invoice_stream.is_open())
|
||||||
|
{
|
||||||
|
std::cout << "Error opening file:" << filename << '\n';
|
||||||
|
std::cout << "Error: " << strerror(errno) << '\n';
|
||||||
|
}
|
||||||
|
nlohmann::json result;
|
||||||
|
invoice_stream >> result;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("test_example_statement")
|
||||||
|
{
|
||||||
|
auto invoice = read_json_file(get_adjacent_file("invoice.json"));
|
||||||
|
auto plays = read_json_file(get_adjacent_file("plays.json"));
|
||||||
|
|
||||||
|
Approvals::verify(statement(invoice, plays));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("test_statement_with_new_play_types")
|
||||||
|
{
|
||||||
|
auto invoice = read_json_file(get_adjacent_file("invoice_new_plays.json"));
|
||||||
|
auto plays = read_json_file(get_adjacent_file("new_plays.json"));
|
||||||
|
CHECK_THROWS_AS(statement(invoice, plays), std::domain_error);
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
Statement for BigCo
|
||||||
|
Hamlet: $650.00 (55 seats)
|
||||||
|
As You Like It: $580.00 (35 seats)
|
||||||
|
Othello: $500.00 (40 seats)
|
||||||
|
Amount owed is $1,730.00
|
||||||
|
You earned 47 credits
|
||||||
2606
cpp/third_party/ApprovalTests.hpp
vendored
Normal file
2606
cpp/third_party/ApprovalTests.hpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
5939
cpp/third_party/doctest.h
vendored
Normal file
5939
cpp/third_party/doctest.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
22684
cpp/third_party/json.hpp
vendored
Normal file
22684
cpp/third_party/json.hpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user