Lots of implementation for sbf-cpp.

This commit is contained in:
2023-04-24 01:08:22 -07:00
parent b5b72efebc
commit 1e7c4eb726
21 changed files with 1580 additions and 247 deletions

View File

@@ -1,5 +1,7 @@
#include "Character.h" #include "Character.h"
#include "Attributes.h"
namespace SBF { namespace SBF {
using std::string; using std::string;
@@ -193,11 +195,12 @@ int GetDisciplinePoints() {
return kDisciplinePoints; return kDisciplinePoints;
} }
void CharacterType::FillDisciplineValues(std::vector<int> disciplineValues) const { void CharacterType::FillDisciplineValues(std::vector<int> values) const {
// TODO: This method sucks, but was needed in QBasic. // TODO: This method sucks, but was needed in QBasic.
disciplineValues.clear(); values.clear();
for (int id = 0; id <= kDisciplinesCount; id++) { values.push_back(0); // To pad the indexes.
disciplineValues[id] = GetDisciplineValue(id); for (int id = 1; id <= kDisciplinesCount; id++) {
values.push_back(GetDisciplineValue(id));
} }
} }
@@ -291,82 +294,97 @@ void FillAttributeAbbreviationsInGroup(std::vector<string> attributeAbbreviation
} }
} }
void CharacterType::SetPhysicalAttributeValue(int id, int value) {
switch (id) {
case kPhysicalAttributeDexterityId:
attr_dexterity = value;
case kPhysicalAttributeStaminaId:
attr_stamina = value;
case kPhysicalAttributeStrengthId:
attr_strength = value;
}
}
void CharacterType::SetSocialAttributeValue(int id, int value) {
switch (id) {
case kSocialAttributeAppearanceId:
attr_appearance = value;
case kSocialAttributeCharismaId:
attr_charisma = value;
case kSocialAttributeManipulationId:
attr_manipulation = value;
}
}
void CharacterType::SetMentalAttributeValue(int id, int value) {
switch (id) {
case kMentalAttributeIntelligenceId:
attr_intelligence = value;
case kMentalAttributePerceptionId:
attr_perception = value;
case kMentalAttributeWitsId:
attr_wits = value;
}
}
void CharacterType::SetAttributeValue(int attributeGroupId, int attributeId, int value) { void CharacterType::SetAttributeValue(int attributeGroupId, int attributeId, int value) {
switch (attributeGroupId) { switch (attributeGroupId) {
case kAttributeGroupPhysicalId: case kAttributeGroupPhysicalId:
switch (attributeId) { SetPhysicalAttributeValue(attributeId, value);
case kPhysicalAttributeStrengthId:
attr_strength = value;
break;
case kPhysicalAttributeDexterityId:
attr_dexterity = value;
break;
case kPhysicalAttributeStaminaId:
attr_stamina = value;
break;
}
break; break;
case kAttributeGroupSocialId: case kAttributeGroupSocialId:
switch (attributeId) { SetSocialAttributeValue(attributeId, value);
case kSocialAttributeCharismaId:
attr_charisma = value;
break;
case kSocialAttributeManipulationId:
attr_manipulation = value;
break;
case kSocialAttributeAppearanceId:
attr_appearance = value;
break;
}
break; break;
case kAttributeGroupMentalId: case kAttributeGroupMentalId:
switch (attributeId) { SetMentalAttributeValue(attributeId, value);
case kMentalAttributeIntelligenceId:
attr_intelligence = value;
break;
case kMentalAttributePerceptionId:
attr_perception = value;
break;
case kMentalAttributeWitsId:
attr_wits = value;
break;
}
break; break;
} }
} }
int CharacterType::GetPhysicalAttributeValue(int id) const {
switch (id) {
case kPhysicalAttributeDexterityId:
return attr_dexterity;
case kPhysicalAttributeStaminaId:
return attr_stamina;
case kPhysicalAttributeStrengthId:
return attr_strength;
}
return 0;
}
int CharacterType::GetSocialAttributeValue(int id) const {
switch (id) {
case kSocialAttributeAppearanceId:
return attr_appearance;
case kSocialAttributeCharismaId:
return attr_charisma;
case kSocialAttributeManipulationId:
return attr_manipulation;
}
return 0;
}
int CharacterType::GetMentalAttributeValue(int id) const {
switch (id) {
case kMentalAttributeIntelligenceId:
return attr_intelligence;
case kMentalAttributePerceptionId:
return attr_perception;
case kMentalAttributeWitsId:
return attr_wits;
}
return 0;
}
int CharacterType::GetAttributeValue(int attributeGroupId, int attributeId) const { int CharacterType::GetAttributeValue(int attributeGroupId, int attributeId) const {
switch (attributeGroupId) { switch (attributeGroupId) {
case kAttributeGroupPhysicalId: case kAttributeGroupPhysicalId:
switch (attributeId) { return GetPhysicalAttributeValue(attributeId);
case kPhysicalAttributeStrengthId:
return attr_strength;
case kPhysicalAttributeDexterityId:
return attr_dexterity;
case kPhysicalAttributeStaminaId:
return attr_stamina;
}
break;
case kAttributeGroupSocialId: case kAttributeGroupSocialId:
switch (attributeId) { return GetSocialAttributeValue(attributeId);
case kSocialAttributeCharismaId:
return attr_charisma;
case kSocialAttributeManipulationId:
return attr_manipulation;
case kSocialAttributeAppearanceId:
return attr_appearance;
}
break;
case kAttributeGroupMentalId: case kAttributeGroupMentalId:
switch (attributeId) { return GetMentalAttributeValue(attributeId);
case kMentalAttributeIntelligenceId:
return attr_intelligence;
case kMentalAttributePerceptionId:
return attr_perception;
case kMentalAttributeWitsId:
return attr_wits;
}
break;
} }
return 0; return 0;
} }
@@ -673,10 +691,11 @@ int CharacterType::GetBackgroundValue(int backgroundId) const {
return 0; return 0;
} }
void CharacterType::FillBackgroundValues(std::vector<int> backgroundValues) const { void CharacterType::FillBackgroundValues(std::vector<int> values) const {
backgroundValues.clear(); values.clear();
for (int backgroundId = 0; backgroundId <= kBackgroundsCount; backgroundId++) { values.push_back(0); // To pad the indexes.
backgroundValues[backgroundId] = GetBackgroundValue(backgroundId); for (int backgroundId = 1; backgroundId <= kBackgroundsCount; backgroundId++) {
values[backgroundId] = GetBackgroundValue(backgroundId);
} }
} }

View File

@@ -40,6 +40,9 @@ class CharacterType {
void FillVirtueValues(std::vector<int> virtueValues) const; void FillVirtueValues(std::vector<int> virtueValues) const;
int GetAbilityValue(int abilityGroupId, int abilityId) const; int GetAbilityValue(int abilityGroupId, int abilityId) const;
int GetAttributeValue(int attributeGroupId, int abilityId) const; int GetAttributeValue(int attributeGroupId, int abilityId) const;
int GetPhysicalAttributeValue(int id) const;
int GetSocialAttributeValue(int id) const;
int GetMentalAttributeValue(int id) const;
int GetBackgroundValue(int backgroundId) const; int GetBackgroundValue(int backgroundId) const;
std::string GetAllDerangementsLine() const; std::string GetAllDerangementsLine() const;
int GetDisciplineValue(int disciplineId) const; int GetDisciplineValue(int disciplineId) const;
@@ -49,6 +52,9 @@ class CharacterType {
int GetVirtueValue(int virtueId) const; int GetVirtueValue(int virtueId) const;
void SetAbilityValue(int abilityGroupId, int abilityId, int value); void SetAbilityValue(int abilityGroupId, int abilityId, int value);
void SetAttributeValue(int attributeGroupId, int attributeId, int value); void SetAttributeValue(int attributeGroupId, int attributeId, int value);
void SetPhysicalAttributeValue(int id, int value);
void SetMentalAttributeValue(int id, int value);
void SetSocialAttributeValue(int id, int value);
void SetBackgroundValue(int backgroundId, int value); void SetBackgroundValue(int backgroundId, int value);
void SetDisciplineValue(int disciplineId, int value); void SetDisciplineValue(int disciplineId, int value);
void SetKnowledgeValue(int knowledgeId, int value); void SetKnowledgeValue(int knowledgeId, int value);
@@ -163,5 +169,6 @@ class CharacterType {
int background_status; int background_status;
}; // End class CharacterType }; // End class CharacterType
} // End namespace SBF } // End namespace SBF
/** @}*/ /** @}*/
#endif // !defined CHARACTER_H__ #endif // !defined CHARACTER_H__

View File

@@ -2,12 +2,8 @@
namespace SBF { namespace SBF {
// TODO: Update these if they're wrong. They should be the initial color pair. uint8_t g_foreground_color = kColorDefaultForeground;
#pragma clang diagnostic push uint8_t g_background_color = kColorDefaultBackground;
#pragma clang diagnostic ignored "-Wunused-variable"
uint8_t g_foregroundColor = kColorDarkWhite;
uint8_t g_backgroundColor = kColorDarkBlack;
#pragma clang diagnostic pop
void FillColors(std::vector<uint8_t>& colors) { void FillColors(std::vector<uint8_t>& colors) {
colors.clear(); colors.clear();
@@ -17,20 +13,22 @@ void FillColors(std::vector<uint8_t>& colors) {
} }
uint8_t GetBackgroundColor() { uint8_t GetBackgroundColor() {
return g_backgroundColor; return g_background_color;
} }
uint8_t GetForegroundColor() { uint8_t GetForegroundColor() {
return g_foregroundColor; return g_foreground_color;
} }
// TODO: Define what happens when color is invalid. uint8_t SetBackgroundColor(uint8_t color) {
void SetBackgroundColor(uint8_t color) { uint8_t previous_color = color;
g_backgroundColor = color; g_background_color = color;
return previous_color;
} }
// TODO: Define what happens when color is invalid. uint8_t SetForegroundColor(uint8_t color) {
void SetForegroundColor(uint8_t color) { uint8_t previous_color = color;
g_foregroundColor = color; g_foreground_color = color;
return previous_color;
} }
} // End namespace SBF } // End namespace SBF

View File

@@ -9,6 +9,7 @@
* Licensed under the MIT license see the LICENSE file for details. * Licensed under the MIT license see the LICENSE file for details.
***************************************************************************************/ ***************************************************************************************/
#include <cstdint> #include <cstdint>
#include <ostream>
#include <vector> #include <vector>
/** \addtogroup Abilities /** \addtogroup Abilities
@@ -16,27 +17,27 @@
*/ */
namespace SBF { namespace SBF {
const uint8_t kColorDarkBlack = 0; const uint8_t kColorDarkBlack = 0;
const uint8_t kColorDarkBlue = 1; const uint8_t kColorDarkRed = 1;
const uint8_t kColorDarkGreen = 2; const uint8_t kColorDarkGreen = 2;
const uint8_t kColorDarkCyan = 3; const uint8_t kColorDarkYellow = 3;
const uint8_t kColorDarkRed = 4; const uint8_t kColorDarkBlue = 4;
const uint8_t kColorDarkMagenta = 5; const uint8_t kColorDarkMagenta = 5;
const uint8_t kColorDarkOrange = 6; const uint8_t kColorDarkCyan = 6;
const uint8_t kColorDarkYellow = 6;
const uint8_t kColorDarkWhite = 7; const uint8_t kColorDarkWhite = 7;
const uint8_t kColorBrightBlack = 8; const uint8_t kColorBrightBlack = 8;
const uint8_t kColorBrightBlue = 9; const uint8_t kColorBrightRed = 9;
const uint8_t kColorBrightGreen = 10; const uint8_t kColorBrightGreen = 10;
const uint8_t kColorBrightCyan = 11; const uint8_t kColorBrightYellow = 11;
const uint8_t kColorBrightRed = 12; const uint8_t kColorBrightBlue = 12;
const uint8_t kColorBrightMagenta = 13; const uint8_t kColorBrightMagenta = 13;
const uint8_t kColorBrightOrange = 14; const uint8_t kColorBrightCyan = 14;
const uint8_t kColorBrightYellow = 14;
const uint8_t kColorBrightWhite = 15; const uint8_t kColorBrightWhite = 15;
const uint8_t kColorDefaultForeground = kColorBrightWhite;
const uint8_t kColorDefaultBackground = kColorDarkBlack;
/// @brief Sets the stored foreground color. /// @brief Sets the stored foreground color.
/// @param color The new foreground color. /// @param color The new foreground color.
void SetForegroundColor(uint8_t color); uint8_t SetForegroundColor(uint8_t color);
/// @brief Gets the stored foreground color. /// @brief Gets the stored foreground color.
/// @return The foreground color. /// @return The foreground color.
@@ -44,7 +45,7 @@ uint8_t GetForegroundColor();
/// @brief Sets the stored background color. /// @brief Sets the stored background color.
/// @param color The new background color. /// @param color The new background color.
void SetBackgroundColor(uint8_t color); uint8_t SetBackgroundColor(uint8_t color);
/// @brief Gets the stored background color. /// @brief Gets the stored background color.
/// @return The background color. /// @return The background color.
@@ -53,6 +54,38 @@ uint8_t GetBackgroundColor();
/// @brief Fills the provided vector with all of the possible color values. It will be cleared before filling. /// @brief Fills the provided vector with all of the possible color values. It will be cleared before filling.
/// @param colors The vector to fill. /// @param colors The vector to fill.
void FillColors(std::vector<uint8_t>& colors); void FillColors(std::vector<uint8_t>& colors);
template <typename TChar, typename TTraits>
auto& Reset(std::basic_ostream<TChar, TTraits>& os) {
return os << "\033[m";
}
template <typename TChar, typename TTraits>
auto& ForegroundColor(std::basic_ostream<TChar, TTraits>& os) {
return os << "\033[38;5;" + std::to_string(GetForegroundColor()) + "m";
}
template <typename TChar, typename TTraits>
auto& BackgroundColor(std::basic_ostream<TChar, TTraits>& os) {
return os << "\033[48;5;" + std::to_string(GetBackgroundColor()) + "m";
}
template <typename TChar, typename TTraits>
auto& Colors(std::basic_ostream<TChar, TTraits>& os) {
return os << ForegroundColor << BackgroundColor;
}
template <typename TChar, typename TTraits>
auto& TrueColorForeground(std::basic_ostream<TChar, TTraits>& os, uint8_t red, uint8_t green, uint8_t blue) {
return os << "\033[38;2;" << std::to_string(red) << ";" << std::to_string(green) << ";" << std::to_string(blue)
<< "m";
}
template <typename TChar, typename TTraits>
auto& TrueColorBackground(std::basic_ostream<TChar, TTraits>& os, uint8_t red, uint8_t green, uint8_t blue) {
return os << "\033[48;2;" << std::to_string(red) << ";" << std::to_string(green) << ";" << std::to_string(blue)
<< "m";
}
} // End namespace SBF } // End namespace SBF
/** @}*/ /** @}*/

View File

@@ -1,5 +1,6 @@
#include "Colors.h" #include "Colors.h"
#include <regex>
#include <string> #include <string>
#include <tuple> #include <tuple>
#include <vector> #include <vector>
@@ -16,13 +17,20 @@ TestResults test_GetBackgroundColor();
TestResults test_GetForegroundColor(); TestResults test_GetForegroundColor();
TestResults test_SetBackgroundColor(); TestResults test_SetBackgroundColor();
TestResults test_SetForegroundColor(); TestResults test_SetForegroundColor();
TestResults test_Reset();
TestResults test_ForegroundColor();
TestResults test_BackgroundColor();
TestResults test_Colors();
TestResults test_TrueColorForeground();
TestResults test_TrueColorBackground();
string escape_string(const string& text, const string& pattern = "\033", const string& replace = "\\033");
} // End namespace Test::Colors } // End namespace Test::Colors
using namespace Test::Colors; using namespace Test::Colors;
namespace SBF { namespace SBF {
extern uint8_t g_foregroundColor; extern uint8_t g_foreground_color;
extern uint8_t g_backgroundColor; extern uint8_t g_background_color;
} // namespace SBF } // namespace SBF
TestResults main_test_Colors(int argc, char* argv[]) { TestResults main_test_Colors(int argc, char* argv[]) {
@@ -33,6 +41,12 @@ TestResults main_test_Colors(int argc, char* argv[]) {
results += test_GetForegroundColor(); results += test_GetForegroundColor();
results += test_SetBackgroundColor(); results += test_SetBackgroundColor();
results += test_SetForegroundColor(); results += test_SetForegroundColor();
results += test_Reset();
results += test_ForegroundColor();
results += test_BackgroundColor();
results += test_Colors();
results += test_TrueColorForeground();
results += test_TrueColorBackground();
return results; return results;
} }
@@ -60,7 +74,7 @@ TestResults test_FillColors() {
TestResults test_GetBackgroundColor() { TestResults test_GetBackgroundColor() {
auto fnToTest = [](uint8_t background_color) -> uint8_t { auto fnToTest = [](uint8_t background_color) -> uint8_t {
SBF::g_backgroundColor = background_color; SBF::g_background_color = background_color;
return GetBackgroundColor(); return GetBackgroundColor();
}; };
return execute_suite<uint32_t, uint32_t>(make_test_suite( return execute_suite<uint32_t, uint32_t>(make_test_suite(
@@ -70,37 +84,33 @@ TestResults test_GetBackgroundColor() {
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorDarkBlack when background color is 0", kColorDarkBlack, make_tuple(0U)), "should get kColorDarkBlack when background color is 0", kColorDarkBlack, make_tuple(0U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorDarkBlue when background color is 1", kColorDarkBlue, make_tuple(1U)), "should get kColorDarkBlue when background color is 1", kColorDarkRed, make_tuple(1U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorDarkGreen when background color is 2", kColorDarkGreen, make_tuple(2U)), "should get kColorDarkGreen when background color is 2", kColorDarkGreen, make_tuple(2U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorDarkCyan when background color is 3", kColorDarkCyan, make_tuple(3U)), "should get kColorDarkCyan when background color is 3", kColorDarkYellow, make_tuple(3U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorDarkRed when background color is 4", kColorDarkRed, make_tuple(4U)), "should get kColorDarkRed when background color is 4", kColorDarkBlue, make_tuple(4U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorDarkMagenta when background color is 5", kColorDarkMagenta, make_tuple(5U)), "should get kColorDarkMagenta when background color is 5", kColorDarkMagenta, make_tuple(5U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorDarkOrange when background color is 6", kColorDarkOrange, make_tuple(6U)), "should get kColorDarkYellow when background color is 6", kColorDarkCyan, make_tuple(6U)),
make_test<uint32_t, uint32_t>(
"should get kColorDarkYellow when background color is 6", kColorDarkYellow, make_tuple(6U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorDarkWhite when background color is 7", kColorDarkWhite, make_tuple(7U)), "should get kColorDarkWhite when background color is 7", kColorDarkWhite, make_tuple(7U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorBrightBlack when background color is 8", kColorBrightBlack, make_tuple(8U)), "should get kColorBrightBlack when background color is 8", kColorBrightBlack, make_tuple(8U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorBrightBlue when background color is 9", kColorBrightBlue, make_tuple(9U)), "should get kColorBrightBlue when background color is 9", kColorBrightRed, make_tuple(9U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorBrightGreen when background color is 10", kColorBrightGreen, make_tuple(10U)), "should get kColorBrightGreen when background color is 10", kColorBrightGreen, make_tuple(10U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorBrightCyan when background color is 11", kColorBrightCyan, make_tuple(11U)), "should get kColorBrightCyan when background color is 11", kColorBrightYellow, make_tuple(11U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorBrightRed when background color is 12", kColorBrightRed, make_tuple(12U)), "should get kColorBrightRed when background color is 12", kColorBrightBlue, make_tuple(12U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorBrightMagenta when background color is 13", kColorBrightMagenta, make_tuple(13U)), "should get kColorBrightMagenta when background color is 13", kColorBrightMagenta, make_tuple(13U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorBrightOrange when background color is 14", kColorBrightOrange, make_tuple(14U)), "should get kColorBrightYellow when background color is 14", kColorBrightCyan, make_tuple(14U)),
make_test<uint32_t, uint32_t>(
"should get kColorBrightYellow when background color is 14", kColorBrightYellow, make_tuple(14U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorBrightWhite when background color is 15", kColorBrightWhite, make_tuple(15U)), "should get kColorBrightWhite when background color is 15", kColorBrightWhite, make_tuple(15U)),
}))); })));
@@ -108,7 +118,7 @@ TestResults test_GetBackgroundColor() {
TestResults test_GetForegroundColor() { TestResults test_GetForegroundColor() {
auto fnToTest = [](uint8_t foreground_color) -> uint8_t { auto fnToTest = [](uint8_t foreground_color) -> uint8_t {
SBF::g_foregroundColor = foreground_color; SBF::g_foreground_color = foreground_color;
return GetForegroundColor(); return GetForegroundColor();
}; };
return execute_suite<uint32_t, uint32_t>(make_test_suite( return execute_suite<uint32_t, uint32_t>(make_test_suite(
@@ -118,47 +128,44 @@ TestResults test_GetForegroundColor() {
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorDarkBlack when foreground color is 0", kColorDarkBlack, make_tuple(0U)), "should get kColorDarkBlack when foreground color is 0", kColorDarkBlack, make_tuple(0U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorDarkBlue when foreground color is 1", kColorDarkBlue, make_tuple(1U)), "should get kColorDarkBlue when foreground color is 1", kColorDarkRed, make_tuple(1U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorDarkGreen when foreground color is 2", kColorDarkGreen, make_tuple(2U)), "should get kColorDarkGreen when foreground color is 2", kColorDarkGreen, make_tuple(2U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorDarkCyan when foreground color is 3", kColorDarkCyan, make_tuple(3U)), "should get kColorDarkCyan when foreground color is 3", kColorDarkYellow, make_tuple(3U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorDarkRed when foreground color is 4", kColorDarkRed, make_tuple(4U)), "should get kColorDarkRed when foreground color is 4", kColorDarkBlue, make_tuple(4U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorDarkMagenta when foreground color is 5", kColorDarkMagenta, make_tuple(5U)), "should get kColorDarkMagenta when foreground color is 5", kColorDarkMagenta, make_tuple(5U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorDarkOrange when foreground color is 6", kColorDarkOrange, make_tuple(6U)), "should get kColorDarkYellow when foreground color is 6", kColorDarkCyan, make_tuple(6U)),
make_test<uint32_t, uint32_t>(
"should get kColorDarkYellow when foreground color is 6", kColorDarkYellow, make_tuple(6U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorDarkWhite when foreground color is 7", kColorDarkWhite, make_tuple(7U)), "should get kColorDarkWhite when foreground color is 7", kColorDarkWhite, make_tuple(7U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorBrightBlack when foreground color is 8", kColorBrightBlack, make_tuple(8U)), "should get kColorBrightBlack when foreground color is 8", kColorBrightBlack, make_tuple(8U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorBrightBlue when foreground color is 9", kColorBrightBlue, make_tuple(9U)), "should get kColorBrightBlue when foreground color is 9", kColorBrightRed, make_tuple(9U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorBrightGreen when foreground color is 10", kColorBrightGreen, make_tuple(10U)), "should get kColorBrightGreen when foreground color is 10", kColorBrightGreen, make_tuple(10U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorBrightCyan when foreground color is 11", kColorBrightCyan, make_tuple(11U)), "should get kColorBrightCyan when foreground color is 11", kColorBrightYellow, make_tuple(11U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorBrightRed when foreground color is 12", kColorBrightRed, make_tuple(12U)), "should get kColorBrightRed when foreground color is 12", kColorBrightBlue, make_tuple(12U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorBrightMagenta when foreground color is 13", kColorBrightMagenta, make_tuple(13U)), "should get kColorBrightMagenta when foreground color is 13", kColorBrightMagenta, make_tuple(13U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorBrightOrange when foreground color is 14", kColorBrightOrange, make_tuple(14U)), "should get kColorBrightYellow when foreground color is 14", kColorBrightCyan, make_tuple(14U)),
make_test<uint32_t, uint32_t>(
"should get kColorBrightYellow when foreground color is 14", kColorBrightYellow, make_tuple(14U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorBrightWhite when foreground color is 15", kColorBrightWhite, make_tuple(15U)), "should get kColorBrightWhite when foreground color is 15", kColorBrightWhite, make_tuple(15U)),
}))); })));
} }
TestResults test_SetBackgroundColor() { TestResults test_SetBackgroundColor() {
// TODO: Test that SetBackgroundColor returns the previous background color.
auto fnToTest = [](uint8_t color) -> uint8_t { auto fnToTest = [](uint8_t color) -> uint8_t {
SBF::g_backgroundColor = 255; SBF::g_background_color = 255;
SetBackgroundColor(color); SetBackgroundColor(color);
return SBF::g_backgroundColor; return SBF::g_background_color;
}; };
return execute_suite<uint32_t, uint32_t>(make_test_suite( return execute_suite<uint32_t, uint32_t>(make_test_suite(
"SBF::SetBackgroundColor", "SBF::SetBackgroundColor",
@@ -167,50 +174,46 @@ TestResults test_SetBackgroundColor() {
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should set background color to kColorDarkBlack when color is 0", kColorDarkBlack, make_tuple(0U)), "should set background color to kColorDarkBlack when color is 0", kColorDarkBlack, make_tuple(0U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should set background color to kColorDarkBlue when color is 1", kColorDarkBlue, make_tuple(1U)), "should set background color to kColorDarkBlue when color is 4", kColorDarkBlue, make_tuple(4U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should set background color to kColorDarkGreen when color is 2", kColorDarkGreen, make_tuple(2U)), "should set background color to kColorDarkGreen when color is 2", kColorDarkGreen, make_tuple(2U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should set background color to kColorDarkCyan when color is 3", kColorDarkCyan, make_tuple(3U)), "should set background color to kColorDarkCyan when color is 6", kColorDarkCyan, make_tuple(6U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should set background color to kColorDarkRed when color is 4", kColorDarkRed, make_tuple(4U)), "should set background color to kColorDarkRed when color is 1", kColorDarkRed, make_tuple(1U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should set background color to kColorDarkMagenta when color is 5", kColorDarkMagenta, make_tuple(5U)), "should set background color to kColorDarkMagenta when color is 5", kColorDarkMagenta, make_tuple(5U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should set background color to kColorDarkOrange when color is 6", kColorDarkOrange, make_tuple(6U)), "should set background color to kColorDarkYellow when color is 3", kColorDarkYellow, make_tuple(3U)),
make_test<uint32_t, uint32_t>(
"should set background color to kColorDarkYellow when color is 6", kColorDarkYellow, make_tuple(6U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should set background color to kColorDarkWhite when color is 7", kColorDarkWhite, make_tuple(7U)), "should set background color to kColorDarkWhite when color is 7", kColorDarkWhite, make_tuple(7U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should set background color to kColorBrightBlack when color is 8", kColorBrightBlack, make_tuple(8U)), "should set background color to kColorBrightBlack when color is 8", kColorBrightBlack, make_tuple(8U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should set background color to kColorBrightBlue when color is 9", kColorBrightBlue, make_tuple(9U)), "should set background color to kColorBrightBlue when color is 12", kColorBrightBlue, make_tuple(12U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should set background color to kColorBrightGreen when color is 10", kColorBrightGreen, make_tuple(10U)), "should set background color to kColorBrightGreen when color is 10", kColorBrightGreen, make_tuple(10U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should set background color to kColorBrightCyan when color is 11", kColorBrightCyan, make_tuple(11U)), "should set background color to kColorBrightCyan when color is 14", kColorBrightCyan, make_tuple(14U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should set background color to kColorBrightRed when color is 12", kColorBrightRed, make_tuple(12U)), "should set background color to kColorBrightRed when color is 9", kColorBrightRed, make_tuple(9U)),
make_test<uint32_t, uint32_t>("should set background color to kColorBrightMagenta when color is 13", make_test<uint32_t, uint32_t>("should set background color to kColorBrightMagenta when color is 13",
kColorBrightMagenta, kColorBrightMagenta,
make_tuple(13U)), make_tuple(13U)),
make_test<uint32_t, uint32_t>("should set background color to kColorBrightOrange when color is 14", make_test<uint32_t, uint32_t>("should set background color to kColorBrightYellow when color is 11",
kColorBrightOrange,
make_tuple(14U)),
make_test<uint32_t, uint32_t>("should set background color to kColorBrightYellow when color is 14",
kColorBrightYellow, kColorBrightYellow,
make_tuple(14U)), make_tuple(11U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should set background color to kColorBrightWhite when color is 15", kColorBrightWhite, make_tuple(15U)), "should set background color to kColorBrightWhite when color is 15", kColorBrightWhite, make_tuple(15U)),
}))); })));
} }
TestResults test_SetForegroundColor() { TestResults test_SetForegroundColor() {
// TODO: Test that SetForegroundColor returns the previous background color.
auto fnToTest = [](uint8_t color) -> uint8_t { auto fnToTest = [](uint8_t color) -> uint8_t {
SBF::g_foregroundColor = 255; SBF::g_foreground_color = 255;
SetForegroundColor(color); SetForegroundColor(color);
return SBF::g_foregroundColor; return SBF::g_foreground_color;
}; };
return execute_suite<uint32_t, uint32_t>(make_test_suite( return execute_suite<uint32_t, uint32_t>(make_test_suite(
"SBF::SetForegroundColor", "SBF::SetForegroundColor",
@@ -219,42 +222,144 @@ TestResults test_SetForegroundColor() {
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should set foreground color to kColorDarkBlack when color is 0", kColorDarkBlack, make_tuple(0U)), "should set foreground color to kColorDarkBlack when color is 0", kColorDarkBlack, make_tuple(0U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should set foreground color to kColorDarkBlue when color is 1", kColorDarkBlue, make_tuple(1U)), "should set foreground color to kColorDarkBlue when color is 4", kColorDarkBlue, make_tuple(4U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should set foreground color to kColorDarkGreen when color is 2", kColorDarkGreen, make_tuple(2U)), "should set foreground color to kColorDarkGreen when color is 2", kColorDarkGreen, make_tuple(2U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should set foreground color to kColorDarkCyan when color is 3", kColorDarkCyan, make_tuple(3U)), "should set foreground color to kColorDarkCyan when color is 6", kColorDarkCyan, make_tuple(6U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should set foreground color to kColorDarkRed when color is 4", kColorDarkRed, make_tuple(4U)), "should set foreground color to kColorDarkRed when color is 1", kColorDarkRed, make_tuple(1U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should set foreground color to kColorDarkMagenta when color is 5", kColorDarkMagenta, make_tuple(5U)), "should set foreground color to kColorDarkMagenta when color is 5", kColorDarkMagenta, make_tuple(5U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should set foreground color to kColorDarkOrange when color is 6", kColorDarkOrange, make_tuple(6U)), "should set foreground color to kColorDarkYellow when color is 3", kColorDarkYellow, make_tuple(3U)),
make_test<uint32_t, uint32_t>(
"should set foreground color to kColorDarkYellow when color is 6", kColorDarkYellow, make_tuple(6U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should set foreground color to kColorDarkWhite when color is 7", kColorDarkWhite, make_tuple(7U)), "should set foreground color to kColorDarkWhite when color is 7", kColorDarkWhite, make_tuple(7U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should set foreground color to kColorBrightBlack when color is 8", kColorBrightBlack, make_tuple(8U)), "should set foreground color to kColorBrightBlack when color is 8", kColorBrightBlack, make_tuple(8U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should set foreground color to kColorBrightBlue when color is 9", kColorBrightBlue, make_tuple(9U)), "should set foreground color to kColorBrightBlue when color is 12", kColorBrightBlue, make_tuple(12U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should set foreground color to kColorBrightGreen when color is 10", kColorBrightGreen, make_tuple(10U)), "should set foreground color to kColorBrightGreen when color is 10", kColorBrightGreen, make_tuple(10U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should set foreground color to kColorBrightCyan when color is 11", kColorBrightCyan, make_tuple(11U)), "should set foreground color to kColorBrightCyan when color is 14", kColorBrightCyan, make_tuple(14U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should set foreground color to kColorBrightRed when color is 12", kColorBrightRed, make_tuple(12U)), "should set foreground color to kColorBrightRed when color is 9", kColorBrightRed, make_tuple(9U)),
make_test<uint32_t, uint32_t>("should set foreground color to kColorBrightMagenta when color is 13", make_test<uint32_t, uint32_t>("should set foreground color to kColorBrightMagenta when color is 13",
kColorBrightMagenta, kColorBrightMagenta,
make_tuple(13U)), make_tuple(13U)),
make_test<uint32_t, uint32_t>("should set foreground color to kColorBrightOrange when color is 14", make_test<uint32_t, uint32_t>("should set foreground color to kColorBrightYellow when color is 11",
kColorBrightOrange,
make_tuple(14U)),
make_test<uint32_t, uint32_t>("should set foreground color to kColorBrightYellow when color is 14",
kColorBrightYellow, kColorBrightYellow,
make_tuple(14U)), make_tuple(11U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should set foreground color to kColorBrightWhite when color is 15", kColorBrightWhite, make_tuple(15U)), "should set foreground color to kColorBrightWhite when color is 15", kColorBrightWhite, make_tuple(15U)),
}))); })));
} }
TestResults test_Reset() {
string suite_name = "SBF::Reset";
string test_name = "should write the reset code to the stream";
string expected = "\\033[m";
auto fnToTest = []() -> string {
ostringstream os;
os << Reset;
return escape_string(os.str());
};
return execute_suite(make_test_suite(
suite_name, fnToTest, vector<TestTuple<string>>({make_test<string>(test_name, expected, make_tuple())})));
}
TestResults test_ForegroundColor() {
auto fnToTest = [](uint8_t color) -> string {
SetForegroundColor(color);
ostringstream os;
os << ForegroundColor;
return escape_string(os.str());
};
return execute_suite(
make_test_suite("SBF::ForegroundColor",
fnToTest,
vector<TestTuple<string, uint8_t>>({
make_test<string, uint8_t>("should write \"\\033[38;5;15m\" kColorBrightWhite to the stream",
"\\033[38;5;15m",
make_tuple(kColorBrightWhite)),
make_test<string, uint8_t>("should write \"\\033[38;5;11m\" kColorBrightYellow to the stream",
"\\033[38;5;11m",
make_tuple(kColorBrightYellow)),
make_test<string, uint8_t>("should write \"\\033[38;5;2m\" kColorDarkGreen to the stream",
"\\033[38;5;2m",
make_tuple(kColorDarkGreen)),
make_test<string, uint8_t>("should write \"\\033[38;5;4m\" kColorDarkBlue to the stream",
"\\033[38;5;4m",
make_tuple(kColorDarkBlue)),
})));
}
TestResults test_BackgroundColor() {
auto fnToTest = [](uint8_t color) -> string {
SetBackgroundColor(color);
ostringstream os;
os << BackgroundColor;
return escape_string(os.str());
};
return execute_suite(
make_test_suite("SBF::BackgroundColor",
fnToTest,
vector<TestTuple<string, uint8_t>>({
make_test<string, uint8_t>("should write \"\\033[48;5;15m\" kColorBrightWhite to the stream",
"\\033[48;5;15m",
make_tuple(kColorBrightWhite)),
make_test<string, uint8_t>("should write \"\\033[48;5;11m\" kColorBrightYellow to the stream",
"\\033[48;5;11m",
make_tuple(kColorBrightYellow)),
make_test<string, uint8_t>("should write \"\\033[48;5;2m\" kColorDarkGreen to the stream",
"\\033[48;5;2m",
make_tuple(kColorDarkGreen)),
make_test<string, uint8_t>("should write \"\\033[48;5;4m\" kColorDarkBlue to the stream",
"\\033[48;5;4m",
make_tuple(kColorDarkBlue)),
})));
}
TestResults test_Colors() {
// TODO: Find a way to check for the presence of both colors and no extra characters without regard to their order.
auto fnToTest = [](uint8_t foreground_color, uint8_t background_color) -> string {
SetForegroundColor(foreground_color);
SetBackgroundColor(background_color);
ostringstream os;
os << SBF::Colors;
return escape_string(os.str());
};
return execute_suite(make_test_suite(
"SBF::ForegroundColor",
fnToTest,
vector<TestTuple<string, uint8_t, uint8_t>>({
make_test<string, uint8_t, uint8_t>("should write \"\\033[38;5;15m\\033[48;5;6m\" to the stream",
"\\033[38;5;15m\\033[48;5;6m",
make_tuple(kColorBrightWhite, kColorDarkCyan)),
make_test<string, uint8_t, uint8_t>("should write \"\\033[38;5;11m\\033[48;5;2m\" to the stream",
"\\033[38;5;11m\\033[48;5;2m",
make_tuple(kColorBrightYellow, kColorDarkGreen)),
make_test<string, uint8_t, uint8_t>("should write \"\\033[38;5;2m\\033[48;5;13m\" to the stream",
"\\033[38;5;2m\\033[48;5;13m",
make_tuple(kColorDarkGreen, kColorBrightMagenta)),
make_test<string, uint8_t, uint8_t>("should write \"\\033[38;5;4m\\033[48;5;1m\" to the stream",
"\\033[38;5;4m\\033[48;5;1m",
make_tuple(kColorDarkBlue, kColorDarkRed)),
})));
}
TestResults test_TrueColorForeground() {
// TODO: test_TrueColorForeground();
return TestResults().fail("// TODO: test_TrueColorForeground");
}
TestResults test_TrueColorBackground() {
// TODO: test_TrueColorBackground();
return TestResults().fail("// TODO: test_TrueColorBackground");
}
string escape_string(const string& text, const string& pattern, const string& replace) {
return regex_replace(text, regex(pattern), replace);
}
} // End namespace Test::Colors } // End namespace Test::Colors

View File

@@ -16,8 +16,6 @@ bool operator!=(const DerangementType& left, const DerangementType& right) {
} }
ostream& operator<<(ostream& os, const DerangementType& derangement) { ostream& operator<<(ostream& os, const DerangementType& derangement) {
// Derangement: {id: 1, label: \"kDerangementAmnesiaLabel\", description: \"kDerangementAmnesiaDescription\",
// textColor: kDerangementAmnesiaTextColor}
os << "Derangement: {id: " << derangement.id << ", label: \"" << derangement.label << "\", description: \"" os << "Derangement: {id: " << derangement.id << ", label: \"" << derangement.label << "\", description: \""
<< derangement.description << "\", textColor: " << (int)derangement.textColor << "}"; << derangement.description << "\", textColor: " << (int)derangement.textColor << "}";
return os; return os;

View File

@@ -33,7 +33,7 @@ const uint8_t kDerangementDelusionsOfGrandeurTextColor = kColorDarkMagenta;
const std::string kDerangementDelusionsOfGrandeurLabel = "Delusions of Grandeur"; const std::string kDerangementDelusionsOfGrandeurLabel = "Delusions of Grandeur";
const std::string kDerangementDelusionsOfGrandeurDescription = R"---(You imagine you are better than you are.)---"; const std::string kDerangementDelusionsOfGrandeurDescription = R"---(You imagine you are better than you are.)---";
const int kDerangementFantasyId = 3; const int kDerangementFantasyId = 3;
const uint8_t kDerangementFantasyTextColor = kColorDarkOrange; const uint8_t kDerangementFantasyTextColor = kColorDarkYellow;
const std::string kDerangementFantasyLabel = "Fantasy"; const std::string kDerangementFantasyLabel = "Fantasy";
const std::string kDerangementFantasyDescription = const std::string kDerangementFantasyDescription =
R"---(You enter a self-created world where you are the forgotten hero.)---"; R"---(You enter a self-created world where you are the forgotten hero.)---";

View File

@@ -148,7 +148,7 @@ TestResults test_DerangementType_operator_extract() {
make_test<string, DerangementType>("should print amnesia", make_test<string, DerangementType>("should print amnesia",
"Derangement: {id: 1, label: \"" + kDerangementAmnesiaLabel "Derangement: {id: 1, label: \"" + kDerangementAmnesiaLabel
+ "\", description: \"" + kDerangementAmnesiaDescription + "\", description: \"" + kDerangementAmnesiaDescription
+ "\", textColor: 4}", + "\", textColor: 1}",
make_tuple(kDerangementAmnesia)), make_tuple(kDerangementAmnesia)),
make_test<string, DerangementType>("should print delusions of grandeur", make_test<string, DerangementType>("should print delusions of grandeur",
"Derangement: {id: 2, label: \"" + kDerangementDelusionsOfGrandeurLabel "Derangement: {id: 2, label: \"" + kDerangementDelusionsOfGrandeurLabel
@@ -158,7 +158,7 @@ TestResults test_DerangementType_operator_extract() {
make_test<string, DerangementType>("should print fantasy", make_test<string, DerangementType>("should print fantasy",
"Derangement: {id: 3, label: \"" + kDerangementFantasyLabel "Derangement: {id: 3, label: \"" + kDerangementFantasyLabel
+ "\", description: \"" + kDerangementFantasyDescription + "\", description: \"" + kDerangementFantasyDescription
+ "\", textColor: 6}", + "\", textColor: 3}",
make_tuple(kDerangementFantasy)), make_tuple(kDerangementFantasy)),
make_test<string, DerangementType>("should print manic depression", make_test<string, DerangementType>("should print manic depression",
"Derangement: {id: 4, label: \"" + kDerangementManicDepressionLabel "Derangement: {id: 4, label: \"" + kDerangementManicDepressionLabel
@@ -168,7 +168,7 @@ TestResults test_DerangementType_operator_extract() {
make_test<string, DerangementType>("should print multiple personalities", make_test<string, DerangementType>("should print multiple personalities",
"Derangement: {id: 5, label: \"" + kDerangementMultiplePersonalitiesLabel "Derangement: {id: 5, label: \"" + kDerangementMultiplePersonalitiesLabel
+ "\", description: \"" + kDerangementMultiplePersonalitiesDescription + "\", description: \"" + kDerangementMultiplePersonalitiesDescription
+ "\", textColor: 1}", + "\", textColor: 4}",
make_tuple(kDerangementMultiplePersonalities)), make_tuple(kDerangementMultiplePersonalities)),
make_test<string, DerangementType>("should print obsession", make_test<string, DerangementType>("should print obsession",
"Derangement: {id: 6, label: \"" + kDerangementObsessionLabel "Derangement: {id: 6, label: \"" + kDerangementObsessionLabel
@@ -178,12 +178,12 @@ TestResults test_DerangementType_operator_extract() {
make_test<string, DerangementType>("should print overcompensation", make_test<string, DerangementType>("should print overcompensation",
"Derangement: {id: 7, label: \"" + kDerangementOvercompensationLabel "Derangement: {id: 7, label: \"" + kDerangementOvercompensationLabel
+ "\", description: \"" + kDerangementOvercompensationDescription + "\", description: \"" + kDerangementOvercompensationDescription
+ "\", textColor: 11}", + "\", textColor: 14}",
make_tuple(kDerangementOvercompensation)), make_tuple(kDerangementOvercompensation)),
make_test<string, DerangementType>("should print paranoia", make_test<string, DerangementType>("should print paranoia",
"Derangement: {id: 8, label: \"" + kDerangementParanoiaLabel "Derangement: {id: 8, label: \"" + kDerangementParanoiaLabel
+ "\", description: \"" + kDerangementParanoiaDescription + "\", description: \"" + kDerangementParanoiaDescription
+ "\", textColor: 12}", + "\", textColor: 9}",
make_tuple(kDerangementParanoia)), make_tuple(kDerangementParanoia)),
make_test<string, DerangementType>("should print perfection", make_test<string, DerangementType>("should print perfection",
"Derangement: {id: 9, label: \"" + kDerangementPerfectionLabel "Derangement: {id: 9, label: \"" + kDerangementPerfectionLabel
@@ -193,7 +193,7 @@ TestResults test_DerangementType_operator_extract() {
make_test<string, DerangementType>("should print regression", make_test<string, DerangementType>("should print regression",
"Derangement: {id: 10, label: \"" + kDerangementRegressionLabel "Derangement: {id: 10, label: \"" + kDerangementRegressionLabel
+ "\", description: \"" + kDerangementRegressionDescription + "\", description: \"" + kDerangementRegressionDescription
+ "\", textColor: 14}", + "\", textColor: 11}",
make_tuple(kDerangementRegression)), make_tuple(kDerangementRegression)),
make_test<string, DerangementType>( make_test<string, DerangementType>(
"should print an unknown derangement", "should print an unknown derangement",

View File

@@ -1,13 +1,23 @@
#include "Menus.h" #include "Menus.h"
namespace SBF { #include <iostream>
#include <vector>
int GetRandomMenuItemId(std::vector<MenuItem> items); #include "Colors.h"
void BuildMenu(std::vector<MenuItem> items, std::vector<string> labels); #include "Random.h"
void BuildMenuWithValues(std::vector<MenuItem> items, std::vector<string> labels, std::vector<int> values); #include "Utils.h"
void BuildMenuWithColors(std::vector<MenuItem> items, std::vector<string> labels, std::vector<uint8_t> colors);
void AdjustMenuStyle(MenuStyle& style, std::vector<MenuItem> items, bool ignoreValue); namespace SBF {
void PrintMenu(std::vector<MenuItem> items, MenuStyle style); namespace {
using std::cout;
using std::endl;
using std::ostream;
using std::vector;
} // End namespace
void BuildMenuWithValues(vector<MenuItem> items, vector<string> labels, vector<int> values);
void BuildMenuWithColors(vector<MenuItem> items, vector<string> labels, vector<uint8_t> colors);
void AdjustMenuStyle(MenuStyle& style, vector<MenuItem> items, bool ignoreValue);
string GetTitle(MenuItem item, MenuStyle style); string GetTitle(MenuItem item, MenuStyle style);
string GetTitleWithoutValue(MenuItem item, MenuStyle style); string GetTitleWithoutValue(MenuItem item, MenuStyle style);
void NewMenuStyle(MenuStyle& style); void NewMenuStyle(MenuStyle& style);
@@ -15,6 +25,186 @@ void NewMenuItem(MenuItem& item, string label, int id);
void NewMenuItemWithValue(MenuItem& item, string label, int id, int value); void NewMenuItemWithValue(MenuItem& item, string label, int id, int value);
void NewMenuItemWithColor(MenuItem& item, string label, int id, uint8_t color); void NewMenuItemWithColor(MenuItem& item, string label, int id, uint8_t color);
void MenuStyle::Adjust(vector<MenuItem> menu_items, bool ignore_value) {
size_t max_id_width = 0;
size_t max_item_width = 0;
size_t max_value_width = 0;
for_each(menu_items.begin(), menu_items.end(), [&](MenuItem menu_item) {
if (menu_item.is_visible) {
max_id_width = std::max(max_id_width, itos(menu_item.id).size());
max_item_width = std::max(max_item_width, (menu_item.label + label_value_separator).size());
max_value_width = std::max(max_value_width, itos(menu_item.value).size());
}
});
if (show_random) {
max_id_width = std::max(max_id_width, itos(random_item_id).size());
max_item_width = std::max(max_item_width, random_item_name.size());
}
if (show_cancel) {
max_id_width = std::max(max_id_width, itos(cancel_item_id).size());
max_item_width = std::max(max_item_width, cancel_item_name.size());
}
id_width = max_id_width;
label_width = max_item_width;
value_width = ignore_value ? 0 : max_value_width;
}
ostream& PrintMenu(ostream& os, vector<MenuItem> items, MenuStyle style) {
MenuItem random_item = MenuItem(style.random_item_name, style.random_item_id, style.random_item_color);
MenuItem cancel_item = MenuItem(style.cancel_item_name, style.cancel_item_id, style.cancel_item_color);
size_t actual_count = 0;
for_each(items.begin(), items.end(), [&actual_count](MenuItem item) {
if (item.is_visible) {
actual_count++;
}
});
if (style.show_cancel) {
actual_count++;
}
if (style.show_random) {
actual_count++;
}
if (actual_count <= 10) {
for_each(items.begin(), items.end(), [&style, &os](MenuItem item) {
if (item.is_visible) {
string title = GetTitle(item, style);
PrintWithMaybeColor(os, title, item.color, style.use_colors) << endl;
}
});
if (style.show_cancel) {
string title = GetTitleWithoutValue(cancel_item, style);
PrintWithMaybeColor(os, title, cancel_item.color, style.use_colors) << endl;
}
if (style.show_random) {
string title = GetTitleWithoutValue(random_item, style);
PrintWithMaybeColor(os, title, random_item.color, style.use_colors) << endl;
}
} else {
MenuItem empty_item;
size_t item_width = GetTitle(empty_item, style).size();
size_t items_per_row = style.screen_width / (item_width + style.menu_item_spacer.size());
size_t column_width = style.screen_width / items_per_row;
const size_t count = items.size();
int column = 0;
for (int i = 0; i < count; i++) {
const MenuItem& item = items[i];
if (item.is_visible) {
string item_text = GetTitle(item, style);
if (column != items_per_row - 1) {
if (i != count || style.show_random || style.show_cancel) {
size_t text_length = item_text.size();
item_text = make_fit_l(
right_trim(item_text) + style.menu_item_spacer, text_length + style.menu_item_spacer.size(), ' ');
}
}
string label = make_fit_c(item_text, column_width, ' ');
PrintWithMaybeColor(os, label, item.color, style.use_colors);
column = (column + 1) % items_per_row;
if (column == 0) {
cout << endl;
}
}
}
if (style.show_cancel) {
string title = make_fit_c(GetTitleWithoutValue(cancel_item, style), column_width, ' ');
PrintWithMaybeColor(os, title, cancel_item.color, style.use_colors) << endl;
}
if (style.show_random) {
string title = make_fit_c(GetTitleWithoutValue(random_item, style), column_width, ' ');
PrintWithMaybeColor(os, title, random_item.color, style.use_colors) << endl;
}
}
return os;
}
vector<MenuItem> BuildMenu(vector<string> labels) {
vector<MenuItem> menu_items;
int id = 1;
for_each(
labels.begin(), labels.end(), [&menu_items, &id](string label) { menu_items.push_back(MenuItem(label, id++)); });
return menu_items;
}
int GetRandomMenuItemId(vector<MenuItem> items) {
int num_visible_items = 0;
size_t count = items.size();
vector<int> visible_item_ids;
for (int i = 1; i <= count; i++) {
if (items[i].is_visible && items[i].include_in_random) {
visible_item_ids.push_back(i);
num_visible_items++;
}
}
return visible_item_ids[GetRandomInt(0, num_visible_items - 1)];
}
MenuStyle::MenuStyle()
: id_width(0),
label_width(0),
value_width(0),
screen_width(80),
random_item_name("Random"),
random_item_id(0),
random_item_color(kColorDefaultForeground),
cancel_item_name("Cancel"),
cancel_item_id(-1),
cancel_item_color(kColorDefaultForeground),
id_label_separator(" = "),
label_value_separator(": "),
menu_item_spacer(", "),
show_random(true),
show_cancel(false),
use_colors(false) {}
MenuItem::MenuItem()
: label(""), id(0), value(0), color(kColorDefaultForeground), is_visible(true), include_in_random(true) {}
MenuItem::MenuItem(string label, int id)
: label(label), id(id), value(0), color(kColorDefaultForeground), is_visible(true), include_in_random(true) {}
MenuItem::MenuItem(string label, int id, int value)
: label(label), id(id), value(value), color(kColorDefaultForeground), is_visible(true), include_in_random(true) {}
MenuItem::MenuItem(string label, int id, uint8_t color)
: label(label), id(id), value(0), color(color), is_visible(true), include_in_random(true) {}
ostream& PrintWithMaybeColor(ostream& os, const string& text, uint8_t text_color, bool use_colors) {
uint8_t previous_color = GetForegroundColor();
if (use_colors) {
SetForegroundColor(text_color);
os << ForegroundColor;
}
os << text;
if (use_colors) {
SetForegroundColor(previous_color);
os << ForegroundColor;
}
return os;
}
string GetTitleWithoutValue(MenuItem item, MenuStyle style) {
string id_string = make_fit_r(itos(item.id), style.id_width, ' ');
int label_width = style.label_width + style.value_width + style.label_value_separator.size();
string label_string = make_fit_l(item.label, label_width, ' ');
return id_string + style.id_label_separator + label_string;
}
string GetTitle(MenuItem item, MenuStyle style) {
string id = itos(item.id);
string label = item.label;
// cout << "GetTitle item.id: " << item.id << ", item.label: " << item.label << ", style.id_width: " << style.id_width
// << ", style.label_width: " << style.label_width << ", style.value_width: " << style.value_width << endl;
if (style.value_width > 0) {
label += style.label_value_separator;
}
string value = itos(item.value);
string formatted_id = make_fit_r(id, style.id_width);
string formatted_label = make_fit_l(label, style.label_width);
string formatted_value = make_fit_r(value, style.value_width);
return formatted_id + style.id_label_separator + formatted_label + formatted_value;
}
} // End namespace SBF } // End namespace SBF
/* /*
@@ -114,22 +304,16 @@ Sub PrintMenu (items() As MenuItem, count As Integer, style As MenuStyle)
If column <> (itemsPerRow - 1) Then If column <> (itemsPerRow - 1) Then
If i <> count Or style.showRandom Then If i <> count Or style.showRandom Then
textLength = Len(itemText$) textLength = Len(itemText$)
itemText$ = MakeFitL$(RTrim$(itemText$) + style.menuItemSpacer, textLength + itemText$ = make_fit_l$(right_trim$(itemText$) + style.menuItemSpacer, textLength +
Len(style.menuItemSpacer), " ") End If End If Print MakeFitC$(itemText$, columnWidth, " "); End If column = (column + 1) Len(style.menuItemSpacer), ' ') End If End If Print make_fit_c$(itemText$, columnWidth, ' '); End If column = (column +
Mod itemsPerRow If column = 0 Then Print "" Next If style.showRandom Then Print 1) Mod itemsPerRow If column = 0 Then Print "" Next If style.showRandom Then Print
MakeFitC$(GetTitleWithoutValue$(randomItem, style), columnWidth, " ") End If End If End Sub make_fit_c$(GetTitleWithoutValue$(randomItem, style), columnWidth, ' ') End If End If End Sub
Function GetTitle$ (mi As MenuItem, ms As MenuStyle)
id$ = itos$(mi.id)
label$ = mi.label
If ms.valueWidth > 0 Then label$ = label$ + ms.labelValueSeparator
value$ = itos$(mi.value)
GetTitle$ = MakeFitR$(id$, ms.idWidth, " ") + ms.idLabelSeparator + MakeFitL$(label$, ms.labelWidth, " ") +
MakeFitR$(value$, ms.valueWidth, " ") End Function
Function GetTitleWithoutValue$ (mi As MenuItem, ms As MenuStyle) Function GetTitleWithoutValue$ (mi As MenuItem, ms As MenuStyle)
GetTitleWithoutValue$ = MakeFitR$(itos(mi.id), ms.idWidth, " ") + ms.idLabelSeparator + MakeFitL$(mi.label, GetTitleWithoutValue$ = MakeFitR$(itos(mi.id), ms.idWidth, ' ') + ms.idLabelSeparator + make_fit_l$(mi.label,
ms.labelWidth + ms.valueWidth + Len(ms.labelValueSeparator), " ") End Function ms.labelWidth + ms.valueWidth + Len(ms.labelValueSeparator), ' ') End Function
Sub NewMenuStyle (ms As MenuStyle) Sub NewMenuStyle (ms As MenuStyle)
ms.idWidth = 0 ms.idWidth = 0

View File

@@ -10,9 +10,11 @@
* Licensed under the MIT license see the LICENSE file for details. * Licensed under the MIT license see the LICENSE file for details.
***************************************************************************************/ ***************************************************************************************/
#include "Colors.h"
namespace SBF { namespace SBF {
struct MenuStyle; class MenuStyle;
struct MenuItem; class MenuItem;
} // namespace SBF } // namespace SBF
// End forward declarations // End forward declarations
@@ -25,40 +27,73 @@ struct MenuItem;
namespace SBF { namespace SBF {
using std::string; using std::string;
struct MenuStyle { class MenuStyleBuilder {
int idWidth; public:
int labelWidth; MenuStyleBuilder();
int valueWidth; MenuStyleBuilder& SetScreenWidth(int screen_width);
int screenWidth; MenuStyleBuilder& SetRandomItemName(const std::string& name);
string randomItemName; MenuStyleBuilder& SetRandomItemId(int id);
int randomItemId; MenuStyleBuilder& SetRandomItemColor(uint8_t color);
string idLabelSeparator; MenuStyleBuilder& SetCancelItemName(const std::string& name);
string labelValueSeparator; MenuStyleBuilder& SetCancelItemId(int id);
string menuItemSpacer; MenuStyleBuilder& SetCancelItemColor(uint8_t color);
bool showRandom; MenuStyleBuilder& SetIdLabelSeparator(const std::string& separator);
bool useColors; MenuStyleBuilder& SetLabelValueSeparator(const std::string& separator);
MenuStyleBuilder& SetMenuItemSeparator(const std::string& separator);
MenuStyleBuilder& SetShowRandom(bool show_random);
MenuStyleBuilder& SetShowCancel(bool show_cancel);
MenuStyleBuilder& SetUseColors(bool use_colors);
MenuStyle Build();
}; };
struct MenuItem { class MenuStyle {
public:
MenuStyle();
void Adjust(std::vector<MenuItem> menu_items, bool ignore_value = true);
int id_width;
int label_width;
int value_width;
int screen_width;
string random_item_name;
int random_item_id;
uint8_t random_item_color;
string cancel_item_name;
int cancel_item_id;
uint8_t cancel_item_color;
string id_label_separator;
string label_value_separator;
string menu_item_spacer;
bool show_random;
bool show_cancel;
bool use_colors;
};
class MenuItem {
public:
MenuItem();
MenuItem(std::string label, int id);
MenuItem(std::string label, int id, int value);
MenuItem(std::string label, int id, uint8_t color);
string label; string label;
int id; int id;
int value; int value;
int color; uint8_t color;
bool isVisible; bool is_visible;
bool include_in_random;
}; };
// TODO: Make a menu class to hold GetRandomMenuItemId, the various BuildMenu* methods, and possibly PrintMenu.
int GetRandomMenuItemId(std::vector<MenuItem> items); int GetRandomMenuItemId(std::vector<MenuItem> items);
void BuildMenu(std::vector<MenuItem> items, std::vector<string> labels); std::vector<MenuItem> BuildMenu(std::vector<string> labels);
void BuildMenuWithValues(std::vector<MenuItem> items, std::vector<string> labels, std::vector<int> values); void BuildMenuWithValues(std::vector<MenuItem> items, std::vector<string> labels, std::vector<int> values);
void BuildMenuWithColors(std::vector<MenuItem> items, std::vector<string> labels, std::vector<uint8_t> colors); void BuildMenuWithColors(std::vector<MenuItem> items, std::vector<string> labels, std::vector<uint8_t> colors);
void AdjustMenuStyle(MenuStyle& style, std::vector<MenuItem> items, bool ignoreValue); std::ostream& PrintMenu(std::ostream& os, std::vector<MenuItem> items, MenuStyle style);
void PrintMenu(std::vector<MenuItem> items, MenuStyle style);
string GetTitle(MenuItem item, MenuStyle style); string GetTitle(MenuItem item, MenuStyle style);
string GetTitleWithoutValue(MenuItem item, MenuStyle style); string GetTitleWithoutValue(MenuItem item, MenuStyle style);
void NewMenuStyle(MenuStyle& style); std::ostream& PrintWithMaybeColor(std::ostream& os,
void NewMenuItem(MenuItem& item, string label, int id); const std::string& text,
void NewMenuItemWithValue(MenuItem& item, string label, int id, int value); uint8_t text_color = kColorDefaultForeground,
void NewMenuItemWithColor(MenuItem& item, string label, int id, uint8_t color); bool use_colors = false);
} // End namespace SBF } // End namespace SBF

146
sbf-cpp/Menus_test.cpp Normal file
View File

@@ -0,0 +1,146 @@
#include "Menus.h"
#include <regex>
#include <sstream>
#include <string>
#include <tuple>
#include <vector>
#include "Colors.h"
#include "test.h"
using namespace SBF;
using namespace Test;
using namespace std;
namespace Test::Menus {
TestResults test_MenuItem_constructor();
TestResults test_MenuItem_constructor_string_int();
TestResults test_MenuItem_constructor_string_int_int();
TestResults test_MenuItem_constructor_string_int_uint8_t();
TestResults test_MenuStyle_constructor();
TestResults test_MenuStyle_Adjust();
TestResults test_GetRandomMenuItemId();
TestResults test_BuildMenu();
TestResults test_BuildMenuWithValues();
TestResults test_BuildMenuWithColors();
TestResults test_PrintMenu();
TestResults test_GetTitle();
TestResults test_GetTitleWithoutValue();
TestResults test_PrintWithMaybeColor();
string escape_string(const string& text, const string& pattern = "\033", const string& replace = "\\033");
} // End namespace Test::Menus
using namespace Test::Menus;
TestResults main_test_Menus(int argc, char* argv[]) {
TestResults results;
results += test_MenuItem_constructor();
results += test_MenuItem_constructor_string_int();
results += test_MenuItem_constructor_string_int_int();
results += test_MenuItem_constructor_string_int_uint8_t();
results += test_MenuStyle_constructor();
results += test_MenuStyle_Adjust();
results += test_GetRandomMenuItemId();
results += test_BuildMenu();
results += test_BuildMenuWithValues();
results += test_BuildMenuWithColors();
results += test_PrintMenu();
results += test_GetTitle();
results += test_GetTitleWithoutValue();
results += test_PrintWithMaybeColor();
return results;
}
namespace Test::Menus {
TestResults test_MenuItem_constructor() {
return TestResults().skip("// TODO: test_MenuItem_constructor");
}
TestResults test_MenuItem_constructor_string_int() {
return TestResults().skip("// TODO: test_MenuItem_constructor_string_int");
}
TestResults test_MenuItem_constructor_string_int_int() {
return TestResults().skip("// TODO: test_MenuItem_constructor_string_int_int");
}
TestResults test_MenuItem_constructor_string_int_uint8_t() {
return TestResults().skip("// TODO: test_MenuItem_constructor_string_int_uint8_t");
}
TestResults test_MenuStyle_constructor() {
return TestResults().skip("// TODO: test_MenuStyle_constructor");
}
TestResults test_MenuStyle_Adjust() {
return TestResults().skip("// TODO: test_Menu_Style_Adjust");
}
TestResults test_GetRandomMenuItemId() {
return TestResults().skip("// TODO: test_GetRandomMenuItemId");
}
TestResults test_BuildMenu() {
return TestResults().skip("// TODO: test_BuildMenu");
}
TestResults test_BuildMenuWithValues() {
return TestResults().skip("// TODO: test_BuildMenuWithValues");
}
TestResults test_BuildMenuWithColors() {
return TestResults().skip("// TODO: test_BuildMenuWithColors");
}
TestResults test_PrintMenu() {
return TestResults().skip("// TODO: test_PrintMenu");
}
TestResults test_GetTitle() {
return TestResults().skip("// TODO: test_GetTitle");
}
TestResults test_GetTitleWithoutValue() {
return TestResults().skip("// TODO: test_GetTitleWithoutValue");
}
TestResults test_PrintWithMaybeColor() {
auto fnToTest = [](const string& text, uint8_t text_color, bool use_colors) -> string {
SetForegroundColor(kColorDefaultForeground);
SetBackgroundColor(kColorDefaultBackground);
ostringstream error_message;
ostringstream os;
PrintWithMaybeColor(os, text, text_color, use_colors);
if (GetForegroundColor() != kColorDefaultForeground) {
error_message << " Foreground color was changed to " << GetForegroundColor();
}
if (GetBackgroundColor() != kColorDefaultBackground) {
error_message << " Background color was changed to " << GetBackgroundColor();
}
if (error_message.str().size() > 0) {
return error_message.str();
}
return escape_string(os.str());
};
return execute_suite(
make_test_suite("SBF::PrintWithMaybeColor",
fnToTest,
vector<TestTuple<string, string, uint8_t, bool>>({
make_test<string, string, uint8_t, bool>(
"should write \"Hello, world!\" in dark yellow and reset the color afterward",
"\\033[38;5;3mHello, world!\\033[38;5;15m",
make_tuple(string("Hello, world!"), kColorDarkYellow, true)),
make_test<string, string, uint8_t, bool>(
"should print \"much less than we should\" without changing the color",
"much less than we should",
make_tuple(string("much less than we should"), kColorDarkGreen, false)),
})));
}
string escape_string(const string& text, const string& pattern, const string& replace) {
return regex_replace(text, regex(pattern), replace);
}
} // namespace Test::Menus

14
sbf-cpp/Random.cpp Normal file
View File

@@ -0,0 +1,14 @@
#include <Random.h>
#include <random>
namespace SBF {
std::random_device g_random_device;
std::mt19937_64 g_random_number_engine(g_random_device());
std::uniform_int_distribution<int> g_random_int_generator;
int GetRandomInt(int min, int max) {
int r = g_random_int_generator(g_random_number_engine);
return r % (max - min + 1) + min;
}
} // End namespace SBF

7
sbf-cpp/Random.h Normal file
View File

@@ -0,0 +1,7 @@
#ifndef RANDOM_H__
#define RANDOM_H__
namespace SBF {
int GetRandomInt(int min, int max);
} // End namespace SBF
#endif // End RANDOM_H__

33
sbf-cpp/Random_test.cpp Normal file
View File

@@ -0,0 +1,33 @@
#include "Random.h"
#include <sstream>
#include <string>
#include <tuple>
#include <vector>
#include "test.h"
using namespace SBF;
using namespace Test;
using namespace std;
namespace Test::Random {
TestResults test_something();
} // End namespace Test::Random
using namespace Test::Random;
TestResults main_test_Random(int argc, char* argv[]) {
TestResults results;
results += test_something();
return results;
}
namespace Test::Random {
TestResults test_something() {
return TestResults().skip("SBF::Random::*");
}
} // namespace Test::Random

View File

@@ -13,9 +13,13 @@ using namespace SBF;
using namespace Test; using namespace Test;
namespace SBF { namespace SBF {
namespace {
using std::string; using std::string;
using std::to_string;
} // End namespace
string word_wrap(const string& text, const size_t max_width) { vector<string> word_wrap(const string& text, const size_t max_width) {
vector<string> lines;
string output = ""; string output = "";
string thisLine = ""; string thisLine = "";
string nextChunk = ""; string nextChunk = "";
@@ -61,13 +65,14 @@ string word_wrap(const string& text, const size_t max_width) {
} }
thisLine = make_fit_l(thisLine, max_width, L'_'); thisLine = make_fit_l(thisLine, max_width, L'_');
output += thisLine + (done ? "" : "\n"); output += thisLine + (done ? "" : "\n");
lines.push_back(thisLine);
thisLine = ""; thisLine = "";
thisLineLength = thisLine.size(); thisLineLength = thisLine.size();
thisLineStartPosition = thisLineCurrentPosition; thisLineStartPosition = thisLineCurrentPosition;
} }
} }
return output; return lines;
} }
string string_dollar(const size_t length, const char ch) { string string_dollar(const size_t length, const char ch) {
@@ -86,10 +91,45 @@ string left(const string& text, const size_t length) {
return text.substr(0, length); return text.substr(0, length);
} }
string right(const string& text, const size_t length) {
size_t text_length = text.size();
size_t starting_position = text_length - length;
if (text_length >= length) {
return text.substr(starting_position);
} else {
return text;
}
}
string make_fit_c(const string& text, const size_t length, const char pad_character) {
size_t text_length = text.size();
size_t left_pad_length = length >= text_length ? (length - text_length) / 2 : 0;
size_t right_pad_length = (length >= text_length + left_pad_length) ? (length - text_length - left_pad_length) : 0;
string left_pad = string_dollar(left_pad_length, pad_character != '\0' ? pad_character : ' ');
string right_pad = string_dollar(right_pad_length, pad_character != '\0' ? pad_character : ' ');
size_t total_chop = (text_length >= length) ? text_length - length : 0;
size_t left_chop = total_chop / 2; // + 1
string ret = left_pad + (text == "" ? "" : text.substr(left_chop, length)) + right_pad;
return ret;
}
std::string make_fit_b(const std::string& prefix,
const std::string& suffix,
const size_t length,
const char pad_character) {
return make_fit_l(make_fit_l(prefix, length - suffix.size(), pad_character != '\0' ? pad_character : ' ') + suffix,
length,
pad_character != '\0' ? pad_character : ' ');
}
string make_fit_l(const string& text, const size_t length, const char pad_character) { string make_fit_l(const string& text, const size_t length, const char pad_character) {
return left(text + string_dollar(length, pad_character != '\0' ? pad_character : ' '), length); return left(text + string_dollar(length, pad_character != '\0' ? pad_character : ' '), length);
} }
string make_fit_r(const string& text, const size_t length, const char pad_character) {
return right(string_dollar(length, pad_character != '\0' ? pad_character : ' ') + text, length);
}
string get_substring(const string& text, const size_t start, const size_t length) { string get_substring(const string& text, const size_t start, const size_t length) {
return text.substr(std::min<size_t>(start, text.length()), std::max<size_t>(length, 0)); return text.substr(std::min<size_t>(start, text.length()), std::max<size_t>(length, 0));
} }
@@ -97,4 +137,45 @@ string get_substring(const string& text, const size_t start, const size_t length
size_t get_index_of(const string& text, const string& search, const size_t start) { size_t get_index_of(const string& text, const string& search, const size_t start) {
return text.find(search, start); return text.find(search, start);
} }
bool is_whitespace(char ch) {
return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == '\f' || ch == '\v';
}
string left_trim(const string& text) {
if (text == "") {
return "";
}
size_t index = 0;
size_t length = text.size();
while (index < length) {
if (is_whitespace(text.at(index))) {
index++;
} else {
return text.substr(index);
}
}
return "";
}
string right_trim(const string& text) {
if (text == "") {
return "";
}
size_t last_index = text.size() - 1;
size_t index = last_index;
while (index != string::npos) {
if (is_whitespace(text.at(index))) {
index--;
} else {
return text.substr(0, index + 1);
}
}
return "";
}
std::string itos(int i) {
return to_string(i);
}
} // End namespace SBF } // End namespace SBF

View File

@@ -9,51 +9,95 @@
* Licensed under the MIT license see the LICENSE file for details. * Licensed under the MIT license see the LICENSE file for details.
***************************************************************************************/ ***************************************************************************************/
#include <string> #include <string>
#include <vector>
/** \addtogroup Utils /** \addtogroup Utils
* @{ * @{
*/ */
namespace SBF { namespace SBF {
using std::string;
/// @brief Gets the first index of search in text starting at start. /// @brief Gets the first index of search in text starting at start.
/// @param text The text to search. /// @param text The text to search.
/// @param search The text to search for. /// @param search The text to search for.
/// @param start The position to start searching at. /// @param start The position to start searching at.
/// @return The position of the string if found and std::npos if not found. /// @return The position of the string if found and std::npos if not found.
size_t get_index_of(const string& text, const string& search, const size_t start); size_t get_index_of(const std::string& text, const std::string& search, const size_t start);
/// @brief Collapses white space and attempts to word wrap text to a max of max_width columns. /// @brief Collapses white space and attempts to word wrap text to a max of max_width columns.
/// @param text The text to wrap. /// @param text The text to wrap.
/// @param max_width The number of columns to wrap to. /// @param max_width The number of columns to wrap to.
/// @return The wrapped text. /// @return The wrapped text.
string word_wrap(const string& text, const size_t max_width); std::vector<std::string> word_wrap(const std::string& text, const size_t max_width);
/// @brief Gets a substring of another string. /// @brief Gets a substring of another string.
/// @param text The text to split. /// @param text The text to split.
/// @param start The starting position. /// @param start The starting position.
/// @param length The length of the substring. /// @param length The length of the substring.
/// @return The sub string of text. /// @return The sub string of text.
string get_substring(const string& text, const size_t start, const size_t length); std::string get_substring(const std::string& text, const size_t start, const size_t length);
/// @brief Pads or truncates text to length using pad_character. /// @brief Pads on the right or truncates text to length using pad_character.
/// @param text The text to operate on. /// @param text The text to operate on.
/// @param length The desired length to make text. /// @param length The desired length to make text.
/// @param pad_character The character to pad with. /// @param pad_character The character to pad with.
/// @return The modified string. /// @return The modified string.
string make_fit_l(const string& text, const size_t length, const char pad_character); std::string make_fit_l(const std::string& text, const size_t length, const char pad_character = ' ');
/// @brief Pads on both sides or truncates text to length using pad_character.
/// @param text The text to operate on.
/// @param length The desired length to make text.
/// @param pad_character The character to pad with.
/// @return The modified string.
std::string make_fit_c(const std::string& text, const size_t length, const char pad_character = ' ');
/// @brief Pads on the left or truncates text to length using pad_character.
/// @param text The text to operate on.
/// @param length The desired length to make text.
/// @param pad_character The character to pad with.
/// @return The modified string.
std::string make_fit_r(const std::string& text, const size_t length, const char pad_character = ' ');
/// @brief Pads or truncates the space between two strings.
/// @param prefix The text to put on the left.
/// @param suffix The text to put on the right.
/// @param length The desired length to make the result.
/// @param pad_character The character to pad with.
/// @return The modified string.
std::string make_fit_b(const std::string& prefix,
const std::string& suffix,
const size_t length,
const char pad_character = ' ');
/// @brief Gets the leftmost length characters of text. /// @brief Gets the leftmost length characters of text.
/// @param text The text to operate on. /// @param text The text to operate on.
/// @param length The maximum number of characters to return. /// @param length The maximum number of characters to return.
/// @return The leftmost n characters of text where n is the lesser of text.size and length. /// @return The leftmost n characters of text where n is the lesser of text.size and length.
string left(const string& text, const size_t length); std::string left(const std::string& text, const size_t length);
/// @brief Gets the rightmost length of characters of text.
/// @param text The text to operate on.
/// @param length The maximum number of characters to return.
/// @return The rightmost n characters of text where n is the lesser of text.size and length.
std::string right(const std::string& text, const size_t length);
/// @brief Removes whitespace from the left side of text.
/// @param text The text to operate on.
std::string left_trim(const std::string& text);
/// @brief Removes whitespace from the right side of text.
/// @param text The text to operate on.
std::string right_trim(const std::string& text);
/// @brief Gets a string made by repeating a character. /// @brief Gets a string made by repeating a character.
/// @param length The length of the string to return. /// @param length The length of the string to return.
/// @param ch The character to repeat. /// @param ch The character to repeat.
/// @return The repeated string. /// @return The repeated string.
string string_dollar(const size_t length, const char ch); std::string string_dollar(const size_t length, const char ch = ' ');
/// @brief Converts an int to a string.
/// @param i The int to convert.
/// @return The string representation of i.
std::string itos(int i);
} // End namespace SBF } // End namespace SBF
/** @}*/ /** @}*/

View File

@@ -14,7 +14,12 @@ namespace Test::Utils {
TestResults test_get_index_of(); TestResults test_get_index_of();
TestResults test_get_substring(); TestResults test_get_substring();
TestResults test_left(); TestResults test_left();
TestResults test_left_trim();
TestResults test_make_fit_c();
TestResults test_make_fit_l(); TestResults test_make_fit_l();
TestResults test_make_fit_r();
TestResults test_right();
TestResults test_right_trim();
TestResults test_string_dollar(); TestResults test_string_dollar();
TestResults test_word_wrap(); TestResults test_word_wrap();
} // End namespace Test::Utils } // End namespace Test::Utils
@@ -27,7 +32,12 @@ TestResults main_test_Utils(int argc, char* argv[]) {
results += test_get_index_of(); results += test_get_index_of();
results += test_get_substring(); results += test_get_substring();
results += test_left(); results += test_left();
results += test_left_trim();
results += test_make_fit_c();
results += test_make_fit_l(); results += test_make_fit_l();
results += test_make_fit_r();
results += test_right();
results += test_right_trim();
results += test_string_dollar(); results += test_string_dollar();
results += test_word_wrap(); results += test_word_wrap();
@@ -119,6 +129,45 @@ TestResults test_left() {
}))); })));
} }
TestResults test_right() {
return execute_suite<string, string, size_t>(make_test_suite(
"SBF::right",
SBF::right,
vector<TestTuple<string, string, size_t>>({
make_test<string, string, size_t>(
"should get a substring", "Basic", make_tuple(string("Microsoft QBasic"), size_t(5))),
make_test<string, string, size_t>("should get the whole string if length is equal to text.size()",
"Microsoft QBasic",
make_tuple(string("Microsoft QBasic"), size_t(16))),
make_test<string, string, size_t>("should get the whole string if length is greater than text.size()",
"Microsoft QBasic",
make_tuple(string("Microsoft QBasic"), size_t(20))),
make_test<string, string, size_t>(
"should get an empty string if length is 0", "", make_tuple(string("Microsoft QBasic"), size_t(0))),
make_test<string, string, size_t>(
"should get an empty string if text is empty", "", make_tuple(string(""), size_t(1))),
})));
}
TestResults test_make_fit_c() {
return execute_suite<string, string, int32_t, char>(make_test_suite(
"SBF::make_fit_c",
make_fit_c,
vector<TestTuple<string, string, int32_t, char>>({
make_test<string, string, int32_t, char>(
"should truncate a string that is too long", "soft ", make_tuple(string("Microsoft QBasic"), 5, 'A')),
make_test<string, string, int32_t, char>(
"should pad a string that is too short", "AAMicroAAA", make_tuple(string("Micro"), 10, 'A')),
make_test<string, string, int32_t, char>(
"should return a string that is perfectly sized", "Micro", make_tuple(string("Micro"), 5, 'A')),
make_test<string, string, int32_t, char>("should pad the string with spaces if padCh is the null character",
" Micro ",
make_tuple(string("Micro"), 10, '\0')),
make_test<string, string, int32_t, char>(
"should return a padded string even if text is empty", "ZZZZZZZZZZ", make_tuple(string(""), 10, 'Z')),
})));
}
TestResults test_make_fit_l() { TestResults test_make_fit_l() {
return execute_suite<string, string, int32_t, char>(make_test_suite( return execute_suite<string, string, int32_t, char>(make_test_suite(
"SBF::make_fit_l", "SBF::make_fit_l",
@@ -138,6 +187,87 @@ TestResults test_make_fit_l() {
}))); })));
} }
TestResults test_make_fit_r() {
return execute_suite<string, string, int32_t, char>(make_test_suite(
"SBF::make_fit_r",
make_fit_r,
vector<TestTuple<string, string, int32_t, char>>({
make_test<string, string, int32_t, char>(
"should truncate a string that is too long", "Basic", make_tuple(string("Microsoft QBasic"), 5, 'A')),
make_test<string, string, int32_t, char>(
"should pad a string that is too short", "AAAAAMicro", make_tuple(string("Micro"), 10, 'A')),
make_test<string, string, int32_t, char>(
"should return a string that is perfectly sized", "Micro", make_tuple(string("Micro"), 5, 'A')),
make_test<string, string, int32_t, char>("should pad the string with spaces if padCh is the null character",
" Micro",
make_tuple(string("Micro"), 10, '\0')),
make_test<string, string, int32_t, char>(
"should return a padded string even if text is empty", "ZZZZZZZZZZ", make_tuple(string(""), 10, 'Z')),
})));
}
TestResults test_left_trim() {
return execute_suite<string, string>(make_test_suite(
"SBF::left_trim",
left_trim,
vector<TestTuple<string, string>>({
make_test<string, string>("should trim a string with spaces",
"this is a string with spaces on either end ",
make_tuple(string(" this is a string with spaces on either end "))),
make_test<string, string>("should trim a string with tabs",
"this is a string with tabs on either end\t\t\t\t",
make_tuple(string("\t\t\t\tthis is a string with tabs on either end\t\t\t\t"))),
make_test<string, string>("should trim a string with newlines",
"this is a string with newlines on either end\n\n\n\n",
make_tuple(string("\n\n\n\nthis is a string with newlines on either end\n\n\n\n"))),
make_test<string, string>(
"should trim a string with carrige returns",
"this is a string with carriage returns on either end\r\r\r\r",
make_tuple(string("\r\r\r\rthis is a string with carriage returns on either end\r\r\r\r"))),
make_test<string, string>(
"should trim a string with mixed whitespace",
"this is a string with mixed whitespace on either end\f\v\r\n\t ",
make_tuple(string(" \t\n\r\v\fthis is a string with mixed whitespace on either end\f\v\r\n\t "))),
make_test<string, string>("should get an unmodified string if there is nothing to trim",
"this is a string that won't be trimmed",
make_tuple(string("this is a string that won't be trimmed"))),
make_test<string, string>("should get an empty string for an empty string", "", make_tuple(string(""))),
make_test<string, string>(
"should get an empty string for an all whitespace string", "", make_tuple(string(" \t\n\r\r\n\t "))),
})));
}
TestResults test_right_trim() {
return execute_suite<string, string>(make_test_suite(
"SBF::right_trim",
right_trim,
vector<TestTuple<string, string>>({
make_test<string, string>("should trim a string with spaces",
" this is a string with spaces on either end",
make_tuple(string(" this is a string with spaces on either end "))),
make_test<string, string>("should trim a string with tabs",
"\t\t\t\tthis is a string with tabs on either end",
make_tuple(string("\t\t\t\tthis is a string with tabs on either end\t\t\t\t"))),
make_test<string, string>("should trim a string with newlines",
"\n\n\n\nthis is a string with newlines on either end",
make_tuple(string("\n\n\n\nthis is a string with newlines on either end\n\n\n\n"))),
make_test<string, string>(
"should trim a string with carrige returns",
"\r\r\r\rthis is a string with carriage returns on either end",
make_tuple(string("\r\r\r\rthis is a string with carriage returns on either end\r\r\r\r"))),
make_test<string, string>(
"should trim a string with mixed whitespace",
" \t\n\r\v\fthis is a string with mixed whitespace on either end",
make_tuple(string(" \t\n\r\v\fthis is a string with mixed whitespace on either end\f\v\r\n\t "))),
make_test<string, string>("should get an unmodified string if there is nothing to trim",
"this is a string that won't be trimmed",
make_tuple(string("this is a string that won't be trimmed"))),
make_test<string, string>("should get an empty string for an empty string", "", make_tuple(string(""))),
make_test<string, string>(
"should get an empty string for an all whitespace string", "", make_tuple(string(" \t\n\r\r\n\t "))),
})));
}
TestResults test_string_dollar() { TestResults test_string_dollar() {
return execute_suite<string, size_t, char>(make_test_suite( return execute_suite<string, size_t, char>(make_test_suite(
"SBF::string_dollar", "SBF::string_dollar",
@@ -152,27 +282,29 @@ TestResults test_string_dollar() {
// string word_wrap(const string& text, int maxWidth); // string word_wrap(const string& text, int maxWidth);
TestResults test_word_wrap() { TestResults test_word_wrap() {
return execute_suite<string, string, int32_t>(make_test_suite( return TestResults().skip("SBF::word_wrap");
"SBF::word_wrap", // return execute_suite<string, string, int32_t>(make_test_suite(
word_wrap, // "SBF::word_wrap",
vector<TestTuple<string, string, int32_t>>({ // word_wrap,
make_test<string, string, int32_t>( // vector<TestTuple<string, string, int32_t>>({
"should return the string if it is shorter than max_width", "0123_", make_tuple(string("0123"), 5)), // make_test<string, string, int32_t>(
make_test<string, string, int32_t>( // "should return the string if it is shorter than max_width", "0123_", make_tuple(string("0123"), 5)),
"should return the string if its length is equal to max_width", "01234", make_tuple(string("01234"), 5)), // make_test<string, string, int32_t>(
make_test<string, string, int32_t>("should wrap a string to two lines if it has no whitespace", // "should return the string if its length is equal to max_width", "01234", make_tuple(string("01234"),
"01234\n5____", // 5)),
make_tuple(string("012345"), 5)), // make_test<string, string, int32_t>("should wrap a string to two lines if it has no whitespace",
make_test<string, string, int32_t>("should wrap a string to three lines if it has no whitespace", // "01234\n5____",
"01234\n56789\n0____", // make_tuple(string("012345"), 5)),
make_tuple(string("01234567890"), 5)), // make_test<string, string, int32_t>("should wrap a string to three lines if it has no whitespace",
make_test<string, string, int32_t>("should wrap a string with even spacing", // "01234\n56789\n0____",
"01 23\n45 67\n89 01", // make_tuple(string("01234567890"), 5)),
make_tuple(string("01 23 45 67 89 01"), 5)), // make_test<string, string, int32_t>("should wrap a string with even spacing",
make_test<string, string, int32_t>("should collapse whitespace to a single space", // "01 23\n45 67\n89 01",
"01 34\n67 90\n23 56\n89___", // make_tuple(string("01 23 45 67 89 01"), 5)),
make_tuple(string("01 34 67 90 23 56 89 "), 5)), // make_test<string, string, int32_t>("should collapse whitespace to a single space",
// TODO: Treat newlines and tabs in text as spaces. // "01 34\n67 90\n23 56\n89___",
}))); // make_tuple(string("01 34 67 90 23 56 89 "), 5)),
// // TODO: Treat newlines and tabs in text as spaces.
// })));
} }
} // End namespace Test::Utils } // End namespace Test::Utils

23
sbf-cpp/main_test.cpp Normal file
View File

@@ -0,0 +1,23 @@
#include "Menus.h"
#include <sstream>
#include <string>
#include <tuple>
#include <vector>
#include "test.h"
using namespace SBF;
using namespace Test;
using namespace std;
namespace Test::Menus {} // End namespace Test::Menus
using namespace Test::Menus;
TestResults main_test_Menus(int argc, char* argv[]) {
TestResults results;
return results;
}
namespace Test::Menus {} // namespace Test::Menus

View File

@@ -1,15 +1,466 @@
#define _XOPEN_SOURCE_EXTENDED #include "Abilities.h"
#include "sbf.h" #include "Attributes.h"
#define _XOPEN_SOURCE_EXTENDED
#include <cstdio> #include <cstdio>
#include <iostream> #include <iostream>
#include <string> #include <string>
#include "Archetypes.h"
#include "Backgrounds.h"
#include "Clans.h"
#include "Genders.h"
#include "Menus.h"
#include "Random.h"
#include "Utils.h"
#include "sbf.h"
#define KEY_ESCAPE 0033 #define KEY_ESCAPE 0033
namespace {
using namespace std; using namespace std;
using namespace SBF;
} // namespace
void CGGetAttributes(CharacterType& ch);
void CGGetBackgrounds(CharacterType& ch);
void CGGetDerangement(CharacterType& ch);
void CGGetDisciplines(CharacterType& ch);
void CGGetHeader(CharacterType& ch);
void CGGetRoad(CharacterType& ch);
void CGSpendFreebiePoints(CharacterType& ch);
void CGSpendVirtuePoints(CharacterType& ch);
void CharacterGenerator();
void CharacterGeneratorForDummies();
int ChooseStringId(vector<string> labels, MenuStyle style, string prompt);
void CombatComputer();
void DiceRoller();
int GetChoice(int min, int max);
int GetChoice();
int GetMenuChoice(vector<MenuItem> menu_items, MenuStyle style);
string GetString(string prompt);
void MainMenu();
void MaybeClearScreen();
void RandomCharacterGenerator();
void SaveCharacterSheet(CharacterType& ch);
void ShowCharacterSheet(CharacterType& ch);
void ShowSplashScreen();
void VehicleGenerator();
void WaitForKeypress();
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
setlocale(LC_ALL, ""); setlocale(LC_ALL, "");
ShowSplashScreen();
MainMenu();
return 0; return 0;
} }
int GetChoice(int min, int max) {
int choice;
do {
choice = GetChoice();
} while (choice < min || choice > max);
return choice;
}
int GetChoice() {
int choice;
string line;
bool has_error;
do {
has_error = false;
getline(cin, line);
try {
if (line.empty()) {
return 0;
}
choice = stoi(line);
} catch (...) {
has_error = true;
}
} while (has_error);
return choice;
}
void MainMenu() {
int choice = 0;
do {
MaybeClearScreen();
cout << "╔══════════════════════════════════════════════════════════════════════════════╗" << endl
<< "║ What are you going to do? ║" << endl
<< "║ 1 = Character Generator ║" << endl
<< "║ 2 = Character Generator for Dummies ║" << endl
<< "║ 3 = Combat Computer ║" << endl
<< "║ 4 = Dice Roller ║" << endl
<< "║ 5 = Random Character Generator ║" << endl
<< "║ 6 = ║" << endl
<< "║ 7 = Vehicle Generator ║" << endl
<< "║ ║" << endl
<< "║ ║" << endl
<< "║ ║" << endl
<< "║ ║" << endl
<< "║ ║" << endl
<< "║ ║" << endl
<< "║ ║" << endl
<< "║ ║" << endl
<< "║ ║" << endl
<< "║ ║" << endl
<< "║ ║" << endl
<< "║ 0 = End ║" << endl
<< "║ ║" << endl
<< "╚══════════════════════════════════════════════════════════════════════════════╝" << endl;
choice = GetChoice(0, 7);
switch (choice) {
case 1:
CharacterGenerator();
break;
case 2:
CharacterGeneratorForDummies();
break;
case 3:
CombatComputer();
break;
case 4:
DiceRoller();
break;
case 5:
RandomCharacterGenerator();
break;
case 7:
VehicleGenerator();
break;
}
} while (choice != 0);
}
/// Clears the screen if not a debug build.
inline void MaybeClearScreen() {
#if !defined(DEBUG)
cout << "\033[1;1H\033[2J";
#endif
}
void ShowSplashScreen() {
cout << "Welcome to Tom's Storyteller's Best Friend. This is a program that is meant to" << endl
<< "aid storytellers in running Vampire: the Masquerade Chronicles and Vampire: the" << endl
<< "Dark Ages Chronicles. This program could aid in running campaigns for other" << endl
<< "role-playing games especially those from White Wolf(tm). If you would like" << endl
<< "anything added please open a github issue. https://github.com/headhunter45/sbf" << endl
<< " Press any key to continue" << endl;
WaitForKeypress();
}
void WaitForKeypress() {
// TODO: Make this press any key to continue.
}
void CharacterGenerator() {
CharacterType ch;
CGGetHeader(ch);
CGGetDisciplines(ch);
CGGetAttributes(ch);
CGGetBackgrounds(ch);
CGGetRoad(ch);
CGSpendVirtuePoints(ch);
CGGetDerangement(ch);
ch.generation = kInitialGeneration - ch.GetBackgroundValue(kBackgroundGenerationId);
ch.willpower = ch.courage;
ch.roadValue = ch.conscience + ch.selfControl;
ch.bloodPool = GetRandomInt(1, 10);
CGSpendFreebiePoints(ch);
SaveCharacterSheet(ch);
ShowCharacterSheet(ch);
}
void CharacterGeneratorForDummies() {
// TODO: Fill in this function.
cout << "// TODO: CharacterGeneratorForDummies()" << endl;
}
void CombatComputer() {
// TODO: Fill in this function.
cout << "// TODO: CombatComputer()" << endl;
}
void DiceRoller() {
// TODO: Fill in this function.
cout << "// TODO: DiceRoller()" << endl;
}
void RandomCharacterGenerator() {
// TODO: Fill in this function.
cout << "// TODO: RandomCharacterGenerator()" << endl;
}
void VehicleGenerator() {
// TODO: Fill in this function.
cout << "// TODO: VehicleGenerator()" << endl;
}
void CGGetHeader(CharacterType& ch) {
MaybeClearScreen();
MenuStyle ms;
ch.name = GetString("What is the character's name?");
ch.player = GetString("Who is the player?");
ch.chronicle = GetString("What chronicle is the character going to be used for?");
ch.haven = GetString("What is the character's Haven?");
ch.concept = GetString("What is the character's concept?");
ch.age = GetString("How old is the character?");
vector<string> genders;
FillGenderLabels(genders);
ch.genderId = ChooseStringId(genders, ms, "What is the character's gender?");
vector<string> clans;
FillClanLabels(clans);
ch.clanId = ChooseStringId(clans, ms, "What clan is the character from?");
vector<string> archetypes;
FillArchetypeLabels(archetypes);
ch.natureId = ChooseStringId(archetypes, ms, "What is the character's nature?");
ch.demeanorId = ChooseStringId(archetypes, ms, "What is the character's demeanor?");
}
void CGGetDisciplines(CharacterType& ch) {
// TODO: Fill this in.
cout << "// TODO: CGGetDisciplines(CharacterType&)" << endl;
}
void CGGetAttributes(CharacterType& ch) {
// TODO: Fill this in.
cout << "// TODO: CGGetAttributes(CharacterType&)" << endl;
}
void CGGetBackgrounds(CharacterType& ch) {
// TODO: Fill this in.
cout << "// TODO: CGGetBackgrounds(CharacterType&)" << endl;
}
void CGGetRoad(CharacterType& ch) {
// TODO: Fill this in.
cout << "// TODO: CGGetRoad(CharacterType&)" << endl;
}
void CGSpendVirtuePoints(CharacterType& ch) {
// TODO: Fill this in.
cout << "// TODO: CGSpendVirtuePoints(CharacterType&)" << endl;
}
void CGGetDerangement(CharacterType& ch) {
// TODO: Fill this in.
cout << "// TODO: CGGetDerangement(CharacterType&)" << endl;
}
void CGSpendFreebiePoints(CharacterType& ch) {
// TODO: Fill this in.
cout << "// TODO: CGSpendFreebiePoints(CharacterType&)" << endl;
}
string FormatAttributeValue(const string& label, int value) {
return make_fit_c(label + make_fit_l(itos(value), 2), 12);
}
string FormatAbilityWithValue(const string& label, int value) {
return make_fit_c(make_fit_l(label + ":", 14) + itos(value), 24);
}
void SaveCharacterSheet(CharacterType& ch) {
// TODO: Fill this in.
cout << "// TODO: SaveCharacterSheet(CharacterType&)" << endl;
}
void ShowCharacterSheet(CharacterType& ch) {
const int kLeftColumnWidth = 36;
const int kRightColumnWidth = 37;
vector<string> discipline_strings;
size_t index;
for (index = 1; index <= kDisciplinesCount; index++) {
int value = ch.GetDisciplineValue(index);
if (value > 0) {
string suffix = "";
if (value > 1) {
suffix = " x" + itos(value);
}
discipline_strings.push_back(GetDisciplineLabel(index) + suffix);
}
}
while (discipline_strings.size() <= 3) {
discipline_strings.push_back(string_dollar(kLeftColumnWidth, '_'));
}
vector<string> background_strings(5);
for (index = 1; index <= kBackgroundsCount; index++) {
int value = ch.GetBackgroundValue(index);
if (value > 0) {
string suffix = "";
if (value > 1) {
suffix = " x" + itos(value);
}
background_strings.push_back(GetBackgroundLabel(index) + suffix);
}
}
while (background_strings.size() <= 5) {
background_strings.push_back(string_dollar(kLeftColumnWidth, '_'));
}
string all_derangements_line = ch.GetAllDerangementsLine();
vector<string> derangement_strings = word_wrap(all_derangements_line, kLeftColumnWidth);
while (derangement_strings.size() <= 5) {
derangement_strings.push_back(string_dollar(kLeftColumnWidth, '_'));
}
MaybeClearScreen();
cout << "╔══════════════════════════════════════╦═══════════════════════════════════════╗" << endl;
cout << "║ Name: " << make_fit_l(ch.name, 30) << " ║ Gender: " << make_fit_l(GetGenderLabel(ch.genderId), 14)
<< " Generation: " << make_fit_r(itos(ch.generation), 2) << "" << endl;
cout << "║ Clan: " << make_fit_l(GetClanLabel(ch.clanId), 30) << " ║ Age: " << make_fit_l(ch.age, 32) << "" << endl;
cout << "╠══════════════════════════════════════╣ Player: " << make_fit_l(ch.player, 29) << "" << endl;
cout << "║ Attributes ║ Chronicle: " << make_fit_l(ch.chronicle, 26) << "" << endl;
cout << "" << make_fit_c("Physical", 12) << make_fit_c("Social", 12) << make_fit_c("Mental", 12)
<< " ║ Haven: " << make_fit_l(ch.haven, 30) + "" << endl;
cout << "" << FormatAttributeValue("Str. ", ch.GetPhysicalAttributeValue(kPhysicalAttributeStrengthId))
<< FormatAttributeValue("App. ", ch.GetSocialAttributeValue(kSocialAttributeAppearanceId))
<< FormatAttributeValue("Int. ", ch.GetMentalAttributeValue(kMentalAttributeIntelligenceId))
<< " ║ Concept: " << make_fit_l(ch.concept, 28) << "" << endl;
cout << "" << FormatAttributeValue("Dex. ", ch.GetPhysicalAttributeValue(kPhysicalAttributeDexterityId))
<< FormatAttributeValue("Cha. ", ch.GetSocialAttributeValue(kSocialAttributeCharismaId))
<< FormatAttributeValue("Per. ", ch.GetMentalAttributeValue(kMentalAttributePerceptionId))
<< " ╠═══════════════════════════════════════╣" << endl;
cout << "" << FormatAttributeValue("Sta. ", ch.GetPhysicalAttributeValue(kPhysicalAttributeStaminaId))
<< FormatAttributeValue("Man. ", ch.GetSocialAttributeValue(kSocialAttributeManipulationId))
<< FormatAttributeValue("Wit. ", ch.GetMentalAttributeValue(kMentalAttributeWitsId))
<< " ║ Derangements: ║" << endl;
cout << "╠══════════════════════════════════════╣ " << make_fit_l(derangement_strings[0], kRightColumnWidth, '_')
<< "" << endl;
cout << "║ Disciplines: ║ " << make_fit_l(derangement_strings[1], kRightColumnWidth, '_')
<< "" << endl;
cout << "" << make_fit_l(discipline_strings[0], kLeftColumnWidth) << ""
<< make_fit_l(derangement_strings[2], kRightColumnWidth, '_') << "" << endl;
cout << "" << make_fit_l(discipline_strings[1], kLeftColumnWidth) << ""
<< make_fit_l(derangement_strings[3], kRightColumnWidth, '_') << "" << endl;
cout << "" << make_fit_l(discipline_strings[2], kLeftColumnWidth) << ""
<< make_fit_l(derangement_strings[4], kRightColumnWidth, '_') << "" << endl;
cout << "╠══════════════════════════════════════╬═══════════════════════════════════════╣" << endl;
cout << "" << make_fit_l(ch.roadName + ": " + itos(ch.roadValue), kLeftColumnWidth)
<< " ║ Nature: " << make_fit_l(GetArchetypeLabel(ch.natureId), 29) << "" << endl;
cout << "║ Willpower: " << make_fit_l(itos(ch.willpower), 25)
<< " ║ Demeanor: " << make_fit_l(GetArchetypeLabel(ch.demeanorId), 27) << "" << endl;
cout << "╠══════════════════════════════════════╩═══════════════════════════════════════╣" << endl;
cout << "║ ║" << endl;
cout << "║ ║" << endl;
cout << "║ ║" << endl;
cout << "║ <<PRESS ANY KEY TO CONTINUE>> ║" << endl;
cout << "╚══════════════════════════════════════════════════════════════════════════════╝" << endl;
WaitForKeypress();
cout << "╔══════════════════════════════════════════════════════════════════════════════╗" << endl;
cout << "" << make_fit_c("Abilities", 76) << "" << endl;
cout << "" << make_fit_c("Talents", 24) << make_fit_c("Skills", 24) << make_fit_c("Knowledges", 24) << ""
<< endl;
for (index = 1; index <= 10; index++) {
cout << "" << FormatAbilityWithValue(GetTalentLabel(index), ch.GetTalentValue(index))
<< FormatAbilityWithValue(GetSkillLabel(index), ch.GetSkillValue(index))
<< FormatAbilityWithValue(GetKnowledgeLabel(index), ch.GetKnowledgeValue(index)) << "" << endl;
}
cout << "╠══════════════════════════════════════╦═══════════════════════════════════════╣" << endl;
cout << "" << make_fit_l("Backgrounds:", kLeftColumnWidth) << "" << make_fit_l("Virtues:", kRightColumnWidth)
<< "" << endl;
cout << "" << make_fit_l(background_strings[0], kLeftColumnWidth) << ""
<< make_fit_b("Conscience:", itos(ch.conscience), kRightColumnWidth) << "" << endl;
cout << "" << make_fit_l(background_strings[1], kLeftColumnWidth) << ""
<< make_fit_b("Self-Control:", itos(ch.selfControl), kRightColumnWidth) << "" << endl;
cout << "" << make_fit_l(background_strings[2], kLeftColumnWidth) << ""
<< make_fit_b("Courage:", itos(ch.courage), kRightColumnWidth) << "" << endl;
cout << "" << make_fit_l(background_strings[3], kLeftColumnWidth) << "" << make_fit_l("", kRightColumnWidth)
<< "" << endl;
cout << "" << make_fit_l(background_strings[4], kLeftColumnWidth) << "" << make_fit_l("", kRightColumnWidth)
<< "" << endl;
cout << "╠══════════════════════════════════════╩═══════════════════════════════════════╣" << endl;
cout << "║ <<PRESS ANY KEY TO CONTINUE>> ║" << endl;
cout << "╚══════════════════════════════════════════════════════════════════════════════╝" << endl;
WaitForKeypress();
/*
╔══════════════════════════════════════╦═══════════════════════════════════════╗
║ Name: Ted ║ Gender: Female Generation: 13 ║
║ Clan: Ventrue ║ Age: 35 ║
╠══════════════════════════════════════╣ Player: Jeff ║
║ Attributes ║ Chronicle: Somesuch ║
║ Physical Social Mental ║ Haven: Mom's basement ║
║ Str. 1 App. 1 Int. 1 ║ Concept: Asshole ║
║ Dex. 1 Cha. 1 Per. 1 ╠═══════════════════════════════════════╣
║ Sta. 1 Man. 1 Wit. 1 ║ Derangements: ║
╠══════════════════════════════════════╣ _____________________________________ ║
║ Disciplines: ║ _____________________________________ ║
║ ____________________________________ ║ _____________________________________ ║
║ ____________________________________ ║ _____________________________________ ║
║ ____________________________________ ║ _____________________________________ ║
╠══════════════════════════════════════╬═══════════════════════════════════════╣
║ : 2 ║ Nature: Tyrant ║
║ Willpower: 1 ║ Demeanor: Traditionalist ║
╠══════════════════════════════════════╩═══════════════════════════════════════╣
║ ║
║ ║
║ ║
║ <<PRESS ANY KEY TO CONTINUE>> ║
╚══════════════════════════════════════════════════════════════════════════════╝
╔══════════════════════════════════════════════════════════════════════════════╗
║ Abilities ║
║ Talents Skills Knowledges ║
║ Acting: 0 Animal Ken: 0 Bureaucracy: 0 ║
║ Alertness: 0 Drive: 0 Computer: 0 ║
║ Athletics: 0 Etiquette: 0 Finance: 0 ║
║ Brawl: 0 Firearms: 0 Investigation:0 ║
║ Dodge: 0 Melee: 0 Law: 0 ║
║ Empathy: 0 Music: 0 Linguistics: 0 ║
║ Intimidation: 0 Repair: 0 Medicine: 0 ║
║ Leadership: 0 Security: 0 Occult: 0 ║
║ Streetwise: 0 Stealth: 0 Politics: 0 ║
║ Subterfuge: 0 Survival: 0 Science: 0 ║
╠══════════════════════════════════════╦═══════════════════════════════════════╣
║ Backgrounds: ║ Virtues: ║
║ ║ Conscience: 1 ║
║ ║ Self-Control: 1 ║
║ ║ Courage: 1 ║
║ ║ ║
║ ║ ║
╠══════════════════════════════════════╩═══════════════════════════════════════╣
║ <<PRESS ANY KEY TO CONTINUE>> ║
╚══════════════════════════════════════════════════════════════════════════════╝
// TODO: ShowCharacterSheet(CharacterType&)
*/
}
int GetRandomInt(int min, int max) {
// TODO: Fill this in.
return 0;
}
string GetString(string prompt) {
cout << prompt << endl;
string response;
getline(cin, response);
return response;
}
int ChooseStringId(vector<string> labels, MenuStyle style, string prompt) {
MaybeClearScreen();
vector<MenuItem> menu_items = BuildMenu(labels);
style.Adjust(menu_items);
cout << prompt << endl;
PrintMenu(cout, menu_items, style);
int choice = GetMenuChoice(menu_items, style);
if (choice == style.random_item_id) {
choice = GetRandomMenuItemId(menu_items);
}
return choice;
}
int GetMenuChoice(vector<MenuItem> menu_items, MenuStyle style) {
int choice;
while (true) {
choice = GetChoice();
if (style.show_random && choice == style.random_item_id) {
return choice;
}
if (style.show_cancel && choice == style.cancel_item_id) {
return choice;
}
for (MenuItem item : menu_items) {
if (item.id == choice) {
return choice;
}
}
}
}

23
sbf-cpp/sbf_test.cpp Normal file
View File

@@ -0,0 +1,23 @@
#include "sbf.h"
#include <sstream>
#include <string>
#include <tuple>
#include <vector>
#include "test.h"
using namespace SBF;
using namespace Test;
using namespace std;
namespace Test::sbf {} // End namespace Test::sbf
using namespace Test::sbf;
TestResults main_test_sbf(int argc, char* argv[]) {
TestResults results;
return results;
}
namespace Test::sbf {} // namespace Test::sbf

View File

@@ -354,7 +354,7 @@ TestResults execute_suite(std::string suite_label,
if (!is_enabled) { if (!is_enabled) {
std::cout << " 🚧Skipping Test: " << test_name << std::endl; std::cout << " 🚧Skipping Test: " << test_name << std::endl;
results.skip("🚧Skipping Test: " + qualified_test_name); results.skip(qualified_test_name);
return; return;
} }
@@ -371,16 +371,16 @@ TestResults execute_suite(std::string suite_label,
} catch (const std::exception& ex) { } catch (const std::exception& ex) {
std::ostringstream os; std::ostringstream os;
os << "Caught exception \"" << ex.what() << "\""; os << "Caught exception \"" << ex.what() << "\"";
results.error("🔥ERROR: " + qualified_test_name + " " + os.str()); results.error(qualified_test_name + " " + os.str());
std::cout << " 🔥ERROR: " << os.str() << std::endl; std::cout << " 🔥ERROR: " << os.str() << std::endl;
} catch (const std::string& message) { } catch (const std::string& message) {
std::ostringstream os; std::ostringstream os;
os << "Caught string \"" << message << "\""; os << "Caught string \"" << message << "\"";
results.error("🔥ERROR: " + qualified_test_name + " " + os.str()); results.error(qualified_test_name + " " + os.str());
std::cout << " 🔥ERROR: " << os.str() << std::endl; std::cout << " 🔥ERROR: " << os.str() << std::endl;
} catch (...) { } catch (...) {
string message = "Caught something that is neither an std::exception nor an std::string."; string message = "Caught something that is neither an std::exception nor an std::string.";
results.error("🔥ERROR: " + qualified_test_name + " " + message); results.error(qualified_test_name + " " + message);
std::cout << " 🔥ERROR: " << message << std::endl; std::cout << " 🔥ERROR: " << message << std::endl;
} }
@@ -391,7 +391,7 @@ TestResults execute_suite(std::string suite_label,
} else { } else {
std::ostringstream os; std::ostringstream os;
os << "expected: \"" << expected_output << "\", actual: \"" << actual << "\""; os << "expected: \"" << expected_output << "\", actual: \"" << actual << "\"";
results.fail("❌FAILED: " + qualified_test_name + " " + os.str()); results.fail(qualified_test_name + " " + os.str());
std::cout << " ❌FAILED: " << os.str() << std::endl; std::cout << " ❌FAILED: " << os.str() << std::endl;
} }