Configures clang-format and clangd.

Runs clang-format on all c++ files.
This commit is contained in:
2023-04-21 21:55:17 -07:00
parent 64c7632806
commit 5e57ac277d
51 changed files with 6131 additions and 6019 deletions

260
.clang-format Normal file
View File

@@ -0,0 +1,260 @@
---
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
Language: Cpp
# BasedOnStyle: Google
AccessModifierOffset: -1
AlignAfterOpenBracket: Align
AlignArrayOfStructures: None
AlignConsecutiveAssignments:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: true
AlignConsecutiveBitFields:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: false
AlignConsecutiveDeclarations:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: false
AlignConsecutiveMacros:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: false
AlignEscapedNewlines: Left
AlignOperands: AlignAfterOperator
AlignTrailingComments:
Kind: Always
OverEmptyLines: 0
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortEnumsOnASingleLine: true
AllowShortFunctionsOnASingleLine: Inline
AllowShortIfStatementsOnASingleLine: WithoutElse
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: Yes
AttributeMacros:
- __capability
BinPackArguments: false
BinPackParameters: false
BitFieldColonSpacing: Both
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterExternBlock: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakAfterAttributes: Never
BreakAfterJavaFieldAnnotations: false
BreakArrays: true
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeConceptDeclarations: Always
BreakBeforeBraces: Attach
BreakBeforeInlineASMColon: OnlyMultiline
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeColon
BreakInheritanceList: BeforeColon
BreakStringLiterals: true
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IfMacros:
- KJ_IF_MAYBE
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^<ext/.*\.h>'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^<.*\.h>'
Priority: 1
SortPriority: 0
CaseSensitive: false
- Regex: '^<.*'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '.*'
Priority: 3
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: '([-_](test|unittest))?$'
IncludeIsMainSourceRegex: ''
IndentAccessModifiers: false
IndentCaseBlocks: false
IndentCaseLabels: true
IndentExternBlock: AfterExternBlock
IndentGotoLabels: true
IndentPPDirectives: None
IndentRequiresClause: true
IndentWidth: 2
IndentWrappedFunctionNames: false
InsertBraces: false
InsertNewlineAtEOF: false
InsertTrailingCommas: None
IntegerLiteralSeparator:
Binary: 0
BinaryMinDigits: 0
Decimal: 0
DecimalMinDigits: 0
Hex: 0
HexMinDigits: 0
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
LambdaBodyIndentation: Signature
LineEnding: DeriveLF
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Never
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PackConstructorInitializers: NextLine
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakOpenParenthesis: 0
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyIndentedWhitespace: 0
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Left
PPIndentWidth: -1
QualifierAlignment: Leave
RawStringFormats:
- Language: Cpp
Delimiters:
- cc
- CC
- cpp
- Cpp
- CPP
- 'c++'
- 'C++'
CanonicalDelimiter: ''
BasedOnStyle: google
- Language: TextProto
Delimiters:
- pb
- PB
- proto
- PROTO
EnclosingFunctions:
- EqualsProto
- EquivToProto
- PARSE_PARTIAL_TEXT_PROTO
- PARSE_TEST_PROTO
- PARSE_TEXT_PROTO
- ParseTextOrDie
- ParseTextProtoOrDie
- ParseTestProto
- ParsePartialTestProto
CanonicalDelimiter: pb
BasedOnStyle: google
ReferenceAlignment: Pointer
ReflowComments: true
RemoveBracesLLVM: false
RemoveSemicolon: false
RequiresClausePosition: OwnLine
RequiresExpressionIndentation: OuterScope
SeparateDefinitionBlocks: Always
ShortNamespaceLines: 1
SortIncludes: CaseSensitive
SortJavaStaticImport: Before
SortUsingDeclarations: LexicographicNumeric
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceAroundPointerQualifiers: Default
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterForeachMacros: true
AfterFunctionDefinitionName: false
AfterFunctionDeclarationName: false
AfterIfMacros: true
AfterOverloadedOperator: false
AfterRequiresInClause: false
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: Never
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Auto
StatementAttributeLikeMacros:
- Q_EMIT
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 8
UseTab: Never
WhitespaceSensitiveMacros:
- BOOST_PP_STRINGIZE
- CF_SWIFT_NAME
- NS_SWIFT_NAME
- PP_STRINGIZE
- STRINGIZE
...

1
.gitignore vendored
View File

@@ -7,3 +7,4 @@
/dos/sbf/sbf_start.command /dos/sbf/sbf_start.command
/build /build
*.o *.o
.cache

View File

@@ -63,7 +63,7 @@ MANDATORY_TARGETS = Makefile
.Phony: all clean app test run_all_tests run_incremental_tests targets docs read-docs .Phony: all clean app test run_all_tests run_incremental_tests targets docs read-docs
all: $(patsubst %, $(BUILD_DIR)/%, $(APPS)) app all: compile_commands.json $(patsubst %, $(BUILD_DIR)/%, $(APPS)) app
clean: clean:
rm -rf "$(BUILD_DIR)" rm -rf "$(BUILD_DIR)"
@@ -210,3 +210,6 @@ $(TEST_HARNESS_OBJ): $(TEST_HARNESS_CPP) $(SRC_DIR)/*.h $(TEST_CPP) $(MANDATORY_
$(TEST_HARNESS_APP): $(TEST_HARNESS_OBJ) $(APP_OBJECTS) $(TEST_OBJ) $(BUILD_DIR)/test.o $(MANDATORY_TARGETS) $(TEST_HARNESS_APP): $(TEST_HARNESS_OBJ) $(APP_OBJECTS) $(TEST_OBJ) $(BUILD_DIR)/test.o $(MANDATORY_TARGETS)
$(LD) $(LDFLAGS) -o $@ $< $(APP_OBJECTS) $(TEST_OBJ) $(BUILD_DIR)/test.o $(LD) $(LDFLAGS) -o $@ $< $(APP_OBJECTS) $(TEST_OBJ) $(BUILD_DIR)/test.o
endif endif
compile_commands.json: $(MANDATORY_TARGETS)
make clean; bear -- make

727
compile_commands.json Normal file
View File

@@ -0,0 +1,727 @@
[
{
"arguments": [
"/usr/bin/clang++",
"-std=c++17",
"-Wall",
"-fno-objc-arc",
"-finput-charset=UTF-8",
"-Isbf-cpp",
"-I/opt/homebrew/opt/ncurses/include",
"-O2",
"-arch",
"arm64",
"-arch",
"x86_64",
"-fdiagnostics-show-template-tree",
"-fno-elide-type",
"-c",
"-o",
"build/sbf.o",
"sbf-cpp/sbf.cpp"
],
"directory": "/Users/tom/Projects/sbf2000",
"file": "/Users/tom/Projects/sbf2000/sbf-cpp/sbf.cpp",
"output": "/Users/tom/Projects/sbf2000/build/sbf.o"
},
{
"arguments": [
"/usr/bin/clang++",
"-std=c++17",
"-Wall",
"-fno-objc-arc",
"-finput-charset=UTF-8",
"-Isbf-cpp",
"-I/opt/homebrew/opt/ncurses/include",
"-O2",
"-arch",
"arm64",
"-arch",
"x86_64",
"-fdiagnostics-show-template-tree",
"-fno-elide-type",
"-c",
"-o",
"build/Abilities.o",
"sbf-cpp/Abilities.cpp"
],
"directory": "/Users/tom/Projects/sbf2000",
"file": "/Users/tom/Projects/sbf2000/sbf-cpp/Abilities.cpp",
"output": "/Users/tom/Projects/sbf2000/build/Abilities.o"
},
{
"arguments": [
"/usr/bin/clang++",
"-std=c++17",
"-Wall",
"-fno-objc-arc",
"-finput-charset=UTF-8",
"-Isbf-cpp",
"-I/opt/homebrew/opt/ncurses/include",
"-O2",
"-arch",
"arm64",
"-arch",
"x86_64",
"-fdiagnostics-show-template-tree",
"-fno-elide-type",
"-c",
"-o",
"build/Archetypes.o",
"sbf-cpp/Archetypes.cpp"
],
"directory": "/Users/tom/Projects/sbf2000",
"file": "/Users/tom/Projects/sbf2000/sbf-cpp/Archetypes.cpp",
"output": "/Users/tom/Projects/sbf2000/build/Archetypes.o"
},
{
"arguments": [
"/usr/bin/clang++",
"-std=c++17",
"-Wall",
"-fno-objc-arc",
"-finput-charset=UTF-8",
"-Isbf-cpp",
"-I/opt/homebrew/opt/ncurses/include",
"-O2",
"-arch",
"arm64",
"-arch",
"x86_64",
"-fdiagnostics-show-template-tree",
"-fno-elide-type",
"-c",
"-o",
"build/Attributes.o",
"sbf-cpp/Attributes.cpp"
],
"directory": "/Users/tom/Projects/sbf2000",
"file": "/Users/tom/Projects/sbf2000/sbf-cpp/Attributes.cpp",
"output": "/Users/tom/Projects/sbf2000/build/Attributes.o"
},
{
"arguments": [
"/usr/bin/clang++",
"-std=c++17",
"-Wall",
"-fno-objc-arc",
"-finput-charset=UTF-8",
"-Isbf-cpp",
"-I/opt/homebrew/opt/ncurses/include",
"-O2",
"-arch",
"arm64",
"-arch",
"x86_64",
"-fdiagnostics-show-template-tree",
"-fno-elide-type",
"-c",
"-o",
"build/Backgrounds.o",
"sbf-cpp/Backgrounds.cpp"
],
"directory": "/Users/tom/Projects/sbf2000",
"file": "/Users/tom/Projects/sbf2000/sbf-cpp/Backgrounds.cpp",
"output": "/Users/tom/Projects/sbf2000/build/Backgrounds.o"
},
{
"arguments": [
"/usr/bin/clang++",
"-std=c++17",
"-Wall",
"-fno-objc-arc",
"-finput-charset=UTF-8",
"-Isbf-cpp",
"-I/opt/homebrew/opt/ncurses/include",
"-O2",
"-arch",
"arm64",
"-arch",
"x86_64",
"-fdiagnostics-show-template-tree",
"-fno-elide-type",
"-c",
"-o",
"build/Character.o",
"sbf-cpp/Character.cpp"
],
"directory": "/Users/tom/Projects/sbf2000",
"file": "/Users/tom/Projects/sbf2000/sbf-cpp/Character.cpp",
"output": "/Users/tom/Projects/sbf2000/build/Character.o"
},
{
"arguments": [
"/usr/bin/clang++",
"-std=c++17",
"-Wall",
"-fno-objc-arc",
"-finput-charset=UTF-8",
"-Isbf-cpp",
"-I/opt/homebrew/opt/ncurses/include",
"-O2",
"-arch",
"arm64",
"-arch",
"x86_64",
"-fdiagnostics-show-template-tree",
"-fno-elide-type",
"-c",
"-o",
"build/Clans.o",
"sbf-cpp/Clans.cpp"
],
"directory": "/Users/tom/Projects/sbf2000",
"file": "/Users/tom/Projects/sbf2000/sbf-cpp/Clans.cpp",
"output": "/Users/tom/Projects/sbf2000/build/Clans.o"
},
{
"arguments": [
"/usr/bin/clang++",
"-std=c++17",
"-Wall",
"-fno-objc-arc",
"-finput-charset=UTF-8",
"-Isbf-cpp",
"-I/opt/homebrew/opt/ncurses/include",
"-O2",
"-arch",
"arm64",
"-arch",
"x86_64",
"-fdiagnostics-show-template-tree",
"-fno-elide-type",
"-c",
"-o",
"build/Colors.o",
"sbf-cpp/Colors.cpp"
],
"directory": "/Users/tom/Projects/sbf2000",
"file": "/Users/tom/Projects/sbf2000/sbf-cpp/Colors.cpp",
"output": "/Users/tom/Projects/sbf2000/build/Colors.o"
},
{
"arguments": [
"/usr/bin/clang++",
"-std=c++17",
"-Wall",
"-fno-objc-arc",
"-finput-charset=UTF-8",
"-Isbf-cpp",
"-I/opt/homebrew/opt/ncurses/include",
"-O2",
"-arch",
"arm64",
"-arch",
"x86_64",
"-fdiagnostics-show-template-tree",
"-fno-elide-type",
"-c",
"-o",
"build/Derangements.o",
"sbf-cpp/Derangements.cpp"
],
"directory": "/Users/tom/Projects/sbf2000",
"file": "/Users/tom/Projects/sbf2000/sbf-cpp/Derangements.cpp",
"output": "/Users/tom/Projects/sbf2000/build/Derangements.o"
},
{
"arguments": [
"/usr/bin/clang++",
"-std=c++17",
"-Wall",
"-fno-objc-arc",
"-finput-charset=UTF-8",
"-Isbf-cpp",
"-I/opt/homebrew/opt/ncurses/include",
"-O2",
"-arch",
"arm64",
"-arch",
"x86_64",
"-fdiagnostics-show-template-tree",
"-fno-elide-type",
"-c",
"-o",
"build/Disciplines.o",
"sbf-cpp/Disciplines.cpp"
],
"directory": "/Users/tom/Projects/sbf2000",
"file": "/Users/tom/Projects/sbf2000/sbf-cpp/Disciplines.cpp",
"output": "/Users/tom/Projects/sbf2000/build/Disciplines.o"
},
{
"arguments": [
"/usr/bin/clang++",
"-std=c++17",
"-Wall",
"-fno-objc-arc",
"-finput-charset=UTF-8",
"-Isbf-cpp",
"-I/opt/homebrew/opt/ncurses/include",
"-O2",
"-arch",
"arm64",
"-arch",
"x86_64",
"-fdiagnostics-show-template-tree",
"-fno-elide-type",
"-c",
"-o",
"build/Genders.o",
"sbf-cpp/Genders.cpp"
],
"directory": "/Users/tom/Projects/sbf2000",
"file": "/Users/tom/Projects/sbf2000/sbf-cpp/Genders.cpp",
"output": "/Users/tom/Projects/sbf2000/build/Genders.o"
},
{
"arguments": [
"/usr/bin/clang++",
"-std=c++17",
"-Wall",
"-fno-objc-arc",
"-finput-charset=UTF-8",
"-Isbf-cpp",
"-I/opt/homebrew/opt/ncurses/include",
"-O2",
"-arch",
"arm64",
"-arch",
"x86_64",
"-fdiagnostics-show-template-tree",
"-fno-elide-type",
"-c",
"-o",
"build/Ranks.o",
"sbf-cpp/Ranks.cpp"
],
"directory": "/Users/tom/Projects/sbf2000",
"file": "/Users/tom/Projects/sbf2000/sbf-cpp/Ranks.cpp",
"output": "/Users/tom/Projects/sbf2000/build/Ranks.o"
},
{
"arguments": [
"/usr/bin/clang++",
"-std=c++17",
"-Wall",
"-fno-objc-arc",
"-finput-charset=UTF-8",
"-Isbf-cpp",
"-I/opt/homebrew/opt/ncurses/include",
"-O2",
"-arch",
"arm64",
"-arch",
"x86_64",
"-fdiagnostics-show-template-tree",
"-fno-elide-type",
"-c",
"-o",
"build/Utils.o",
"sbf-cpp/Utils.cpp"
],
"directory": "/Users/tom/Projects/sbf2000",
"file": "/Users/tom/Projects/sbf2000/sbf-cpp/Utils.cpp",
"output": "/Users/tom/Projects/sbf2000/build/Utils.o"
},
{
"arguments": [
"/usr/bin/clang++",
"-std=c++17",
"-Wall",
"-fno-objc-arc",
"-finput-charset=UTF-8",
"-Isbf-cpp",
"-I/opt/homebrew/opt/ncurses/include",
"-O2",
"-arch",
"arm64",
"-arch",
"x86_64",
"-fdiagnostics-show-template-tree",
"-fno-elide-type",
"-c",
"-o",
"build/Virtues.o",
"sbf-cpp/Virtues.cpp"
],
"directory": "/Users/tom/Projects/sbf2000",
"file": "/Users/tom/Projects/sbf2000/sbf-cpp/Virtues.cpp",
"output": "/Users/tom/Projects/sbf2000/build/Virtues.o"
},
{
"arguments": [
"/usr/bin/clang++",
"-std=c++17",
"-Wall",
"-fno-objc-arc",
"-finput-charset=UTF-8",
"-Isbf-cpp",
"-I/opt/homebrew/opt/ncurses/include",
"-O2",
"-arch",
"arm64",
"-arch",
"x86_64",
"-fdiagnostics-show-template-tree",
"-fno-elide-type",
"-c",
"-o",
"build/Abilities_test.o",
"sbf-cpp/Abilities_test.cpp"
],
"directory": "/Users/tom/Projects/sbf2000",
"file": "/Users/tom/Projects/sbf2000/sbf-cpp/Abilities_test.cpp",
"output": "/Users/tom/Projects/sbf2000/build/Abilities_test.o"
},
{
"arguments": [
"/usr/bin/clang++",
"-std=c++17",
"-Wall",
"-fno-objc-arc",
"-finput-charset=UTF-8",
"-Isbf-cpp",
"-I/opt/homebrew/opt/ncurses/include",
"-O2",
"-arch",
"arm64",
"-arch",
"x86_64",
"-fdiagnostics-show-template-tree",
"-fno-elide-type",
"-c",
"-o",
"build/Archetypes_test.o",
"sbf-cpp/Archetypes_test.cpp"
],
"directory": "/Users/tom/Projects/sbf2000",
"file": "/Users/tom/Projects/sbf2000/sbf-cpp/Archetypes_test.cpp",
"output": "/Users/tom/Projects/sbf2000/build/Archetypes_test.o"
},
{
"arguments": [
"/usr/bin/clang++",
"-std=c++17",
"-Wall",
"-fno-objc-arc",
"-finput-charset=UTF-8",
"-Isbf-cpp",
"-I/opt/homebrew/opt/ncurses/include",
"-O2",
"-arch",
"arm64",
"-arch",
"x86_64",
"-fdiagnostics-show-template-tree",
"-fno-elide-type",
"-c",
"-o",
"build/Attributes_test.o",
"sbf-cpp/Attributes_test.cpp"
],
"directory": "/Users/tom/Projects/sbf2000",
"file": "/Users/tom/Projects/sbf2000/sbf-cpp/Attributes_test.cpp",
"output": "/Users/tom/Projects/sbf2000/build/Attributes_test.o"
},
{
"arguments": [
"/usr/bin/clang++",
"-std=c++17",
"-Wall",
"-fno-objc-arc",
"-finput-charset=UTF-8",
"-Isbf-cpp",
"-I/opt/homebrew/opt/ncurses/include",
"-O2",
"-arch",
"arm64",
"-arch",
"x86_64",
"-fdiagnostics-show-template-tree",
"-fno-elide-type",
"-c",
"-o",
"build/Backgrounds_test.o",
"sbf-cpp/Backgrounds_test.cpp"
],
"directory": "/Users/tom/Projects/sbf2000",
"file": "/Users/tom/Projects/sbf2000/sbf-cpp/Backgrounds_test.cpp",
"output": "/Users/tom/Projects/sbf2000/build/Backgrounds_test.o"
},
{
"arguments": [
"/usr/bin/clang++",
"-std=c++17",
"-Wall",
"-fno-objc-arc",
"-finput-charset=UTF-8",
"-Isbf-cpp",
"-I/opt/homebrew/opt/ncurses/include",
"-O2",
"-arch",
"arm64",
"-arch",
"x86_64",
"-fdiagnostics-show-template-tree",
"-fno-elide-type",
"-c",
"-o",
"build/Character_test.o",
"sbf-cpp/Character_test.cpp"
],
"directory": "/Users/tom/Projects/sbf2000",
"file": "/Users/tom/Projects/sbf2000/sbf-cpp/Character_test.cpp",
"output": "/Users/tom/Projects/sbf2000/build/Character_test.o"
},
{
"arguments": [
"/usr/bin/clang++",
"-std=c++17",
"-Wall",
"-fno-objc-arc",
"-finput-charset=UTF-8",
"-Isbf-cpp",
"-I/opt/homebrew/opt/ncurses/include",
"-O2",
"-arch",
"arm64",
"-arch",
"x86_64",
"-fdiagnostics-show-template-tree",
"-fno-elide-type",
"-c",
"-o",
"build/Clans_test.o",
"sbf-cpp/Clans_test.cpp"
],
"directory": "/Users/tom/Projects/sbf2000",
"file": "/Users/tom/Projects/sbf2000/sbf-cpp/Clans_test.cpp",
"output": "/Users/tom/Projects/sbf2000/build/Clans_test.o"
},
{
"arguments": [
"/usr/bin/clang++",
"-std=c++17",
"-Wall",
"-fno-objc-arc",
"-finput-charset=UTF-8",
"-Isbf-cpp",
"-I/opt/homebrew/opt/ncurses/include",
"-O2",
"-arch",
"arm64",
"-arch",
"x86_64",
"-fdiagnostics-show-template-tree",
"-fno-elide-type",
"-c",
"-o",
"build/Colors_test.o",
"sbf-cpp/Colors_test.cpp"
],
"directory": "/Users/tom/Projects/sbf2000",
"file": "/Users/tom/Projects/sbf2000/sbf-cpp/Colors_test.cpp",
"output": "/Users/tom/Projects/sbf2000/build/Colors_test.o"
},
{
"arguments": [
"/usr/bin/clang++",
"-std=c++17",
"-Wall",
"-fno-objc-arc",
"-finput-charset=UTF-8",
"-Isbf-cpp",
"-I/opt/homebrew/opt/ncurses/include",
"-O2",
"-arch",
"arm64",
"-arch",
"x86_64",
"-fdiagnostics-show-template-tree",
"-fno-elide-type",
"-c",
"-o",
"build/Derangements_test.o",
"sbf-cpp/Derangements_test.cpp"
],
"directory": "/Users/tom/Projects/sbf2000",
"file": "/Users/tom/Projects/sbf2000/sbf-cpp/Derangements_test.cpp",
"output": "/Users/tom/Projects/sbf2000/build/Derangements_test.o"
},
{
"arguments": [
"/usr/bin/clang++",
"-std=c++17",
"-Wall",
"-fno-objc-arc",
"-finput-charset=UTF-8",
"-Isbf-cpp",
"-I/opt/homebrew/opt/ncurses/include",
"-O2",
"-arch",
"arm64",
"-arch",
"x86_64",
"-fdiagnostics-show-template-tree",
"-fno-elide-type",
"-c",
"-o",
"build/Disciplines_test.o",
"sbf-cpp/Disciplines_test.cpp"
],
"directory": "/Users/tom/Projects/sbf2000",
"file": "/Users/tom/Projects/sbf2000/sbf-cpp/Disciplines_test.cpp",
"output": "/Users/tom/Projects/sbf2000/build/Disciplines_test.o"
},
{
"arguments": [
"/usr/bin/clang++",
"-std=c++17",
"-Wall",
"-fno-objc-arc",
"-finput-charset=UTF-8",
"-Isbf-cpp",
"-I/opt/homebrew/opt/ncurses/include",
"-O2",
"-arch",
"arm64",
"-arch",
"x86_64",
"-fdiagnostics-show-template-tree",
"-fno-elide-type",
"-c",
"-o",
"build/Genders_test.o",
"sbf-cpp/Genders_test.cpp"
],
"directory": "/Users/tom/Projects/sbf2000",
"file": "/Users/tom/Projects/sbf2000/sbf-cpp/Genders_test.cpp",
"output": "/Users/tom/Projects/sbf2000/build/Genders_test.o"
},
{
"arguments": [
"/usr/bin/clang++",
"-std=c++17",
"-Wall",
"-fno-objc-arc",
"-finput-charset=UTF-8",
"-Isbf-cpp",
"-I/opt/homebrew/opt/ncurses/include",
"-O2",
"-arch",
"arm64",
"-arch",
"x86_64",
"-fdiagnostics-show-template-tree",
"-fno-elide-type",
"-c",
"-o",
"build/Ranks_test.o",
"sbf-cpp/Ranks_test.cpp"
],
"directory": "/Users/tom/Projects/sbf2000",
"file": "/Users/tom/Projects/sbf2000/sbf-cpp/Ranks_test.cpp",
"output": "/Users/tom/Projects/sbf2000/build/Ranks_test.o"
},
{
"arguments": [
"/usr/bin/clang++",
"-std=c++17",
"-Wall",
"-fno-objc-arc",
"-finput-charset=UTF-8",
"-Isbf-cpp",
"-I/opt/homebrew/opt/ncurses/include",
"-O2",
"-arch",
"arm64",
"-arch",
"x86_64",
"-fdiagnostics-show-template-tree",
"-fno-elide-type",
"-c",
"-o",
"build/Utils_test.o",
"sbf-cpp/Utils_test.cpp"
],
"directory": "/Users/tom/Projects/sbf2000",
"file": "/Users/tom/Projects/sbf2000/sbf-cpp/Utils_test.cpp",
"output": "/Users/tom/Projects/sbf2000/build/Utils_test.o"
},
{
"arguments": [
"/usr/bin/clang++",
"-std=c++17",
"-Wall",
"-fno-objc-arc",
"-finput-charset=UTF-8",
"-Isbf-cpp",
"-I/opt/homebrew/opt/ncurses/include",
"-O2",
"-arch",
"arm64",
"-arch",
"x86_64",
"-fdiagnostics-show-template-tree",
"-fno-elide-type",
"-c",
"-o",
"build/Virtues_test.o",
"sbf-cpp/Virtues_test.cpp"
],
"directory": "/Users/tom/Projects/sbf2000",
"file": "/Users/tom/Projects/sbf2000/sbf-cpp/Virtues_test.cpp",
"output": "/Users/tom/Projects/sbf2000/build/Virtues_test.o"
},
{
"arguments": [
"/usr/bin/clang++",
"-std=c++17",
"-Wall",
"-fno-objc-arc",
"-finput-charset=UTF-8",
"-Isbf-cpp",
"-I/opt/homebrew/opt/ncurses/include",
"-O2",
"-arch",
"arm64",
"-arch",
"x86_64",
"-fdiagnostics-show-template-tree",
"-fno-elide-type",
"-c",
"-o",
"build/test_main.o",
"build/test_main.cpp"
],
"directory": "/Users/tom/Projects/sbf2000",
"file": "/Users/tom/Projects/sbf2000/build/test_main.cpp",
"output": "/Users/tom/Projects/sbf2000/build/test_main.o"
},
{
"arguments": [
"/usr/bin/clang++",
"-std=c++17",
"-Wall",
"-fno-objc-arc",
"-finput-charset=UTF-8",
"-Isbf-cpp",
"-I/opt/homebrew/opt/ncurses/include",
"-O2",
"-arch",
"arm64",
"-arch",
"x86_64",
"-fdiagnostics-show-template-tree",
"-fno-elide-type",
"-c",
"-o",
"build/test.o",
"sbf-cpp/test.cpp"
],
"directory": "/Users/tom/Projects/sbf2000",
"file": "/Users/tom/Projects/sbf2000/sbf-cpp/test.cpp",
"output": "/Users/tom/Projects/sbf2000/build/test.o"
}
]

View File

@@ -1,164 +1,162 @@
#include "Abilities.h" #include "Abilities.h"
#include <string>
#include <iostream> #include <iostream>
#include <string>
namespace SBF { namespace SBF {
using std::string; using std::ostream;
using std::ostream; using std::string;
using std::vector; using std::vector;
ostream& operator<<(ostream& os, const AbilityType& ability) { ostream& operator<<(ostream& os, const AbilityType& ability) {
os << "AbilityGroup: {id: " << ability.id os << "AbilityGroup: {id: " << ability.id << ", singular: \"" << ability.singular << "\", plural: \""
<< ", singular: \"" << ability.singular << ability.plural << "\"}";
<< "\", plural: \"" << ability.plural << "\"}"; return os;
return os; }
}
bool operator==(const AbilityType& left, const AbilityType& right) { bool operator==(const AbilityType& left, const AbilityType& right) {
return left.id == right.id && return left.id == right.id && left.singular == right.singular && left.plural == right.plural;
left.singular == right.singular && }
left.plural == right.plural;
}
bool operator!=(const AbilityType& left, const AbilityType& right) { bool operator!=(const AbilityType& left, const AbilityType& right) {
return !(left == right); return !(left == right);
} }
void FillAbilities(vector<AbilityType>& abilities) { void FillAbilities(vector<AbilityType>& abilities) {
abilities.clear(); abilities.clear();
abilities.push_back(kAbilityGroupTalents); abilities.push_back(kAbilityGroupTalents);
abilities.push_back(kAbilityGroupSkills); abilities.push_back(kAbilityGroupSkills);
abilities.push_back(kAbilityGroupKnowledges); abilities.push_back(kAbilityGroupKnowledges);
} }
void FillAbilitiesForAbilityGroup(vector<string>& abilities, int id) { void FillAbilitiesForAbilityGroup(vector<string>& abilities, int id) {
abilities.clear(); abilities.clear();
int numAbilities = GetNumItemsForAbilityGroup(id); int numAbilities = GetNumItemsForAbilityGroup(id);
switch (id) { switch (id) {
case kAbilityTalentsId: case kAbilityTalentsId:
for (int talentId = 0; talentId <= numAbilities; talentId++) { for (int talentId = 0; talentId <= numAbilities; talentId++) {
if (talentId >= 0 && talentId <= kTalentsCount) { if (talentId >= 0 && talentId <= kTalentsCount) {
abilities.push_back(kTalents[talentId]); abilities.push_back(kTalents[talentId]);
}
}
break;
case kAbilitySkillsId:
for (int skillId = 0; skillId <= numAbilities; skillId++) {
if (skillId >= 0 && skillId <= kSkillsCount) {
abilities.push_back(kSkills[skillId]);
}
}
break;
case kAbilityKnowledgesId:
for (int knowledgeId = 0; knowledgeId <= numAbilities; knowledgeId++) {
if (knowledgeId >= 0 && knowledgeId <= kKnowledgesCount) {
abilities.push_back(kKnowledges[knowledgeId]);
}
}
break;
} }
} }
break;
void FillAbilityLabels(vector<string>& labels, int id) { case kAbilitySkillsId:
labels.clear(); for (int skillId = 0; skillId <= numAbilities; skillId++) {
switch (id) { if (skillId >= 0 && skillId <= kSkillsCount) {
case kAbilityTalentsId: abilities.push_back(kSkills[skillId]);
FillTalentLabels(labels);
break;
case kAbilitySkillsId:
FillSkillLabels(labels);
break;
case kAbilityKnowledgesId:
FillKnowledgeLabels(labels);
break;
} }
} }
break;
void FillKnowledgeLabels(vector<string>& labels) { case kAbilityKnowledgesId:
labels.clear(); for (int knowledgeId = 0; knowledgeId <= numAbilities; knowledgeId++) {
int numAbilities = GetNumItemsForAbilityGroup(kAbilityKnowledgesId); if (knowledgeId >= 0 && knowledgeId <= kKnowledgesCount) {
for (int knowledgeId = 0; knowledgeId <= numAbilities; knowledgeId++) { abilities.push_back(kKnowledges[knowledgeId]);
if (knowledgeId >= 0 && knowledgeId <= kKnowledgesCount) {
labels.push_back(kKnowledges[knowledgeId]);
}
} }
} }
break;
}
}
void FillSkillLabels(vector<string>& labels) { void FillAbilityLabels(vector<string>& labels, int id) {
labels.clear(); labels.clear();
int numAbilities = GetNumItemsForAbilityGroup(kAbilitySkillsId); switch (id) {
for (int skillId = 0; skillId <= numAbilities; skillId++) { case kAbilityTalentsId:
if (skillId >= 0 && skillId <= kSkillsCount) { FillTalentLabels(labels);
labels.push_back(kSkills[skillId]); break;
} case kAbilitySkillsId:
} FillSkillLabels(labels);
} break;
case kAbilityKnowledgesId:
void FillTalentLabels(vector<string>& labels) { FillKnowledgeLabels(labels);
labels.clear(); break;
int numAbilities = GetNumItemsForAbilityGroup(kAbilityTalentsId); }
for (int talentId = 0; talentId <= numAbilities; talentId++) { }
if (talentId >= 0 && talentId <= kTalentsCount) {
labels.push_back(kTalents[talentId]);
}
}
}
const AbilityType& GetAbility(int abilityGroupId) { void FillKnowledgeLabels(vector<string>& labels) {
switch(abilityGroupId) { labels.clear();
case kAbilityTalentsId: int numAbilities = GetNumItemsForAbilityGroup(kAbilityKnowledgesId);
return kAbilityGroupTalents; for (int knowledgeId = 0; knowledgeId <= numAbilities; knowledgeId++) {
case kAbilitySkillsId: if (knowledgeId >= 0 && knowledgeId <= kKnowledgesCount) {
return kAbilityGroupSkills; labels.push_back(kKnowledges[knowledgeId]);
case kAbilityKnowledgesId:
return kAbilityGroupKnowledges;
};
return kAbilityGroupUnknown;
} }
}
}
const string GetAbilityLabel(int abilityGroupId, int abilityId) { void FillSkillLabels(vector<string>& labels) {
switch (abilityGroupId) { labels.clear();
case kAbilityTalentsId: int numAbilities = GetNumItemsForAbilityGroup(kAbilitySkillsId);
return GetTalentLabel(abilityId); for (int skillId = 0; skillId <= numAbilities; skillId++) {
case kAbilitySkillsId: if (skillId >= 0 && skillId <= kSkillsCount) {
return GetSkillLabel(abilityId); labels.push_back(kSkills[skillId]);
case kAbilityKnowledgesId:
return GetKnowledgeLabel(abilityId);
};
return "";
} }
}
}
const std::string GetKnowledgeLabel(int talentId){ void FillTalentLabels(vector<string>& labels) {
if (talentId > 0 && talentId <= kKnowledgesCount) { labels.clear();
return kKnowledges[talentId]; int numAbilities = GetNumItemsForAbilityGroup(kAbilityTalentsId);
} for (int talentId = 0; talentId <= numAbilities; talentId++) {
return ""; if (talentId >= 0 && talentId <= kTalentsCount) {
labels.push_back(kTalents[talentId]);
} }
}
}
int GetNumItemsForAbilityGroup(int abilityGroupId) { const AbilityType& GetAbility(int abilityGroupId) {
switch (abilityGroupId) { switch (abilityGroupId) {
case kAbilityTalentsId: case kAbilityTalentsId:
return kTalentsCount; return kAbilityGroupTalents;
case kAbilitySkillsId: case kAbilitySkillsId:
return kSkillsCount; return kAbilityGroupSkills;
case kAbilityKnowledgesId: case kAbilityKnowledgesId:
return kKnowledgesCount; return kAbilityGroupKnowledges;
} };
return 0; return kAbilityGroupUnknown;
} }
const std::string GetSkillLabel(int skillId) {
if (skillId > 0 && skillId <= kSkillsCount) {
return kSkills[skillId];
}
return "";
}
const std::string GetTalentLabel(int talentId) { const string GetAbilityLabel(int abilityGroupId, int abilityId) {
if (talentId > 0 && talentId <= kTalentsCount) { switch (abilityGroupId) {
return kTalents[talentId]; case kAbilityTalentsId:
} return GetTalentLabel(abilityId);
return ""; case kAbilitySkillsId:
} return GetSkillLabel(abilityId);
case kAbilityKnowledgesId:
} // End namespace SBF return GetKnowledgeLabel(abilityId);
};
return "";
}
const std::string GetKnowledgeLabel(int talentId) {
if (talentId > 0 && talentId <= kKnowledgesCount) {
return kKnowledges[talentId];
}
return "";
}
int GetNumItemsForAbilityGroup(int abilityGroupId) {
switch (abilityGroupId) {
case kAbilityTalentsId:
return kTalentsCount;
case kAbilitySkillsId:
return kSkillsCount;
case kAbilityKnowledgesId:
return kKnowledgesCount;
}
return 0;
}
const std::string GetSkillLabel(int skillId) {
if (skillId > 0 && skillId <= kSkillsCount) {
return kSkills[skillId];
}
return "";
}
const std::string GetTalentLabel(int talentId) {
if (talentId > 0 && talentId <= kTalentsCount) {
return kTalents[talentId];
}
return "";
}
} // End namespace SBF

View File

@@ -1,233 +1,250 @@
#ifndef ABILITIES_H__ #ifndef ABILITIES_H__
#define ABILITIES_H__ #define ABILITIES_H__
/*************************************************************************************** /***************************************************************************************
* @file Abilities.h * @file Abilities.h
* *
* @brief Defines AbiiltyType, ability and ability group constants, and ability and * @brief Defines AbiiltyType, ability and ability group constants, and ability and
* ability group functions. * ability group functions.
* @copyright * @copyright
* Copyright 2023 Tom Hicks * Copyright 2023 Tom Hicks
* 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> #include <vector>
/** \addtogroup Abilities /** \addtogroup Abilities
* @{ * @{
*/ */
namespace SBF { namespace SBF {
const int kAbilityTalentsId = 1; const int kAbilityTalentsId = 1;
const std::string kAbilityTalentsSingular = "Talent"; const std::string kAbilityTalentsSingular = "Talent";
const std::string kAbilityTalentsPlural = "Talents"; const std::string kAbilityTalentsPlural = "Talents";
const int kAbilitySkillsId = 2; const int kAbilitySkillsId = 2;
const std::string kAbilitySkillsSingular = "Skill"; const std::string kAbilitySkillsSingular = "Skill";
const std::string kAbilitySkillsPlural = "Skills"; const std::string kAbilitySkillsPlural = "Skills";
const int kAbilityKnowledgesId = 3; const int kAbilityKnowledgesId = 3;
const std::string kAbilityKnowledgesSingular = "Knowledge"; const std::string kAbilityKnowledgesSingular = "Knowledge";
const std::string kAbilityKnowledgesPlural = "Knowledges"; const std::string kAbilityKnowledgesPlural = "Knowledges";
const int kAbilitiesCount = 3; const int kAbilitiesCount = 3;
/// @brief This type represents an ability group such as Talents, Skills or Knowledges. /// @brief This type represents an ability group such as Talents, Skills or Knowledges.
struct AbilityType { struct AbilityType {
/// @brief The id of this ability group /// @brief The id of this ability group
int id; int id;
/// @brief The singular form of this group i.e. Talent. /// @brief The singular form of this group i.e. Talent.
std::string singular; std::string singular;
/// @brief The plural form of this group i.e. Talents. /// @brief The plural form of this group i.e. Talents.
std::string plural; std::string plural;
}; };
const AbilityType kAbilityGroupUnknown = {0, "", ""};
const AbilityType kAbilityGroupTalents = {kAbilityTalentsId, kAbilityTalentsSingular, kAbilityTalentsPlural};
const AbilityType kAbilityGroupSkills = {kAbilitySkillsId, kAbilitySkillsSingular, kAbilitySkillsPlural};
const AbilityType kAbilityGroupKnowledges = {kAbilityKnowledgesId, kAbilityKnowledgesSingular, kAbilityKnowledgesPlural};
const AbilityType kAbilities[] {
kAbilityGroupUnknown,
kAbilityGroupTalents,
kAbilityGroupSkills,
kAbilityGroupKnowledges,
};
const std::string kAbilityUnknownLabel = ""; const AbilityType kAbilityGroupUnknown = {0, "", ""};
const AbilityType kAbilityGroupTalents = {
kAbilityTalentsId,
kAbilityTalentsSingular,
kAbilityTalentsPlural,
};
const AbilityType kAbilityGroupSkills = {
kAbilitySkillsId,
kAbilitySkillsSingular,
kAbilitySkillsPlural,
};
const AbilityType kAbilityGroupKnowledges = {
kAbilityKnowledgesId,
kAbilityKnowledgesSingular,
kAbilityKnowledgesPlural,
};
const AbilityType kAbilities[]{
kAbilityGroupUnknown,
kAbilityGroupTalents,
kAbilityGroupSkills,
kAbilityGroupKnowledges,
};
const int kTalentActingId = 1; const std::string kAbilityUnknownLabel = "";
const std::string kTalentActingLabel = "Acting";
const int kTalentAlertnessId = 2;
const std::string kTalentAlertnessLabel = "Alertness";
const int kTalentAthleticsId = 3;
const std::string kTalentAthleticsLabel = "Athletics";
const int kTalentBrawlId = 4;
const std::string kTalentBrawlLabel = "Brawl";
const int kTalentDodgeId = 5;
const std::string kTalentDodgeLabel = "Dodge";
const int kTalentEmpathyId = 6;
const std::string kTalentEmpathyLabel = "Empathy";
const int kTalentIntimidationId = 7;
const std::string kTalentIntimidationLabel = "Intimidation";
const int kTalentLeadershipId = 8;
const std::string kTalentLeadershipLabel = "Leadership";
const int kTalentStreetwiseId = 9;
const std::string kTalentStreetwiseLabel = "Streetwise";
const int kTalentSubterfugeId = 10;
const std::string kTalentSubterfugeLabel = "Subterfuge";
const int kTalentsCount = 10;
const std::string kTalents[] = {
kAbilityUnknownLabel,
kTalentActingLabel,
kTalentAlertnessLabel,
kTalentAthleticsLabel,
kTalentBrawlLabel,
kTalentDodgeLabel,
kTalentEmpathyLabel,
kTalentIntimidationLabel,
kTalentLeadershipLabel,
kTalentStreetwiseLabel,
kTalentSubterfugeLabel,
};
const int kSkillAnimalKenId = 1; const int kTalentActingId = 1;
const std::string kSkillAnimalKenLabel = "Animal Ken"; const std::string kTalentActingLabel = "Acting";
const int kSkillDriveId = 2; const int kTalentAlertnessId = 2;
const std::string kSkillDriveLabel = "Drive"; const std::string kTalentAlertnessLabel = "Alertness";
const int kSkillEtiquetteId = 3; const int kTalentAthleticsId = 3;
const std::string kSkillEtiquetteLabel = "Etiquette"; const std::string kTalentAthleticsLabel = "Athletics";
const int kSkillFirearmsId = 4; const int kTalentBrawlId = 4;
const std::string kSkillFirearmsLabel = "Firearms"; const std::string kTalentBrawlLabel = "Brawl";
const int kSkillMeleeId = 5; const int kTalentDodgeId = 5;
const std::string kSkillMeleeLabel = "Melee"; const std::string kTalentDodgeLabel = "Dodge";
const int kSkillMusicId = 6; const int kTalentEmpathyId = 6;
const std::string kSkillMusicLabel = "Music"; const std::string kTalentEmpathyLabel = "Empathy";
const int kSkillRepairId = 7; const int kTalentIntimidationId = 7;
const std::string kSkillRepairLabel = "Repair"; const std::string kTalentIntimidationLabel = "Intimidation";
const int kSkillSecurityId = 8; const int kTalentLeadershipId = 8;
const std::string kSkillSecurityLabel = "Security"; const std::string kTalentLeadershipLabel = "Leadership";
const int kSkillStealthId = 9; const int kTalentStreetwiseId = 9;
const std::string kSkillStealthLabel = "Stealth"; const std::string kTalentStreetwiseLabel = "Streetwise";
const int kSkillSurvivalId = 10; const int kTalentSubterfugeId = 10;
const std::string kSkillSurvivalLabel = "Survival"; const std::string kTalentSubterfugeLabel = "Subterfuge";
const int kSkillsCount = 10; const int kTalentsCount = 10;
const std::string kSkills[] = { const std::string kTalents[] = {
kAbilityUnknownLabel, kAbilityUnknownLabel,
kSkillAnimalKenLabel, kTalentActingLabel,
kSkillDriveLabel, kTalentAlertnessLabel,
kSkillEtiquetteLabel, kTalentAthleticsLabel,
kSkillFirearmsLabel, kTalentBrawlLabel,
kSkillMeleeLabel, kTalentDodgeLabel,
kSkillMusicLabel, kTalentEmpathyLabel,
kSkillRepairLabel, kTalentIntimidationLabel,
kSkillSecurityLabel, kTalentLeadershipLabel,
kSkillStealthLabel, kTalentStreetwiseLabel,
kSkillSurvivalLabel, kTalentSubterfugeLabel,
}; };
const int kKnowledgeBureaucracyId = 1; const int kSkillAnimalKenId = 1;
const std::string kKnowledgeBureaucracyLabel = "Bureaucracy"; const std::string kSkillAnimalKenLabel = "Animal Ken";
const int kKnowledgeComputerId = 2; const int kSkillDriveId = 2;
const std::string kKnowledgeComputerLabel = "Computer"; const std::string kSkillDriveLabel = "Drive";
const int kKnowledgeFinanceId = 3; const int kSkillEtiquetteId = 3;
const std::string kKnowledgeFinanceLabel = "Finance"; const std::string kSkillEtiquetteLabel = "Etiquette";
const int kKnowledgeInvestigationId = 4; const int kSkillFirearmsId = 4;
const std::string kKnowledgeInvestigationLabel = "Investigation"; const std::string kSkillFirearmsLabel = "Firearms";
const int kKnowledgeLawId = 5; const int kSkillMeleeId = 5;
const std::string kKnowledgeLawLabel = "Law"; const std::string kSkillMeleeLabel = "Melee";
const int kKnowledgeLinguisticsId = 6; const int kSkillMusicId = 6;
const std::string kKnowledgeLinguisticsLabel = "Linguistics"; const std::string kSkillMusicLabel = "Music";
const int kKnowledgeMedicineId = 7; const int kSkillRepairId = 7;
const std::string kKnowledgeMedicineLabel = "Medicine"; const std::string kSkillRepairLabel = "Repair";
const int kKnowledgeOccultId = 8; const int kSkillSecurityId = 8;
const std::string kKnowledgeOccultLabel = "Occult"; const std::string kSkillSecurityLabel = "Security";
const int kKnowledgePoliticsId = 9; const int kSkillStealthId = 9;
const std::string kKnowledgePoliticsLabel = "Politics"; const std::string kSkillStealthLabel = "Stealth";
const int kKnowledgeScienceId = 10; const int kSkillSurvivalId = 10;
const std::string kKnowledgeScienceLabel = "Science"; const std::string kSkillSurvivalLabel = "Survival";
const int kKnowledgesCount = 10; const int kSkillsCount = 10;
const std::string kKnowledges[] = { const std::string kSkills[] = {
kAbilityUnknownLabel, kAbilityUnknownLabel,
kKnowledgeBureaucracyLabel, kSkillAnimalKenLabel,
kKnowledgeComputerLabel, kSkillDriveLabel,
kKnowledgeFinanceLabel, kSkillEtiquetteLabel,
kKnowledgeInvestigationLabel, kSkillFirearmsLabel,
kKnowledgeLawLabel, kSkillMeleeLabel,
kKnowledgeLinguisticsLabel, kSkillMusicLabel,
kKnowledgeMedicineLabel, kSkillRepairLabel,
kKnowledgeOccultLabel, kSkillSecurityLabel,
kKnowledgePoliticsLabel, kSkillStealthLabel,
kKnowledgeScienceLabel, kSkillSurvivalLabel,
}; };
/// @brief This function writes an AbilityType value to an output stream; const int kKnowledgeBureaucracyId = 1;
/// @param os The output stream to write to. const std::string kKnowledgeBureaucracyLabel = "Bureaucracy";
/// @param group The AbilityType to write. const int kKnowledgeComputerId = 2;
/// @return Thw output stream for chaining. const std::string kKnowledgeComputerLabel = "Computer";
std::ostream& operator<<(std::ostream& os, const AbilityType& group); const int kKnowledgeFinanceId = 3;
const std::string kKnowledgeFinanceLabel = "Finance";
const int kKnowledgeInvestigationId = 4;
const std::string kKnowledgeInvestigationLabel = "Investigation";
const int kKnowledgeLawId = 5;
const std::string kKnowledgeLawLabel = "Law";
const int kKnowledgeLinguisticsId = 6;
const std::string kKnowledgeLinguisticsLabel = "Linguistics";
const int kKnowledgeMedicineId = 7;
const std::string kKnowledgeMedicineLabel = "Medicine";
const int kKnowledgeOccultId = 8;
const std::string kKnowledgeOccultLabel = "Occult";
const int kKnowledgePoliticsId = 9;
const std::string kKnowledgePoliticsLabel = "Politics";
const int kKnowledgeScienceId = 10;
const std::string kKnowledgeScienceLabel = "Science";
const int kKnowledgesCount = 10;
const std::string kKnowledges[] = {
kAbilityUnknownLabel,
kKnowledgeBureaucracyLabel,
kKnowledgeComputerLabel,
kKnowledgeFinanceLabel,
kKnowledgeInvestigationLabel,
kKnowledgeLawLabel,
kKnowledgeLinguisticsLabel,
kKnowledgeMedicineLabel,
kKnowledgeOccultLabel,
kKnowledgePoliticsLabel,
kKnowledgeScienceLabel,
};
/// @brief This function compares two AbilityType values for equality. /// @brief This function writes an AbilityType value to an output stream;
/// @param left The first AbilityType. /// @param os The output stream to write to.
/// @param right The second AbilityType. /// @param group The AbilityType to write.
/// @return True if left is equal to right and false otherwise. /// @return Thw output stream for chaining.
bool operator==(const AbilityType& left, const AbilityType& right); std::ostream& operator<<(std::ostream& os, const AbilityType& group);
/// @brief This function compares two AbilityType values for equality. /// @brief This function compares two AbilityType values for equality.
/// @param left The first AbilityType. /// @param left The first AbilityType.
/// @param right The second AbilityType. /// @param right The second AbilityType.
/// @return True if left and right are not equal and false otherwise. /// @return True if left is equal to right and false otherwise.
bool operator!=(const AbilityType& left, const AbilityType& right); bool operator==(const AbilityType& left, const AbilityType& right);
/// @brief Fills the provided vector with all of the available ability groups. It will be cleared before filling. /// @brief This function compares two AbilityType values for equality.
/// @param abilities The vector to fill. /// @param left The first AbilityType.
void FillAbilities(std::vector<AbilityType>& abilities); /// @param right The second AbilityType.
/// @return True if left and right are not equal and false otherwise.
bool operator!=(const AbilityType& left, const AbilityType& right);
/// @brief Fills the provided vector with all of the ability labels in the specified group. It will be cleared before filling. /// @brief Fills the provided vector with all of the available ability groups. It will be cleared before filling.
/// @param abilities The vector to fill. /// @param abilities The vector to fill.
/// @param id The id of the ability group to fill for. void FillAbilities(std::vector<AbilityType>& abilities);
void FillAbilitiesForAbilityGroup(std::vector<std::string>& abilities, int id);
/// @brief Fills the provided vector with all of the ability labels in the specified group. It will be cleared before filling. /// @brief Fills the provided vector with all of the ability labels in the specified group. It will be cleared before
/// @param labels The vector to fill. /// filling.
/// @param id The id of the ability group to fill for. /// @param abilities The vector to fill.
void FillAbilityLabels(std::vector<std::string>& labels, int id); /// @param id The id of the ability group to fill for.
void FillAbilitiesForAbilityGroup(std::vector<std::string>& abilities, int id);
/// @brief Fills the provided vector with all of the knowledge labels. It will be cleared before filling. /// @brief Fills the provided vector with all of the ability labels in the specified group. It will be cleared before
/// @param labels The vector to fill. /// filling.
void FillKnowledgeLabels(std::vector<std::string>& labels); /// @param labels The vector to fill.
/// @param id The id of the ability group to fill for.
void FillAbilityLabels(std::vector<std::string>& labels, int id);
/// @brief Fills the provided vector with all of the skill labels. It will be cleared before filling. /// @brief Fills the provided vector with all of the knowledge labels. It will be cleared before filling.
/// @param labels The vector to fill. /// @param labels The vector to fill.
void FillSkillLabels(std::vector<std::string>& labels); void FillKnowledgeLabels(std::vector<std::string>& labels);
/// @brief Fills the provided vector with all of the talent labels. It will be cleared before filling. /// @brief Fills the provided vector with all of the skill labels. It will be cleared before filling.
/// @param labels The vector to fill. /// @param labels The vector to fill.
void FillTalentLabels(std::vector<std::string>& labels); void FillSkillLabels(std::vector<std::string>& labels);
/// @brief Gets an ability group for a given id. /// @brief Fills the provided vector with all of the talent labels. It will be cleared before filling.
/// @param id The id of the ability group to return. /// @param labels The vector to fill.
/// @return The ability group with an id of id or kAbilityGroupUnknown if id is invalid. void FillTalentLabels(std::vector<std::string>& labels);
const AbilityType& GetAbility(int id);
/// @brief Gets the label for an ability given its ability group (talents/skills/knowledges) and its id (acting, brawl, dodge, ...). /// @brief Gets an ability group for a given id.
/// @param group_id The id for the ability group (talents/skills/knowledges). /// @param id The id of the ability group to return.
/// @param id The id for the ability within the ability group (acting, dodge, brawl, ...). /// @return The ability group with an id of id or kAbilityGroupUnknown if id is invalid.
/// @return The label for the specific ability ("Acting"). const AbilityType& GetAbility(int id);
const std::string GetAbilityLabel(int group_id, int id);
/// @brief Gets the label for a knowledge ability given its id. /// @brief Gets the label for an ability given its ability group (talents/skills/knowledges) and its id (acting, brawl,
/// @param id The id of the ability to return the label for. /// dodge, ...).
/// @return The label for the specific ability. /// @param group_id The id for the ability group (talents/skills/knowledges).
const std::string GetKnowledgeLabel(int id); /// @param id The id for the ability within the ability group (acting, dodge, brawl, ...).
/// @return The label for the specific ability ("Acting").
const std::string GetAbilityLabel(int group_id, int id);
/// @brief Gets the number of abilities in an ability group. /// @brief Gets the label for a knowledge ability given its id.
/// @param id The id of the ability group to return the number of abilities for. /// @param id The id of the ability to return the label for.
/// @return The number of abilities in the specific ability group. /// @return The label for the specific ability.
int GetNumItemsForAbilityGroup(int id); const std::string GetKnowledgeLabel(int id);
/// @brief Gets the label for a skill ability given its id. /// @brief Gets the number of abilities in an ability group.
/// @param id The id of the ability to return the label for. /// @param id The id of the ability group to return the number of abilities for.
/// @return The label of the specific ability. /// @return The number of abilities in the specific ability group.
const std::string GetSkillLabel(int id); int GetNumItemsForAbilityGroup(int id);
/// @brief Gets the label for a skill ability given its id.
/// @param id The id of the ability to return the label for.
/// @return The label of the specific ability.
const std::string GetSkillLabel(int id);
/// @brief Gets the label for a talent ability given its id.
/// @param id The id of the ability to return.
/// @return The label for the specific ability.
const std::string GetTalentLabel(int id);
} // End namespace SBF
/// @brief Gets the label for a talent ability given its id.
/// @param id The id of the ability to return.
/// @return The label for the specific ability.
const std::string GetTalentLabel(int id);
} // End namespace SBF
/** @}*/ /** @}*/
#endif // End !defined ABILITIES_H__ #endif // End !defined ABILITIES_H__

File diff suppressed because it is too large Load Diff

View File

@@ -1,20 +1,20 @@
#include "Archetypes.h" #include "Archetypes.h"
#include <string> #include <string>
#include <vector> #include <vector>
namespace SBF { namespace SBF {
std::string GetArchetypeLabel(int archetypeId) { std::string GetArchetypeLabel(int archetypeId) {
if (archetypeId >= 0 && archetypeId <= kArchetypesCount) { if (archetypeId >= 0 && archetypeId <= kArchetypesCount) {
return kArchetypes[archetypeId]; return kArchetypes[archetypeId];
} }
return ""; return "";
} }
void FillArchetypeLabels(std::vector<std::string>& labels) {
labels.clear();
for (int id = 0; id <= kArchetypesCount; id++) {
labels.push_back(GetArchetypeLabel(id));
}
}
} // End namespace SBF
void FillArchetypeLabels(std::vector<std::string>& labels) {
labels.clear();
for (int id = 0; id <= kArchetypesCount; id++) {
labels.push_back(GetArchetypeLabel(id));
}
}
} // End namespace SBF

View File

@@ -1,123 +1,124 @@
#ifndef ARCHETYPES_H__ #ifndef ARCHETYPES_H__
#define ARCHETYPES_H__ #define ARCHETYPES_H__
/*************************************************************************************** /***************************************************************************************
* @file Archetypes.h * @file Archetypes.h
* *
* @brief Defines constants and functions for working with archetypes. * @brief Defines constants and functions for working with archetypes.
* @copyright * @copyright
* Copyright 2023 Tom Hicks * Copyright 2023 Tom Hicks
* 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> #include <vector>
/** \addtogroup Archetypes /** \addtogroup Archetypes
* @{ * @{
*/ */
namespace SBF { namespace SBF {
const int kArchetypeArchitectId = 1; const int kArchetypeArchitectId = 1;
const std::string kArchetypeArchitectLabel = "Architect"; const std::string kArchetypeArchitectLabel = "Architect";
const int kArchetypeAutocratId = 2; const int kArchetypeAutocratId = 2;
const std::string kArchetypeAutocratLabel = "Autocrat"; const std::string kArchetypeAutocratLabel = "Autocrat";
const int kArchetypeBarbarianId = 3; const int kArchetypeBarbarianId = 3;
const std::string kArchetypeBarbarianLabel = "Barbarian"; const std::string kArchetypeBarbarianLabel = "Barbarian";
const int kArchetypeBonVivantId = 4; const int kArchetypeBonVivantId = 4;
const std::string kArchetypeBonVivantLabel = "Bon Vivant"; const std::string kArchetypeBonVivantLabel = "Bon Vivant";
const int kArchetypeBravoId = 5; const int kArchetypeBravoId = 5;
const std::string kArchetypeBravoLabel = "Bravo"; const std::string kArchetypeBravoLabel = "Bravo";
const int kArchetypeCaregiverId = 6; const int kArchetypeCaregiverId = 6;
const std::string kArchetypeCaregiverLabel = "Caregiver"; const std::string kArchetypeCaregiverLabel = "Caregiver";
const int kArchetypeCaretakerId = 7; const int kArchetypeCaretakerId = 7;
const std::string kArchetypeCaretakerLabel = "Caretaker"; const std::string kArchetypeCaretakerLabel = "Caretaker";
const int kArchetypeCelebrantId = 8; const int kArchetypeCelebrantId = 8;
const std::string kArchetypeCelebrantLabel = "Celebrant"; const std::string kArchetypeCelebrantLabel = "Celebrant";
const int kArchetypeChildId = 9; const int kArchetypeChildId = 9;
const std::string kArchetypeChildLabel = "Child"; const std::string kArchetypeChildLabel = "Child";
const int kArchetypeConformist = 10; const int kArchetypeConformist = 10;
const std::string kArchetypeConformistLabel = "Conformist"; const std::string kArchetypeConformistLabel = "Conformist";
const int kArchetypeConniverId = 11; const int kArchetypeConniverId = 11;
const std::string kArchetypeConniverLabel = "Conniver"; const std::string kArchetypeConniverLabel = "Conniver";
const int kArchetypeCurmudgeonId = 12; const int kArchetypeCurmudgeonId = 12;
const std::string kArchetypeCurmudgeonLabel = "Curmudgeon"; const std::string kArchetypeCurmudgeonLabel = "Curmudgeon";
const int kArchetypeDefenderId = 13; const int kArchetypeDefenderId = 13;
const std::string kArchetypeDefenderLabel = "Defender"; const std::string kArchetypeDefenderLabel = "Defender";
const int kArchetypeDeviantId = 14; const int kArchetypeDeviantId = 14;
const std::string kArchetypeDeviantLabel = "Deviant"; const std::string kArchetypeDeviantLabel = "Deviant";
const int kArchetypeDirectorId = 15; const int kArchetypeDirectorId = 15;
const std::string kArchetypeDirectorLabel = "Director"; const std::string kArchetypeDirectorLabel = "Director";
const int kArchetypeFanaticId = 16; const int kArchetypeFanaticId = 16;
const std::string kArchetypeFanaticLabel = "Fanatic"; const std::string kArchetypeFanaticLabel = "Fanatic";
const int kArchetypeGallantId = 17; const int kArchetypeGallantId = 17;
const std::string kArchetypeGallantLabel = "Gallant"; const std::string kArchetypeGallantLabel = "Gallant";
const int kArchetypeInnovatorId = 18; const int kArchetypeInnovatorId = 18;
const std::string kArchetypeInnovatorLabel = "Innovator"; const std::string kArchetypeInnovatorLabel = "Innovator";
const int kArchetypeJesterId = 19; const int kArchetypeJesterId = 19;
const std::string kArchetypeJesterLabel = "Jester"; const std::string kArchetypeJesterLabel = "Jester";
const int kArchetypeJudgeId = 20; const int kArchetypeJudgeId = 20;
const std::string kArchetypeJudgeLabel = "Judge"; const std::string kArchetypeJudgeLabel = "Judge";
const int kArchetypeLoanerId = 21; const int kArchetypeLoanerId = 21;
const std::string kArchetypeLoanerLabel = "Loaner"; const std::string kArchetypeLoanerLabel = "Loaner";
const int kArchetypeMartyrId = 22; const int kArchetypeMartyrId = 22;
const std::string kArchetypeMartyrLabel = "Martyr"; const std::string kArchetypeMartyrLabel = "Martyr";
const int kArchetypeMonsterId = 23; const int kArchetypeMonsterId = 23;
const std::string kArchetypeMonsterLabel = "Monster"; const std::string kArchetypeMonsterLabel = "Monster";
const int kArchetypePenitentId = 24; const int kArchetypePenitentId = 24;
const std::string kArchetypePenitentLabel = "Penitent"; const std::string kArchetypePenitentLabel = "Penitent";
const int kArchetypeRebelId = 25; const int kArchetypeRebelId = 25;
const std::string kArchetypeRebelLabel = "Rebel"; const std::string kArchetypeRebelLabel = "Rebel";
const int kArchetypeRogueId = 26; const int kArchetypeRogueId = 26;
const std::string kArchetypeRogueLabel = "Rogue"; const std::string kArchetypeRogueLabel = "Rogue";
const int kArchetypeSurvivorId = 27; const int kArchetypeSurvivorId = 27;
const std::string kArchetypeSurvivorLabel = "Survivor"; const std::string kArchetypeSurvivorLabel = "Survivor";
const int kArchetypeTraditionalistId = 28; const int kArchetypeTraditionalistId = 28;
const std::string kArchetypeTraditionalistLabel = "Traditionalist"; const std::string kArchetypeTraditionalistLabel = "Traditionalist";
const int kArchetypeTyrantId = 29; const int kArchetypeTyrantId = 29;
const std::string kArchetypeTyrantLabel = "Tyrant"; const std::string kArchetypeTyrantLabel = "Tyrant";
const int kArchetypeVisionaryId = 30; const int kArchetypeVisionaryId = 30;
const std::string kArchetypeVisionaryLabel = "Visionary"; const std::string kArchetypeVisionaryLabel = "Visionary";
const int kArchetypesCount = 30; const int kArchetypesCount = 30;
const std::string kArchetypes[] = { const std::string kArchetypes[] = {
"", "",
kArchetypeArchitectLabel, kArchetypeArchitectLabel,
kArchetypeAutocratLabel, kArchetypeAutocratLabel,
kArchetypeBarbarianLabel, kArchetypeBarbarianLabel,
kArchetypeBonVivantLabel, kArchetypeBonVivantLabel,
kArchetypeBravoLabel, kArchetypeBravoLabel,
kArchetypeCaregiverLabel, kArchetypeCaregiverLabel,
kArchetypeCaretakerLabel, kArchetypeCaretakerLabel,
kArchetypeCelebrantLabel, kArchetypeCelebrantLabel,
kArchetypeChildLabel, kArchetypeChildLabel,
kArchetypeConformistLabel, kArchetypeConformistLabel,
kArchetypeConniverLabel, kArchetypeConniverLabel,
kArchetypeCurmudgeonLabel, kArchetypeCurmudgeonLabel,
kArchetypeDefenderLabel, kArchetypeDefenderLabel,
kArchetypeDeviantLabel, kArchetypeDeviantLabel,
kArchetypeDirectorLabel, kArchetypeDirectorLabel,
kArchetypeFanaticLabel, kArchetypeFanaticLabel,
kArchetypeGallantLabel, kArchetypeGallantLabel,
kArchetypeInnovatorLabel, kArchetypeInnovatorLabel,
kArchetypeJesterLabel, kArchetypeJesterLabel,
kArchetypeJudgeLabel, kArchetypeJudgeLabel,
kArchetypeLoanerLabel, kArchetypeLoanerLabel,
kArchetypeMartyrLabel, kArchetypeMartyrLabel,
kArchetypeMonsterLabel, kArchetypeMonsterLabel,
kArchetypePenitentLabel, kArchetypePenitentLabel,
kArchetypeRebelLabel, kArchetypeRebelLabel,
kArchetypeRogueLabel, kArchetypeRogueLabel,
kArchetypeSurvivorLabel, kArchetypeSurvivorLabel,
kArchetypeTraditionalistLabel, kArchetypeTraditionalistLabel,
kArchetypeTyrantLabel, kArchetypeTyrantLabel,
kArchetypeVisionaryLabel, kArchetypeVisionaryLabel,
}; };
/// @brief Gets the label for the given archetype id. /// @brief Gets the label for the given archetype id.
/// @param archetypeId The id of the archetype to get the label for. /// @param archetypeId The id of the archetype to get the label for.
/// @return The label for the requested archetype. /// @return The label for the requested archetype.
std::string GetArchetypeLabel(int archetypeId); std::string GetArchetypeLabel(int archetypeId);
/// @brief Fills the provided vector with all of the archetype labels. It clears the vector before filling.
/// @param archetypeLabels The vector to fill.
void FillArchetypeLabels(std::vector<std::string>& archetypeLabels);
} // End namespace SBF
/// @brief Fills the provided vector with all of the archetype labels. It clears the vector before filling.
/// @param archetypeLabels The vector to fill.
void FillArchetypeLabels(std::vector<std::string>& archetypeLabels);
} // End namespace SBF
/** @}*/ /** @}*/
#endif // End !defined ARCHETYPES_H__ #endif // End !defined ARCHETYPES_H__

View File

@@ -1,185 +1,91 @@
#include "Archetypes.h" #include "Archetypes.h"
#include "test.h"
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include "test.h"
using namespace SBF; using namespace SBF;
using namespace Test; using namespace Test;
using namespace std; using namespace std;
namespace Test::Archetypes { namespace Test::Archetypes {
TestResults test_GetArchetypeLabel(); TestResults test_GetArchetypeLabel();
TestResults test_FillArchetypeLabels(); TestResults test_FillArchetypeLabels();
} // End namespace Test::Archetypes } // End namespace Test::Archetypes
using namespace Test::Archetypes; using namespace Test::Archetypes;
TestResults main_test_Archetypes(int argc, char** argv) { TestResults main_test_Archetypes(int argc, char** argv) {
TestResults results; TestResults results;
results += test_GetArchetypeLabel();
results += test_FillArchetypeLabels();
return results; results += test_GetArchetypeLabel();
results += test_FillArchetypeLabels();
return results;
} }
namespace Test::Archetypes { namespace Test::Archetypes {
TestResults test_GetArchetypeLabel() { TestResults test_GetArchetypeLabel() {
return execute_suite<string, int>(make_test_suite( return execute_suite<string, int>(make_test_suite(
"SBF::GetArchetypeLabel", "SBF::GetArchetypeLabel",
GetArchetypeLabel, GetArchetypeLabel,
vector<TestTuple<string, int>>({ vector<TestTuple<string, int>>({
make_test<string, int>( make_test<string, int>("should return \"\" for id 0", "", make_tuple(0)),
"should return \"\" for id 0", make_test<string, int>("should return \"Architect\" for id 1", "Architect", make_tuple(1)),
"", make_test<string, int>("should return \"Autocrat\" for id 2", "Autocrat", make_tuple(2)),
make_tuple(0)), make_test<string, int>("should return \"Barbarian\" for id 3", "Barbarian", make_tuple(3)),
make_test<string, int>( make_test<string, int>("should return \"Bon Vivant\" for id 4", "Bon Vivant", make_tuple(4)),
"should return \"Architect\" for id 1", make_test<string, int>("should return \"Bravo\" for id 5", "Bravo", make_tuple(5)),
"Architect", make_test<string, int>("should return \"Caregiver\" for id 6", "Caregiver", make_tuple(6)),
make_tuple(1)), make_test<string, int>("should return \"Caretaker\" for id 7", "Caretaker", make_tuple(7)),
make_test<string, int>( make_test<string, int>("should return \"Celebrant\" for id 8", "Celebrant", make_tuple(8)),
"should return \"Autocrat\" for id 2", make_test<string, int>("should return \"Child\" for id 9", "Child", make_tuple(9)),
"Autocrat", make_test<string, int>("should return \"Conformist\" for id 10", "Conformist", make_tuple(10)),
make_tuple(2)), make_test<string, int>("should return \"Conniver\" for id 11", "Conniver", make_tuple(11)),
make_test<string, int>( make_test<string, int>("should return \"Curmudgeon\" for id 12", "Curmudgeon", make_tuple(12)),
"should return \"Barbarian\" for id 3", make_test<string, int>("should return \"Defender\" for id 13", "Defender", make_tuple(13)),
"Barbarian", make_test<string, int>("should return \"Deviant\" for id 14", "Deviant", make_tuple(14)),
make_tuple(3)), make_test<string, int>("should return \"Director\" for id 15", "Director", make_tuple(15)),
make_test<string, int>( make_test<string, int>("should return \"Fanatic\" for id 16", "Fanatic", make_tuple(16)),
"should return \"Bon Vivant\" for id 4", make_test<string, int>("should return \"Gallant\" for id 17", "Gallant", make_tuple(17)),
"Bon Vivant", make_test<string, int>("should return \"Innovator\" for id 18", "Innovator", make_tuple(18)),
make_tuple(4)), make_test<string, int>("should return \"Jester\" for id 19", "Jester", make_tuple(19)),
make_test<string, int>( make_test<string, int>("should return \"Judge\" for id 20", "Judge", make_tuple(20)),
"should return \"Bravo\" for id 5", make_test<string, int>("should return \"Loaner\" for id 21", "Loaner", make_tuple(21)),
"Bravo", make_test<string, int>("should return \"Martyr\" for id 22", "Martyr", make_tuple(22)),
make_tuple(5)), make_test<string, int>("should return \"Monster\" for id 23", "Monster", make_tuple(23)),
make_test<string, int>( make_test<string, int>("should return \"Penitent\" for id 24", "Penitent", make_tuple(24)),
"should return \"Caregiver\" for id 6", make_test<string, int>("should return \"Rebel\" for id 25", "Rebel", make_tuple(25)),
"Caregiver", make_test<string, int>("should return \"Rogue\" for id 26", "Rogue", make_tuple(26)),
make_tuple(6)), make_test<string, int>("should return \"Survivor\" for id 27", "Survivor", make_tuple(27)),
make_test<string, int>( make_test<string, int>("should return \"Traditionalist\" for id 28", "Traditionalist", make_tuple(28)),
"should return \"Caretaker\" for id 7", make_test<string, int>("should return \"Tyrant\" for id 29", "Tyrant", make_tuple(29)),
"Caretaker", make_test<string, int>("should return \"Visionary\" for id 30", "Visionary", make_tuple(30)),
make_tuple(7)), make_test<string, int>("should return \"\" for an invalid id", "", make_tuple(31)),
make_test<string, int>( })));
"should return \"Celebrant\" for id 8", }
"Celebrant",
make_tuple(8)),
make_test<string, int>(
"should return \"Child\" for id 9",
"Child",
make_tuple(9)),
make_test<string, int>(
"should return \"Conformist\" for id 10",
"Conformist",
make_tuple(10)),
make_test<string, int>(
"should return \"Conniver\" for id 11",
"Conniver",
make_tuple(11)),
make_test<string, int>(
"should return \"Curmudgeon\" for id 12",
"Curmudgeon",
make_tuple(12)),
make_test<string, int>(
"should return \"Defender\" for id 13",
"Defender",
make_tuple(13)),
make_test<string, int>(
"should return \"Deviant\" for id 14",
"Deviant",
make_tuple(14)),
make_test<string, int>(
"should return \"Director\" for id 15",
"Director",
make_tuple(15)),
make_test<string, int>(
"should return \"Fanatic\" for id 16",
"Fanatic",
make_tuple(16)),
make_test<string, int>(
"should return \"Gallant\" for id 17",
"Gallant",
make_tuple(17)),
make_test<string, int>(
"should return \"Innovator\" for id 18",
"Innovator",
make_tuple(18)),
make_test<string, int>(
"should return \"Jester\" for id 19",
"Jester",
make_tuple(19)),
make_test<string, int>(
"should return \"Judge\" for id 20",
"Judge",
make_tuple(20)),
make_test<string, int>(
"should return \"Loaner\" for id 21",
"Loaner",
make_tuple(21)),
make_test<string, int>(
"should return \"Martyr\" for id 22",
"Martyr",
make_tuple(22)),
make_test<string, int>(
"should return \"Monster\" for id 23",
"Monster",
make_tuple(23)),
make_test<string, int>(
"should return \"Penitent\" for id 24",
"Penitent",
make_tuple(24)),
make_test<string, int>(
"should return \"Rebel\" for id 25",
"Rebel",
make_tuple(25)),
make_test<string, int>(
"should return \"Rogue\" for id 26",
"Rogue",
make_tuple(26)),
make_test<string, int>(
"should return \"Survivor\" for id 27",
"Survivor",
make_tuple(27)),
make_test<string, int>(
"should return \"Traditionalist\" for id 28",
"Traditionalist",
make_tuple(28)),
make_test<string, int>(
"should return \"Tyrant\" for id 29",
"Tyrant",
make_tuple(29)),
make_test<string, int>(
"should return \"Visionary\" for id 30",
"Visionary",
make_tuple(30)),
make_test<string, int>(
"should return \"\" for an invalid id",
"",
make_tuple(31)),
})
));
}
TestResults test_FillArchetypeLabels() { TestResults test_FillArchetypeLabels() {
return execute_suite<string>(make_test_suite( return execute_suite<string>(make_test_suite(
"SBF::FillArchetypeLabels", "SBF::FillArchetypeLabels",
[]()->string{ []() -> string {
ostringstream error_message; ostringstream error_message;
vector<string> expected = {"", "Architect", "Autocrat", "Barbarian", "Bon Vivant", "Bravo", "Caregiver", "Caretaker", "Celebrant", "Child", "Conformist", "Conniver", "Curmudgeon", "Defender", "Deviant", "Director", "Fanatic", "Gallant", "Innovator", "Jester", "Judge", "Loaner", "Martyr", "Monster", "Penitent", "Rebel", "Rogue", "Survivor", "Traditionalist", "Tyrant", "Visionary"}; vector<string> expected = {
vector<string> actual = {"This should be removed."}; "", "Architect", "Autocrat", "Barbarian", "Bon Vivant", "Bravo", "Caregiver", "Caretaker",
FillArchetypeLabels(actual); "Celebrant", "Child", "Conformist", "Conniver", "Curmudgeon", "Defender", "Deviant", "Director",
compare(error_message, expected, actual); "Fanatic", "Gallant", "Innovator", "Jester", "Judge", "Loaner", "Martyr", "Monster",
string error = error_message.str(); "Penitent", "Rebel", "Rogue", "Survivor", "Traditionalist", "Tyrant", "Visionary"};
if (error.size() > 0) { vector<string> actual = {"This should be removed."};
return error; FillArchetypeLabels(actual);
} compare(error_message, expected, actual);
return "no errors"; string error = error_message.str();
}, if (error.size() > 0) {
vector<TestTuple<string>>({ return error;
make_test<string>( }
"should fill archetype labels", return "no errors";
"no errors", },
make_tuple()), vector<TestTuple<string>>({
}) make_test<string>("should fill archetype labels", "no errors", make_tuple()),
)); })));
} }
} // End namespace Test::Archetypes } // End namespace Test::Archetypes

View File

@@ -1,140 +1,140 @@
#include "Attributes.h" #include "Attributes.h"
#include <sstream>
#include <string> #include <string>
#include <vector> #include <vector>
#include <sstream>
namespace SBF{ namespace SBF {
using std::string; using std::string;
string GetAttributeGroupLabel(int attributeGroupId) { string GetAttributeGroupLabel(int attributeGroupId) {
if (attributeGroupId > 0 && attributeGroupId <= kAttributeGroupsCount) { if (attributeGroupId > 0 && attributeGroupId <= kAttributeGroupsCount) {
return kAttributeGroups[attributeGroupId]; return kAttributeGroups[attributeGroupId];
} }
return ""; return "";
} }
string GetAttributeLabel(int attributeGroupId, int attributeId) { string GetAttributeLabel(int attributeGroupId, int attributeId) {
switch (attributeGroupId) { switch (attributeGroupId) {
case kAttributeGroupPhysicalId: case kAttributeGroupPhysicalId:
return GetPhysicalAttributeLabel(attributeId); return GetPhysicalAttributeLabel(attributeId);
case kAttributeGroupSocialId: case kAttributeGroupSocialId:
return GetSocialAttributeLabel(attributeId); return GetSocialAttributeLabel(attributeId);
case kAttributeGroupMentalId: case kAttributeGroupMentalId:
return GetMentalAttributeLabel(attributeId); return GetMentalAttributeLabel(attributeId);
default: default:
return ""; return "";
} }
} }
string GetAttributeLabelAbbreviation(int attributeGroupId, int attributeId) { string GetAttributeLabelAbbreviation(int attributeGroupId, int attributeId) {
switch (attributeGroupId) { switch (attributeGroupId) {
case kAttributeGroupPhysicalId: case kAttributeGroupPhysicalId:
return GetPhysicalAttributeLabelAbbreviation(attributeId); return GetPhysicalAttributeLabelAbbreviation(attributeId);
case kAttributeGroupSocialId: case kAttributeGroupSocialId:
return GetSocialAttributeLabelAbbreviation(attributeId); return GetSocialAttributeLabelAbbreviation(attributeId);
case kAttributeGroupMentalId: case kAttributeGroupMentalId:
return GetMentalAttributeLabelAbbreviation(attributeId); return GetMentalAttributeLabelAbbreviation(attributeId);
default: default:
return ""; return "";
} }
} }
int GetNumAttributesInGroup(int attributeGroupId) { int GetNumAttributesInGroup(int attributeGroupId) {
switch (attributeGroupId) { switch (attributeGroupId) {
case kAttributeGroupPhysicalId: case kAttributeGroupPhysicalId:
return kPhysicalAttributesCount; return kPhysicalAttributesCount;
case kAttributeGroupSocialId: case kAttributeGroupSocialId:
return kSocialAttributesCount; return kSocialAttributesCount;
case kAttributeGroupMentalId: case kAttributeGroupMentalId:
return kMentalAttributesCount; return kMentalAttributesCount;
} }
return 0; return 0;
} }
string GetPhysicalAttributeLabel(int attributeId) { string GetPhysicalAttributeLabel(int attributeId) {
if (attributeId > 0 && attributeId <= kPhysicalAttributesCount) { if (attributeId > 0 && attributeId <= kPhysicalAttributesCount) {
return kPhysicalAttributeLabels[attributeId]; return kPhysicalAttributeLabels[attributeId];
} }
return ""; return "";
} }
string GetPhysicalAttributeLabelAbbreviation(int attributeId) { string GetPhysicalAttributeLabelAbbreviation(int attributeId) {
if (attributeId > 0 && attributeId <= kPhysicalAttributesCount) { if (attributeId > 0 && attributeId <= kPhysicalAttributesCount) {
return kPhysicalAttributeLabelAbbreviations[attributeId]; return kPhysicalAttributeLabelAbbreviations[attributeId];
} }
return ""; return "";
} }
string GetSocialAttributeLabel(int attributeId) { string GetSocialAttributeLabel(int attributeId) {
if (attributeId > 0 && attributeId <= kSocialAttributesCount) { if (attributeId > 0 && attributeId <= kSocialAttributesCount) {
return kSocialAttributeLabels[attributeId]; return kSocialAttributeLabels[attributeId];
} }
return ""; return "";
} }
string GetSocialAttributeLabelAbbreviation(int attributeId) { string GetSocialAttributeLabelAbbreviation(int attributeId) {
if (attributeId > 0 && attributeId <= kSocialAttributesCount) { if (attributeId > 0 && attributeId <= kSocialAttributesCount) {
return kSocialAttributeLabelAbbreviations[attributeId]; return kSocialAttributeLabelAbbreviations[attributeId];
} }
return ""; return "";
} }
string GetMentalAttributeLabel(int attributeId) { string GetMentalAttributeLabel(int attributeId) {
if (attributeId > 0 && attributeId <= kMentalAttributesCount) { if (attributeId > 0 && attributeId <= kMentalAttributesCount) {
return kMentalAttributeLabels[attributeId]; return kMentalAttributeLabels[attributeId];
} }
return ""; return "";
} }
string GetMentalAttributeLabelAbbreviation(int attributeId) { string GetMentalAttributeLabelAbbreviation(int attributeId) {
if (attributeId > 0 && attributeId <= kMentalAttributesCount) { if (attributeId > 0 && attributeId <= kMentalAttributesCount) {
return kMentalAttributeLabelAbbreviations[attributeId]; return kMentalAttributeLabelAbbreviations[attributeId];
} }
return ""; return "";
} }
void FillAttributeGroupLabels(std::vector<std::string>& labels) { void FillAttributeGroupLabels(std::vector<std::string>& labels) {
labels.clear(); labels.clear();
for (int id = 1; id <= kAttributeGroupsCount; id++) { for (int id = 1; id <= kAttributeGroupsCount; id++) {
labels.push_back(kAttributeGroups[id]); labels.push_back(kAttributeGroups[id]);
} }
} }
void FillAttributeLabelsInGroup(std::vector<std::string>& labels, int groupId) { void FillAttributeLabelsInGroup(std::vector<std::string>& labels, int groupId) {
labels.clear(); labels.clear();
switch (groupId) { switch (groupId) {
case kAttributeGroupPhysicalId: case kAttributeGroupPhysicalId:
FillPhysicalAttributeLabels(labels); FillPhysicalAttributeLabels(labels);
break; break;
case kAttributeGroupSocialId: case kAttributeGroupSocialId:
FillSocialAttributeLabels(labels); FillSocialAttributeLabels(labels);
break; break;
case kAttributeGroupMentalId: case kAttributeGroupMentalId:
FillMentalAttributeLabels(labels); FillMentalAttributeLabels(labels);
break; break;
} }
} }
void FillPhysicalAttributeLabels(std::vector<std::string>& labels) { void FillPhysicalAttributeLabels(std::vector<std::string>& labels) {
labels.clear(); labels.clear();
for (int id = 1; id <= kPhysicalAttributesCount; id++) { for (int id = 1; id <= kPhysicalAttributesCount; id++) {
labels.push_back(kPhysicalAttributeLabels[id]); labels.push_back(kPhysicalAttributeLabels[id]);
} }
} }
void FillSocialAttributeLabels(std::vector<std::string>& labels) { void FillSocialAttributeLabels(std::vector<std::string>& labels) {
labels.clear(); labels.clear();
for (int id = 1; id <= kSocialAttributesCount; id++) { for (int id = 1; id <= kSocialAttributesCount; id++) {
labels.push_back(kSocialAttributeLabels[id]); labels.push_back(kSocialAttributeLabels[id]);
} }
} }
void FillMentalAttributeLabels(std::vector<std::string>& labels) { void FillMentalAttributeLabels(std::vector<std::string>& labels) {
labels.clear(); labels.clear();
for (int id = 1; id <= kMentalAttributesCount; id++) { for (int id = 1; id <= kMentalAttributesCount; id++) {
labels.push_back(kMentalAttributeLabels[id]); labels.push_back(kMentalAttributeLabels[id]);
} }
} }
} // End namespace SBF } // End namespace SBF

View File

@@ -1,175 +1,176 @@
#ifndef ATTRIBUTES_H__ #ifndef ATTRIBUTES_H__
#define ATTRIBUTES_H__ #define ATTRIBUTES_H__
/*************************************************************************************** /***************************************************************************************
* @file Attributes.h * @file Attributes.h
* *
* @brief Defines constants and functions for working with attribute groups and attriubtes. * @brief Defines constants and functions for working with attribute groups and attriubtes.
* @copyright * @copyright
* Copyright 2023 Tom Hicks * Copyright 2023 Tom Hicks
* 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> #include <vector>
/** \addtogroup Attributes /** \addtogroup Attributes
* @{ * @{
*/ */
namespace SBF { namespace SBF {
const int kPhysicalAttributeStrengthId = 1; const int kPhysicalAttributeStrengthId = 1;
const std::string kPhysicalAttributeStrengthLabel = "Strength"; const std::string kPhysicalAttributeStrengthLabel = "Strength";
const std::string kPhysicalAttributeStrengthAbbreviation = "Str."; const std::string kPhysicalAttributeStrengthAbbreviation = "Str.";
const int kPhysicalAttributeDexterityId = 2; const int kPhysicalAttributeDexterityId = 2;
const std::string kPhysicalAttributeDexterityLabel = "Dexterity"; const std::string kPhysicalAttributeDexterityLabel = "Dexterity";
const std::string kPhysicalAttributeDexterityAbbreviation = "Dex."; const std::string kPhysicalAttributeDexterityAbbreviation = "Dex.";
const int kPhysicalAttributeStaminaId = 3; const int kPhysicalAttributeStaminaId = 3;
const std::string kPhysicalAttributeStaminaLabel = "Stamina"; const std::string kPhysicalAttributeStaminaLabel = "Stamina";
const std::string kPhysicalAttributeStaminaAbbreviation = "Sta."; const std::string kPhysicalAttributeStaminaAbbreviation = "Sta.";
const int kPhysicalAttributesCount = 3; const int kPhysicalAttributesCount = 3;
const std::string kPhysicalAttributeLabels[] = { const std::string kPhysicalAttributeLabels[] = {
"", "",
kPhysicalAttributeStrengthLabel, kPhysicalAttributeStrengthLabel,
kPhysicalAttributeDexterityLabel, kPhysicalAttributeDexterityLabel,
kPhysicalAttributeStaminaLabel, kPhysicalAttributeStaminaLabel,
}; };
const std::string kPhysicalAttributeLabelAbbreviations[] = { const std::string kPhysicalAttributeLabelAbbreviations[] = {
"", "",
kPhysicalAttributeStrengthAbbreviation, kPhysicalAttributeStrengthAbbreviation,
kPhysicalAttributeDexterityAbbreviation, kPhysicalAttributeDexterityAbbreviation,
kPhysicalAttributeStaminaAbbreviation, kPhysicalAttributeStaminaAbbreviation,
}; };
const int kSocialAttributeCharismaId = 1; const int kSocialAttributeCharismaId = 1;
const std::string kSocialAttributeCharismaLabel = "Charisma"; const std::string kSocialAttributeCharismaLabel = "Charisma";
const std::string kSocialAttributeCharismaAbbreviation = "Cha."; const std::string kSocialAttributeCharismaAbbreviation = "Cha.";
const int kSocialAttributeManipulationId = 2; const int kSocialAttributeManipulationId = 2;
const std::string kSocialAttributeManipulationLabel = "Manipulation"; const std::string kSocialAttributeManipulationLabel = "Manipulation";
const std::string kSocialAttributeManipulationAbbreviation = "Man."; const std::string kSocialAttributeManipulationAbbreviation = "Man.";
const int kSocialAttributeAppearanceId = 3; const int kSocialAttributeAppearanceId = 3;
const std::string kSocialAttributeAppearanceLabel = "Appearance"; const std::string kSocialAttributeAppearanceLabel = "Appearance";
const std::string kSocialAttributeAppearanceAbbreviation = "App."; const std::string kSocialAttributeAppearanceAbbreviation = "App.";
const int kSocialAttributesCount = 3; const int kSocialAttributesCount = 3;
const std::string kSocialAttributeLabels[] = { const std::string kSocialAttributeLabels[] = {
"", "",
kSocialAttributeCharismaLabel, kSocialAttributeCharismaLabel,
kSocialAttributeManipulationLabel, kSocialAttributeManipulationLabel,
kSocialAttributeAppearanceLabel, kSocialAttributeAppearanceLabel,
}; };
const std::string kSocialAttributeLabelAbbreviations[] = { const std::string kSocialAttributeLabelAbbreviations[] = {
"", "",
kSocialAttributeCharismaAbbreviation, kSocialAttributeCharismaAbbreviation,
kSocialAttributeManipulationAbbreviation, kSocialAttributeManipulationAbbreviation,
kSocialAttributeAppearanceAbbreviation, kSocialAttributeAppearanceAbbreviation,
}; };
const int kMentalAttributeIntelligenceId = 1; const int kMentalAttributeIntelligenceId = 1;
const std::string kMentalAttributeIntelligenceLabel = "Intelligence"; const std::string kMentalAttributeIntelligenceLabel = "Intelligence";
const std::string kMentalAttributeIntelligenceAbbreviation = "Int."; const std::string kMentalAttributeIntelligenceAbbreviation = "Int.";
const int kMentalAttributePerceptionId = 2; const int kMentalAttributePerceptionId = 2;
const std::string kMentalAttributePerceptionLabel = "Perception"; const std::string kMentalAttributePerceptionLabel = "Perception";
const std::string kMentalAttributePerceptionAbbreviation = "Per."; const std::string kMentalAttributePerceptionAbbreviation = "Per.";
const int kMentalAttributeWitsId = 3; const int kMentalAttributeWitsId = 3;
const std::string kMentalAttributeWitsLabel = "Wits"; const std::string kMentalAttributeWitsLabel = "Wits";
const std::string kMentalAttributeWitsAbbreviation = "Wits"; const std::string kMentalAttributeWitsAbbreviation = "Wits";
const int kMentalAttributesCount = 3; const int kMentalAttributesCount = 3;
const std::string kMentalAttributeLabels[] = { const std::string kMentalAttributeLabels[] = {
"", "",
kMentalAttributeIntelligenceLabel, kMentalAttributeIntelligenceLabel,
kMentalAttributePerceptionLabel, kMentalAttributePerceptionLabel,
kMentalAttributeWitsLabel, kMentalAttributeWitsLabel,
}; };
const std::string kMentalAttributeLabelAbbreviations[] = { const std::string kMentalAttributeLabelAbbreviations[] = {
"", "",
kMentalAttributeIntelligenceAbbreviation, kMentalAttributeIntelligenceAbbreviation,
kMentalAttributePerceptionAbbreviation, kMentalAttributePerceptionAbbreviation,
kMentalAttributeWitsAbbreviation, kMentalAttributeWitsAbbreviation,
}; };
const int kAttributeGroupPhysicalId = 1; const int kAttributeGroupPhysicalId = 1;
const std::string kAttributeGroupPhysicalLabel = "Physical"; const std::string kAttributeGroupPhysicalLabel = "Physical";
const int kAttributeGroupSocialId = 2; const int kAttributeGroupSocialId = 2;
const std::string kAttributeGroupSocialLabel = "Social"; const std::string kAttributeGroupSocialLabel = "Social";
const int kAttributeGroupMentalId = 3; const int kAttributeGroupMentalId = 3;
const std::string kAttributeGroupMentalLabel = "Mental"; const std::string kAttributeGroupMentalLabel = "Mental";
const int kAttributeGroupsCount = 3; const int kAttributeGroupsCount = 3;
const std::string kAttributeGroups[] = { const std::string kAttributeGroups[] = {
"", "",
kAttributeGroupPhysicalLabel, kAttributeGroupPhysicalLabel,
kAttributeGroupSocialLabel, kAttributeGroupSocialLabel,
kAttributeGroupMentalLabel, kAttributeGroupMentalLabel,
}; };
/// @brief Gets the label for the attribute group with the specified id. /// @brief Gets the label for the attribute group with the specified id.
/// @param attribute_group_id The id of the attribute group to return the label for. /// @param attribute_group_id The id of the attribute group to return the label for.
/// @return The label of the specified attribute group. /// @return The label of the specified attribute group.
std::string GetAttributeGroupLabel(int attribute_group_id); std::string GetAttributeGroupLabel(int attribute_group_id);
/// @brief Gets the label for the attribute with a specific pair of group and attribute ids. /// @brief Gets the label for the attribute with a specific pair of group and attribute ids.
/// @param attribute_group_id The id of the attribute group to get the label for. /// @param attribute_group_id The id of the attribute group to get the label for.
/// @param attribute_id The id of the attribute within the group to return the label for. /// @param attribute_id The id of the attribute within the group to return the label for.
/// @return The label of the specified attribute or an empty string if either id is invalid. /// @return The label of the specified attribute or an empty string if either id is invalid.
std::string GetAttributeLabel(int attribute_group_id, int attribute_id); std::string GetAttributeLabel(int attribute_group_id, int attribute_id);
/// @brief Gets the label abbreviation for the attribute with a specific pair of group and attribute ids. /// @brief Gets the label abbreviation for the attribute with a specific pair of group and attribute ids.
/// @param attribute_group_id The id of the attribute group to get the label abbreviation for. /// @param attribute_group_id The id of the attribute group to get the label abbreviation for.
/// @param attribute_id The id of the attribute within the group to return the label abbreviation for. /// @param attribute_id The id of the attribute within the group to return the label abbreviation for.
/// @return The label abbreviation of the specified attribute or an empty string if either id is invalid. /// @return The label abbreviation of the specified attribute or an empty string if either id is invalid.
std::string GetAttributeLabelAbbreviation(int attribute_group_id, int attribute_id); std::string GetAttributeLabelAbbreviation(int attribute_group_id, int attribute_id);
/// @brief Gets the label for the physical attribute with a specific id. /// @brief Gets the label for the physical attribute with a specific id.
/// @param attribute_id The id of the physical attribute to get the label for. /// @param attribute_id The id of the physical attribute to get the label for.
/// @return The label of the specified attribute or an empty string if the id is invalid. /// @return The label of the specified attribute or an empty string if the id is invalid.
std::string GetPhysicalAttributeLabel(int attribute_id); std::string GetPhysicalAttributeLabel(int attribute_id);
/// @brief Gets the label abbreviation for the physical attribute with a specific id. /// @brief Gets the label abbreviation for the physical attribute with a specific id.
/// @param attribute_id The id of the physical attribute to get the label abbreviation for. /// @param attribute_id The id of the physical attribute to get the label abbreviation for.
/// @return The label abbreviation of the specified attribute or an empty string if the id is invalid. /// @return The label abbreviation of the specified attribute or an empty string if the id is invalid.
std::string GetPhysicalAttributeLabelAbbreviation(int attribute_id); std::string GetPhysicalAttributeLabelAbbreviation(int attribute_id);
/// @brief Gets the number of attributes in a specific attribute group. /// @brief Gets the number of attributes in a specific attribute group.
/// @param attribute_group_id The id of the attribute group. /// @param attribute_group_id The id of the attribute group.
/// @return The number of attributes in the specified group or 0 if the id is invalid. /// @return The number of attributes in the specified group or 0 if the id is invalid.
int GetNumAttributesInGroup(int attribute_group_id); int GetNumAttributesInGroup(int attribute_group_id);
/// @brief Gets the label for the social attribute with a specific id. /// @brief Gets the label for the social attribute with a specific id.
/// @param attribute_id The id of the social attribute to get the label for. /// @param attribute_id The id of the social attribute to get the label for.
/// @return The label of the specified attribute or an empty string if the id is invalid. /// @return The label of the specified attribute or an empty string if the id is invalid.
std::string GetSocialAttributeLabel(int attribute_id); std::string GetSocialAttributeLabel(int attribute_id);
/// @brief Gets the label abbreviation for the social attribute with a specific id. /// @brief Gets the label abbreviation for the social attribute with a specific id.
/// @param attribute_id The id of the social attribute to get the label abbreviation for. /// @param attribute_id The id of the social attribute to get the label abbreviation for.
/// @return The label abbreviation of the specified attribute or an empty string if the id is invalid. /// @return The label abbreviation of the specified attribute or an empty string if the id is invalid.
std::string GetSocialAttributeLabelAbbreviation(int attribute_id); std::string GetSocialAttributeLabelAbbreviation(int attribute_id);
/// @brief Gets the label for the mental attribute with a specific id. /// @brief Gets the label for the mental attribute with a specific id.
/// @param attribute_id The id of the mental attribute to get the label for. /// @param attribute_id The id of the mental attribute to get the label for.
/// @return The label of the specified attribute or an empty string if the id is invalid. /// @return The label of the specified attribute or an empty string if the id is invalid.
std::string GetMentalAttributeLabel(int attribute_id); std::string GetMentalAttributeLabel(int attribute_id);
/// @brief Gets the label abbreviation for the mental attribute with a specific id. /// @brief Gets the label abbreviation for the mental attribute with a specific id.
/// @param attribute_id The id of the mental attribute to get the label abbreviation for. /// @param attribute_id The id of the mental attribute to get the label abbreviation for.
/// @return The label abbreviation of the specified attribute or an empty string if the id is invalid. /// @return The label abbreviation of the specified attribute or an empty string if the id is invalid.
std::string GetMentalAttributeLabelAbbreviation(int attribute_id); std::string GetMentalAttributeLabelAbbreviation(int attribute_id);
/// @brief Fills the provided vector with all of the valid attribute group labels /// @brief Fills the provided vector with all of the valid attribute group labels
/// @param labels The vector to fill. It will be cleared first. /// @param labels The vector to fill. It will be cleared first.
void FillAttributeGroupLabels(std::vector<std::string>& labels); void FillAttributeGroupLabels(std::vector<std::string>& labels);
/// @brief Fills the provided vector with all of the valid attribute labels in a specific group. /// @brief Fills the provided vector with all of the valid attribute labels in a specific group.
/// @param labels The vector to fill. It will be cleared first. /// @param labels The vector to fill. It will be cleared first.
/// @param group_id The group to fill attribute labels for. /// @param group_id The group to fill attribute labels for.
void FillAttributeLabelsInGroup(std::vector<std::string>& labels, int group_id); void FillAttributeLabelsInGroup(std::vector<std::string>& labels, int group_id);
/// @brief Fills the provided vector with all of the valid physical attribute labels. /// @brief Fills the provided vector with all of the valid physical attribute labels.
/// @param labels The vector to fill. It will be cleared first. /// @param labels The vector to fill. It will be cleared first.
void FillPhysicalAttributeLabels(std::vector<std::string>& labels); void FillPhysicalAttributeLabels(std::vector<std::string>& labels);
/// @brief Fills the provided vector with all of the valid social attribute labels. /// @brief Fills the provided vector with all of the valid social attribute labels.
/// @param labels The vector to fill. It will be cleared first. /// @param labels The vector to fill. It will be cleared first.
void FillSocialAttributeLabels(std::vector<std::string>& labels); void FillSocialAttributeLabels(std::vector<std::string>& labels);
/// @brief Fills the provided vector with all of the valid mental attribute labels.
/// @param labels The vector to fill. It will be cleared first.
void FillMentalAttributeLabels(std::vector<std::string>& labels);
} // End namespace SBF
/// @brief Fills the provided vector with all of the valid mental attribute labels.
/// @param labels The vector to fill. It will be cleared first.
void FillMentalAttributeLabels(std::vector<std::string>& labels);
} // End namespace SBF
/** @}*/ /** @}*/
#endif // End !defined ATTRIBUTES_H__ #endif // End !defined ATTRIBUTES_H__

View File

@@ -1,9 +1,11 @@
#include "Attributes.h" #include "Attributes.h"
#include "test.h"
#include <string>
#include <vector>
#include <tuple>
#include <sstream> #include <sstream>
#include <string>
#include <tuple>
#include <vector>
#include "test.h"
using namespace SBF; using namespace SBF;
using namespace Test; using namespace Test;
@@ -25,518 +27,298 @@ TestResults test_FillAttributeLabelsInGroup();
TestResults test_FillPhysicalAttributeLabels(); TestResults test_FillPhysicalAttributeLabels();
TestResults test_FillSocialAttributeLabels(); TestResults test_FillSocialAttributeLabels();
TestResults test_FillMentalAttributeLabels(); TestResults test_FillMentalAttributeLabels();
} // End namespace Test::Attributes } // End namespace Test::Attributes
using namespace Test::Attributes; using namespace Test::Attributes;
TestResults main_test_Attributes(int argc, char** argv) { TestResults main_test_Attributes(int argc, char** argv) {
TestResults results; TestResults results;
results += test_GetAttributeGroupLabel();
results += test_GetAttributeLabel();
results += test_GetAttributeLabelAbbreviation();
results += test_GetNumAttributesInGroup();
results += test_GetPhysicalAttributeLabel();
results += test_GetPhysicalAttributeLabelAbbreviation();
results += test_GetSocialAttributeLabel();
results += test_GetSocialAttributeLabelAbbreviation();
results += test_GetMentalAttributeLabel();
results += test_GetMentalAttributeLabelAbbreviation();
results += test_FillAttributeGroupLabels();
results += test_FillAttributeLabelsInGroup();
results += test_FillPhysicalAttributeLabels();
results += test_FillSocialAttributeLabels();
results += test_FillMentalAttributeLabels();
return results; results += test_GetAttributeGroupLabel();
results += test_GetAttributeLabel();
results += test_GetAttributeLabelAbbreviation();
results += test_GetNumAttributesInGroup();
results += test_GetPhysicalAttributeLabel();
results += test_GetPhysicalAttributeLabelAbbreviation();
results += test_GetSocialAttributeLabel();
results += test_GetSocialAttributeLabelAbbreviation();
results += test_GetMentalAttributeLabel();
results += test_GetMentalAttributeLabelAbbreviation();
results += test_FillAttributeGroupLabels();
results += test_FillAttributeLabelsInGroup();
results += test_FillPhysicalAttributeLabels();
results += test_FillSocialAttributeLabels();
results += test_FillMentalAttributeLabels();
return results;
} }
namespace Test::Attributes { namespace Test::Attributes {
TestResults test_GetAttributeGroupLabel() { TestResults test_GetAttributeGroupLabel() {
return execute_suite<string, int>(make_test_suite( return execute_suite<string, int>(
"SBF::GetAttributeGroupLabel", make_test_suite("SBF::GetAttributeGroupLabel",
GetAttributeGroupLabel, GetAttributeGroupLabel,
vector<TestTuple<string, int>>({ vector<TestTuple<string, int>>({
make_test<string, int>( make_test<string, int>("should get \"\" for id 0", "", make_tuple(0)),
"should get \"\" for id 0", make_test<string, int>("should get \"Physical\" for id 1", "Physical", make_tuple(1)),
"", make_test<string, int>("should get \"Social\" for id 2", "Social", make_tuple(2)),
make_tuple(0)), make_test<string, int>("should get \"Mental\" for id 3", "Mental", make_tuple(3)),
make_test<string, int>( make_test<string, int>("should get \"\" for id 4", "", make_tuple(4)),
"should get \"Physical\" for id 1", })));
"Physical",
make_tuple(1)),
make_test<string, int>(
"should get \"Social\" for id 2",
"Social",
make_tuple(2)),
make_test<string, int>(
"should get \"Mental\" for id 3",
"Mental",
make_tuple(3)),
make_test<string, int>(
"should get \"\" for id 4",
"",
make_tuple(4)),
})
));
} }
TestResults test_GetAttributeLabel() { TestResults test_GetAttributeLabel() {
return execute_suite<string, int, int>(make_test_suite( return execute_suite<string, int, int>(make_test_suite(
"SBF::GetAttributeLabel", "SBF::GetAttributeLabel",
GetAttributeLabel, GetAttributeLabel,
vector<TestTuple<string, int, int>>({ vector<TestTuple<string, int, int>>({
make_test<string, int, int>( make_test<string, int, int>("should get \"Strength\" for group id 1 and id 1", "Strength", make_tuple(1, 1)),
"should get \"Strength\" for group id 1 and id 1", make_test<string, int, int>(
"Strength", "should get \"Dexterity\" for group id 1 and id 2", "Dexterity", make_tuple(1, 2)),
make_tuple(1, 1)), make_test<string, int, int>("should get \"Stamina\" for group id 1 and id 3", "Stamina", make_tuple(1, 3)),
make_test<string, int, int>( make_test<string, int, int>("should get \"Charisma\" for group id 2 and id 1", "Charisma", make_tuple(2, 1)),
"should get \"Dexterity\" for group id 1 and id 2", make_test<string, int, int>(
"Dexterity", "should get \"Manipulation\" for group id 2 and id 2", "Manipulation", make_tuple(2, 2)),
make_tuple(1, 2)), make_test<string, int, int>(
make_test<string, int, int>( "should get \"Appearance\" for group id 2 and id 3", "Appearance", make_tuple(2, 3)),
"should get \"Stamina\" for group id 1 and id 3", make_test<string, int, int>(
"Stamina", "should get \"Intelligence\" for group id 3 and id 1", "Intelligence", make_tuple(3, 1)),
make_tuple(1, 3)), make_test<string, int, int>(
make_test<string, int, int>( "should get \"Perception\" for group id 3 and id 2", "Perception", make_tuple(3, 2)),
"should get \"Charisma\" for group id 2 and id 1", make_test<string, int, int>("should get \"Wits\" for group id 3 and id 3", "Wits", make_tuple(3, 3)),
"Charisma", make_test<string, int, int>("should get \"\" for an invalid group id 0", "", make_tuple(0, 1)),
make_tuple(2, 1)), make_test<string, int, int>("should get \"\" for an invalid id 0", "", make_tuple(1, 0)),
make_test<string, int, int>( make_test<string, int, int>("should get \"\" for invalid group id 4", "", make_tuple(4, 1)),
"should get \"Manipulation\" for group id 2 and id 2", make_test<string, int, int>("should get \"\" for an invalid id 4", "", make_tuple(1, 4)),
"Manipulation", })));
make_tuple(2, 2)),
make_test<string, int, int>(
"should get \"Appearance\" for group id 2 and id 3",
"Appearance",
make_tuple(2, 3)),
make_test<string, int, int>(
"should get \"Intelligence\" for group id 3 and id 1",
"Intelligence",
make_tuple(3, 1)),
make_test<string, int, int>(
"should get \"Perception\" for group id 3 and id 2",
"Perception",
make_tuple(3, 2)),
make_test<string, int, int>(
"should get \"Wits\" for group id 3 and id 3",
"Wits",
make_tuple(3, 3)),
make_test<string, int, int>(
"should get \"\" for an invalid group id 0",
"",
make_tuple(0, 1)),
make_test<string, int, int>(
"should get \"\" for an invalid id 0",
"",
make_tuple(1, 0)),
make_test<string, int, int>(
"should get \"\" for invalid group id 4",
"",
make_tuple(4, 1)),
make_test<string, int, int>(
"should get \"\" for an invalid id 4",
"",
make_tuple(1, 4)),
})
));
} }
TestResults test_GetAttributeLabelAbbreviation() { TestResults test_GetAttributeLabelAbbreviation() {
return execute_suite<string, int, int>(make_test_suite( return execute_suite<string, int, int>(make_test_suite(
"SBF::GetAttributeLabelAbbreviation", "SBF::GetAttributeLabelAbbreviation",
GetAttributeLabelAbbreviation, GetAttributeLabelAbbreviation,
vector<TestTuple<string, int, int>>({ vector<TestTuple<string, int, int>>({
make_test<string, int, int>( make_test<string, int, int>("should get \"Str.\" for group id 1 and id 1", "Str.", make_tuple(1, 1)),
"should get \"Str.\" for group id 1 and id 1", make_test<string, int, int>("should get \"Dex.\" for group id 1 and id 2", "Dex.", make_tuple(1, 2)),
"Str.", make_test<string, int, int>("should get \"Sta.\" for group id 1 and id 3", "Sta.", make_tuple(1, 3)),
make_tuple(1, 1)), make_test<string, int, int>("should get \"Cha.\" for group id 2 and id 1", "Cha.", make_tuple(2, 1)),
make_test<string, int, int>( make_test<string, int, int>("should get \"Man.\" for group id 2 and id 2", "Man.", make_tuple(2, 2)),
"should get \"Dex.\" for group id 1 and id 2", make_test<string, int, int>("should get \"App.\" for group id 2 and id 3", "App.", make_tuple(2, 3)),
"Dex.", make_test<string, int, int>("should get \"Int.\" for group id 3 and id 1", "Int.", make_tuple(3, 1)),
make_tuple(1, 2)), make_test<string, int, int>("should get \"Per.\" for group id 3 and id 2", "Per.", make_tuple(3, 2)),
make_test<string, int, int>( make_test<string, int, int>("should get \"Wits\" for group id 3 and id 3", "Wits", make_tuple(3, 3)),
"should get \"Sta.\" for group id 1 and id 3", make_test<string, int, int>("should get \"\" for an invalid group id 0", "", make_tuple(0, 1)),
"Sta.", make_test<string, int, int>("should get \"\" for an invalid id 0", "", make_tuple(1, 0)),
make_tuple(1, 3)), make_test<string, int, int>("should get \"\" for invalid group id 4", "", make_tuple(4, 1)),
make_test<string, int, int>( make_test<string, int, int>("should get \"\" for an invalid id 4", "", make_tuple(1, 4)),
"should get \"Cha.\" for group id 2 and id 1", })));
"Cha.",
make_tuple(2, 1)),
make_test<string, int, int>(
"should get \"Man.\" for group id 2 and id 2",
"Man.",
make_tuple(2, 2)),
make_test<string, int, int>(
"should get \"App.\" for group id 2 and id 3",
"App.",
make_tuple(2, 3)),
make_test<string, int, int>(
"should get \"Int.\" for group id 3 and id 1",
"Int.",
make_tuple(3, 1)),
make_test<string, int, int>(
"should get \"Per.\" for group id 3 and id 2",
"Per.",
make_tuple(3, 2)),
make_test<string, int, int>(
"should get \"Wits\" for group id 3 and id 3",
"Wits",
make_tuple(3, 3)),
make_test<string, int, int>(
"should get \"\" for an invalid group id 0",
"",
make_tuple(0, 1)),
make_test<string, int, int>(
"should get \"\" for an invalid id 0",
"",
make_tuple(1, 0)),
make_test<string, int, int>(
"should get \"\" for invalid group id 4",
"",
make_tuple(4, 1)),
make_test<string, int, int>(
"should get \"\" for an invalid id 4",
"",
make_tuple(1, 4)),
})
));
} }
TestResults test_GetPhysicalAttributeLabel() { TestResults test_GetPhysicalAttributeLabel() {
return execute_suite<string, int>(make_test_suite( return execute_suite<string, int>(
"SBF::GetPhysicalAttributeLabel", make_test_suite("SBF::GetPhysicalAttributeLabel",
GetPhysicalAttributeLabel, GetPhysicalAttributeLabel,
vector<TestTuple<string, int>>({ vector<TestTuple<string, int>>({
make_test<string, int>( make_test<string, int>("should get \"Strength\" for id 1", "Strength", make_tuple(1)),
"should get \"Strength\" for id 1", make_test<string, int>("should get \"Dexterity\" for id 2", "Dexterity", make_tuple(2)),
"Strength", make_test<string, int>("should get \"Stamina\" for id 3", "Stamina", make_tuple(3)),
make_tuple(1)), make_test<string, int>("should get \"\" for invalid id 0", "", make_tuple(0)),
make_test<string, int>( make_test<string, int>("should get \"\" for invalid id 4", "", make_tuple(4)),
"should get \"Dexterity\" for id 2", })));
"Dexterity",
make_tuple(2)),
make_test<string, int>(
"should get \"Stamina\" for id 3",
"Stamina",
make_tuple(3)),
make_test<string, int>(
"should get \"\" for invalid id 0",
"",
make_tuple(0)),
make_test<string, int>(
"should get \"\" for invalid id 4",
"",
make_tuple(4)),
})
));
} }
TestResults test_GetPhysicalAttributeLabelAbbreviation() { TestResults test_GetPhysicalAttributeLabelAbbreviation() {
return execute_suite<string, int>(make_test_suite( return execute_suite<string, int>(
"SBF::GetPhysicalAttributeLabelAbbreviation", make_test_suite("SBF::GetPhysicalAttributeLabelAbbreviation",
GetPhysicalAttributeLabelAbbreviation, GetPhysicalAttributeLabelAbbreviation,
vector<TestTuple<string, int>>({ vector<TestTuple<string, int>>({
make_test<string, int>( make_test<string, int>("should get \"Str.\" for id 1", "Str.", make_tuple(1)),
"should get \"Str.\" for id 1", make_test<string, int>("should get \"Dex.\" for id 2", "Dex.", make_tuple(2)),
"Str.", make_test<string, int>("should get \"Sta.\" for id 3", "Sta.", make_tuple(3)),
make_tuple(1)), make_test<string, int>("should get \"\" for invalid id 0", "", make_tuple(0)),
make_test<string, int>( make_test<string, int>("should get \"\" for invalid id 4", "", make_tuple(4)),
"should get \"Dex.\" for id 2", })));
"Dex.",
make_tuple(2)),
make_test<string, int>(
"should get \"Sta.\" for id 3",
"Sta.",
make_tuple(3)),
make_test<string, int>(
"should get \"\" for invalid id 0",
"",
make_tuple(0)),
make_test<string, int>(
"should get \"\" for invalid id 4",
"",
make_tuple(4)),
})
));
} }
TestResults test_GetSocialAttributeLabel() { TestResults test_GetSocialAttributeLabel() {
return execute_suite<string, int>(make_test_suite( return execute_suite<string, int>(
"SBF::GetSocialAttributeLabel", make_test_suite("SBF::GetSocialAttributeLabel",
GetSocialAttributeLabel, GetSocialAttributeLabel,
vector<TestTuple<string, int>>({ vector<TestTuple<string, int>>({
make_test<string, int>( make_test<string, int>("should get \"Charisma\" for id 1", "Charisma", make_tuple(1)),
"should get \"Charisma\" for id 1", make_test<string, int>("should get \"Manipulation\" for id 2", "Manipulation", make_tuple(2)),
"Charisma", make_test<string, int>("should get \"Appearance\" for id 3", "Appearance", make_tuple(3)),
make_tuple(1)), make_test<string, int>("should get \"\" for invalid id 0", "", make_tuple(0)),
make_test<string, int>( make_test<string, int>("should get \"\" for invalid id 4", "", make_tuple(4)),
"should get \"Manipulation\" for id 2", })));
"Manipulation",
make_tuple(2)),
make_test<string, int>(
"should get \"Appearance\" for id 3",
"Appearance",
make_tuple(3)),
make_test<string, int>(
"should get \"\" for invalid id 0",
"",
make_tuple(0)),
make_test<string, int>(
"should get \"\" for invalid id 4",
"",
make_tuple(4)),
})
));
} }
TestResults test_GetSocialAttributeLabelAbbreviation() { TestResults test_GetSocialAttributeLabelAbbreviation() {
return execute_suite<string, int>(make_test_suite( return execute_suite<string, int>(
"SBF::GetSocialAttributeLabelAbbreviation", make_test_suite("SBF::GetSocialAttributeLabelAbbreviation",
GetSocialAttributeLabelAbbreviation, GetSocialAttributeLabelAbbreviation,
vector<TestTuple<string, int>>({ vector<TestTuple<string, int>>({
make_test<string, int>( make_test<string, int>("should get \"Cha.\" for id 1", "Cha.", make_tuple(1)),
"should get \"Cha.\" for id 1", make_test<string, int>("should get \"Man.\" for id 2", "Man.", make_tuple(2)),
"Cha.", make_test<string, int>("should get \"App.\" for id 3", "App.", make_tuple(3)),
make_tuple(1)), make_test<string, int>("should get \"\" for invalid id 0", "", make_tuple(0)),
make_test<string, int>( make_test<string, int>("should get \"\" for invalid id 4", "", make_tuple(4)),
"should get \"Man.\" for id 2", })));
"Man.",
make_tuple(2)),
make_test<string, int>(
"should get \"App.\" for id 3",
"App.",
make_tuple(3)),
make_test<string, int>(
"should get \"\" for invalid id 0",
"",
make_tuple(0)),
make_test<string, int>(
"should get \"\" for invalid id 4",
"",
make_tuple(4)),
})
));
} }
TestResults test_GetMentalAttributeLabel() { TestResults test_GetMentalAttributeLabel() {
return execute_suite<string, int>(make_test_suite( return execute_suite<string, int>(
"SBF::GetMentalAttributeLabel", make_test_suite("SBF::GetMentalAttributeLabel",
GetMentalAttributeLabel, GetMentalAttributeLabel,
vector<TestTuple<string, int>>({ vector<TestTuple<string, int>>({
make_test<string, int>( make_test<string, int>("should get \"Intelligence\" for id 1", "Intelligence", make_tuple(1)),
"should get \"Intelligence\" for id 1", make_test<string, int>("should get \"Perception\" for id 2", "Perception", make_tuple(2)),
"Intelligence", make_test<string, int>("should get \"Wits\" for id 3", "Wits", make_tuple(3)),
make_tuple(1)), make_test<string, int>("should get \"\" for invalid id 0", "", make_tuple(0)),
make_test<string, int>( make_test<string, int>("should get \"\" for invalid id 4", "", make_tuple(4)),
"should get \"Perception\" for id 2", })));
"Perception",
make_tuple(2)),
make_test<string, int>(
"should get \"Wits\" for id 3",
"Wits",
make_tuple(3)),
make_test<string, int>(
"should get \"\" for invalid id 0",
"",
make_tuple(0)),
make_test<string, int>(
"should get \"\" for invalid id 4",
"",
make_tuple(4)),
})
));
} }
TestResults test_GetMentalAttributeLabelAbbreviation() { TestResults test_GetMentalAttributeLabelAbbreviation() {
return execute_suite<string, int>(make_test_suite( return execute_suite<string, int>(
"SBF::GetMentalAttributeLabelAbbreviation", make_test_suite("SBF::GetMentalAttributeLabelAbbreviation",
GetMentalAttributeLabelAbbreviation, GetMentalAttributeLabelAbbreviation,
vector<TestTuple<string, int>>({ vector<TestTuple<string, int>>({
make_test<string, int>( make_test<string, int>("should get \"Int.\" for id 1", "Int.", make_tuple(1)),
"should get \"Int.\" for id 1", make_test<string, int>("should get \"Per.\" for id 2", "Per.", make_tuple(2)),
"Int.", make_test<string, int>("should get \"Wits\" for id 3", "Wits", make_tuple(3)),
make_tuple(1)), make_test<string, int>("should get \"\" for invalid id 0", "", make_tuple(0)),
make_test<string, int>( make_test<string, int>("should get \"\" for invalid id 4", "", make_tuple(4)),
"should get \"Per.\" for id 2", })));
"Per.",
make_tuple(2)),
make_test<string, int>(
"should get \"Wits\" for id 3",
"Wits",
make_tuple(3)),
make_test<string, int>(
"should get \"\" for invalid id 0",
"",
make_tuple(0)),
make_test<string, int>(
"should get \"\" for invalid id 4",
"",
make_tuple(4)),
})
));
} }
TestResults test_GetNumAttributesInGroup() { TestResults test_GetNumAttributesInGroup() {
return execute_suite<int, int>(make_test_suite( return execute_suite<int, int>(
"SBF::GetNumAttributesInGroup", make_test_suite("SBF::GetNumAttributesInGroup",
GetNumAttributesInGroup, GetNumAttributesInGroup,
vector<TestTuple<int, int>>({ vector<TestTuple<int, int>>({
make_test<int, int>( make_test<int, int>("should get 0 for invalid group 0", 0, make_tuple(0)),
"should get 0 for invalid group 0", make_test<int, int>("should get 3 for group 1 kAttributeGroupPhysicalId", 3, make_tuple(1)),
0, make_test<int, int>("should get 3 for group 2 kAttributeGropuSocialId", 3, make_tuple(2)),
make_tuple(0)), make_test<int, int>("should get 3 for group 3 kAttributeGroupMentalId", 3, make_tuple(3)),
make_test<int, int>( make_test<int, int>("should get 0 for invalid group 4", 0, make_tuple(4)),
"should get 3 for group 1 kAttributeGroupPhysicalId", })));
3,
make_tuple(1)),
make_test<int, int>(
"should get 3 for group 2 kAttributeGropuSocialId",
3,
make_tuple(2)),
make_test<int, int>(
"should get 3 for group 3 kAttributeGroupMentalId",
3,
make_tuple(3)),
make_test<int, int>(
"should get 0 for invalid group 4",
0,
make_tuple(4)),
})
));
} }
TestResults test_FillAttributeGroupLabels() { TestResults test_FillAttributeGroupLabels() {
return execute_suite<string>(make_test_suite( return execute_suite<string>(make_test_suite(
"SBF::FillAttributeGroupLabels", "SBF::FillAttributeGroupLabels",
[]()->string { []() -> string {
ostringstream error_message; ostringstream error_message;
vector<string> expected = {"Physical", "Social", "Mental"}; vector<string> expected = {"Physical", "Social", "Mental"};
vector<string> actual = {"This should be removed."}; vector<string> actual = {"This should be removed."};
FillAttributeGroupLabels(actual); FillAttributeGroupLabels(actual);
compare(error_message, expected, actual); compare(error_message, expected, actual);
string error = error_message.str(); string error = error_message.str();
if (error.size() > 0) { if (error.size() > 0) {
return error; return error;
} }
return "no errors"; return "no errors";
}, },
vector<TestTuple<string>>({ vector<TestTuple<string>>({
make_test<string>( make_test<string>("should fill attribute group labels", "no errors", make_tuple()),
"should fill attribute group labels", })));
"no errors",
make_tuple()),
})
));
} }
// void FillAttributeLabelInGroup(std::vector<std::string> attributeLabels); // void FillAttributeLabelInGroup(std::vector<std::string> attributeLabels);
TestResults test_FillAttributeLabelsInGroup() { TestResults test_FillAttributeLabelsInGroup() {
return execute_suite<string, int, vector<string>>(make_test_suite( return execute_suite<string, int, vector<string>>(make_test_suite(
"SBF::FillAttributeLabelsInGroup", "SBF::FillAttributeLabelsInGroup",
[](int id, vector<string> expected)->string { [](int id, vector<string> expected) -> string {
ostringstream error_message; ostringstream error_message;
vector<string> actual = {"This should be removed."}; vector<string> actual = {"This should be removed."};
FillAttributeLabelsInGroup(actual, id); FillAttributeLabelsInGroup(actual, id);
compare(error_message, expected, actual); compare(error_message, expected, actual);
string error = error_message.str(); string error = error_message.str();
if (error.size() > 0) { if (error.size() > 0) {
return error; return error;
} }
return "no errors"; return "no errors";
}, },
vector<TestTuple<string, int, vector<string>>>({ vector<TestTuple<string, int, vector<string>>>({
make_test<string, int, vector<string>>( make_test<string, int, vector<string>>(
"should fill an empty list for invalid group 0", "should fill an empty list for invalid group 0", "no errors", make_tuple(0, vector<string>({}))),
"no errors", make_test<string, int, vector<string>>(
make_tuple(0, vector<string>({}))), "should fill physical attribute labels for group 1 kAttributeGropuPhysicalId",
make_test<string, int, vector<string>>( "no errors",
"should fill physical attribute labels for group 1 kAttributeGropuPhysicalId", make_tuple(1, vector<string>({"Strength", "Dexterity", "Stamina"}))),
"no errors", make_test<string, int, vector<string>>(
make_tuple(1, vector<string>({"Strength", "Dexterity", "Stamina"}))), "should fill social attribute labels for group 2 kAttributeGroupSocialId",
make_test<string, int, vector<string>>( "no errors",
"should fill social attribute labels for group 2 kAttributeGroupSocialId", make_tuple(2, vector<string>({"Charisma", "Manipulation", "Appearance"}))),
"no errors", make_test<string, int, vector<string>>(
make_tuple(2, vector<string>({"Charisma", "Manipulation", "Appearance"}))), "should should fill mental attribute labels for group 3 kAttributeGroupMentalId",
make_test<string, int, vector<string>>( "no errors",
"should should fill mental attribute labels for group 3 kAttributeGroupMentalId", make_tuple(3, vector<string>({"Intelligence", "Perception", "Wits"}))),
"no errors", make_test<string, int, vector<string>>(
make_tuple(3, vector<string>({"Intelligence", "Perception", "Wits"}))), "should fill an empty list for invalid group 4", "no errors", make_tuple(4, vector<string>({}))),
make_test<string, int, vector<string>>( })));
"should fill an empty list for invalid group 4",
"no errors",
make_tuple(4, vector<string>({}))),
})
));
} }
TestResults test_FillPhysicalAttributeLabels() { TestResults test_FillPhysicalAttributeLabels() {
return execute_suite<string>(make_test_suite( return execute_suite<string>(make_test_suite(
"SBF::FillPhysicalAttributeLabels", "SBF::FillPhysicalAttributeLabels",
[]()->string { []() -> string {
ostringstream error_message; ostringstream error_message;
vector<string> expected = {"Strength", "Dexterity", "Stamina"}; vector<string> expected = {"Strength", "Dexterity", "Stamina"};
vector<string> actual = {"This should be removed."}; vector<string> actual = {"This should be removed."};
FillPhysicalAttributeLabels(actual); FillPhysicalAttributeLabels(actual);
compare(error_message, expected, actual); compare(error_message, expected, actual);
string error = error_message.str(); string error = error_message.str();
if (error.size() > 0) { if (error.size() > 0) {
return error; return error;
} }
return "no errors"; return "no errors";
}, },
vector<TestTuple<string>>({ vector<TestTuple<string>>({
make_test<string>( make_test<string>("should fill physical attribute labels", "no errors", make_tuple()),
"should fill physical attribute labels", })));
"no errors",
make_tuple()),
})
));
} }
// void FillSocialAttributeLabels(std::vector<std::string> socialAttributeLabels); // void FillSocialAttributeLabels(std::vector<std::string> socialAttributeLabels);
TestResults test_FillSocialAttributeLabels() { TestResults test_FillSocialAttributeLabels() {
return execute_suite<string>(make_test_suite( return execute_suite<string>(make_test_suite(
"SBF::FillSocialAttributeLabels", "SBF::FillSocialAttributeLabels",
[]()->string { []() -> string {
ostringstream error_message; ostringstream error_message;
vector<string> expected = {"Charisma", "Manipulation", "Appearance"}; vector<string> expected = {"Charisma", "Manipulation", "Appearance"};
vector<string> actual = {"This should be removed."}; vector<string> actual = {"This should be removed."};
FillSocialAttributeLabels(actual); FillSocialAttributeLabels(actual);
compare(error_message, expected, actual); compare(error_message, expected, actual);
string error = error_message.str(); string error = error_message.str();
if (error.size() > 0) { if (error.size() > 0) {
return error; return error;
} }
return "no errors"; return "no errors";
}, },
vector<TestTuple<string>>({ vector<TestTuple<string>>({
make_test<string>( make_test<string>("should fill social attribute labels", "no errors", make_tuple()),
"should fill social attribute labels", })));
"no errors",
make_tuple()),
})
));
} }
// void FillMentalAttributeLabels(std::vector<std::string> mentalAttributeLabels); // void FillMentalAttributeLabels(std::vector<std::string> mentalAttributeLabels);
TestResults test_FillMentalAttributeLabels() { TestResults test_FillMentalAttributeLabels() {
return execute_suite<string>(make_test_suite( return execute_suite<string>(make_test_suite(
"SBF::FillMentalAttributeLabels", "SBF::FillMentalAttributeLabels",
[]()->string { []() -> string {
ostringstream error_message; ostringstream error_message;
vector<string> expected = {"Intelligence", "Perception", "Wits"}; vector<string> expected = {"Intelligence", "Perception", "Wits"};
vector<string> actual = {"This should be removed."}; vector<string> actual = {"This should be removed."};
FillMentalAttributeLabels(actual); FillMentalAttributeLabels(actual);
compare(error_message, expected, actual); compare(error_message, expected, actual);
string error = error_message.str(); string error = error_message.str();
if (error.size() > 0) { if (error.size() > 0) {
return error; return error;
} }
return "no errors"; return "no errors";
}, },
vector<TestTuple<string>>({ vector<TestTuple<string>>({
make_test<string>( make_test<string>("should fill mental attribute labels", "no errors", make_tuple()),
"should fill mental attribute labels", })));
"no errors",
make_tuple()),
})
));
}
} }
} // namespace Test::Attributes

View File

@@ -1,19 +1,20 @@
#include "Backgrounds.h" #include "Backgrounds.h"
#include <string> #include <string>
#include <vector> #include <vector>
namespace SBF { namespace SBF {
std::string GetBackgroundLabel(int backgroundId) { std::string GetBackgroundLabel(int backgroundId) {
if (backgroundId > 0 && backgroundId <= kBackgroundsCount) { if (backgroundId > 0 && backgroundId <= kBackgroundsCount) {
return kBackgroundLabels[backgroundId]; return kBackgroundLabels[backgroundId];
} }
return ""; return "";
} }
void FillBackgroundLabels(std::vector<std::string>& labels) { void FillBackgroundLabels(std::vector<std::string>& labels) {
labels.clear(); labels.clear();
for (int id = 1; id <= kBackgroundsCount; id++) { for (int id = 1; id <= kBackgroundsCount; id++) {
labels.push_back(kBackgroundLabels[id]); labels.push_back(kBackgroundLabels[id]);
} }
} }
} // End namespace SBF } // End namespace SBF

View File

@@ -1,64 +1,65 @@
#ifndef BACKGROUNDS_H__ #ifndef BACKGROUNDS_H__
#define BACKGROUNDS_H__ #define BACKGROUNDS_H__
/*************************************************************************************** /***************************************************************************************
* @file Backgrounds.h * @file Backgrounds.h
* *
* @brief Defines constants and funcions for working with backgrounds. * @brief Defines constants and funcions for working with backgrounds.
* @copyright * @copyright
* Copyright 2023 Tom Hicks * Copyright 2023 Tom Hicks
* 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> #include <vector>
/** \addtogroup Backgrounds /** \addtogroup Backgrounds
* @{ * @{
*/ */
namespace SBF { namespace SBF {
const int kBackgroundPoints = 5; const int kBackgroundPoints = 5;
const int kBackgroundAlliesId = 1; const int kBackgroundAlliesId = 1;
const std::string kBackgroundAlliesLabel = "Allies"; const std::string kBackgroundAlliesLabel = "Allies";
const int kBackgroundContactsId = 2; const int kBackgroundContactsId = 2;
const std::string kBackgroundContactsLabel = "Contacts"; const std::string kBackgroundContactsLabel = "Contacts";
const int kBackgroundFameId = 3; const int kBackgroundFameId = 3;
const std::string kBackgroundFameLabel = "Fame"; const std::string kBackgroundFameLabel = "Fame";
const int kBackgroundGenerationId = 4; const int kBackgroundGenerationId = 4;
const std::string kBackgroundGenerationLabel = "Generation"; const std::string kBackgroundGenerationLabel = "Generation";
const int kBackgroundHerdId = 5; const int kBackgroundHerdId = 5;
const std::string kBackgroundHerdLabel = "Herd"; const std::string kBackgroundHerdLabel = "Herd";
const int kBackgroundInfluenceId = 6; const int kBackgroundInfluenceId = 6;
const std::string kBackgroundInfluenceLabel = "Influence"; const std::string kBackgroundInfluenceLabel = "Influence";
const int kBackgroundMentorId = 7; const int kBackgroundMentorId = 7;
const std::string kBackgroundMentorLabel = "Mentor"; const std::string kBackgroundMentorLabel = "Mentor";
const int kBackgroundResourcesId = 8; const int kBackgroundResourcesId = 8;
const std::string kBackgroundResourcesLabel = "Resources"; const std::string kBackgroundResourcesLabel = "Resources";
const int kBackgroundRetainersId = 9; const int kBackgroundRetainersId = 9;
const std::string kBackgroundRetainersLabel = "Retainers"; const std::string kBackgroundRetainersLabel = "Retainers";
const int kBackgroundStatusId = 10; const int kBackgroundStatusId = 10;
const std::string kBackgroundStatusLabel = "Status"; const std::string kBackgroundStatusLabel = "Status";
const int kBackgroundsCount = 10; const int kBackgroundsCount = 10;
const std::string kBackgroundLabels[] = { const std::string kBackgroundLabels[] = {
"", "",
kBackgroundAlliesLabel, kBackgroundAlliesLabel,
kBackgroundContactsLabel, kBackgroundContactsLabel,
kBackgroundFameLabel, kBackgroundFameLabel,
kBackgroundGenerationLabel, kBackgroundGenerationLabel,
kBackgroundHerdLabel, kBackgroundHerdLabel,
kBackgroundInfluenceLabel, kBackgroundInfluenceLabel,
kBackgroundMentorLabel, kBackgroundMentorLabel,
kBackgroundResourcesLabel, kBackgroundResourcesLabel,
kBackgroundRetainersLabel, kBackgroundRetainersLabel,
kBackgroundStatusLabel, kBackgroundStatusLabel,
}; };
/// @brief Gets the label for a background with a specific id. /// @brief Gets the label for a background with a specific id.
/// @param background_id The id of the background to get the label for. /// @param background_id The id of the background to get the label for.
/// @return The label for the specified background or an empty string if background_id is invalid. /// @return The label for the specified background or an empty string if background_id is invalid.
std::string GetBackgroundLabel(int background_id); std::string GetBackgroundLabel(int background_id);
/// @brief Fills the provided vector with all valid background labels.
/// @param background_labels The vector to fill. It will be emptied first.
void FillBackgroundLabels(std::vector<std::string>& background_labels);
} // End namespace SBF
/// @brief Fills the provided vector with all valid background labels.
/// @param background_labels The vector to fill. It will be emptied first.
void FillBackgroundLabels(std::vector<std::string>& background_labels);
} // End namespace SBF
/** @}*/ /** @}*/
#endif // End !defined BACKGROUNDS_H__ #endif // End !defined BACKGROUNDS_H__

View File

@@ -1,9 +1,11 @@
#include "Backgrounds.h" #include "Backgrounds.h"
#include "test.h"
#include <string>
#include <vector>
#include <tuple>
#include <sstream> #include <sstream>
#include <string>
#include <tuple>
#include <vector>
#include "test.h"
using namespace SBF; using namespace SBF;
using namespace Test; using namespace Test;
@@ -12,98 +14,76 @@ using namespace std;
namespace Test::Backgrounds { namespace Test::Backgrounds {
TestResults test_GetBackgroundLabel(); TestResults test_GetBackgroundLabel();
TestResults test_FillBackgroundLabels(); TestResults test_FillBackgroundLabels();
} // End namespace Test::Attributes } // namespace Test::Backgrounds
using namespace Test::Backgrounds; using namespace Test::Backgrounds;
TestResults main_test_Backgrounds(int argc, char** argv) { TestResults main_test_Backgrounds(int argc, char** argv) {
TestResults results; TestResults results;
results += test_GetBackgroundLabel(); results += test_GetBackgroundLabel();
results += test_FillBackgroundLabels(); results += test_FillBackgroundLabels();
return results; return results;
} }
namespace Test::Backgrounds { namespace Test::Backgrounds {
TestResults test_GetBackgroundLabel() { TestResults test_GetBackgroundLabel() {
return execute_suite<string, int>(make_test_suite( return execute_suite<string, int>(make_test_suite(
"SBF::GetBackgroundLabel", "SBF::GetBackgroundLabel",
GetBackgroundLabel, GetBackgroundLabel,
vector<TestTuple<string, int>>({ vector<TestTuple<string, int>>({
make_test<string, int>( make_test<string, int>("should get \"\" for invalid background 0", "", make_tuple(0)),
"should get \"\" for invalid background 0", make_test<string, int>(
"", "should get \"Allies\" for background 1 kBackgroundAlliesLabel", "Allies", make_tuple(1)),
make_tuple(0)), make_test<string, int>(
make_test<string, int>( "should get \"Contacts\" for background 2 kBackgroundContactsLabel", "Contacts", make_tuple(2)),
"should get \"Allies\" for background 1 kBackgroundAlliesLabel", make_test<string, int>("should get \"Fame\" for background 3 kBackgroundFameLabel", "Fame", make_tuple(3)),
"Allies", make_test<string, int>(
make_tuple(1)), "should get \"Generation\" for background 4 kBackgroundGenerationLabel", "Generation", make_tuple(4)),
make_test<string, int>( make_test<string, int>("should get \"Herd\" for background 5 kBackgroundHerdLabel", "Herd", make_tuple(5)),
"should get \"Contacts\" for background 2 kBackgroundContactsLabel", make_test<string, int>(
"Contacts", "should get \"Influence\" for background 6 kBackgroundInfluenceLabel", "Influence", make_tuple(6)),
make_tuple(2)), make_test<string, int>(
make_test<string, int>( "should get \"Mentor\" for background 7 kBackgroundMentorLabel", "Mentor", make_tuple(7)),
"should get \"Fame\" for background 3 kBackgroundFameLabel", make_test<string, int>(
"Fame", "should get \"Resources\" for background 8 kBackgroundResourcesLabel", "Resources", make_tuple(8)),
make_tuple(3)), make_test<string, int>(
make_test<string, int>( "should get \"Retainers\" for background 9 kBackgroundRetainersLabel", "Retainers", make_tuple(9)),
"should get \"Generation\" for background 4 kBackgroundGenerationLabel", make_test<string, int>(
"Generation", "should get \"Status\" for background 10 kBackgroundStatusLabel", "Status", make_tuple(10)),
make_tuple(4)), make_test<string, int>("should get \"\" for invalid background 11", "", make_tuple(11)),
make_test<string, int>( })));
"should get \"Herd\" for background 5 kBackgroundHerdLabel",
"Herd",
make_tuple(5)),
make_test<string, int>(
"should get \"Influence\" for background 6 kBackgroundInfluenceLabel",
"Influence",
make_tuple(6)),
make_test<string, int>(
"should get \"Mentor\" for background 7 kBackgroundMentorLabel",
"Mentor",
make_tuple(7)),
make_test<string, int>(
"should get \"Resources\" for background 8 kBackgroundResourcesLabel",
"Resources",
make_tuple(8)),
make_test<string, int>(
"should get \"Retainers\" for background 9 kBackgroundRetainersLabel",
"Retainers",
make_tuple(9)),
make_test<string, int>(
"should get \"Status\" for background 10 kBackgroundStatusLabel",
"Status",
make_tuple(10)),
make_test<string, int>(
"should get \"\" for invalid background 11",
"",
make_tuple(11)),
})
));
} }
TestResults test_FillBackgroundLabels() { TestResults test_FillBackgroundLabels() {
return execute_suite<string>(make_test_suite( return execute_suite<string>(make_test_suite(
"SBF::FillBackgroundLabels", "SBF::FillBackgroundLabels",
[]()->string { []() -> string {
ostringstream error_message; ostringstream error_message;
vector<string> expected = {"Allies", "Contacts", "Fame", "Generation", "Herd", "Influence", "Mentor", "Resources", "Retainers", "Status" }; vector<string> expected = {"Allies",
vector<string> actual = {"This should be removed."}; "Contacts",
FillBackgroundLabels(actual); "Fame",
compare(error_message, expected, actual); "Generation",
string error = error_message.str(); "Herd",
if (error.size() > 0) { "Influence",
return error; "Mentor",
} "Resources",
return "no errors"; "Retainers",
}, "Status"};
vector<TestTuple<string>>({ vector<string> actual = {"This should be removed."};
make_test<string>( FillBackgroundLabels(actual);
"should fill background labels", compare(error_message, expected, actual);
"no errors", string error = error_message.str();
make_tuple()), if (error.size() > 0) {
}) return error;
}
)); return "no errors";
},
vector<TestTuple<string>>({
make_test<string>("should fill background labels", "no errors", make_tuple()),
})
));
} }
} // End namespace Test::Backgrounds } // End namespace Test::Backgrounds

File diff suppressed because it is too large Load Diff

View File

@@ -1,166 +1,167 @@
#ifndef CHARACTER_H__ #ifndef CHARACTER_H__
#define CHARACTER_H__ #define CHARACTER_H__
/*************************************************************************************** /***************************************************************************************
* @file Character.h * @file Character.h
* *
* @brief Defines CharacterType. * @brief Defines CharacterType.
* @copyright * @copyright
* Copyright 2023 Tom Hicks * Copyright 2023 Tom Hicks
* 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" #include <cstdint>
#include "Ranks.h" #include <string>
#include <vector>
#include "Abilities.h"
#include "Attributes.h"
#include "Backgrounds.h"
#include "Clans.h" #include "Clans.h"
#include "Colors.h"
#include "Derangements.h" #include "Derangements.h"
#include "Disciplines.h" #include "Disciplines.h"
#include "Ranks.h"
#include "Virtues.h" #include "Virtues.h"
#include "Attributes.h"
#include "Abilities.h"
#include "Backgrounds.h"
#include <string>
#include <cstdint>
#include <vector>
/** \addtogroup Character /** \addtogroup Character
* @{ * @{
*/ */
namespace SBF { namespace SBF {
int GetDisciplinePoints(); int GetDisciplinePoints();
int GetVirtuePoints(); int GetVirtuePoints();
class CharacterType {
public:
CharacterType();
void FillAbilityValues(std::vector<int>abilityValues, int abilityGroupId) const;
void FillAttributeValues(std::vector<int> attributeValues, int groupId) const;
void FillBackgroundValues(std::vector<int> backgroundValues) const;
void FillDisciplineValues(std::vector<int> disciplineValues) const;
void FillDerangements(std::vector<DerangementType> derangements) const;
void FillVirtueValues(std::vector<int> virtueValues) const;
int GetAbilityValue(int abilityGroupId, int abilityId) const;
int GetAttributeValue(int attributeGroupId, int abilityId) const;
int GetBackgroundValue(int backgroundId) const;
std::string GetAllDerangementsLine() const;
int GetDisciplineValue(int disciplineId) const;
int GetKnowledgeValue(int knowledgeId) const;
int GetSkillValue(int skillId) const;
int GetTalentValue(int talentId) const;
int GetVirtueValue(int virtueId) const;
void SetAbilityValue(int abilityGroupId, int abilityId, int value);
void SetAttributeValue(int attributeGroupId, int attributeId, int value);
void SetBackgroundValue(int backgroundId, int value);
void SetDisciplineValue(int disciplineId, int value);
void SetKnowledgeValue(int knowledgeId, int value);
void SetSkillValue(int skillId, int value);
void SetTalentValue(int talentId, int value);
void SetVirtueValue(int virtueId, int value);
std::string name;
std::string player;
std::string chronicle;
std::string haven;
std::string concept;
std::string age;
int genderId;
int clanId;
int natureId;
int demeanorId;
int conscience;
int selfControl;
int courage;
int generation;
std::string roadName;
int roadValue;
int willpower;
int bloodPool;
int derangementId;
private: class CharacterType {
// Disciplines public:
int discipline_animalism; CharacterType();
int discipline_auspex; void FillAbilityValues(std::vector<int> abilityValues, int abilityGroupId) const;
int discipline_bardo; void FillAttributeValues(std::vector<int> attributeValues, int groupId) const;
int discipline_celerity; void FillBackgroundValues(std::vector<int> backgroundValues) const;
int discipline_chimestry; void FillDisciplineValues(std::vector<int> disciplineValues) const;
int discipline_dementation; void FillDerangements(std::vector<DerangementType> derangements) const;
int discipline_dominate; void FillVirtueValues(std::vector<int> virtueValues) const;
int discipline_fortitude; int GetAbilityValue(int abilityGroupId, int abilityId) const;
int discipline_melpominee; int GetAttributeValue(int attributeGroupId, int abilityId) const;
int discipline_mortis; int GetBackgroundValue(int backgroundId) const;
int discipline_mytherceria; std::string GetAllDerangementsLine() const;
int discipline_necromancy; int GetDisciplineValue(int disciplineId) const;
int discipline_obeah; int GetKnowledgeValue(int knowledgeId) const;
int discipline_obfuscate; int GetSkillValue(int skillId) const;
int discipline_obtenebration; int GetTalentValue(int talentId) const;
int discipline_potence; int GetVirtueValue(int virtueId) const;
int discipline_presence; void SetAbilityValue(int abilityGroupId, int abilityId, int value);
int discipline_protean; void SetAttributeValue(int attributeGroupId, int attributeId, int value);
int discipline_quietus; void SetBackgroundValue(int backgroundId, int value);
int discipline_serpentis; void SetDisciplineValue(int disciplineId, int value);
int discipline_spiritus; void SetKnowledgeValue(int knowledgeId, int value);
int discipline_thanantosis; void SetSkillValue(int skillId, int value);
int discipline_thaumaturgy; void SetTalentValue(int talentId, int value);
int discipline_vicissitude; void SetVirtueValue(int virtueId, int value);
// Attributes std::string name;
int attr_strength; std::string player;
int attr_dexterity; std::string chronicle;
int attr_stamina; std::string haven;
int attr_appearance; std::string concept;
int attr_charisma; std::string age;
int attr_manipulation; int genderId;
int attr_intelligence; int clanId;
int attr_perception; int natureId;
int attr_wits; int demeanorId;
int conscience;
int selfControl;
int courage;
int generation;
std::string roadName;
int roadValue;
int willpower;
int bloodPool;
int derangementId;
// Talents private:
int talent_acting; // Disciplines
int talent_alertness; int discipline_animalism;
int talent_athletics; int discipline_auspex;
int talent_brawl; int discipline_bardo;
int talent_dodge; int discipline_celerity;
int talent_empathy; int discipline_chimestry;
int talent_intimidation; int discipline_dementation;
int talent_leadership; int discipline_dominate;
int talent_streetwise; int discipline_fortitude;
int talent_subterfuge; int discipline_melpominee;
int discipline_mortis;
int discipline_mytherceria;
int discipline_necromancy;
int discipline_obeah;
int discipline_obfuscate;
int discipline_obtenebration;
int discipline_potence;
int discipline_presence;
int discipline_protean;
int discipline_quietus;
int discipline_serpentis;
int discipline_spiritus;
int discipline_thanantosis;
int discipline_thaumaturgy;
int discipline_vicissitude;
// Skills // Attributes
int skill_animalKen; int attr_strength;
int skill_drive; int attr_dexterity;
int skill_etiquette; int attr_stamina;
int skill_firearms; int attr_appearance;
int skill_melee; int attr_charisma;
int skill_music; int attr_manipulation;
int skill_repair; int attr_intelligence;
int skill_security; int attr_perception;
int skill_stealth; int attr_wits;
int skill_survival;
// Knowledges // Talents
int knowledge_bureaucracy; int talent_acting;
int knowledge_computer; int talent_alertness;
int knowledge_finance; int talent_athletics;
int knowledge_investigation; int talent_brawl;
int knowledge_law; int talent_dodge;
int knowledge_linguistics; int talent_empathy;
int knowledge_medicine; int talent_intimidation;
int knowledge_occult; int talent_leadership;
int knowledge_politics; int talent_streetwise;
int knowledge_science; int talent_subterfuge;
// Backgrounds // Skills
int background_allies; int skill_animalKen;
int background_contacts; int skill_drive;
int background_fame; int skill_etiquette;
int background_generation; int skill_firearms;
int background_herd; int skill_melee;
int background_influence; int skill_music;
int background_mentor; int skill_repair;
int background_resources; int skill_security;
int background_retainers; int skill_stealth;
int background_status; int skill_survival;
}; // End class CharacterType
} // End namespace SBF // Knowledges
int knowledge_bureaucracy;
int knowledge_computer;
int knowledge_finance;
int knowledge_investigation;
int knowledge_law;
int knowledge_linguistics;
int knowledge_medicine;
int knowledge_occult;
int knowledge_politics;
int knowledge_science;
// Backgrounds
int background_allies;
int background_contacts;
int background_fame;
int background_generation;
int background_herd;
int background_influence;
int background_mentor;
int background_resources;
int background_retainers;
int background_status;
}; // End class CharacterType
} // End namespace SBF
/** @}*/ /** @}*/
#endif // !defined CHARACTER_H__ #endif // !defined CHARACTER_H__

View File

@@ -1,10 +1,11 @@
#include "Character.h" #include "Character.h"
#include "test.h" #include "test.h"
using namespace SBF; using namespace SBF;
using namespace Test; using namespace Test;
TestResults main_test_Character(int argc, char** argv) { TestResults main_test_Character(int argc, char** argv) {
TestResults results; TestResults results;
return results; return results;
} }

View File

@@ -1,19 +1,20 @@
#include "Clans.h" #include "Clans.h"
#include <string> #include <string>
#include <vector> #include <vector>
namespace SBF { namespace SBF {
std::string GetClanLabel(int clanId) { std::string GetClanLabel(int clanId) {
if (clanId > 0 && clanId <= kClansCount) { if (clanId > 0 && clanId <= kClansCount) {
return kClanLabels[clanId]; return kClanLabels[clanId];
} }
return ""; return "";
} }
void FillClanLabels(std::vector<std::string>& labels) { void FillClanLabels(std::vector<std::string>& labels) {
labels.clear(); labels.clear();
for (int id = 1; id <= kClansCount; id++) { for (int id = 1; id <= kClansCount; id++) {
labels.push_back(GetClanLabel(id)); labels.push_back(GetClanLabel(id));
} }
} }
} // End namespace SBF } // End namespace SBF

View File

@@ -1,87 +1,88 @@
#ifndef CLANS_H__ #ifndef CLANS_H__
#define CLANS_H__ #define CLANS_H__
/*************************************************************************************** /***************************************************************************************
* @file Clans.h * @file Clans.h
* *
* @brief Defines constants and functions for working with clans. * @brief Defines constants and functions for working with clans.
* @copyright * @copyright
* Copyright 2023 Tom Hicks * Copyright 2023 Tom Hicks
* 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> #include <vector>
/** \addtogroup Clans /** \addtogroup Clans
* @{ * @{
*/ */
namespace SBF { namespace SBF {
const int kClanAnarch = 1; const int kClanAnarch = 1;
const std::string kClanAnarchLabel = "Anarch"; const std::string kClanAnarchLabel = "Anarch";
const int kClanAssamite = 2; const int kClanAssamite = 2;
const std::string kClanAssamiteLabel = "Assamite"; const std::string kClanAssamiteLabel = "Assamite";
const int kClanBaali = 3; const int kClanBaali = 3;
const std::string kClanBaaliLabel = "Baali"; const std::string kClanBaaliLabel = "Baali";
const int kClanBrujah = 4; const int kClanBrujah = 4;
const std::string kClanBrujahLabel = "Brujah"; const std::string kClanBrujahLabel = "Brujah";
const int kClanCaitiff = 5; const int kClanCaitiff = 5;
const std::string kClanCaitiffLabel = "Caitiff"; const std::string kClanCaitiffLabel = "Caitiff";
const int kClanCappadocian = 6; const int kClanCappadocian = 6;
const std::string kClanCappadocianLabel = "Cappadocian"; const std::string kClanCappadocianLabel = "Cappadocian";
const int kClanGangrel = 7; const int kClanGangrel = 7;
const std::string kClanGangrelLabel = "Gangrel"; const std::string kClanGangrelLabel = "Gangrel";
const int kClanGiovanni = 8; const int kClanGiovanni = 8;
const std::string kClanGiovanniLabel = "Giovanni"; const std::string kClanGiovanniLabel = "Giovanni";
const int kClanInconnu = 9; const int kClanInconnu = 9;
const std::string kClanInconnuLabel = "Inconnu"; const std::string kClanInconnuLabel = "Inconnu";
const int kClanLasombra = 10; const int kClanLasombra = 10;
const std::string kClanLasombraLabel = "Lasombra"; const std::string kClanLasombraLabel = "Lasombra";
const int kClanMalkavian = 11; const int kClanMalkavian = 11;
const std::string kClanMalkavianLabel = "Malkavian"; const std::string kClanMalkavianLabel = "Malkavian";
const int kClanNosferatu = 12; const int kClanNosferatu = 12;
const std::string kClanNosferatuLabel = "Nosferatu"; const std::string kClanNosferatuLabel = "Nosferatu";
const int kClanRavanos = 13; const int kClanRavanos = 13;
const std::string kClanRavanosLabel = "Ravanos"; const std::string kClanRavanosLabel = "Ravanos";
const int kClanSettite = 14; const int kClanSettite = 14;
const std::string kClanSettiteLabel = "Settite"; const std::string kClanSettiteLabel = "Settite";
const int kClanToreador = 15; const int kClanToreador = 15;
const std::string kClanToreadorLabel = "Toreador"; const std::string kClanToreadorLabel = "Toreador";
const int kClanTremere = 16; const int kClanTremere = 16;
const std::string kClanTremereLabel = "Tremere"; const std::string kClanTremereLabel = "Tremere";
const int kClanTzismice = 17; const int kClanTzismice = 17;
const std::string kClanTzismiceLabel = "Tzismice"; const std::string kClanTzismiceLabel = "Tzismice";
const int kClanVentrue = 18; const int kClanVentrue = 18;
const std::string kClanVentrueLabel = "Ventrue"; const std::string kClanVentrueLabel = "Ventrue";
const int kClansCount = 18; const int kClansCount = 18;
const std::string kClanLabels[] = { const std::string kClanLabels[] = {
"", "",
kClanAnarchLabel, kClanAnarchLabel,
kClanAssamiteLabel, kClanAssamiteLabel,
kClanBaaliLabel, kClanBaaliLabel,
kClanBrujahLabel, kClanBrujahLabel,
kClanCaitiffLabel, kClanCaitiffLabel,
kClanCappadocianLabel, kClanCappadocianLabel,
kClanGangrelLabel, kClanGangrelLabel,
kClanGiovanniLabel, kClanGiovanniLabel,
kClanInconnuLabel, kClanInconnuLabel,
kClanLasombraLabel, kClanLasombraLabel,
kClanMalkavianLabel, kClanMalkavianLabel,
kClanNosferatuLabel, kClanNosferatuLabel,
kClanRavanosLabel, kClanRavanosLabel,
kClanSettiteLabel, kClanSettiteLabel,
kClanToreadorLabel, kClanToreadorLabel,
kClanTremereLabel, kClanTremereLabel,
kClanTzismiceLabel, kClanTzismiceLabel,
kClanVentrueLabel, kClanVentrueLabel,
}; };
/// @brief Gets the label for a clan with a specific id. /// @brief Gets the label for a clan with a specific id.
/// @param clan_id The id of the clan to get the label for. /// @param clan_id The id of the clan to get the label for.
/// @return The label of the specified clan or an empty string if clan_id is invalid. /// @return The label of the specified clan or an empty string if clan_id is invalid.
std::string GetClanLabel(int clan_id); std::string GetClanLabel(int clan_id);
/// @brief Fills the provided vector with all valid clans.
/// @param clans The vector to fill. It will be emptied first.
void FillClanLabels(std::vector<std::string>& clans);
} // End namespace SBF
/// @brief Fills the provided vector with all valid clans.
/// @param clans The vector to fill. It will be emptied first.
void FillClanLabels(std::vector<std::string>& clans);
} // End namespace SBF
/** @}*/ /** @}*/
#endif // End !defined CLANS_H__ #endif // End !defined CLANS_H__

View File

@@ -1,9 +1,11 @@
#include "Clans.h" #include "Clans.h"
#include "test.h"
#include <sstream>
#include <string> #include <string>
#include <tuple> #include <tuple>
#include <vector> #include <vector>
#include <sstream>
#include "test.h"
using namespace SBF; using namespace SBF;
using namespace Test; using namespace Test;
@@ -12,130 +14,85 @@ using namespace std;
namespace Test::Clans { namespace Test::Clans {
TestResults test_GetClanLabel(); TestResults test_GetClanLabel();
TestResults test_FillClanLabels(); TestResults test_FillClanLabels();
} // End namespace Test::Clans } // End namespace Test::Clans
using namespace Test::Clans; using namespace Test::Clans;
TestResults main_test_Clans(int argc, char** argv) { TestResults main_test_Clans(int argc, char** argv) {
TestResults results; TestResults results;
results += test_GetClanLabel(); results += test_GetClanLabel();
results += test_FillClanLabels(); results += test_FillClanLabels();
return results; return results;
} }
namespace Test::Clans { namespace Test::Clans {
TestResults test_GetClanLabel() { TestResults test_GetClanLabel() {
return execute_suite<string, int>(make_test_suite( return execute_suite<string, int>(make_test_suite(
"SBF::GetClanLabel", "SBF::GetClanLabel",
GetClanLabel, GetClanLabel,
vector<TestTuple<string, int>>({ vector<TestTuple<string, int>>({
make_test<string, int>( make_test<string, int>("should get \"\" for invalid clan 0", "", make_tuple(0)),
"should get \"\" for invalid clan 0", make_test<string, int>("should get \"Anarch\" for clan 1 kClanAnarch", "Anarch", make_tuple(1)),
"", make_test<string, int>("should get \"Assamite\" for clan 2 kClanAssamite", "Assamite", make_tuple(2)),
make_tuple(0)), make_test<string, int>("should get \"Baali\" for clan 3 kClanBaali", "Baali", make_tuple(3)),
make_test<string, int>( make_test<string, int>("should get \"Brujah\" for clan 4 kClanBrujah", "Brujah", make_tuple(4)),
"should get \"Anarch\" for clan 1 kClanAnarch", make_test<string, int>("should get \"Caitiff\" for clan 5 kClanCaitiff", "Caitiff", make_tuple(5)),
"Anarch", make_test<string, int>(
make_tuple(1)), "should get \"Cappadocian\" for clan 6 kClanCappadocian", "Cappadocian", make_tuple(6)),
make_test<string, int>( make_test<string, int>("should get \"Gangrel\" for clan 7 kClanGangrel", "Gangrel", make_tuple(7)),
"should get \"Assamite\" for clan 2 kClanAssamite", make_test<string, int>("should get \"Giovanni\" for clan 8 kClanGiovanni", "Giovanni", make_tuple(8)),
"Assamite", make_test<string, int>("should get \"Inconnu\" for clan 9 kClanInconnu", "Inconnu", make_tuple(9)),
make_tuple(2)), make_test<string, int>("should get \"Lasombra\" for clan 10 kClanLasombra", "Lasombra", make_tuple(10)),
make_test<string, int>( make_test<string, int>("should get \"Malkavian\" for clan 11 kClanMalkavian", "Malkavian", make_tuple(11)),
"should get \"Baali\" for clan 3 kClanBaali", make_test<string, int>("should get \"Nosferatu\" for clan 12 kClanNosferatu", "Nosferatu", make_tuple(12)),
"Baali", make_test<string, int>("should get \"Ravanos\" for clan 13 kClanRavanos", "Ravanos", make_tuple(13)),
make_tuple(3)), make_test<string, int>("should get \"Settite\" for clan 14 kClanSettite", "Settite", make_tuple(14)),
make_test<string, int>( make_test<string, int>("should get \"Toreador\" for clan 15 kClanToreador", "Toreador", make_tuple(15)),
"should get \"Brujah\" for clan 4 kClanBrujah", make_test<string, int>("should get \"Tremere\" for clan 16 kClanTremere", "Tremere", make_tuple(16)),
"Brujah", make_test<string, int>("should get \"Tzismice\" for clan 17 kClanTzismice", "Tzismice", make_tuple(17)),
make_tuple(4)), make_test<string, int>("should get \"Ventrue\" for clan 18 kClanVentrue", "Ventrue", make_tuple(18)),
make_test<string, int>( make_test<string, int>("should get \"\" for invalid clan 19", "", make_tuple(19)),
"should get \"Caitiff\" for clan 5 kClanCaitiff", })));
"Caitiff",
make_tuple(5)),
make_test<string, int>(
"should get \"Cappadocian\" for clan 6 kClanCappadocian",
"Cappadocian",
make_tuple(6)),
make_test<string, int>(
"should get \"Gangrel\" for clan 7 kClanGangrel",
"Gangrel",
make_tuple(7)),
make_test<string, int>(
"should get \"Giovanni\" for clan 8 kClanGiovanni",
"Giovanni",
make_tuple(8)),
make_test<string, int>(
"should get \"Inconnu\" for clan 9 kClanInconnu",
"Inconnu",
make_tuple(9)),
make_test<string, int>(
"should get \"Lasombra\" for clan 10 kClanLasombra",
"Lasombra",
make_tuple(10)),
make_test<string, int>(
"should get \"Malkavian\" for clan 11 kClanMalkavian",
"Malkavian",
make_tuple(11)),
make_test<string, int>(
"should get \"Nosferatu\" for clan 12 kClanNosferatu",
"Nosferatu",
make_tuple(12)),
make_test<string, int>(
"should get \"Ravanos\" for clan 13 kClanRavanos",
"Ravanos",
make_tuple(13)),
make_test<string, int>(
"should get \"Settite\" for clan 14 kClanSettite",
"Settite",
make_tuple(14)),
make_test<string, int>(
"should get \"Toreador\" for clan 15 kClanToreador",
"Toreador",
make_tuple(15)),
make_test<string, int>(
"should get \"Tremere\" for clan 16 kClanTremere",
"Tremere",
make_tuple(16)),
make_test<string, int>(
"should get \"Tzismice\" for clan 17 kClanTzismice",
"Tzismice",
make_tuple(17)),
make_test<string, int>(
"should get \"Ventrue\" for clan 18 kClanVentrue",
"Ventrue",
make_tuple(18)),
make_test<string, int>(
"should get \"\" for invalid clan 19",
"",
make_tuple(19)),
})
));
} }
TestResults test_FillClanLabels() { TestResults test_FillClanLabels() {
return execute_suite<string>(make_test_suite( return execute_suite<string>(make_test_suite(
"SBF::FillClanLabels", "SBF::FillClanLabels",
[]()->string { []() -> string {
ostringstream error_message; ostringstream error_message;
vector<string> expected = {"Anarch", "Assamite", "Baali", "Brujah", "Caitiff", "Cappadocian", "Gangrel", "Giovanni", "Inconnu", "Lasombra", "Malkavian", "Nosferatu", "Ravanos", "Settite", "Toreador", "Tremere", "Tzismice", "Ventrue"}; vector<string> expected = {"Anarch",
vector<string> actual = {"This should be removed."}; "Assamite",
FillClanLabels(actual); "Baali",
compare(error_message, expected, actual); "Brujah",
string error = error_message.str(); "Caitiff",
if (error.size() > 0) { "Cappadocian",
return error; "Gangrel",
} "Giovanni",
return "no errors"; "Inconnu",
}, "Lasombra",
vector<TestTuple<string>>({ "Malkavian",
make_test<string>( "Nosferatu",
"should fill clan labels", "Ravanos",
"no errors", "Settite",
make_tuple()), "Toreador",
}) "Tremere",
"Tzismice",
)); "Ventrue"};
vector<string> actual = {"This should be removed."};
FillClanLabels(actual);
compare(error_message, expected, actual);
string error = error_message.str();
if (error.size() > 0) {
return error;
}
return "no errors";
},
vector<TestTuple<string>>({
make_test<string>("should fill clan labels", "no errors", make_tuple()),
})
));
} }
} // End namespace Test::Clans } // End namespace Test::Clans

View File

@@ -1,49 +1,49 @@
#include "Colors.h" #include "Colors.h"
namespace SBF { namespace SBF {
// TODO: Update these if they're wrong. They should be the initial color pair.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-variable"
uint8_t g_foregroundColor = kColorDarkWhite;
uint8_t g_backgroundColor = kColorDarkBlack;
#pragma clang diagnostic pop
// void SetForegroundColor(uint8_t foregroundColor) { // TODO: Update these if they're wrong. They should be the initial color pair.
// g_foregroundColor = foregroundColor; #pragma clang diagnostic push
// // TODO: update g_color with g_foregroundColor and g_backgroundColor. #pragma clang diagnostic ignored "-Wunused-variable"
// } uint8_t g_foregroundColor = kColorDarkWhite;
// uint8_t GetForegroundColor() { uint8_t g_backgroundColor = kColorDarkBlack;
// return g_foregroundColor; #pragma clang diagnostic pop
// }
// // ncurses color pair // void SetForegroundColor(uint8_t foregroundColor) {
// uint16_t GetColor() { // g_foregroundColor = foregroundColor;
// return g_color; // // TODO: update g_color with g_foregroundColor and g_backgroundColor.
// } // }
// uint8_t GetForegroundColor() {
// return g_foregroundColor;
// }
void FillColors(std::vector<uint8_t>& colors) { // // ncurses color pair
colors.clear(); // uint16_t GetColor() {
for (uint8_t color = kColorDarkBlack; color <= kColorBrightWhite; color++) { // return g_color;
colors.push_back(color); // }
}
}
uint8_t GetBackgroundColor() { void FillColors(std::vector<uint8_t>& colors) {
return g_backgroundColor; colors.clear();
} for (uint8_t color = kColorDarkBlack; color <= kColorBrightWhite; color++) {
colors.push_back(color);
}
}
uint8_t GetForegroundColor() { uint8_t GetBackgroundColor() {
return g_foregroundColor; return g_backgroundColor;
} }
// TODO: Define what happens when color is invalid. uint8_t GetForegroundColor() {
void SetBackgroundColor(uint8_t color) { return g_foregroundColor;
g_backgroundColor = color; }
}
// TODO: Define what happens when color is invalid. // TODO: Define what happens when color is invalid.
void SetForegroundColor(uint8_t color) { void SetBackgroundColor(uint8_t color) {
g_foregroundColor = color; g_backgroundColor = color;
} }
} // End namespace SBF
// TODO: Define what happens when color is invalid.
void SetForegroundColor(uint8_t color) {
g_foregroundColor = color;
}
} // End namespace SBF

View File

@@ -1,58 +1,59 @@
#ifndef COLORS_H__ #ifndef COLORS_H__
#define COLORS_H__ #define COLORS_H__
/*************************************************************************************** /***************************************************************************************
* @file Colors.h * @file Colors.h
* *
* @brief Defines constants and functions for working with screen colors. * @brief Defines constants and functions for working with screen colors.
* @copyright * @copyright
* Copyright 2023 Tom Hicks * Copyright 2023 Tom Hicks
* 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 <vector> #include <vector>
/** \addtogroup Abilities /** \addtogroup Abilities
* @{ * @{
*/ */
namespace SBF { namespace SBF {
const uint8_t kColorDarkBlack = 0; const uint8_t kColorDarkBlack = 0;
const uint8_t kColorDarkBlue = 1; const uint8_t kColorDarkBlue = 1;
const uint8_t kColorDarkGreen = 2; const uint8_t kColorDarkGreen = 2;
const uint8_t kColorDarkCyan = 3; const uint8_t kColorDarkCyan = 3;
const uint8_t kColorDarkRed = 4; const uint8_t kColorDarkRed = 4;
const uint8_t kColorDarkMagenta = 5; const uint8_t kColorDarkMagenta = 5;
const uint8_t kColorDarkOrange = 6; const uint8_t kColorDarkOrange = 6;
const uint8_t kColorDarkYellow = 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 kColorBrightBlue = 9;
const uint8_t kColorBrightGreen = 10; const uint8_t kColorBrightGreen = 10;
const uint8_t kColorBrightCyan = 11; const uint8_t kColorBrightCyan = 11;
const uint8_t kColorBrightRed = 12; const uint8_t kColorBrightRed = 12;
const uint8_t kColorBrightMagenta = 13; const uint8_t kColorBrightMagenta = 13;
const uint8_t kColorBrightOrange = 14; const uint8_t kColorBrightOrange = 14;
const uint8_t kColorBrightYellow = 14; const uint8_t kColorBrightYellow = 14;
const uint8_t kColorBrightWhite = 15; const uint8_t kColorBrightWhite = 15;
/// @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); void SetForegroundColor(uint8_t color);
/// @brief Gets the stored foreground color. /// @brief Gets the stored foreground color.
/// @return The foreground color. /// @return The foreground color.
uint8_t GetForegroundColor(); 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); void SetBackgroundColor(uint8_t color);
/// @brief Gets the stored background color. /// @brief Gets the stored background color.
/// @return The background color. /// @return The background color.
uint8_t GetBackgroundColor(); uint8_t GetBackgroundColor();
/// @brief Fills the provided vector with all of the possible color values. It will be cleared before filling.
/// @param colors The vector to fill.
void FillColors(std::vector<uint8_t>& colors);
} // End namespace SBF
/// @brief Fills the provided vector with all of the possible color values. It will be cleared before filling.
/// @param colors The vector to fill.
void FillColors(std::vector<uint8_t>& colors);
} // End namespace SBF
/** @}*/ /** @}*/
#endif // End !defined COLORS_H__ #endif // End !defined COLORS_H__

View File

@@ -1,9 +1,11 @@
#include "Colors.h" #include "Colors.h"
#include "test.h"
#include <string> #include <string>
#include <tuple> #include <tuple>
#include <vector> #include <vector>
#include "test.h"
using namespace SBF; using namespace SBF;
using namespace Test; using namespace Test;
using namespace std; using namespace std;
@@ -14,387 +16,245 @@ TestResults test_GetBackgroundColor();
TestResults test_GetForegroundColor(); TestResults test_GetForegroundColor();
TestResults test_SetBackgroundColor(); TestResults test_SetBackgroundColor();
TestResults test_SetForegroundColor(); TestResults test_SetForegroundColor();
} // End namespace Test::Colors } // End namespace Test::Colors
using namespace Test::Colors;
namespace SBF {
extern uint8_t g_foregroundColor;
extern uint8_t g_backgroundColor;
}
TestResults main_test_Colors(int argc, char** argv) {
TestResults results;
results += test_FillColors();
results += test_GetBackgroundColor();
results += test_GetForegroundColor();
results += test_SetBackgroundColor();
results += test_SetForegroundColor();
return results; using namespace Test::Colors;
namespace SBF {
extern uint8_t g_foregroundColor;
extern uint8_t g_backgroundColor;
} // namespace SBF
TestResults main_test_Colors(int argc, char** argv) {
TestResults results;
results += test_FillColors();
results += test_GetBackgroundColor();
results += test_GetForegroundColor();
results += test_SetBackgroundColor();
results += test_SetForegroundColor();
return results;
} }
namespace Test::Colors { namespace Test::Colors {
TestResults test_FillColors() { TestResults test_FillColors() {
return execute_suite<string>(make_test_suite( return execute_suite<string>(make_test_suite(
"SBF::FillColors", "SBF::FillColors",
[]()->string { []() -> string {
ostringstream error_message; ostringstream error_message;
vector<uint8_t> expected = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; vector<uint8_t> expected = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
vector<uint8_t> actual = {255}; vector<uint8_t> actual = {255};
FillColors(actual); FillColors(actual);
compare(error_message, expected, actual); compare(error_message, expected, actual);
string error = error_message.str(); string error = error_message.str();
if (error.size() > 0) { if (error.size() > 0) {
return error; return error;
} }
return "no errors"; return "no errors";
}, },
vector<TestTuple<string>>({ vector<TestTuple<string>>({
make_test<string>( make_test<string>("should fill colors", "no errors", make_tuple()),
"should fill colors", })));
"no errors",
make_tuple()),
})
));
} }
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_backgroundColor = 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(
"SBF::GetBackgroundColor", "SBF::GetBackgroundColor",
fnToTest, fnToTest,
vector<TestTuple<uint32_t, uint32_t>>({ vector<TestTuple<uint32_t, uint32_t>>({
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorDarkBlack when background color is 0", "should get kColorDarkBlack when background color is 0", kColorDarkBlack, make_tuple(0U)),
kColorDarkBlack, make_test<uint32_t, uint32_t>(
make_tuple(0U)), "should get kColorDarkBlue when background color is 1", kColorDarkBlue, make_tuple(1U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorDarkBlue when background color is 1", "should get kColorDarkGreen when background color is 2", kColorDarkGreen, make_tuple(2U)),
kColorDarkBlue, make_test<uint32_t, uint32_t>(
make_tuple(1U)), "should get kColorDarkCyan when background color is 3", kColorDarkCyan, make_tuple(3U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorDarkGreen when background color is 2", "should get kColorDarkRed when background color is 4", kColorDarkRed, make_tuple(4U)),
kColorDarkGreen, make_test<uint32_t, uint32_t>(
make_tuple(2U)), "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 kColorDarkCyan when background color is 3", "should get kColorDarkOrange when background color is 6", kColorDarkOrange, make_tuple(6U)),
kColorDarkCyan, make_test<uint32_t, uint32_t>(
make_tuple(3U)), "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 kColorDarkRed when background color is 4", "should get kColorDarkWhite when background color is 7", kColorDarkWhite, make_tuple(7U)),
kColorDarkRed, make_test<uint32_t, uint32_t>(
make_tuple(4U)), "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 kColorDarkMagenta when background color is 5", "should get kColorBrightBlue when background color is 9", kColorBrightBlue, make_tuple(9U)),
kColorDarkMagenta, make_test<uint32_t, uint32_t>(
make_tuple(5U)), "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 kColorDarkOrange when background color is 6", "should get kColorBrightCyan when background color is 11", kColorBrightCyan, make_tuple(11U)),
kColorDarkOrange, make_test<uint32_t, uint32_t>(
make_tuple(6U)), "should get kColorBrightRed when background color is 12", kColorBrightRed, make_tuple(12U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorDarkYellow when background color is 6", "should get kColorBrightMagenta when background color is 13", kColorBrightMagenta, make_tuple(13U)),
kColorDarkYellow, make_test<uint32_t, uint32_t>(
make_tuple(6U)), "should get kColorBrightOrange when background color is 14", kColorBrightOrange, make_tuple(14U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorDarkWhite when background color is 7", "should get kColorBrightYellow when background color is 14", kColorBrightYellow, make_tuple(14U)),
kColorDarkWhite, make_test<uint32_t, uint32_t>(
make_tuple(7U)), "should get kColorBrightWhite when background color is 15", kColorBrightWhite, make_tuple(15U)),
make_test<uint32_t, uint32_t>( })));
"should get kColorBrightBlack when background color is 8",
kColorBrightBlack,
make_tuple(8U)),
make_test<uint32_t, uint32_t>(
"should get kColorBrightBlue when background color is 9",
kColorBrightBlue,
make_tuple(9U)),
make_test<uint32_t, uint32_t>(
"should get kColorBrightGreen when background color is 10",
kColorBrightGreen,
make_tuple(10U)),
make_test<uint32_t, uint32_t>(
"should get kColorBrightCyan when background color is 11",
kColorBrightCyan,
make_tuple(11U)),
make_test<uint32_t, uint32_t>(
"should get kColorBrightRed when background color is 12",
kColorBrightRed,
make_tuple(12U)),
make_test<uint32_t, uint32_t>(
"should get kColorBrightMagenta when background color is 13",
kColorBrightMagenta,
make_tuple(13U)),
make_test<uint32_t, uint32_t>(
"should get kColorBrightOrange when background color is 14",
kColorBrightOrange,
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>(
"should get kColorBrightWhite when background color is 15",
kColorBrightWhite,
make_tuple(15U)),
})
));
} }
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_foregroundColor = 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(
"SBF::GetForegroundColor", "SBF::GetForegroundColor",
fnToTest, fnToTest,
vector<TestTuple<uint32_t, uint32_t>>({ vector<TestTuple<uint32_t, uint32_t>>({
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorDarkBlack when foreground color is 0", "should get kColorDarkBlack when foreground color is 0", kColorDarkBlack, make_tuple(0U)),
kColorDarkBlack, make_test<uint32_t, uint32_t>(
make_tuple(0U)), "should get kColorDarkBlue when foreground color is 1", kColorDarkBlue, make_tuple(1U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorDarkBlue when foreground color is 1", "should get kColorDarkGreen when foreground color is 2", kColorDarkGreen, make_tuple(2U)),
kColorDarkBlue, make_test<uint32_t, uint32_t>(
make_tuple(1U)), "should get kColorDarkCyan when foreground color is 3", kColorDarkCyan, make_tuple(3U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorDarkGreen when foreground color is 2", "should get kColorDarkRed when foreground color is 4", kColorDarkRed, make_tuple(4U)),
kColorDarkGreen, make_test<uint32_t, uint32_t>(
make_tuple(2U)), "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 kColorDarkCyan when foreground color is 3", "should get kColorDarkOrange when foreground color is 6", kColorDarkOrange, make_tuple(6U)),
kColorDarkCyan, make_test<uint32_t, uint32_t>(
make_tuple(3U)), "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 kColorDarkRed when foreground color is 4", "should get kColorDarkWhite when foreground color is 7", kColorDarkWhite, make_tuple(7U)),
kColorDarkRed, make_test<uint32_t, uint32_t>(
make_tuple(4U)), "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 kColorDarkMagenta when foreground color is 5", "should get kColorBrightBlue when foreground color is 9", kColorBrightBlue, make_tuple(9U)),
kColorDarkMagenta, make_test<uint32_t, uint32_t>(
make_tuple(5U)), "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 kColorDarkOrange when foreground color is 6", "should get kColorBrightCyan when foreground color is 11", kColorBrightCyan, make_tuple(11U)),
kColorDarkOrange, make_test<uint32_t, uint32_t>(
make_tuple(6U)), "should get kColorBrightRed when foreground color is 12", kColorBrightRed, make_tuple(12U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorDarkYellow when foreground color is 6", "should get kColorBrightMagenta when foreground color is 13", kColorBrightMagenta, make_tuple(13U)),
kColorDarkYellow, make_test<uint32_t, uint32_t>(
make_tuple(6U)), "should get kColorBrightOrange when foreground color is 14", kColorBrightOrange, make_tuple(14U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should get kColorDarkWhite when foreground color is 7", "should get kColorBrightYellow when foreground color is 14", kColorBrightYellow, make_tuple(14U)),
kColorDarkWhite, make_test<uint32_t, uint32_t>(
make_tuple(7U)), "should get kColorBrightWhite when foreground color is 15", kColorBrightWhite, make_tuple(15U)),
make_test<uint32_t, uint32_t>( })));
"should get kColorBrightBlack when foreground color is 8",
kColorBrightBlack,
make_tuple(8U)),
make_test<uint32_t, uint32_t>(
"should get kColorBrightBlue when foreground color is 9",
kColorBrightBlue,
make_tuple(9U)),
make_test<uint32_t, uint32_t>(
"should get kColorBrightGreen when foreground color is 10",
kColorBrightGreen,
make_tuple(10U)),
make_test<uint32_t, uint32_t>(
"should get kColorBrightCyan when foreground color is 11",
kColorBrightCyan,
make_tuple(11U)),
make_test<uint32_t, uint32_t>(
"should get kColorBrightRed when foreground color is 12",
kColorBrightRed,
make_tuple(12U)),
make_test<uint32_t, uint32_t>(
"should get kColorBrightMagenta when foreground color is 13",
kColorBrightMagenta,
make_tuple(13U)),
make_test<uint32_t, uint32_t>(
"should get kColorBrightOrange when foreground color is 14",
kColorBrightOrange,
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>(
"should get kColorBrightWhite when foreground color is 15",
kColorBrightWhite,
make_tuple(15U)),
})
));
} }
TestResults test_SetBackgroundColor() { TestResults test_SetBackgroundColor() {
auto fnToTest = [](uint8_t color)->uint8_t { auto fnToTest = [](uint8_t color) -> uint8_t {
SBF::g_backgroundColor = 255; SBF::g_backgroundColor = 255;
SetBackgroundColor(color); SetBackgroundColor(color);
return SBF::g_backgroundColor; return SBF::g_backgroundColor;
}; };
return execute_suite<uint32_t, uint32_t>(make_test_suite( return execute_suite<uint32_t, uint32_t>(make_test_suite(
"SBF::SetBackgroundColor", "SBF::SetBackgroundColor",
fnToTest, fnToTest,
vector<TestTuple<uint32_t, uint32_t>>({ vector<TestTuple<uint32_t, uint32_t>>({
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should set background color to kColorDarkBlack when color is 0", "should set background color to kColorDarkBlack when color is 0", kColorDarkBlack, make_tuple(0U)),
kColorDarkBlack, make_test<uint32_t, uint32_t>(
make_tuple(0U)), "should set background color to kColorDarkBlue when color is 1", kColorDarkBlue, make_tuple(1U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should set background color to kColorDarkBlue when color is 1", "should set background color to kColorDarkGreen when color is 2", kColorDarkGreen, make_tuple(2U)),
kColorDarkBlue, make_test<uint32_t, uint32_t>(
make_tuple(1U)), "should set background color to kColorDarkCyan when color is 3", kColorDarkCyan, make_tuple(3U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should set background color to kColorDarkGreen when color is 2", "should set background color to kColorDarkRed when color is 4", kColorDarkRed, make_tuple(4U)),
kColorDarkGreen, make_test<uint32_t, uint32_t>(
make_tuple(2U)), "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 kColorDarkCyan when color is 3", "should set background color to kColorDarkOrange when color is 6", kColorDarkOrange, make_tuple(6U)),
kColorDarkCyan, make_test<uint32_t, uint32_t>(
make_tuple(3U)), "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 kColorDarkRed when color is 4", "should set background color to kColorDarkWhite when color is 7", kColorDarkWhite, make_tuple(7U)),
kColorDarkRed, make_test<uint32_t, uint32_t>(
make_tuple(4U)), "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 kColorDarkMagenta when color is 5", "should set background color to kColorBrightBlue when color is 9", kColorBrightBlue, make_tuple(9U)),
kColorDarkMagenta, make_test<uint32_t, uint32_t>(
make_tuple(5U)), "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 kColorDarkOrange when color is 6", "should set background color to kColorBrightCyan when color is 11", kColorBrightCyan, make_tuple(11U)),
kColorDarkOrange, make_test<uint32_t, uint32_t>(
make_tuple(6U)), "should set background color to kColorBrightRed when color is 12", kColorBrightRed, make_tuple(12U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>("should set background color to kColorBrightMagenta when color is 13",
"should set background color to kColorDarkYellow when color is 6", kColorBrightMagenta,
kColorDarkYellow, make_tuple(13U)),
make_tuple(6U)), make_test<uint32_t, uint32_t>("should set background color to kColorBrightOrange when color is 14",
make_test<uint32_t, uint32_t>( kColorBrightOrange,
"should set background color to kColorDarkWhite when color is 7", make_tuple(14U)),
kColorDarkWhite, make_test<uint32_t, uint32_t>("should set background color to kColorBrightYellow when color is 14",
make_tuple(7U)), kColorBrightYellow,
make_test<uint32_t, uint32_t>( make_tuple(14U)),
"should set background color to kColorBrightBlack when color is 8", make_test<uint32_t, uint32_t>(
kColorBrightBlack, "should set background color to kColorBrightWhite when color is 15", kColorBrightWhite, make_tuple(15U)),
make_tuple(8U)), })));
make_test<uint32_t, uint32_t>(
"should set background color to kColorBrightBlue when color is 9",
kColorBrightBlue,
make_tuple(9U)),
make_test<uint32_t, uint32_t>(
"should set background color to kColorBrightGreen when color is 10",
kColorBrightGreen,
make_tuple(10U)),
make_test<uint32_t, uint32_t>(
"should set background color to kColorBrightCyan when color is 11",
kColorBrightCyan,
make_tuple(11U)),
make_test<uint32_t, uint32_t>(
"should set background color to kColorBrightRed when color is 12",
kColorBrightRed,
make_tuple(12U)),
make_test<uint32_t, uint32_t>(
"should set background color to kColorBrightMagenta when color is 13",
kColorBrightMagenta,
make_tuple(13U)),
make_test<uint32_t, uint32_t>(
"should set background color to kColorBrightOrange when color is 14",
kColorBrightOrange,
make_tuple(14U)),
make_test<uint32_t, uint32_t>(
"should set background color to kColorBrightYellow when color is 14",
kColorBrightYellow,
make_tuple(14U)),
make_test<uint32_t, uint32_t>(
"should set background color to kColorBrightWhite when color is 15",
kColorBrightWhite,
make_tuple(15U)),
})
));
} }
TestResults test_SetForegroundColor() { TestResults test_SetForegroundColor() {
auto fnToTest = [](uint8_t color)->uint8_t { auto fnToTest = [](uint8_t color) -> uint8_t {
SBF::g_foregroundColor = 255; SBF::g_foregroundColor = 255;
SetForegroundColor(color); SetForegroundColor(color);
return SBF::g_foregroundColor; return SBF::g_foregroundColor;
}; };
return execute_suite<uint32_t, uint32_t>(make_test_suite( return execute_suite<uint32_t, uint32_t>(make_test_suite(
"SBF::SetForegroundColor", "SBF::SetForegroundColor",
fnToTest, fnToTest,
vector<TestTuple<uint32_t, uint32_t>>({ vector<TestTuple<uint32_t, uint32_t>>({
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should set foreground color to kColorDarkBlack when color is 0", "should set foreground color to kColorDarkBlack when color is 0", kColorDarkBlack, make_tuple(0U)),
kColorDarkBlack, make_test<uint32_t, uint32_t>(
make_tuple(0U)), "should set foreground color to kColorDarkBlue when color is 1", kColorDarkBlue, make_tuple(1U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should set foreground color to kColorDarkBlue when color is 1", "should set foreground color to kColorDarkGreen when color is 2", kColorDarkGreen, make_tuple(2U)),
kColorDarkBlue, make_test<uint32_t, uint32_t>(
make_tuple(1U)), "should set foreground color to kColorDarkCyan when color is 3", kColorDarkCyan, make_tuple(3U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>(
"should set foreground color to kColorDarkGreen when color is 2", "should set foreground color to kColorDarkRed when color is 4", kColorDarkRed, make_tuple(4U)),
kColorDarkGreen, make_test<uint32_t, uint32_t>(
make_tuple(2U)), "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 kColorDarkCyan when color is 3", "should set foreground color to kColorDarkOrange when color is 6", kColorDarkOrange, make_tuple(6U)),
kColorDarkCyan, make_test<uint32_t, uint32_t>(
make_tuple(3U)), "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 kColorDarkRed when color is 4", "should set foreground color to kColorDarkWhite when color is 7", kColorDarkWhite, make_tuple(7U)),
kColorDarkRed, make_test<uint32_t, uint32_t>(
make_tuple(4U)), "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 kColorDarkMagenta when color is 5", "should set foreground color to kColorBrightBlue when color is 9", kColorBrightBlue, make_tuple(9U)),
kColorDarkMagenta, make_test<uint32_t, uint32_t>(
make_tuple(5U)), "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 kColorDarkOrange when color is 6", "should set foreground color to kColorBrightCyan when color is 11", kColorBrightCyan, make_tuple(11U)),
kColorDarkOrange, make_test<uint32_t, uint32_t>(
make_tuple(6U)), "should set foreground color to kColorBrightRed when color is 12", kColorBrightRed, make_tuple(12U)),
make_test<uint32_t, uint32_t>( make_test<uint32_t, uint32_t>("should set foreground color to kColorBrightMagenta when color is 13",
"should set foreground color to kColorDarkYellow when color is 6", kColorBrightMagenta,
kColorDarkYellow, make_tuple(13U)),
make_tuple(6U)), make_test<uint32_t, uint32_t>("should set foreground color to kColorBrightOrange when color is 14",
make_test<uint32_t, uint32_t>( kColorBrightOrange,
"should set foreground color to kColorDarkWhite when color is 7", make_tuple(14U)),
kColorDarkWhite, make_test<uint32_t, uint32_t>("should set foreground color to kColorBrightYellow when color is 14",
make_tuple(7U)), kColorBrightYellow,
make_test<uint32_t, uint32_t>( make_tuple(14U)),
"should set foreground color to kColorBrightBlack when color is 8", make_test<uint32_t, uint32_t>(
kColorBrightBlack, "should set foreground color to kColorBrightWhite when color is 15", kColorBrightWhite, make_tuple(15U)),
make_tuple(8U)), })));
make_test<uint32_t, uint32_t>(
"should set foreground color to kColorBrightBlue when color is 9",
kColorBrightBlue,
make_tuple(9U)),
make_test<uint32_t, uint32_t>(
"should set foreground color to kColorBrightGreen when color is 10",
kColorBrightGreen,
make_tuple(10U)),
make_test<uint32_t, uint32_t>(
"should set foreground color to kColorBrightCyan when color is 11",
kColorBrightCyan,
make_tuple(11U)),
make_test<uint32_t, uint32_t>(
"should set foreground color to kColorBrightRed when color is 12",
kColorBrightRed,
make_tuple(12U)),
make_test<uint32_t, uint32_t>(
"should set foreground color to kColorBrightMagenta when color is 13",
kColorBrightMagenta,
make_tuple(13U)),
make_test<uint32_t, uint32_t>(
"should set foreground color to kColorBrightOrange when color is 14",
kColorBrightOrange,
make_tuple(14U)),
make_test<uint32_t, uint32_t>(
"should set foreground color to kColorBrightYellow when color is 14",
kColorBrightYellow,
make_tuple(14U)),
make_test<uint32_t, uint32_t>(
"should set foreground color to kColorBrightWhite when color is 15",
kColorBrightWhite,
make_tuple(15U)),
})
));
} }
} // End namespace Test::Colors } // End namespace Test::Colors

View File

@@ -1,4 +1,5 @@
#include "Derangements.h" #include "Derangements.h"
#include <ostream> #include <ostream>
#include <sstream> #include <sstream>
@@ -6,36 +7,33 @@ namespace SBF {
using std::ostream; using std::ostream;
bool operator==(const DerangementType& left, const DerangementType& right) { bool operator==(const DerangementType& left, const DerangementType& right) {
return left.description == right.description && return left.description == right.description && left.id == right.id && left.label == right.label
left.id == right.id && && left.textColor == right.textColor;
left.label == right.label &&
left.textColor == right.textColor;
} }
bool operator!=(const DerangementType& left, const DerangementType& right) { bool operator!=(const DerangementType& left, const DerangementType& right) {
return !(left == right); return !(left == right);
} }
ostream& operator<<(ostream& os, const DerangementType& derangement) { ostream& operator<<(ostream& os, const DerangementType& derangement) {
//Derangement: {id: 1, label: \"kDerangementAmnesiaLabel\", description: \"kDerangementAmnesiaDescription\", textColor: kDerangementAmnesiaTextColor} // Derangement: {id: 1, label: \"kDerangementAmnesiaLabel\", description: \"kDerangementAmnesiaDescription\",
os << "Derangement: {id: " << derangement.id // textColor: kDerangementAmnesiaTextColor}
<< ", label: \"" << derangement.label os << "Derangement: {id: " << derangement.id << ", label: \"" << derangement.label << "\", description: \""
<< "\", description: \"" << derangement.description << derangement.description << "\", textColor: " << (int)derangement.textColor << "}";
<< "\", textColor: " << (int)derangement.textColor << "}"; return os;
return os;
} }
DerangementType GetDerangement(int derangementId) { DerangementType GetDerangement(int derangementId) {
if (derangementId >0 && derangementId <= kDerangementsCount) { if (derangementId > 0 && derangementId <= kDerangementsCount) {
return kDerangements[derangementId]; return kDerangements[derangementId];
} }
return {}; return {};
} }
void FillDerangements(std::vector<DerangementType>& derangements) { void FillDerangements(std::vector<DerangementType>& derangements) {
derangements.clear(); derangements.clear();
for (int id = 1; id <= kDerangementsCount; id++) { for (int id = 1; id <= kDerangementsCount; id++) {
derangements.push_back(GetDerangement(id)); derangements.push_back(GetDerangement(id));
} }
} }
} // End namespace SBF } // End namespace SBF

View File

@@ -2,212 +2,221 @@
#define DERANGEMENTS_H__ #define DERANGEMENTS_H__
#include "Colors.h" #include "Colors.h"
/*************************************************************************************** /***************************************************************************************
* @file Derangements.h * @file Derangements.h
* *
* @brief Defines constants and functions for working with derangements. * @brief Defines constants and functions for working with derangements.
* @copyright * @copyright
* Copyright 2023 Tom Hicks * Copyright 2023 Tom Hicks
* 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> #include <vector>
/** \addtogroup Derangements /** \addtogroup Derangements
* @{ * @{
*/ */
namespace SBF { namespace SBF {
struct DerangementType { struct DerangementType {
int id; int id;
std::string label; std::string label;
std::string description; std::string description;
uint8_t textColor; uint8_t textColor;
}; };
const int kDerangementAmnesiaId = 1; const int kDerangementAmnesiaId = 1;
const uint8_t kDerangementAmnesiaTextColor= kColorDarkRed; const uint8_t kDerangementAmnesiaTextColor = kColorDarkRed;
const std::string kDerangementAmnesiaLabel = "Amnesia"; const std::string kDerangementAmnesiaLabel = "Amnesia";
const std::string kDerangementAmnesiaDescription = R"---(You forget a segment of your past. Additionally in some cases a character can forget abilities and be unable to use them for the duration.)---"; const std::string kDerangementAmnesiaDescription =
const int kDerangementDelusionsOfGrandeurId = 2; R"---(You forget a segment of your past. Additionally in some cases a character can forget abilities and be unable to use them for the duration.)---";
const uint8_t kDerangementDelusionsOfGrandeurTextColor= kColorDarkMagenta; const int kDerangementDelusionsOfGrandeurId = 2;
const std::string kDerangementDelusionsOfGrandeurLabel = "Delusions of Grandeur"; const uint8_t kDerangementDelusionsOfGrandeurTextColor = kColorDarkMagenta;
const std::string kDerangementDelusionsOfGrandeurDescription = R"---(You imagine you are better than you are.)---"; const std::string kDerangementDelusionsOfGrandeurLabel = "Delusions of Grandeur";
const int kDerangementFantasyId = 3; const std::string kDerangementDelusionsOfGrandeurDescription = R"---(You imagine you are better than you are.)---";
const uint8_t kDerangementFantasyTextColor= kColorDarkOrange; const int kDerangementFantasyId = 3;
const std::string kDerangementFantasyLabel = "Fantasy"; const uint8_t kDerangementFantasyTextColor = kColorDarkOrange;
const std::string kDerangementFantasyDescription = R"---(You enter a self-created world where you are the forgotten hero.)---"; const std::string kDerangementFantasyLabel = "Fantasy";
const int kDerangementManicDepressionId = 4; const std::string kDerangementFantasyDescription =
const uint8_t kDerangementManicDepressionTextColor= kColorDarkWhite; R"---(You enter a self-created world where you are the forgotten hero.)---";
const std::string kDerangementManicDepressionLabel = "Manic-Depression"; const int kDerangementManicDepressionId = 4;
const std::string kDerangementManicDepressionDescription = R"---(You sink into deep and fitful depressions, showing no interest in anything which used to captivate your interests. You will go along with others rather than use the energy to resist. Occasional fits of great energy grab hold of you, and you will work for hours or even days on your projects. During this time you will resist even the need for sleep as you burn up blood and Willpower on your schemes.)---"; const uint8_t kDerangementManicDepressionTextColor = kColorDarkWhite;
const int kDerangementMultiplePersonalitiesId = 5; const std::string kDerangementManicDepressionLabel = "Manic-Depression";
const uint8_t kDerangementMultiplePersonalitiesTextColor= kColorDarkBlue; const std::string kDerangementManicDepressionDescription =
const std::string kDerangementMultiplePersonalitiesLabel = "Multiple Personalities"; R"---(You sink into deep and fitful depressions, showing no interest in anything which used to captivate your interests. You will go along with others rather than use the energy to resist. Occasional fits of great energy grab hold of you, and you will work for hours or even days on your projects. During this time you will resist even the need for sleep as you burn up blood and Willpower on your schemes.)---";
const std::string kDerangementMultiplePersonalitiesDescription = R"---(You possess a number of new personalities. You have amore than one Mature, and will switch between them. Thus you regain Willpower points in defferent ways at defferent times)---"; const int kDerangementMultiplePersonalitiesId = 5;
const int kDerangementObsessionId = 6; const uint8_t kDerangementMultiplePersonalitiesTextColor = kColorDarkBlue;
const uint8_t kDerangementObsessionTextColor= kColorBrightGreen; const std::string kDerangementMultiplePersonalitiesLabel = "Multiple Personalities";
const std::string kDerangementObsessionLabel = "Obsession"; const std::string kDerangementMultiplePersonalitiesDescription =
const std::string kDerangementObsessionDescription = R"---(You become obsessed with some interest or fetish.)---"; R"---(You possess a number of new personalities. You have amore than one Mature, and will switch between them. Thus you regain Willpower points in defferent ways at defferent times)---";
const int kDerangementOvercompensationId = 7; const int kDerangementObsessionId = 6;
const uint8_t kDerangementOvercompensationTextColor= kColorBrightCyan; const uint8_t kDerangementObsessionTextColor = kColorBrightGreen;
const std::string kDerangementOvercompensationLabel = "Overcompensation"; const std::string kDerangementObsessionLabel = "Obsession";
const std::string kDerangementOvercompensationDescription = R"---(You make up for your moral weaknesses by playing up your strengths to an extreme. You don't think you can frenzy and won't stop it.)---"; const std::string kDerangementObsessionDescription = R"---(You become obsessed with some interest or fetish.)---";
const int kDerangementParanoiaId = 8; const int kDerangementOvercompensationId = 7;
const uint8_t kDerangementParanoiaTextColor= kColorBrightRed; const uint8_t kDerangementOvercompensationTextColor = kColorBrightCyan;
const std::string kDerangementParanoiaLabel = "Paranoia"; const std::string kDerangementOvercompensationLabel = "Overcompensation";
const std::string kDerangementParanoiaDescription = R"---(You are convinced that you are being hunted. You hold even your closest Friends under suspicion.)---"; const std::string kDerangementOvercompensationDescription =
const int kDerangementPerfectionId = 9; R"---(You make up for your moral weaknesses by playing up your strengths to an extreme. You don't think you can frenzy and won't stop it.)---";
const uint8_t kDerangementPerfectionTextColor= kColorBrightMagenta; const int kDerangementParanoiaId = 8;
const std::string kDerangementPerfectionLabel = "Perfection"; const uint8_t kDerangementParanoiaTextColor = kColorBrightRed;
const std::string kDerangementPerfectionDescription = R"---(All your energy is directed toward preventing anything from going wong. When it does you must make a self-control roll or frenzy.)---"; const std::string kDerangementParanoiaLabel = "Paranoia";
const int kDerangementRegressionId = 10; const std::string kDerangementParanoiaDescription =
const uint8_t kDerangementRegressionTextColor= kColorBrightYellow; R"---(You are convinced that you are being hunted. You hold even your closest Friends under suspicion.)---";
const std::string kDerangementRegressionLabel = "Regression"; const int kDerangementPerfectionId = 9;
const std::string kDerangementRegressionDescription = R"---(You become childlike retreating to an earlier time when less was expected of you Willpower is regained inthe way a Child's is.)---"; const uint8_t kDerangementPerfectionTextColor = kColorBrightMagenta;
const DerangementType kDerangementUnknown = {0, "", "", 0}; const std::string kDerangementPerfectionLabel = "Perfection";
const DerangementType kDerangementAmnesia = { const std::string kDerangementPerfectionDescription =
kDerangementAmnesiaId, R"---(All your energy is directed toward preventing anything from going wong. When it does you must make a self-control roll or frenzy.)---";
kDerangementAmnesiaLabel, const int kDerangementRegressionId = 10;
kDerangementAmnesiaDescription, const uint8_t kDerangementRegressionTextColor = kColorBrightYellow;
kDerangementAmnesiaTextColor, const std::string kDerangementRegressionLabel = "Regression";
}; const std::string kDerangementRegressionDescription =
const DerangementType kDerangementDelusionsOfGrandeur = { R"---(You become childlike retreating to an earlier time when less was expected of you Willpower is regained inthe way a Child's is.)---";
kDerangementDelusionsOfGrandeurId, const DerangementType kDerangementUnknown = {0, "", "", 0};
kDerangementDelusionsOfGrandeurLabel, const DerangementType kDerangementAmnesia = {
kDerangementDelusionsOfGrandeurDescription, kDerangementAmnesiaId,
kDerangementDelusionsOfGrandeurTextColor, kDerangementAmnesiaLabel,
}; kDerangementAmnesiaDescription,
const DerangementType kDerangementFantasy = { kDerangementAmnesiaTextColor,
kDerangementFantasyId, };
kDerangementFantasyLabel, const DerangementType kDerangementDelusionsOfGrandeur = {
kDerangementFantasyDescription, kDerangementDelusionsOfGrandeurId,
kDerangementFantasyTextColor, kDerangementDelusionsOfGrandeurLabel,
}; kDerangementDelusionsOfGrandeurDescription,
const DerangementType kDerangementManicDepression = { kDerangementDelusionsOfGrandeurTextColor,
kDerangementManicDepressionId, };
kDerangementManicDepressionLabel, const DerangementType kDerangementFantasy = {
kDerangementManicDepressionDescription, kDerangementFantasyId,
kDerangementManicDepressionTextColor, kDerangementFantasyLabel,
}; kDerangementFantasyDescription,
const DerangementType kDerangementMultiplePersonalities = { kDerangementFantasyTextColor,
kDerangementMultiplePersonalitiesId, };
kDerangementMultiplePersonalitiesLabel, const DerangementType kDerangementManicDepression = {
kDerangementMultiplePersonalitiesDescription, kDerangementManicDepressionId,
kDerangementMultiplePersonalitiesTextColor, kDerangementManicDepressionLabel,
}; kDerangementManicDepressionDescription,
const DerangementType kDerangementObsession = { kDerangementManicDepressionTextColor,
kDerangementObsessionId, };
kDerangementObsessionLabel, const DerangementType kDerangementMultiplePersonalities = {
kDerangementObsessionDescription, kDerangementMultiplePersonalitiesId,
kDerangementObsessionTextColor, kDerangementMultiplePersonalitiesLabel,
}; kDerangementMultiplePersonalitiesDescription,
const DerangementType kDerangementOvercompensation = { kDerangementMultiplePersonalitiesTextColor,
kDerangementOvercompensationId, };
kDerangementOvercompensationLabel, const DerangementType kDerangementObsession = {
kDerangementOvercompensationDescription, kDerangementObsessionId,
kDerangementOvercompensationTextColor, kDerangementObsessionLabel,
}; kDerangementObsessionDescription,
const DerangementType kDerangementParanoia = { kDerangementObsessionTextColor,
kDerangementParanoiaId, };
kDerangementParanoiaLabel, const DerangementType kDerangementOvercompensation = {
kDerangementParanoiaDescription, kDerangementOvercompensationId,
kDerangementParanoiaTextColor, kDerangementOvercompensationLabel,
}; kDerangementOvercompensationDescription,
const DerangementType kDerangementPerfection = { kDerangementOvercompensationTextColor,
kDerangementPerfectionId, };
kDerangementPerfectionLabel, const DerangementType kDerangementParanoia = {
kDerangementPerfectionDescription, kDerangementParanoiaId,
kDerangementPerfectionTextColor, kDerangementParanoiaLabel,
}; kDerangementParanoiaDescription,
const DerangementType kDerangementRegression = { kDerangementParanoiaTextColor,
kDerangementRegressionId, };
kDerangementRegressionLabel, const DerangementType kDerangementPerfection = {
kDerangementRegressionDescription, kDerangementPerfectionId,
kDerangementRegressionTextColor, kDerangementPerfectionLabel,
}; kDerangementPerfectionDescription,
const int kDerangementsCount = 10; kDerangementPerfectionTextColor,
};
const DerangementType kDerangementRegression = {
kDerangementRegressionId,
kDerangementRegressionLabel,
kDerangementRegressionDescription,
kDerangementRegressionTextColor,
};
const int kDerangementsCount = 10;
const uint8_t kDerangementTextColors[] = { const uint8_t kDerangementTextColors[] = {
0, 0,
kDerangementAmnesiaTextColor, kDerangementAmnesiaTextColor,
kDerangementDelusionsOfGrandeurTextColor, kDerangementDelusionsOfGrandeurTextColor,
kDerangementFantasyTextColor, kDerangementFantasyTextColor,
kDerangementManicDepressionTextColor, kDerangementManicDepressionTextColor,
kDerangementMultiplePersonalitiesTextColor, kDerangementMultiplePersonalitiesTextColor,
kDerangementObsessionTextColor, kDerangementObsessionTextColor,
kDerangementOvercompensationTextColor, kDerangementOvercompensationTextColor,
kDerangementParanoiaTextColor, kDerangementParanoiaTextColor,
kDerangementPerfectionTextColor, kDerangementPerfectionTextColor,
kDerangementRegressionTextColor, kDerangementRegressionTextColor,
}; };
const std::string kDerangementLabels[] = { const std::string kDerangementLabels[] = {
"", "",
kDerangementAmnesiaLabel, kDerangementAmnesiaLabel,
kDerangementDelusionsOfGrandeurLabel, kDerangementDelusionsOfGrandeurLabel,
kDerangementFantasyLabel, kDerangementFantasyLabel,
kDerangementManicDepressionLabel, kDerangementManicDepressionLabel,
kDerangementMultiplePersonalitiesLabel, kDerangementMultiplePersonalitiesLabel,
kDerangementObsessionLabel, kDerangementObsessionLabel,
kDerangementOvercompensationLabel, kDerangementOvercompensationLabel,
kDerangementParanoiaLabel, kDerangementParanoiaLabel,
kDerangementPerfectionLabel, kDerangementPerfectionLabel,
kDerangementRegressionLabel, kDerangementRegressionLabel,
}; };
const std::string kDerangementDescriptions[] = { const std::string kDerangementDescriptions[] = {
"", "",
kDerangementAmnesiaDescription, kDerangementAmnesiaDescription,
kDerangementDelusionsOfGrandeurDescription, kDerangementDelusionsOfGrandeurDescription,
kDerangementFantasyDescription, kDerangementFantasyDescription,
kDerangementManicDepressionDescription, kDerangementManicDepressionDescription,
kDerangementMultiplePersonalitiesDescription, kDerangementMultiplePersonalitiesDescription,
kDerangementObsessionDescription, kDerangementObsessionDescription,
kDerangementOvercompensationDescription, kDerangementOvercompensationDescription,
kDerangementParanoiaDescription, kDerangementParanoiaDescription,
kDerangementPerfectionDescription, kDerangementPerfectionDescription,
kDerangementRegressionDescription, kDerangementRegressionDescription,
}; };
const DerangementType kDerangements[] = { const DerangementType kDerangements[] = {
{0, "", "", 0}, {0, "", "", 0},
kDerangementAmnesia, kDerangementAmnesia,
kDerangementDelusionsOfGrandeur, kDerangementDelusionsOfGrandeur,
kDerangementFantasy, kDerangementFantasy,
kDerangementManicDepression, kDerangementManicDepression,
kDerangementMultiplePersonalities, kDerangementMultiplePersonalities,
kDerangementObsession, kDerangementObsession,
kDerangementOvercompensation, kDerangementOvercompensation,
kDerangementParanoia, kDerangementParanoia,
kDerangementPerfection, kDerangementPerfection,
kDerangementRegression, kDerangementRegression,
}; };
/// @brief Determines the equality of two derangements. /// @brief Determines the equality of two derangements.
/// @param left A derangement to compare. /// @param left A derangement to compare.
/// @param right A derangement to compare. /// @param right A derangement to compare.
/// @return True if the derangements are equal and false otherwise. /// @return True if the derangements are equal and false otherwise.
bool operator==(const DerangementType& left, const DerangementType& right); bool operator==(const DerangementType& left, const DerangementType& right);
/// @brief Determines the inequality of two derangements. /// @brief Determines the inequality of two derangements.
/// @param left A derangement to compare. /// @param left A derangement to compare.
/// @param right A derangement to compare. /// @param right A derangement to compare.
/// @return Tre if the derangements are unequal and false otherwise. /// @return Tre if the derangements are unequal and false otherwise.
bool operator!=(const DerangementType& left, const DerangementType& right); bool operator!=(const DerangementType& left, const DerangementType& right);
/// @brief Writes a derangement to an ostream. /// @brief Writes a derangement to an ostream.
/// @param os The ostream to write to. /// @param os The ostream to write to.
/// @param derangement The derangement to write. /// @param derangement The derangement to write.
/// @return The provided ostream for chaining. /// @return The provided ostream for chaining.
std::ostream& operator<<(std::ostream& os, const DerangementType& derangement); std::ostream& operator<<(std::ostream& os, const DerangementType& derangement);
/// @brief Gets the derangement with a specific id. /// @brief Gets the derangement with a specific id.
/// @param derangement_id The id of the derangement to get. /// @param derangement_id The id of the derangement to get.
/// @return The derangement with an id of derangement_id or kDerangementUnknown if derangement_id is invalid. /// @return The derangement with an id of derangement_id or kDerangementUnknown if derangement_id is invalid.
DerangementType GetDerangement(int derangement_id); DerangementType GetDerangement(int derangement_id);
/// @brief Fills the provided vector with all valid derangements.
/// @param derangements The vector to fill. It will be emptied first.
void FillDerangements(std::vector<DerangementType>& derangements);
} // End namespace SBF
/// @brief Fills the provided vector with all valid derangements.
/// @param derangements The vector to fill. It will be emptied first.
void FillDerangements(std::vector<DerangementType>& derangements);
} // End namespace SBF
/** @}*/ /** @}*/
#endif // End !defined DERANGEMENTS_H__ #endif // End !defined DERANGEMENTS_H__

View File

@@ -1,9 +1,11 @@
#include "Derangements.h" #include "Derangements.h"
#include "test.h"
#include <string>
#include <vector>
#include <tuple>
#include <sstream> #include <sstream>
#include <string>
#include <tuple>
#include <vector>
#include "test.h"
using namespace SBF; using namespace SBF;
using namespace Test; using namespace Test;
@@ -12,223 +14,240 @@ using namespace std;
namespace Test::Derangements { namespace Test::Derangements {
TestResults test_DerangementType_operator_extract(); TestResults test_DerangementType_operator_extract();
TestResults test_DerangementType_operator_equal_to(); TestResults test_DerangementType_operator_equal_to();
TestResults test_DerangementType_operator_not_equal_to(); TestResults test_DerangementType_operator_not_equal_to();
TestResults test_GetDerangement(); TestResults test_GetDerangement();
TestResults test_FillDerangements(); TestResults test_FillDerangements();
} // End Test::Derangements } // namespace Test::Derangements
using namespace Test::Derangements; using namespace Test::Derangements;
TestResults main_test_Derangements(int argc, char** argv) { TestResults main_test_Derangements(int argc, char** argv) {
TestResults results; TestResults results;
results += test_DerangementType_operator_extract(); results += test_DerangementType_operator_extract();
results += test_DerangementType_operator_equal_to(); results += test_DerangementType_operator_equal_to();
results += test_DerangementType_operator_not_equal_to(); results += test_DerangementType_operator_not_equal_to();
results += test_GetDerangement(); results += test_GetDerangement();
results += test_FillDerangements(); results += test_FillDerangements();
return results; return results;
} }
namespace Test::Derangements { namespace Test::Derangements {
TestResults test_GetDerangement() { TestResults test_GetDerangement() {
return execute_suite<DerangementType, int>(make_test_suite( return execute_suite<DerangementType, int>(make_test_suite(
"SBF::GetDerangement", "SBF::GetDerangement",
GetDerangement, GetDerangement,
vector<TestTuple<DerangementType, int>>({ vector<TestTuple<DerangementType, int>>({
make_test<DerangementType, int>( make_test<DerangementType, int>("should get {0, "
"should get {0, "", "", 0} for invalid derangement id 0", ", "
{0, "", "", 0}, ", 0} for invalid derangement id 0",
make_tuple(0)), {0, "", "", 0},
make_test<DerangementType, int>( make_tuple(0)),
"should get {kDerangementAmnesiaId, kDerangementAmnesiaLabel, kDerangementAmnesiaDescription, kDerangementAmnesiaTextColor} for derangement id 1", make_test<DerangementType, int>(
kDerangementAmnesia, "should get {kDerangementAmnesiaId, kDerangementAmnesiaLabel, kDerangementAmnesiaDescription, "
make_tuple(1)), "kDerangementAmnesiaTextColor} for derangement id 1",
make_test<DerangementType, int>( kDerangementAmnesia,
"should get {kDerangementDelusionsOfGrandeurId, kDerangementDelusionsOfGrandeurLabel, kDerangementDelusionsOfGrandeurDescription, kDerangementDelusionsOfGrandeurTextColor} for derangement id 2", make_tuple(1)),
kDerangementDelusionsOfGrandeur, make_test<DerangementType, int>(
make_tuple(2)), "should get {kDerangementDelusionsOfGrandeurId, kDerangementDelusionsOfGrandeurLabel, "
make_test<DerangementType, int>( "kDerangementDelusionsOfGrandeurDescription, kDerangementDelusionsOfGrandeurTextColor} for derangement "
"should get {kDerangementFantasyId, kDerangementFantasyLabel, kDerangementFantasyDescription, kDerangementFantasyTextColor} for derangement id 3", "id 2",
kDerangementFantasy, kDerangementDelusionsOfGrandeur,
make_tuple(3)), make_tuple(2)),
make_test<DerangementType, int>( make_test<DerangementType, int>(
"should get {kDerangementManicDepressionId, kDerangementManicDepressionLabel, kDerangementManicDepressionDescription, kDerangementManicDepressionTextColor} for derangement id 4", "should get {kDerangementFantasyId, kDerangementFantasyLabel, kDerangementFantasyDescription, "
kDerangementManicDepression, "kDerangementFantasyTextColor} for derangement id 3",
make_tuple(4)), kDerangementFantasy,
make_test<DerangementType, int>( make_tuple(3)),
"should get {kDerangementMultiplePersonalitiesId, kDerangementMultiplePersonalitiesLabel, kDerangementMultiplePersonalitiesDescription, kDerangementMultiplePersonalitiesTextColor} for derangement id 5", make_test<DerangementType, int>(
kDerangementMultiplePersonalities, "should get {kDerangementManicDepressionId, kDerangementManicDepressionLabel, "
make_tuple(5)), "kDerangementManicDepressionDescription, kDerangementManicDepressionTextColor} for derangement id 4",
make_test<DerangementType, int>( kDerangementManicDepression,
"should get {kDerangementObsessionId, kDerangementObsessionLabel, kDerangementObsessionDescription, kDerangementObsessionTextColor} for derangement id 6", make_tuple(4)),
kDerangementObsession, make_test<DerangementType, int>(
make_tuple(6)), "should get {kDerangementMultiplePersonalitiesId, kDerangementMultiplePersonalitiesLabel, "
make_test<DerangementType, int>( "kDerangementMultiplePersonalitiesDescription, kDerangementMultiplePersonalitiesTextColor} for "
"should get {kDerangementOvercompensationId, kDerangementOvercompensationLabel, kDerangementOvercompensationDescription, kDerangementOvercompensationTextColor} for derangement id 7", "derangement id 5",
kDerangementOvercompensation, kDerangementMultiplePersonalities,
make_tuple(7)), make_tuple(5)),
make_test<DerangementType, int>( make_test<DerangementType, int>(
"should get {kDerangementParanoiaId, kDerangementParanoiaLabel, kDerangementParanoiaDescription, kDerangementParanoiaTextColor} for derangement id 8", "should get {kDerangementObsessionId, kDerangementObsessionLabel, kDerangementObsessionDescription, "
kDerangementParanoia, "kDerangementObsessionTextColor} for derangement id 6",
make_tuple(8)), kDerangementObsession,
make_test<DerangementType, int>( make_tuple(6)),
"should get {kDerangementPerfectionId, kDerangementPerfectionLabel, kDerangementPerfectionDescription, kDerangementPerfectionTextColor} for derangement id 9", make_test<DerangementType, int>(
kDerangementPerfection, "should get {kDerangementOvercompensationId, kDerangementOvercompensationLabel, "
make_tuple(9)), "kDerangementOvercompensationDescription, kDerangementOvercompensationTextColor} for derangement id 7",
make_test<DerangementType, int>( kDerangementOvercompensation,
"should get {kDerangementRegressionId, kDerangementRegressionLabel, kDerangementRegressionDescription, kDerangementRegressionTextColor} for derangement id 10", make_tuple(7)),
kDerangementRegression, make_test<DerangementType, int>(
make_tuple(10)), "should get {kDerangementParanoiaId, kDerangementParanoiaLabel, kDerangementParanoiaDescription, "
make_test<DerangementType, int>( "kDerangementParanoiaTextColor} for derangement id 8",
"should get {0, "", "", 0} for invalid derangement id 11", kDerangementParanoia,
{0, "", "", 0}, make_tuple(8)),
make_tuple(11)), make_test<DerangementType, int>(
}) "should get {kDerangementPerfectionId, kDerangementPerfectionLabel, kDerangementPerfectionDescription, "
)); "kDerangementPerfectionTextColor} for derangement id 9",
kDerangementPerfection,
make_tuple(9)),
make_test<DerangementType, int>(
"should get {kDerangementRegressionId, kDerangementRegressionLabel, kDerangementRegressionDescription, "
"kDerangementRegressionTextColor} for derangement id 10",
kDerangementRegression,
make_tuple(10)),
make_test<DerangementType, int>("should get {0, "
", "
", 0} for invalid derangement id 11",
{0, "", "", 0},
make_tuple(11)),
})));
} }
TestResults test_FillDerangements() { TestResults test_FillDerangements() {
auto fnToTest = []()->string { auto fnToTest = []() -> string {
ostringstream error_message; ostringstream error_message;
vector<DerangementType> expected = { vector<DerangementType> expected = {
kDerangementAmnesia, kDerangementAmnesia,
kDerangementDelusionsOfGrandeur, kDerangementDelusionsOfGrandeur,
kDerangementFantasy, kDerangementFantasy,
kDerangementManicDepression, kDerangementManicDepression,
kDerangementMultiplePersonalities, kDerangementMultiplePersonalities,
kDerangementObsession, kDerangementObsession,
kDerangementOvercompensation, kDerangementOvercompensation,
kDerangementParanoia, kDerangementParanoia,
kDerangementPerfection, kDerangementPerfection,
kDerangementRegression, kDerangementRegression,
};
vector<DerangementType> actual = {
{-1, "This should be removed.", "This should be removed.", 255}
};
FillDerangements(actual);
compare(error_message, expected, actual);
string error = error_message.str();
if (error.size() > 0) {
return error;
}
return "no errors";
}; };
return execute_suite<string>(make_test_suite( vector<DerangementType> actual = {{-1, "This should be removed.", "This should be removed.", 255}};
"SBF::FillDerangements", FillDerangements(actual);
fnToTest, compare(error_message, expected, actual);
vector<TestTuple<string>>({ string error = error_message.str();
make_test<string>( if (error.size() > 0) {
"should fill derangements", return error;
"no errors", }
make_tuple()), return "no errors";
}) };
)); return execute_suite<string>(
make_test_suite("SBF::FillDerangements",
fnToTest,
vector<TestTuple<string>>({
make_test<string>("should fill derangements", "no errors", make_tuple()),
})));
} }
TestResults test_DerangementType_operator_extract() { TestResults test_DerangementType_operator_extract() {
return execute_suite<string, DerangementType>(make_test_suite( return execute_suite<string, DerangementType>(make_test_suite(
"SBF::DerangementType::operator<<", "SBF::DerangementType::operator<<",
[](const DerangementType& derangement){ [](const DerangementType& derangement) {
ostringstream os; ostringstream os;
os << derangement; os << derangement;
return os.str(); return os.str();
}, },
vector<TestTuple<string, DerangementType>>({ vector<TestTuple<string, DerangementType>>({
make_test<string, DerangementType>( make_test<string, DerangementType>("should print amnesia",
"should print amnesia", "Derangement: {id: 1, label: \"" + kDerangementAmnesiaLabel
"Derangement: {id: 1, label: \"" + kDerangementAmnesiaLabel + "\", description: \"" + kDerangementAmnesiaDescription + "\", textColor: 4}", + "\", description: \"" + kDerangementAmnesiaDescription
make_tuple(kDerangementAmnesia)), + "\", textColor: 4}",
make_test<string, DerangementType>( make_tuple(kDerangementAmnesia)),
"should print delusions of grandeur", make_test<string, DerangementType>("should print delusions of grandeur",
"Derangement: {id: 2, label: \"" + kDerangementDelusionsOfGrandeurLabel + "\", description: \"" + kDerangementDelusionsOfGrandeurDescription + "\", textColor: 5}", "Derangement: {id: 2, label: \"" + kDerangementDelusionsOfGrandeurLabel
make_tuple(kDerangementDelusionsOfGrandeur)), + "\", description: \"" + kDerangementDelusionsOfGrandeurDescription
make_test<string, DerangementType>( + "\", textColor: 5}",
"should print fantasy", make_tuple(kDerangementDelusionsOfGrandeur)),
"Derangement: {id: 3, label: \"" + kDerangementFantasyLabel + "\", description: \"" + kDerangementFantasyDescription + "\", textColor: 6}", make_test<string, DerangementType>("should print fantasy",
make_tuple(kDerangementFantasy)), "Derangement: {id: 3, label: \"" + kDerangementFantasyLabel
make_test<string, DerangementType>( + "\", description: \"" + kDerangementFantasyDescription
"should print manic depression", + "\", textColor: 6}",
"Derangement: {id: 4, label: \"" + kDerangementManicDepressionLabel + "\", description: \"" + kDerangementManicDepressionDescription + "\", textColor: 7}", make_tuple(kDerangementFantasy)),
make_tuple(kDerangementManicDepression)), make_test<string, DerangementType>("should print manic depression",
make_test<string, DerangementType>( "Derangement: {id: 4, label: \"" + kDerangementManicDepressionLabel
"should print multiple personalities", + "\", description: \"" + kDerangementManicDepressionDescription
"Derangement: {id: 5, label: \"" + kDerangementMultiplePersonalitiesLabel + "\", description: \"" + kDerangementMultiplePersonalitiesDescription + "\", textColor: 1}", + "\", textColor: 7}",
make_tuple(kDerangementMultiplePersonalities)), make_tuple(kDerangementManicDepression)),
make_test<string, DerangementType>( make_test<string, DerangementType>("should print multiple personalities",
"should print obsession", "Derangement: {id: 5, label: \"" + kDerangementMultiplePersonalitiesLabel
"Derangement: {id: 6, label: \"" + kDerangementObsessionLabel + "\", description: \"" + kDerangementObsessionDescription + "\", textColor: 10}", + "\", description: \"" + kDerangementMultiplePersonalitiesDescription
make_tuple(kDerangementObsession)), + "\", textColor: 1}",
make_test<string, DerangementType>( make_tuple(kDerangementMultiplePersonalities)),
"should print overcompensation", make_test<string, DerangementType>("should print obsession",
"Derangement: {id: 7, label: \"" + kDerangementOvercompensationLabel + "\", description: \"" + kDerangementOvercompensationDescription + "\", textColor: 11}", "Derangement: {id: 6, label: \"" + kDerangementObsessionLabel
make_tuple(kDerangementOvercompensation)), + "\", description: \"" + kDerangementObsessionDescription
make_test<string, DerangementType>( + "\", textColor: 10}",
"should print paranoia", make_tuple(kDerangementObsession)),
"Derangement: {id: 8, label: \"" + kDerangementParanoiaLabel + "\", description: \"" + kDerangementParanoiaDescription + "\", textColor: 12}", make_test<string, DerangementType>("should print overcompensation",
make_tuple(kDerangementParanoia)), "Derangement: {id: 7, label: \"" + kDerangementOvercompensationLabel
make_test<string, DerangementType>( + "\", description: \"" + kDerangementOvercompensationDescription
"should print perfection", + "\", textColor: 11}",
"Derangement: {id: 9, label: \"" + kDerangementPerfectionLabel + "\", description: \"" + kDerangementPerfectionDescription + "\", textColor: 13}", make_tuple(kDerangementOvercompensation)),
make_tuple(kDerangementPerfection)), make_test<string, DerangementType>("should print paranoia",
make_test<string, DerangementType>( "Derangement: {id: 8, label: \"" + kDerangementParanoiaLabel
"should print regression", + "\", description: \"" + kDerangementParanoiaDescription
"Derangement: {id: 10, label: \"" + kDerangementRegressionLabel + "\", description: \"" + kDerangementRegressionDescription + "\", textColor: 14}", + "\", textColor: 12}",
make_tuple(kDerangementRegression)), make_tuple(kDerangementParanoia)),
make_test<string, DerangementType>( make_test<string, DerangementType>("should print perfection",
"should print an unknown derangement", "Derangement: {id: 9, label: \"" + kDerangementPerfectionLabel
"Derangement: {id: 0, label: \"MyLabel\", description: \"My Description\", textColor: 5}", + "\", description: \"" + kDerangementPerfectionDescription
make_tuple((DerangementType){ + "\", textColor: 13}",
0, "MyLabel", "My Description", 5})), make_tuple(kDerangementPerfection)),
}) make_test<string, DerangementType>("should print regression",
)); "Derangement: {id: 10, label: \"" + kDerangementRegressionLabel
+ "\", description: \"" + kDerangementRegressionDescription
+ "\", textColor: 14}",
make_tuple(kDerangementRegression)),
make_test<string, DerangementType>(
"should print an unknown derangement",
"Derangement: {id: 0, label: \"MyLabel\", description: \"My Description\", textColor: 5}",
make_tuple((DerangementType){0, "MyLabel", "My Description", 5})),
})));
} }
TestResults test_DerangementType_operator_equal_to() { TestResults test_DerangementType_operator_equal_to() {
return execute_suite<bool, DerangementType, DerangementType>( return execute_suite<bool, DerangementType, DerangementType>(make_test_suite(
make_test_suite( "SBF::DerangementType::operator==",
"SBF::DerangementType::operator==", [](const DerangementType& left, const DerangementType& right) { return left == right; },
[](const DerangementType& left, const DerangementType& right) { vector<TestTuple<bool, DerangementType, DerangementType>>({
return left == right; make_test<bool, DerangementType, DerangementType>(
}, "should return true when comparing a derangement to itself",
vector<TestTuple<bool, DerangementType, DerangementType>>({ true,
make_test<bool, DerangementType, DerangementType>( make_tuple(kDerangementDelusionsOfGrandeur, kDerangementDelusionsOfGrandeur)),
"should return true when comparing a derangement to itself", make_test<bool, DerangementType, DerangementType>(
true, "should return true when comparing two different instances created with the same values",
make_tuple(kDerangementDelusionsOfGrandeur, kDerangementDelusionsOfGrandeur)), true,
make_test<bool, DerangementType, DerangementType>( make_tuple(kDerangementFantasy,
"should return true when comparing two different instances created with the same values", DerangementType({kDerangementFantasyId,
true, kDerangementFantasyLabel,
make_tuple(kDerangementFantasy, DerangementType({kDerangementFantasyId, kDerangementFantasyLabel, kDerangementFantasyDescription, kDerangementFantasyTextColor}))), kDerangementFantasyDescription,
make_test<bool, DerangementType, DerangementType>( kDerangementFantasyTextColor}))),
"should return false when comparing two different derangements", make_test<bool, DerangementType, DerangementType>(
false, "should return false when comparing two different derangements",
make_tuple(kDerangementManicDepression, kDerangementParanoia)), false,
}) make_tuple(kDerangementManicDepression, kDerangementParanoia)),
)); })));
} }
TestResults test_DerangementType_operator_not_equal_to() { TestResults test_DerangementType_operator_not_equal_to() {
return execute_suite<bool, DerangementType, DerangementType>( return execute_suite<bool, DerangementType, DerangementType>(make_test_suite(
make_test_suite( "SBF::DerangementType::operator!=",
"SBF::DerangementType::operator!=", [](const DerangementType& left, const DerangementType& right) { return left != right; },
[](const DerangementType& left, const DerangementType& right) { vector<TestTuple<bool, DerangementType, DerangementType>>({
return left != right; make_test<bool, DerangementType, DerangementType>(
}, "should return false when comparing a derangement to itself",
vector<TestTuple<bool, DerangementType, DerangementType>>({ false,
make_test<bool, DerangementType, DerangementType>( make_tuple(kDerangementDelusionsOfGrandeur, kDerangementDelusionsOfGrandeur)),
"should return false when comparing a derangement to itself", make_test<bool, DerangementType, DerangementType>(
false, "should return false when comparing two different instances created with the same values",
make_tuple(kDerangementDelusionsOfGrandeur, kDerangementDelusionsOfGrandeur)), false,
make_test<bool, DerangementType, DerangementType>( make_tuple(kDerangementFantasy,
"should return false when comparing two different instances created with the same values", DerangementType({kDerangementFantasyId,
false, kDerangementFantasyLabel,
make_tuple(kDerangementFantasy, DerangementType({kDerangementFantasyId, kDerangementFantasyLabel, kDerangementFantasyDescription, kDerangementFantasyTextColor}))), kDerangementFantasyDescription,
make_test<bool, DerangementType, DerangementType>( kDerangementFantasyTextColor}))),
"should return true when comparing two different derangements", make_test<bool, DerangementType, DerangementType>(
true, "should return true when comparing two different derangements",
make_tuple(kDerangementManicDepression, kDerangementParanoia)), true,
}) make_tuple(kDerangementManicDepression, kDerangementParanoia)),
)); })));
} }
} // End Test::Derangements } // namespace Test::Derangements

View File

@@ -1,4 +1,5 @@
#include "Disciplines.h" #include "Disciplines.h"
#include <string> #include <string>
#include <vector> #include <vector>
@@ -7,17 +8,17 @@ using std::string;
using std::vector; using std::vector;
string GetDisciplineLabel(int disciplineId) { string GetDisciplineLabel(int disciplineId) {
if (disciplineId > 0 && disciplineId <= kDisciplinesCount) { if (disciplineId > 0 && disciplineId <= kDisciplinesCount) {
return kDisciplines[disciplineId]; return kDisciplines[disciplineId];
} }
return ""; return "";
} }
void FillDisciplineLabels(vector<string>& labels) { void FillDisciplineLabels(vector<string>& labels) {
labels.clear(); labels.clear();
for (int id = 1; id <= kDisciplinesCount; id++) { for (int id = 1; id <= kDisciplinesCount; id++) {
labels.push_back(GetDisciplineLabel(id)); labels.push_back(GetDisciplineLabel(id));
} }
} }
} // End namespace SBF } // End namespace SBF

View File

@@ -1,107 +1,108 @@
#ifndef DISCIPLINES_H__ #ifndef DISCIPLINES_H__
#define DISCIPLINES_H__ #define DISCIPLINES_H__
/*************************************************************************************** /***************************************************************************************
* @file Disciplines.h * @file Disciplines.h
* *
* @brief Defines constants and functions for working with disciplines. * @brief Defines constants and functions for working with disciplines.
* @copyright * @copyright
* Copyright 2023 Tom Hicks * Copyright 2023 Tom Hicks
* 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> #include <vector>
/** \addtogroup Disciplines /** \addtogroup Disciplines
* @{ * @{
*/ */
namespace SBF { namespace SBF {
const int kDisciplinePoints = 3; const int kDisciplinePoints = 3;
const int kDisciplineAnimalismId = 1; const int kDisciplineAnimalismId = 1;
const std::string kDisciplineAnimalismLabel = "Animalism"; const std::string kDisciplineAnimalismLabel = "Animalism";
const int kDisciplineAuspexId = 2; const int kDisciplineAuspexId = 2;
const std::string kDisciplineAuspexLabel = "Auspex"; const std::string kDisciplineAuspexLabel = "Auspex";
const int kDisciplineBardoId = 3; const int kDisciplineBardoId = 3;
const std::string kDisciplineBardoLabel = "Bardo"; const std::string kDisciplineBardoLabel = "Bardo";
const int kDisciplineCelerityId = 4; const int kDisciplineCelerityId = 4;
const std::string kDisciplineCelerityLabel = "Celerity"; const std::string kDisciplineCelerityLabel = "Celerity";
const int kDisciplineChimestryId = 5; const int kDisciplineChimestryId = 5;
const std::string kDisciplineChimestryLabel = "Chimestry"; const std::string kDisciplineChimestryLabel = "Chimestry";
const int kDisciplineDementationId = 6; const int kDisciplineDementationId = 6;
const std::string kDisciplineDementationLabel = "Dementation"; const std::string kDisciplineDementationLabel = "Dementation";
const int kDisciplineDominateId = 7; const int kDisciplineDominateId = 7;
const std::string kDisciplineDominateLabel = "Dominate"; const std::string kDisciplineDominateLabel = "Dominate";
const int kDisciplineFortitudeId = 8; const int kDisciplineFortitudeId = 8;
const std::string kDisciplineFortitudeLabel = "Fortitude"; const std::string kDisciplineFortitudeLabel = "Fortitude";
const int kDisciplineMelpomineeId = 9; const int kDisciplineMelpomineeId = 9;
const std::string kDisciplineMelpomineeLabel = "Melpominee"; const std::string kDisciplineMelpomineeLabel = "Melpominee";
const int kDisciplineMortisId = 10; const int kDisciplineMortisId = 10;
const std::string kDisciplineMortisLabel = "Mortis"; const std::string kDisciplineMortisLabel = "Mortis";
const int kDisciplineMytherceriaId = 11; const int kDisciplineMytherceriaId = 11;
const std::string kDisciplineMytherceriaLabel = "Mytherceria"; const std::string kDisciplineMytherceriaLabel = "Mytherceria";
const int kDisciplineNecromancyId = 12; const int kDisciplineNecromancyId = 12;
const std::string kDisciplineNecromancyLabel = "Necromancy"; const std::string kDisciplineNecromancyLabel = "Necromancy";
const int kDisciplineObeahId = 13; const int kDisciplineObeahId = 13;
const std::string kDisciplineObeahLabel = "Obeah"; const std::string kDisciplineObeahLabel = "Obeah";
const int kDisciplineObfuscateId = 14; const int kDisciplineObfuscateId = 14;
const std::string kDisciplineObfuscateLabel = "Obfuscate"; const std::string kDisciplineObfuscateLabel = "Obfuscate";
const int kDisciplineObtenebrationId = 15; const int kDisciplineObtenebrationId = 15;
const std::string kDisciplineObtenebrationLabel = "Obtenebration"; const std::string kDisciplineObtenebrationLabel = "Obtenebration";
const int kDisciplinePotenceId = 16; const int kDisciplinePotenceId = 16;
const std::string kDisciplinePotenceLabel = "Potence"; const std::string kDisciplinePotenceLabel = "Potence";
const int kDisciplinePresenceId = 17; const int kDisciplinePresenceId = 17;
const std::string kDisciplinePresenceLabel = "Presence"; const std::string kDisciplinePresenceLabel = "Presence";
const int kDisciplineProteanId = 18; const int kDisciplineProteanId = 18;
const std::string kDisciplineProteanLabel = "Protean"; const std::string kDisciplineProteanLabel = "Protean";
const int kDisciplineQuietusId = 19; const int kDisciplineQuietusId = 19;
const std::string kDisciplineQuietusLabel = "Quietus"; const std::string kDisciplineQuietusLabel = "Quietus";
const int kDisciplineSerpentisId = 20; const int kDisciplineSerpentisId = 20;
const std::string kDisciplineSerpentisLabel = "Serpentis"; const std::string kDisciplineSerpentisLabel = "Serpentis";
const int kDisciplineSpiritusId = 21; const int kDisciplineSpiritusId = 21;
const std::string kDisciplineSpiritusLabel = "Spiritus"; const std::string kDisciplineSpiritusLabel = "Spiritus";
const int kDisciplineThanantosisId = 22; const int kDisciplineThanantosisId = 22;
const std::string kDisciplineThanantosisLabel = "Thanantosis"; const std::string kDisciplineThanantosisLabel = "Thanantosis";
const int kDisciplineThaumaturgyId = 23; const int kDisciplineThaumaturgyId = 23;
const std::string kDisciplineThaumaturgyLabel = "Thaumaturgy"; const std::string kDisciplineThaumaturgyLabel = "Thaumaturgy";
const int kDisciplineVicissitudeId = 24; const int kDisciplineVicissitudeId = 24;
const std::string kDisciplineVicissitudeLabel = "Vicissitude"; const std::string kDisciplineVicissitudeLabel = "Vicissitude";
const int kDisciplinesCount = 24; const int kDisciplinesCount = 24;
const std::string kDisciplines[] = { const std::string kDisciplines[] = {
"", "",
kDisciplineAnimalismLabel, kDisciplineAnimalismLabel,
kDisciplineAuspexLabel, kDisciplineAuspexLabel,
kDisciplineBardoLabel, kDisciplineBardoLabel,
kDisciplineCelerityLabel, kDisciplineCelerityLabel,
kDisciplineChimestryLabel, kDisciplineChimestryLabel,
kDisciplineDementationLabel, kDisciplineDementationLabel,
kDisciplineDominateLabel, kDisciplineDominateLabel,
kDisciplineFortitudeLabel, kDisciplineFortitudeLabel,
kDisciplineMelpomineeLabel, kDisciplineMelpomineeLabel,
kDisciplineMortisLabel, kDisciplineMortisLabel,
kDisciplineMytherceriaLabel, kDisciplineMytherceriaLabel,
kDisciplineNecromancyLabel, kDisciplineNecromancyLabel,
kDisciplineObeahLabel, kDisciplineObeahLabel,
kDisciplineObfuscateLabel, kDisciplineObfuscateLabel,
kDisciplineObtenebrationLabel, kDisciplineObtenebrationLabel,
kDisciplinePotenceLabel, kDisciplinePotenceLabel,
kDisciplinePresenceLabel, kDisciplinePresenceLabel,
kDisciplineProteanLabel, kDisciplineProteanLabel,
kDisciplineQuietusLabel, kDisciplineQuietusLabel,
kDisciplineSerpentisLabel, kDisciplineSerpentisLabel,
kDisciplineSpiritusLabel, kDisciplineSpiritusLabel,
kDisciplineThanantosisLabel, kDisciplineThanantosisLabel,
kDisciplineThaumaturgyLabel, kDisciplineThaumaturgyLabel,
kDisciplineVicissitudeLabel, kDisciplineVicissitudeLabel,
}; };
/// @brief Gets the label for a discipline with a specific id. /// @brief Gets the label for a discipline with a specific id.
/// @param discipline_id The id of the discipline to get the label for. /// @param discipline_id The id of the discipline to get the label for.
/// @return The label of the discipline or an empty string if discipline_id is invalid. /// @return The label of the discipline or an empty string if discipline_id is invalid.
std::string GetDisciplineLabel(int discipline_id); std::string GetDisciplineLabel(int discipline_id);
/// @brief Fills the provided vector with all of the valid discipline labels.
/// @param discipline_labels The vector to fill. It will be cleared first.
void FillDisciplineLabels(std::vector<std::string>& discipline_labels);
} // End namespace SBF
/// @brief Fills the provided vector with all of the valid discipline labels.
/// @param discipline_labels The vector to fill. It will be cleared first.
void FillDisciplineLabels(std::vector<std::string>& discipline_labels);
} // End namespace SBF
/** @}*/ /** @}*/
#endif // End !defined DISCIPLINES_H__ #endif // End !defined DISCIPLINES_H__

View File

@@ -1,9 +1,11 @@
#include "Disciplines.h" #include "Disciplines.h"
#include "test.h"
#include <sstream>
#include <string> #include <string>
#include <tuple> #include <tuple>
#include <vector> #include <vector>
#include <sstream>
#include "test.h"
using namespace SBF; using namespace SBF;
using namespace Test; using namespace Test;
@@ -12,179 +14,81 @@ using namespace std;
namespace Test::Disciplines { namespace Test::Disciplines {
TestResults test_GetDisciplineLabel(); TestResults test_GetDisciplineLabel();
TestResults test_FillDisciplineLabels(); TestResults test_FillDisciplineLabels();
} // End namespace Test::Disciplines } // End namespace Test::Disciplines
using namespace Test::Disciplines; using namespace Test::Disciplines;
TestResults main_test_Disciplines(int argc, char** argv) { TestResults main_test_Disciplines(int argc, char** argv) {
TestResults results; TestResults results;
results += test_GetDisciplineLabel();
results += test_FillDisciplineLabels();
return results; results += test_GetDisciplineLabel();
results += test_FillDisciplineLabels();
return results;
} }
namespace Test::Disciplines { namespace Test::Disciplines {
TestResults test_GetDisciplineLabel() { TestResults test_GetDisciplineLabel() {
return execute_suite<string, int>(make_test_suite( return execute_suite<string, int>(make_test_suite(
"SBF::GetDisciplineLabel", "SBF::GetDisciplineLabel",
GetDisciplineLabel, GetDisciplineLabel,
vector<TestTuple<string, int>>({ vector<TestTuple<string, int>>({
make_test<string, int>( make_test<string, int>("should get \"\" for invalid discipline id 0", "", make_tuple(0)),
"should get \"\" for invalid discipline id 0", make_test<string, int>("should get \"Animalism\" for id 1", "Animalism", make_tuple(1)),
"", make_test<string, int>("should get \"Auspex\" for id 2", "Auspex", make_tuple(2)),
make_tuple(0)), make_test<string, int>("should get \"Bardo\" for id 3", "Bardo", make_tuple(3)),
make_test<string, int>( make_test<string, int>("should get \"Celerity\" for id 4", "Celerity", make_tuple(4)),
"should get \"Animalism\" for id 1", make_test<string, int>("should get \"Chimestry\" for id 5", "Chimestry", make_tuple(5)),
"Animalism", make_test<string, int>("should get \"Dementation\" for id 6", "Dementation", make_tuple(6)),
make_tuple(1)), make_test<string, int>("should get \"Dominate\" for id 7", "Dominate", make_tuple(7)),
make_test<string, int>( make_test<string, int>("should get \"Fortitude\" for id 8", "Fortitude", make_tuple(8)),
"should get \"Auspex\" for id 2", make_test<string, int>("should get \"Melpominee\" for id 9", "Melpominee", make_tuple(9)),
"Auspex", make_test<string, int>("should get \"Mortis\" for id 10", "Mortis", make_tuple(10)),
make_tuple(2)), make_test<string, int>("should get \"Mytherceria\" for id 11", "Mytherceria", make_tuple(11)),
make_test<string, int>( make_test<string, int>("should get \"Necromancy\" for id 12", "Necromancy", make_tuple(12)),
"should get \"Bardo\" for id 3", make_test<string, int>("should get \"Obeah\" for id 13", "Obeah", make_tuple(13)),
"Bardo", make_test<string, int>("should get \"Obfuscate\" for id 14", "Obfuscate", make_tuple(14)),
make_tuple(3)), make_test<string, int>("should get \"Obtenebration\" for id 15", "Obtenebration", make_tuple(15)),
make_test<string, int>( make_test<string, int>("should get \"Potence\" for id 16", "Potence", make_tuple(16)),
"should get \"Celerity\" for id 4", make_test<string, int>("should get \"Presence\" for id 17", "Presence", make_tuple(17)),
"Celerity", make_test<string, int>("should get \"Protean\" for id 18", "Protean", make_tuple(18)),
make_tuple(4)), make_test<string, int>("should get \"Quietus\" for id 19", "Quietus", make_tuple(19)),
make_test<string, int>( make_test<string, int>("should get \"Serpentis\" for id 20", "Serpentis", make_tuple(20)),
"should get \"Chimestry\" for id 5", make_test<string, int>("should get \"Spiritus\" for id 21", "Spiritus", make_tuple(21)),
"Chimestry", make_test<string, int>("should get \"Thanantosis\" for id 22", "Thanantosis", make_tuple(22)),
make_tuple(5)), make_test<string, int>("should get \"Thaumaturgy\" for id 23", "Thaumaturgy", make_tuple(23)),
make_test<string, int>( make_test<string, int>("should get \"Vicissitude\" for id 24", "Vicissitude", make_tuple(24)),
"should get \"Dementation\" for id 6", make_test<string, int>("should get \"\" for invalid discipline id 25", "", make_tuple(25)),
"Dementation", })));
make_tuple(6)),
make_test<string, int>(
"should get \"Dominate\" for id 7",
"Dominate",
make_tuple(7)),
make_test<string, int>(
"should get \"Fortitude\" for id 8",
"Fortitude",
make_tuple(8)),
make_test<string, int>(
"should get \"Melpominee\" for id 9",
"Melpominee",
make_tuple(9)),
make_test<string, int>(
"should get \"Mortis\" for id 10",
"Mortis",
make_tuple(10)),
make_test<string, int>(
"should get \"Mytherceria\" for id 11",
"Mytherceria",
make_tuple(11)),
make_test<string, int>(
"should get \"Necromancy\" for id 12",
"Necromancy",
make_tuple(12)),
make_test<string, int>(
"should get \"Obeah\" for id 13",
"Obeah",
make_tuple(13)),
make_test<string, int>(
"should get \"Obfuscate\" for id 14",
"Obfuscate",
make_tuple(14)),
make_test<string, int>(
"should get \"Obtenebration\" for id 15",
"Obtenebration",
make_tuple(15)),
make_test<string, int>(
"should get \"Potence\" for id 16",
"Potence",
make_tuple(16)),
make_test<string, int>(
"should get \"Presence\" for id 17",
"Presence",
make_tuple(17)),
make_test<string, int>(
"should get \"Protean\" for id 18",
"Protean",
make_tuple(18)),
make_test<string, int>(
"should get \"Quietus\" for id 19",
"Quietus",
make_tuple(19)),
make_test<string, int>(
"should get \"Serpentis\" for id 20",
"Serpentis",
make_tuple(20)),
make_test<string, int>(
"should get \"Spiritus\" for id 21",
"Spiritus",
make_tuple(21)),
make_test<string, int>(
"should get \"Thanantosis\" for id 22",
"Thanantosis",
make_tuple(22)),
make_test<string, int>(
"should get \"Thaumaturgy\" for id 23",
"Thaumaturgy",
make_tuple(23)),
make_test<string, int>(
"should get \"Vicissitude\" for id 24",
"Vicissitude",
make_tuple(24)),
make_test<string, int>(
"should get \"\" for invalid discipline id 25",
"",
make_tuple(25)),
})
));
} }
TestResults test_FillDisciplineLabels() { TestResults test_FillDisciplineLabels() {
auto fnToTest = []()->string { auto fnToTest = []() -> string {
ostringstream error_message; ostringstream error_message;
vector<string> expected = { vector<string> expected = {
kDisciplineAnimalismLabel, kDisciplineAnimalismLabel, kDisciplineAuspexLabel, kDisciplineBardoLabel,
kDisciplineAuspexLabel, kDisciplineCelerityLabel, kDisciplineChimestryLabel, kDisciplineDementationLabel,
kDisciplineBardoLabel, kDisciplineDominateLabel, kDisciplineFortitudeLabel, kDisciplineMelpomineeLabel,
kDisciplineCelerityLabel, kDisciplineMortisLabel, kDisciplineMytherceriaLabel, kDisciplineNecromancyLabel,
kDisciplineChimestryLabel, kDisciplineObeahLabel, kDisciplineObfuscateLabel, kDisciplineObtenebrationLabel,
kDisciplineDementationLabel, kDisciplinePotenceLabel, kDisciplinePresenceLabel, kDisciplineProteanLabel,
kDisciplineDominateLabel, kDisciplineQuietusLabel, kDisciplineSerpentisLabel, kDisciplineSpiritusLabel,
kDisciplineFortitudeLabel, kDisciplineThanantosisLabel, kDisciplineThaumaturgyLabel, kDisciplineVicissitudeLabel,
kDisciplineMelpomineeLabel,
kDisciplineMortisLabel,
kDisciplineMytherceriaLabel,
kDisciplineNecromancyLabel,
kDisciplineObeahLabel,
kDisciplineObfuscateLabel,
kDisciplineObtenebrationLabel,
kDisciplinePotenceLabel,
kDisciplinePresenceLabel,
kDisciplineProteanLabel,
kDisciplineQuietusLabel,
kDisciplineSerpentisLabel,
kDisciplineSpiritusLabel,
kDisciplineThanantosisLabel,
kDisciplineThaumaturgyLabel,
kDisciplineVicissitudeLabel,
};
vector<string> actual = {"This should be removed."};
FillDisciplineLabels(actual);
compare(error_message, expected, actual);
string error = error_message.str();
if (error.size() > 0) {
return error;
}
return "no errors";
}; };
return execute_suite<string>(make_test_suite( vector<string> actual = {"This should be removed."};
"SBF::FillDisciplineLabels", FillDisciplineLabels(actual);
fnToTest, compare(error_message, expected, actual);
vector<TestTuple<string>>({ string error = error_message.str();
make_test<string>( if (error.size() > 0) {
"should fill disciplines", return error;
"no errors", }
make_tuple()), return "no errors";
}) };
)); return execute_suite<string>(
make_test_suite("SBF::FillDisciplineLabels",
fnToTest,
vector<TestTuple<string>>({
make_test<string>("should fill disciplines", "no errors", make_tuple()),
})));
} }
} // End namespace Test::Disciplines } // End namespace Test::Disciplines

View File

@@ -1,4 +1,5 @@
#include "Genders.h" #include "Genders.h"
#include <string> #include <string>
#include <vector> #include <vector>
@@ -7,16 +8,16 @@ using std::string;
using std::vector; using std::vector;
string GetGenderLabel(int genderId) { string GetGenderLabel(int genderId) {
if (genderId > 0 && genderId <= kGendersCount) { if (genderId > 0 && genderId <= kGendersCount) {
return kGenderLabels[genderId]; return kGenderLabels[genderId];
} }
return ""; return "";
} }
void FillGenderLabels(vector<string>& labels) { void FillGenderLabels(vector<string>& labels) {
labels.clear(); labels.clear();
for (int id = 1; id <= kGendersCount; id++) { for (int id = 1; id <= kGendersCount; id++) {
labels.push_back(GetGenderLabel(id)); labels.push_back(GetGenderLabel(id));
} }
} }
} // End namespace SBF } // End namespace SBF

View File

@@ -1,48 +1,49 @@
#ifndef GENDERS_H__ #ifndef GENDERS_H__
#define GENDERS_H__ #define GENDERS_H__
/*************************************************************************************** /***************************************************************************************
* @file Genders.h * @file Genders.h
* *
* @brief Defines constants and functions for working with genders. * @brief Defines constants and functions for working with genders.
* @copyright * @copyright
* Copyright 2023 Tom Hicks * Copyright 2023 Tom Hicks
* 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> #include <vector>
/** \addtogroup Genders /** \addtogroup Genders
* @{ * @{
*/ */
namespace SBF { namespace SBF {
const int kGenderMaleId = 1; const int kGenderMaleId = 1;
const std::string kGenderMaleLabel = "Male"; const std::string kGenderMaleLabel = "Male";
const int kGenderFemaleId = 2; const int kGenderFemaleId = 2;
const std::string kGenderFemaleLabel = "Female"; const std::string kGenderFemaleLabel = "Female";
const int kGenderTransMaleId = 3; const int kGenderTransMaleId = 3;
const std::string kGenderTransMaleLabel = "Trans-Male"; const std::string kGenderTransMaleLabel = "Trans-Male";
const int kGenderTransFemaleId = 4; const int kGenderTransFemaleId = 4;
const std::string kGenderTransFemaleLabel = "Trans-Female"; const std::string kGenderTransFemaleLabel = "Trans-Female";
const int kGenderNonBinaryId = 5; const int kGenderNonBinaryId = 5;
const std::string kGenderNonBinaryLabel = "Non-Binary"; const std::string kGenderNonBinaryLabel = "Non-Binary";
const int kGendersCount = 5; const int kGendersCount = 5;
const std::string kGenderLabels[] = { const std::string kGenderLabels[] = {
"", "",
kGenderMaleLabel, kGenderMaleLabel,
kGenderFemaleLabel, kGenderFemaleLabel,
kGenderTransMaleLabel, kGenderTransMaleLabel,
kGenderTransFemaleLabel, kGenderTransFemaleLabel,
kGenderNonBinaryLabel, kGenderNonBinaryLabel,
}; };
/// @brief Gets a gender label with a specific id. /// @brief Gets a gender label with a specific id.
/// @param gender_id The id of the gender to return the label for. /// @param gender_id The id of the gender to return the label for.
/// @return The label of the specified gender or an empty string if gender_id is invalid. /// @return The label of the specified gender or an empty string if gender_id is invalid.
std::string GetGenderLabel(int gender_id); std::string GetGenderLabel(int gender_id);
/// @brief Fills the provided vector with all of the valid gender labels.
/// @param gender_labels The vector to fill. It will be cleared first.
void FillGenderLabels(std::vector<std::string>& gender_labels);
} // End namespace SBF
/// @brief Fills the provided vector with all of the valid gender labels.
/// @param gender_labels The vector to fill. It will be cleared first.
void FillGenderLabels(std::vector<std::string>& gender_labels);
} // End namespace SBF
/** @}*/ /** @}*/
#endif // End !defined GENDERS_H__ #endif // End !defined GENDERS_H__

View File

@@ -1,9 +1,11 @@
#include "Genders.h" #include "Genders.h"
#include "test.h"
#include <sstream>
#include <string> #include <string>
#include <tuple> #include <tuple>
#include <vector> #include <vector>
#include <sstream>
#include "test.h"
using namespace SBF; using namespace SBF;
using namespace Test; using namespace Test;
@@ -12,84 +14,58 @@ using namespace std;
namespace Test::Genders { namespace Test::Genders {
TestResults test_GetGenderLabel(); TestResults test_GetGenderLabel();
TestResults test_FillGenderLabels(); TestResults test_FillGenderLabels();
} // End namespace Test::Genders } // End namespace Test::Genders
using namespace Test::Genders; using namespace Test::Genders;
TestResults main_test_Genders(int argc, char** argv) { TestResults main_test_Genders(int argc, char** argv) {
TestResults results; TestResults results;
results += test_GetGenderLabel(); results += test_GetGenderLabel();
results += test_FillGenderLabels(); results += test_FillGenderLabels();
return results; return results;
} }
namespace Test::Genders { namespace Test::Genders {
TestResults test_GetGenderLabel() { TestResults test_GetGenderLabel() {
return execute_suite<string, int>(make_test_suite( return execute_suite<string, int>(make_test_suite(
"SBF::GetGenderLabel", "SBF::GetGenderLabel",
GetGenderLabel, GetGenderLabel,
vector<TestTuple<string, int>>({ vector<TestTuple<string, int>>({
make_test<string, int>( make_test<string, int>("should get \"\" for invalid gender id 0", "", make_tuple(0)),
"should get \"\" for invalid gender id 0", make_test<string, int>("should get \"Male\" for gender id 1", "Male", make_tuple(1)),
"", make_test<string, int>("should get \"Female\" for gender id 2", "Female", make_tuple(2)),
make_tuple(0)), make_test<string, int>("should get \"Trans-Male\" for gender id 3", "Trans-Male", make_tuple(3)),
make_test<string, int>( make_test<string, int>("should get \"Trans-Female\" for gender id 4", "Trans-Female", make_tuple(4)),
"should get \"Male\" for gender id 1", make_test<string, int>("should get \"Non-Binary\" for gender id 5", "Non-Binary", make_tuple(5)),
"Male", make_test<string, int>("should get \"\" for invalid gender id 6", "", make_tuple(6)),
make_tuple(1)), })));
make_test<string, int>(
"should get \"Female\" for gender id 2",
"Female",
make_tuple(2)),
make_test<string, int>(
"should get \"Trans-Male\" for gender id 3",
"Trans-Male",
make_tuple(3)),
make_test<string, int>(
"should get \"Trans-Female\" for gender id 4",
"Trans-Female",
make_tuple(4)),
make_test<string, int>(
"should get \"Non-Binary\" for gender id 5",
"Non-Binary",
make_tuple(5)),
make_test<string, int>(
"should get \"\" for invalid gender id 6",
"",
make_tuple(6)),
})
));
} }
TestResults test_FillGenderLabels() { TestResults test_FillGenderLabels() {
auto fnToTest = []()->string { auto fnToTest = []() -> string {
ostringstream error_message; ostringstream error_message;
vector<string> expected = { vector<string> expected = {
kGenderMaleLabel, kGenderMaleLabel,
kGenderFemaleLabel, kGenderFemaleLabel,
kGenderTransMaleLabel, kGenderTransMaleLabel,
kGenderTransFemaleLabel, kGenderTransFemaleLabel,
kGenderNonBinaryLabel, kGenderNonBinaryLabel,
};
vector<string> actual = {"This should be removed."};
FillGenderLabels(actual);
compare(error_message, expected, actual);
string error = error_message.str();
if (error.size() > 0) {
return error;
}
return "no errors";
}; };
return execute_suite<string>(make_test_suite( vector<string> actual = {"This should be removed."};
"SBF::FillGenderLabels", FillGenderLabels(actual);
fnToTest, compare(error_message, expected, actual);
vector<TestTuple<string>>({ string error = error_message.str();
make_test<string>( if (error.size() > 0) {
"should fill genders", return error;
"no errors", }
make_tuple()), return "no errors";
}) };
)); return execute_suite<string>(make_test_suite("SBF::FillGenderLabels",
fnToTest,
vector<TestTuple<string>>({
make_test<string>("should fill genders", "no errors", make_tuple()),
})));
} }
} // End namespace Test::Genders } // End namespace Test::Genders

View File

@@ -2,20 +2,20 @@
namespace SBF { namespace SBF {
int GetRandomMenuItemId (std::vector<MenuItem> items); int GetRandomMenuItemId(std::vector<MenuItem> items);
void BuildMenu(std::vector<MenuItem> items, std::vector<string> labels); void BuildMenu(std::vector<MenuItem> items, 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); void AdjustMenuStyle(MenuStyle& style, std::vector<MenuItem> items, bool ignoreValue);
void PrintMenu(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); void NewMenuStyle(MenuStyle& style);
void NewMenuItem(MenuItem& item, string label, int id); 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);
} // End namespace SBF } // End namespace SBF
/* /*
Function GetRandomMenuItemId (items() As MenuItem, count As Integer) Function GetRandomMenuItemId (items() As MenuItem, count As Integer)
@@ -114,31 +114,22 @@ 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 + Len(style.menuItemSpacer), " ") itemText$ = MakeFitL$(RTrim$(itemText$) + style.menuItemSpacer, textLength +
End If Len(style.menuItemSpacer), " ") End If End If Print MakeFitC$(itemText$, columnWidth, " "); End If column = (column + 1)
End If Mod itemsPerRow If column = 0 Then Print "" Next If style.showRandom Then Print
Print MakeFitC$(itemText$, columnWidth, " "); MakeFitC$(GetTitleWithoutValue$(randomItem, style), columnWidth, " ") End If End If End Sub
End If
column = (column + 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
Function GetTitle$ (mi As MenuItem, ms As MenuStyle) Function GetTitle$ (mi As MenuItem, ms As MenuStyle)
id$ = itos$(mi.id) id$ = itos$(mi.id)
label$ = mi.label label$ = mi.label
If ms.valueWidth > 0 Then label$ = label$ + ms.labelValueSeparator If ms.valueWidth > 0 Then label$ = label$ + ms.labelValueSeparator
value$ = itos$(mi.value) value$ = itos$(mi.value)
GetTitle$ = MakeFitR$(id$, ms.idWidth, " ") + ms.idLabelSeparator + MakeFitL$(label$, ms.labelWidth, " ") + MakeFitR$(value$, ms.valueWidth, " ") GetTitle$ = MakeFitR$(id$, ms.idWidth, " ") + ms.idLabelSeparator + MakeFitL$(label$, ms.labelWidth, " ") +
End Function 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, ms.labelWidth + ms.valueWidth + Len(ms.labelValueSeparator), " ") GetTitleWithoutValue$ = MakeFitR$(itos(mi.id), ms.idWidth, " ") + ms.idLabelSeparator + MakeFitL$(mi.label,
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

@@ -1,63 +1,66 @@
#ifndef MENUS_H__ #ifndef MENUS_H__
#define MENUS_H__ #define MENUS_H__
/*************************************************************************************** /***************************************************************************************
* @file Menus.h * @file Menus.h
* *
* @brief Defines constants and functions for working with menus. * @brief Defines constants and functions for working with menus.
* @copyright * @copyright
* Copyright 2023 Tom Hicks * Copyright 2023 Tom Hicks
* Licensed under the MIT license see the LICENSE file for details. * Licensed under the MIT license see the LICENSE file for details.
***************************************************************************************/ ***************************************************************************************/
namespace SBF { namespace SBF {
struct MenuStyle; struct MenuStyle;
struct MenuItem; struct MenuItem;
} } // namespace SBF
// End forward declarations // End forward declarations
#include <string>
#include <cstdint> #include <cstdint>
#include <string>
/** \addtogroup Menus /** \addtogroup Menus
* @{ * @{
*/ */
namespace SBF { namespace SBF {
using std::string; using std::string;
struct MenuStyle { struct MenuStyle {
int idWidth; int idWidth;
int labelWidth; int labelWidth;
int valueWidth; int valueWidth;
int screenWidth; int screenWidth;
string randomItemName; string randomItemName;
int randomItemId; int randomItemId;
string idLabelSeparator; string idLabelSeparator;
string labelValueSeparator; string labelValueSeparator;
string menuItemSpacer; string menuItemSpacer;
bool showRandom; bool showRandom;
bool useColors; bool useColors;
}; };
struct MenuItem { struct MenuItem {
string label; string label;
int id; int id;
int value; int value;
int color; int color;
bool isVisible; bool isVisible;
}; };
int GetRandomMenuItemId (std::vector<MenuItem> items); int GetRandomMenuItemId(std::vector<MenuItem> items);
void BuildMenu(std::vector<MenuItem> items, std::vector<string> labels); void BuildMenu(std::vector<MenuItem> items, 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); void AdjustMenuStyle(MenuStyle& style, std::vector<MenuItem> items, bool ignoreValue);
void PrintMenu(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); void NewMenuStyle(MenuStyle& style);
void NewMenuItem(MenuItem& item, string label, int id); 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);
} // End namespace SBF
} // End namespace SBF
/** @}*/ /** @}*/
#endif // !defined MENUS_H__ #endif // !defined MENUS_H__

View File

@@ -1,37 +1,37 @@
#include "Ranks.h" #include "Ranks.h"
#include <ostream>
#include <string> #include <string>
#include <vector> #include <vector>
#include <ostream>
namespace SBF { namespace SBF {
using std::string; using std::string;
using std::vector; using std::vector;
std::ostream& operator<<(std::ostream& os, const RankType& rank) { std::ostream& operator<<(std::ostream& os, const RankType& rank) {
os << "Rank: {id: " << rank.id os << "Rank: {id: " << rank.id << ", label: \"" << rank.label << "\"}";
<< ", label: \"" << rank.label << "\"}"; return os;
return os;
} }
bool operator==(const RankType& left, const RankType& right) { bool operator==(const RankType& left, const RankType& right) {
return left.id == right.id && left.label == right.label; return left.id == right.id && left.label == right.label;
} }
bool operator!=(const RankType& left, const RankType& right) { bool operator!=(const RankType& left, const RankType& right) {
return !(left == right); return !(left == right);
} }
RankType GetRank(int rankId) { RankType GetRank(int rankId) {
if (rankId > 0 && rankId <= kRanksCount) { if (rankId > 0 && rankId <= kRanksCount) {
return kRanks[rankId]; return kRanks[rankId];
} }
return kRankUnknown; return kRankUnknown;
} }
void FillRanks(std::vector<RankType>& ranks) { void FillRanks(std::vector<RankType>& ranks) {
ranks.clear(); ranks.clear();
for (int id = 1; id <= kRanksCount; id++) { for (int id = 1; id <= kRanksCount; id++) {
ranks.push_back(GetRank(id)); ranks.push_back(GetRank(id));
} }
} }
} // End namespace SBF } // End namespace SBF

View File

@@ -1,71 +1,72 @@
#ifndef RANKS_H__ #ifndef RANKS_H__
#define RANKS_H__ #define RANKS_H__
/*************************************************************************************** /***************************************************************************************
* @file Ranks.h * @file Ranks.h
* *
* @brief Defines constants and functions for working with ranks. * @brief Defines constants and functions for working with ranks.
* @copyright * @copyright
* Copyright 2023 Tom Hicks * Copyright 2023 Tom Hicks
* 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> #include <vector>
/** \addtogroup /** \addtogroup
* @{ * @{
*/ */
namespace SBF { namespace SBF {
const int kRankPrimaryId = 1; const int kRankPrimaryId = 1;
const std::string kRankPrimaryLabel = "Primary"; const std::string kRankPrimaryLabel = "Primary";
const int kRankSecondaryId = 2; const int kRankSecondaryId = 2;
const std::string kRankSecondaryLabel = "Secondary"; const std::string kRankSecondaryLabel = "Secondary";
const int kRankTertiaryId = 3; const int kRankTertiaryId = 3;
const std::string kRankTertiaryLabel = "Tertiary"; const std::string kRankTertiaryLabel = "Tertiary";
const int kRanksCount = 3; const int kRanksCount = 3;
struct RankType { struct RankType {
int id; int id;
std::string label; std::string label;
}; };
const RankType kRankPrimary = {kRankPrimaryId, kRankPrimaryLabel}; const RankType kRankPrimary = {kRankPrimaryId, kRankPrimaryLabel};
const RankType kRankSecondary = {kRankSecondaryId, kRankSecondaryLabel}; const RankType kRankSecondary = {kRankSecondaryId, kRankSecondaryLabel};
const RankType kRankTertiary = {kRankTertiaryId, kRankTertiaryLabel}; const RankType kRankTertiary = {kRankTertiaryId, kRankTertiaryLabel};
const RankType kRankUnknown = {0, ""}; const RankType kRankUnknown = {0, ""};
const RankType kRanks[] { const RankType kRanks[]{
kRankUnknown, kRankUnknown,
kRankPrimary, kRankPrimary,
kRankSecondary, kRankSecondary,
kRankTertiary, kRankTertiary,
}; };
/// @brief Writes a rank to an ostream. /// @brief Writes a rank to an ostream.
/// @param os The ostream to write to. /// @param os The ostream to write to.
/// @param rank The rank to write. /// @param rank The rank to write.
/// @return The provided ostream for chaining. /// @return The provided ostream for chaining.
std::ostream& operator<<(std::ostream& os, const RankType& rank); std::ostream& operator<<(std::ostream& os, const RankType& rank);
/// @brief Determines if two ranks are equal. /// @brief Determines if two ranks are equal.
/// @param left A rank to compare. /// @param left A rank to compare.
/// @param right A rank to compare. /// @param right A rank to compare.
/// @return True if both ranks are equal and false otherwise. /// @return True if both ranks are equal and false otherwise.
bool operator==(const RankType& left, const RankType& right); bool operator==(const RankType& left, const RankType& right);
/// @brief Determines if two ranks are unequal. /// @brief Determines if two ranks are unequal.
/// @param left A rank to compare. /// @param left A rank to compare.
/// @param right A rank to compare. /// @param right A rank to compare.
/// @return True if both ranks are unequal and false otherwise. /// @return True if both ranks are unequal and false otherwise.
bool operator!=(const RankType& left, const RankType& right); bool operator!=(const RankType& left, const RankType& right);
/// @brief Gets a rank with a specific id. /// @brief Gets a rank with a specific id.
/// @param rank_id The id of the rank to get. /// @param rank_id The id of the rank to get.
/// @return The rank with id == rank_id or the unknown rank kRankUnknown if rank_id is invalid. /// @return The rank with id == rank_id or the unknown rank kRankUnknown if rank_id is invalid.
RankType GetRank(int rank_id); RankType GetRank(int rank_id);
/// @brief Fills the provided vector with all valid rank labels.
/// @param ranks The vector to fill. It will be cleared first.
void FillRanks(std::vector<RankType>& ranks);
} // End namespace SBF
/// @brief Fills the provided vector with all valid rank labels.
/// @param ranks The vector to fill. It will be cleared first.
void FillRanks(std::vector<RankType>& ranks);
} // End namespace SBF
/** @}*/ /** @}*/
#endif // !defined RANKS_H__ #endif // !defined RANKS_H__

View File

@@ -1,9 +1,11 @@
#include "Ranks.h" #include "Ranks.h"
#include "test.h"
#include <sstream>
#include <string> #include <string>
#include <tuple> #include <tuple>
#include <vector> #include <vector>
#include <sstream>
#include "test.h"
using namespace SBF; using namespace SBF;
using namespace Test; using namespace Test;
@@ -15,153 +17,115 @@ TestResults test_RankType_operator_equal_to();
TestResults test_RankType_operator_not_equal_to(); TestResults test_RankType_operator_not_equal_to();
TestResults test_GetRank(); TestResults test_GetRank();
TestResults test_FillRanks(); TestResults test_FillRanks();
} // End namespace Test::Ranks } // End namespace Test::Ranks
using namespace Test::Ranks; using namespace Test::Ranks;
TestResults main_test_Ranks(int argc, char** argv) { TestResults main_test_Ranks(int argc, char** argv) {
TestResults results; TestResults results;
results += test_RankType_operator_extract();
results += test_RankType_operator_equal_to();
results += test_RankType_operator_not_equal_to();
results += test_GetRank();
results += test_FillRanks();
return results; results += test_RankType_operator_extract();
results += test_RankType_operator_equal_to();
results += test_RankType_operator_not_equal_to();
results += test_GetRank();
results += test_FillRanks();
return results;
} }
namespace Test::Ranks { namespace Test::Ranks {
TestResults test_GetRank() { TestResults test_GetRank() {
return execute_suite<RankType, int>(make_test_suite( return execute_suite<RankType, int>(make_test_suite(
"SBF::GetRank", "SBF::GetRank",
GetRank, GetRank,
vector<TestTuple<RankType, int>>({ vector<TestTuple<RankType, int>>({
make_test<RankType, int>( make_test<RankType, int>("should get {0, \"\"} for invalid rank id 0", RankType({0, ""}), make_tuple(0)),
"should get {0, \"\"} for invalid rank id 0", make_test<RankType, int>(
RankType({0, ""}), "should get {1, \"Primary\"} for rank id 1", RankType({1, "Primary"}), make_tuple(1)),
make_tuple(0)), make_test<RankType, int>(
make_test<RankType, int>( "should get {2, \"Secondary\"} for rank id 2", RankType({2, "Secondary"}), make_tuple(2)),
"should get {1, \"Primary\"} for rank id 1", make_test<RankType, int>(
RankType({1, "Primary"}), "should get {3, \"Tertiary\"} for rank id 3", RankType({3, "Tertiary"}), make_tuple(3)),
make_tuple(1)), make_test<RankType, int>("should get {0, \"\"} for invalid rank id 6", RankType({0, ""}), make_tuple(6)),
make_test<RankType, int>( })));
"should get {2, \"Secondary\"} for rank id 2",
RankType({2, "Secondary"}),
make_tuple(2)),
make_test<RankType, int>(
"should get {3, \"Tertiary\"} for rank id 3",
RankType({3, "Tertiary"}),
make_tuple(3)),
make_test<RankType, int>(
"should get {0, \"\"} for invalid rank id 6",
RankType({0, ""}),
make_tuple(6)),
})
));
} }
TestResults test_FillRanks() { TestResults test_FillRanks() {
auto fnToTest = []()->string { auto fnToTest = []() -> string {
ostringstream error_message; ostringstream error_message;
vector<RankType> expected = { vector<RankType> expected = {
kRankPrimary, kRankPrimary,
kRankSecondary, kRankSecondary,
kRankTertiary, kRankTertiary,
};
vector<RankType> actual = {{-5, "This should be removed."}};
FillRanks(actual);
compare(error_message, expected, actual);
string error = error_message.str();
if (error.size() > 0) {
return error;
}
return "no errors";
}; };
return execute_suite<string>(make_test_suite( vector<RankType> actual = {{-5, "This should be removed."}};
"SBF::FillRanks", FillRanks(actual);
fnToTest, compare(error_message, expected, actual);
vector<TestTuple<string>>({ string error = error_message.str();
make_test<string>( if (error.size() > 0) {
"should fill ranks", return error;
"no errors", }
make_tuple()), return "no errors";
}) };
)); return execute_suite<string>(make_test_suite("SBF::FillRanks",
fnToTest,
vector<TestTuple<string>>({
make_test<string>("should fill ranks", "no errors", make_tuple()),
})));
} }
TestResults test_RankType_operator_extract() { TestResults test_RankType_operator_extract() {
auto fnToTest = [](const RankType& rank)->string { auto fnToTest = [](const RankType& rank) -> string {
ostringstream os; ostringstream os;
os << rank; os << rank;
return os.str(); return os.str();
}; };
return execute_suite<string, RankType>(make_test_suite( return execute_suite<string, RankType>(make_test_suite(
"SBF::RankType::operator<<", "SBF::RankType::operator<<",
fnToTest, fnToTest,
vector<TestTuple<string, RankType>>({ vector<TestTuple<string, RankType>>({
make_test<string, RankType>( make_test<string, RankType>(
"should print an invalid rank", "should print an invalid rank", "Rank: {id: 0, label: \"\"}", make_tuple((RankType){0, ""})),
"Rank: {id: 0, label: \"\"}", make_test<string, RankType>(
make_tuple((RankType){0, ""})), "should print primary", "Rank: {id: 1, label: \"Primary\"}", make_tuple(kRankPrimary)),
make_test<string, RankType>( make_test<string, RankType>(
"should print primary", "should print secondary", "Rank: {id: 2, label: \"Secondary\"}", make_tuple(kRankSecondary)),
"Rank: {id: 1, label: \"Primary\"}", make_test<string, RankType>(
make_tuple(kRankPrimary)), "should print tertiary", "Rank: {id: 3, label: \"Tertiary\"}", make_tuple(kRankTertiary)),
make_test<string, RankType>( })));
"should print secondary",
"Rank: {id: 2, label: \"Secondary\"}",
make_tuple(kRankSecondary)),
make_test<string, RankType>(
"should print tertiary",
"Rank: {id: 3, label: \"Tertiary\"}",
make_tuple(kRankTertiary)),
})
));
} }
TestResults test_RankType_operator_equal_to() { TestResults test_RankType_operator_equal_to() {
return execute_suite<bool, RankType, RankType>(make_test_suite( return execute_suite<bool, RankType, RankType>(make_test_suite(
"SBF::RankType::operator==", "SBF::RankType::operator==",
[](const RankType& left, const RankType& right) { [](const RankType& left, const RankType& right) { return left == right; },
return left == right; vector<TestTuple<bool, RankType, RankType>>({
}, make_test<bool, RankType, RankType>(
vector<TestTuple<bool, RankType, RankType>>({ "should return true when comparing an rank to itself", true, make_tuple(kRankPrimary, kRankPrimary)),
make_test<bool, RankType, RankType>( make_test<bool, RankType, RankType>(
"should return true when comparing an rank to itself", "should return true when comparing two different instances created with the same values",
true, true,
make_tuple(kRankPrimary, kRankPrimary)), make_tuple(kRankSecondary, RankType({kRankSecondaryId, kRankSecondaryLabel}))),
make_test<bool, RankType, RankType>( make_test<bool, RankType, RankType>("should return false when comparing two different rank gropus",
"should return true when comparing two different instances created with the same values", false,
true, make_tuple(kRankPrimary, kRankTertiary)),
make_tuple(kRankSecondary, RankType({kRankSecondaryId, kRankSecondaryLabel}))), })));
make_test<bool, RankType, RankType>(
"should return false when comparing two different rank gropus",
false,
make_tuple(kRankPrimary, kRankTertiary)),
})
));
} }
TestResults test_RankType_operator_not_equal_to() { TestResults test_RankType_operator_not_equal_to() {
return execute_suite<bool, RankType, RankType>(make_test_suite( return execute_suite<bool, RankType, RankType>(make_test_suite(
"SBF::RankType::operator!=", "SBF::RankType::operator!=",
[](const RankType& left, const RankType& right) { [](const RankType& left, const RankType& right) { return left != right; },
return left != right; vector<TestTuple<bool, RankType, RankType>>({
}, make_test<bool, RankType, RankType>(
vector<TestTuple<bool, RankType, RankType>>({ "should return false when comparing an rank to itself", false, make_tuple(kRankPrimary, kRankPrimary)),
make_test<bool, RankType, RankType>( make_test<bool, RankType, RankType>(
"should return false when comparing an rank to itself", "should return false when comparing two different instances created with the same values",
false, false,
make_tuple(kRankPrimary, kRankPrimary)), make_tuple(kRankSecondary, RankType({kRankSecondaryId, kRankSecondaryLabel}))),
make_test<bool, RankType, RankType>( make_test<bool, RankType, RankType>("should return true when comparing two different rank gropus",
"should return false when comparing two different instances created with the same values", true,
false, make_tuple(kRankSecondary, kRankTertiary)),
make_tuple(kRankSecondary, RankType({kRankSecondaryId, kRankSecondaryLabel}))), })));
make_test<bool, RankType, RankType>(
"should return true when comparing two different rank gropus",
true,
make_tuple(kRankSecondary, kRankTertiary)),
})
));
}
} }
} // namespace Test::Ranks

View File

@@ -1,106 +1,100 @@
#define _XOPEN_SOURCE_EXTENDED #define _XOPEN_SOURCE_EXTENDED
#include <iostream>
#include <cstdio>
#include <string>
#include <cstdint>
#include <vector>
#include "Utils.h" #include "Utils.h"
#include <cstdint>
#include <cstdio>
#include <iostream>
#include <string>
#include <vector>
#include "test.h" #include "test.h"
using namespace SBF; using namespace SBF;
using namespace Test; using namespace Test;
namespace SBF { namespace SBF {
using std::cout; using std::string;
using std::tuple;
using std::wcerr;
using std::string;
using std::endl;
using std::pair;
using std::get;
using std::make_tuple;
using std::vector;
string word_wrap(const string& text, const size_t max_width) { string word_wrap(const string& text, const size_t max_width) {
string output = ""; string output = "";
string thisLine = ""; string thisLine = "";
string nextChunk = ""; string nextChunk = "";
int32_t thisLineStartPosition = 0; int32_t thisLineStartPosition = 0;
int32_t thisLineCurrentPosition = 0; int32_t thisLineCurrentPosition = 0;
int32_t nextSpace = -1; int32_t nextSpace = -1;
int32_t textLength = text.size(); int32_t textLength = text.size();
size_t thisLineLength = 0; size_t thisLineLength = 0;
bool done = false; bool done = false;
while (!done) { while (!done) {
nextSpace = get_index_of(text, " ", thisLineCurrentPosition); nextSpace = get_index_of(text, " ", thisLineCurrentPosition);
if (nextSpace < 0) { if (nextSpace < 0) {
nextSpace = textLength; nextSpace = textLength;
}
nextChunk = get_substring(text, thisLineCurrentPosition, nextSpace - thisLineCurrentPosition);
auto nextChunkLength = nextChunk.size();
if (nextChunkLength > 0) {
auto needsSpace = thisLine.size() > 0;
if (needsSpace) {
thisLine = thisLine + " ";
}
thisLineLength = thisLine.size();
if (nextChunkLength > max_width) {
nextChunk = get_substring(text, thisLineCurrentPosition, max_width - thisLineLength);
nextSpace = thisLineStartPosition + max_width;
thisLine = thisLine + nextChunk;
thisLineCurrentPosition = nextSpace;
} else if(thisLineLength + nextChunkLength > max_width) {
thisLine = make_fit_l(thisLine, max_width, L' ');
} else {
thisLine = thisLine + nextChunk;
thisLineCurrentPosition = nextSpace + 1;
}
thisLineLength = thisLine.size();
} else {
thisLineCurrentPosition = nextSpace + 1;
}
if (thisLineLength >= max_width || thisLineCurrentPosition > textLength) {
if (thisLineCurrentPosition > textLength) {
done = true;
}
thisLine = make_fit_l(thisLine, max_width, L'_');
output += thisLine + (done ? "" : "\n");
thisLine = "";
thisLineLength = thisLine.size();
thisLineStartPosition = thisLineCurrentPosition;
}
}
return output;
} }
nextChunk = get_substring(text, thisLineCurrentPosition, nextSpace - thisLineCurrentPosition);
string string_dollar(const size_t length, const char ch) { auto nextChunkLength = nextChunk.size();
if (ch == '\0') { if (nextChunkLength > 0) {
return string_dollar(length, ' '); auto needsSpace = thisLine.size() > 0;
} if (needsSpace) {
thisLine = thisLine + " ";
string str = ""; }
for (size_t i = 0; i<length; i++) { thisLineLength = thisLine.size();
str += ch; if (nextChunkLength > max_width) {
} nextChunk = get_substring(text, thisLineCurrentPosition, max_width - thisLineLength);
return str; nextSpace = thisLineStartPosition + max_width;
thisLine = thisLine + nextChunk;
thisLineCurrentPosition = nextSpace;
} else if (thisLineLength + nextChunkLength > max_width) {
thisLine = make_fit_l(thisLine, max_width, L' ');
} else {
thisLine = thisLine + nextChunk;
thisLineCurrentPosition = nextSpace + 1;
}
thisLineLength = thisLine.size();
} else {
thisLineCurrentPosition = nextSpace + 1;
} }
if (thisLineLength >= max_width || thisLineCurrentPosition > textLength) {
string left(const string& text, const size_t length) { if (thisLineCurrentPosition > textLength) {
return text.substr(0, length); done = true;
}
thisLine = make_fit_l(thisLine, max_width, L'_');
output += thisLine + (done ? "" : "\n");
thisLine = "";
thisLineLength = thisLine.size();
thisLineStartPosition = thisLineCurrentPosition;
} }
}
string make_fit_l(const string& text, const size_t length, const char pad_character) { return output;
return left(text + string_dollar(length, pad_character != '\0' ? pad_character : ' '), length); }
}
string get_substring(const string& text, const size_t start, const size_t length) { string string_dollar(const size_t length, const char ch) {
return text.substr(std::min<size_t>(start, text.length()), std::max<size_t>(length, 0)); if (ch == '\0') {
} return string_dollar(length, ' ');
}
size_t get_index_of(const string& text, const string& search, const size_t start) { string str = "";
return text.find(search, start); for (size_t i = 0; i < length; i++) {
} str += ch;
} // End namespace SBF }
return str;
}
string left(const string& text, const size_t length) {
return text.substr(0, length);
}
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);
}
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));
}
size_t get_index_of(const string& text, const string& search, const size_t start) {
return text.find(search, start);
}
} // End namespace SBF

View File

@@ -1,59 +1,60 @@
#ifndef UTILS_H__ #ifndef UTILS_H__
#define UTILS_H__ #define UTILS_H__
/*************************************************************************************** /***************************************************************************************
* @file Utils.h * @file Utils.h
* *
* @brief Defines various utility functions. * @brief Defines various utility functions.
* @copyright * @copyright
* Copyright 2023 Tom Hicks * Copyright 2023 Tom Hicks
* 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>
/** \addtogroup Utils /** \addtogroup Utils
* @{ * @{
*/ */
namespace SBF { namespace SBF {
using std::string; 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 string& text, const 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); string word_wrap(const 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); string get_substring(const string& text, const size_t start, const size_t length);
/// @brief Pads or truncates text to length using pad_character. /// @brief Pads 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); string make_fit_l(const string& text, 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); string left(const string& text, const size_t length);
/// @brief Gets a string made by repeating a character.
/// @param length The length of the string to return.
/// @param ch The character to repeat.
/// @return The repeated string.
string string_dollar(const size_t length, const char ch);
} // End namespace SBF
/// @brief Gets a string made by repeating a character.
/// @param length The length of the string to return.
/// @param ch The character to repeat.
/// @return The repeated string.
string string_dollar(const size_t length, const char ch);
} // End namespace SBF
/** @}*/ /** @}*/
#endif // End !defined UTILS_H__ #endif // End !defined UTILS_H__

View File

@@ -1,9 +1,11 @@
#include "Utils.h" #include "Utils.h"
#include "test.h"
#include <string> #include <string>
#include <tuple> #include <tuple>
#include <vector> #include <vector>
#include "test.h"
using namespace SBF; using namespace SBF;
using namespace Test; using namespace Test;
using namespace std; using namespace std;
@@ -15,212 +17,162 @@ TestResults test_left();
TestResults test_make_fit_l(); TestResults test_make_fit_l();
TestResults test_string_dollar(); TestResults test_string_dollar();
TestResults test_word_wrap(); TestResults test_word_wrap();
} // End namespace Test::Utils } // End namespace Test::Utils
using namespace Test::Utils; using namespace Test::Utils;
TestResults main_test_Utils(int argc, char** argv) { TestResults main_test_Utils(int argc, char** argv) {
TestResults results; TestResults results;
results += test_get_index_of();
results += test_get_substring();
results += test_left();
results += test_make_fit_l();
results += test_string_dollar();
results += test_word_wrap();
return results; results += test_get_index_of();
results += test_get_substring();
results += test_left();
results += test_make_fit_l();
results += test_string_dollar();
results += test_word_wrap();
return results;
} }
namespace Test::Utils { namespace Test::Utils {
TestResults test_get_index_of() { TestResults test_get_index_of() {
string long_text = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."; string long_text =
return execute_suite<size_t, string, string, size_t>(make_test_suite( "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's "
"SBF::get_index_of", "standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to "
get_index_of, "make a type specimen book. It has survived not only five centuries, but also the leap into electronic "
vector<TestTuple<size_t, string, string, size_t>>({ "typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset "
make_test<size_t, string, string, size_t>( "sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker "
"should get 0 for the first word in a string", "including versions of Lorem Ipsum.";
0, return execute_suite<size_t, string, string, size_t>(make_test_suite(
make_tuple(long_text, string("Lorem"), size_t(0))), "SBF::get_index_of",
make_test<size_t, string, string, size_t>( get_index_of,
"should get the location of a word in the larger string", vector<TestTuple<size_t, string, string, size_t>>({
22, make_test<size_t, string, string, size_t>(
make_tuple(long_text, string("dummy"), size_t(0))), "should get 0 for the first word in a string", 0, make_tuple(long_text, string("Lorem"), size_t(0))),
make_test<size_t, string, string, size_t>( make_test<size_t, string, string, size_t>("should get the location of a word in the larger string",
"should get -1 for the location of a word that is not int the string", 22,
-1, make_tuple(long_text, string("dummy"), size_t(0))),
make_tuple(long_text, string("acid"), size_t(0))), make_test<size_t, string, string, size_t>(
make_test<size_t, string, string, size_t>( "should get -1 for the location of a word that is not int the string",
"should should get the location of a subsequent word within the string", -1,
120, make_tuple(long_text, string("acid"), size_t(0))),
make_tuple(long_text, string("dummy"), size_t(100))), make_test<size_t, string, string, size_t>(
make_test<size_t, string, string, size_t>( "should should get the location of a subsequent word within the string",
"should get -1 for the location of a word that is before start location in the string", 120,
-1, make_tuple(long_text, string("dummy"), size_t(100))),
make_tuple(long_text, string("dummy"), size_t(long_text.size()))), make_test<size_t, string, string, size_t>(
make_test<size_t, string, string, size_t>( "should get -1 for the location of a word that is before start location in the string",
"should get the location of a word within a simple string", -1,
6, make_tuple(long_text, string("dummy"), size_t(long_text.size()))),
make_tuple(string("these are words"), string("are"), size_t(0))), make_test<size_t, string, string, size_t>("should get the location of a word within a simple string",
make_test<size_t, string, string, size_t>( 6,
"should get the first location of a word within the string", make_tuple(string("these are words"), string("are"), size_t(0))),
4, make_test<size_t, string, string, size_t>("should get the first location of a word within the string",
make_tuple(string("one two one two"), string("two"), size_t(0))), 4,
make_test<size_t, string, string, size_t>( make_tuple(string("one two one two"), string("two"), size_t(0))),
"should get the second location of a word within the string", make_test<size_t, string, string, size_t>("should get the second location of a word within the string",
12, 12,
make_tuple(string("one two one two"), string("two"), size_t(5))), make_tuple(string("one two one two"), string("two"), size_t(5))),
}) })));
));
} }
TestResults test_get_substring() { TestResults test_get_substring() {
return execute_suite<string, string, size_t, size_t>(make_test_suite( return execute_suite<string, string, size_t, size_t>(make_test_suite(
"SBF::get_substring", "SBF::get_substring",
get_substring, get_substring,
vector<TestTuple<string, string, size_t, size_t>>({ vector<TestTuple<string, string, size_t, size_t>>({
make_test<string, string, size_t, size_t>( make_test<string, string, size_t, size_t>(
"should get an empty string if start is too big", "should get an empty string if start is too big", "", make_tuple(string("asdf"), size_t(6), size_t(2))),
"", make_test<string, string, size_t, size_t>(
make_tuple(string("asdf"), size_t(6), size_t(2))), "should get an empty string if count is 0", "", make_tuple(string("asdf"), size_t(0), size_t(0))),
make_test<string, string, size_t, size_t>( make_test<string, string, size_t, size_t>(
"should get an empty string if count is 0", "should get a string that starts at 0", "as", make_tuple(string("asdf"), size_t(0), size_t(2))),
"", make_test<string, string, size_t, size_t>(
make_tuple(string("asdf"), size_t(0), size_t(0))), "should get the whole string", "asdf", make_tuple(string("asdf"), size_t(0), size_t(4))),
make_test<string, string, size_t, size_t>( make_test<string, string, size_t, size_t>("should get a partial string if count is too big",
"should get a string that starts at 0", "asdf",
"as", make_tuple(string("asdf"), size_t(0), size_t(8))),
make_tuple(string("asdf"), size_t(0), size_t(2))), make_test<string, string, size_t, size_t>(
make_test<string, string, size_t, size_t>( "should get a substring", "234", make_tuple(string("1234567890"), size_t(1), size_t(3))),
"should get the whole string", make_test<string, string, size_t, size_t>(
"asdf", "should get a word", "Paris", make_tuple(string("Where is Paris?"), size_t(9), size_t(5))),
make_tuple(string("asdf"), size_t(0), size_t(4))), })));
make_test<string, string, size_t, size_t>(
"should get a partial string if count is too big",
"asdf",
make_tuple(string("asdf"), size_t(0), size_t(8))),
make_test<string, string, size_t, size_t>(
"should get a substring",
"234",
make_tuple(string("1234567890"), size_t(1), size_t(3))),
make_test<string, string, size_t, size_t>(
"should get a word",
"Paris",
make_tuple(string("Where is Paris?"), size_t(9), size_t(5))),
})
));
} }
TestResults test_left() { TestResults test_left() {
return execute_suite<string, string, size_t>(make_test_suite( return execute_suite<string, string, size_t>(make_test_suite(
"SBF::left", "SBF::left",
SBF::left, SBF::left,
vector<TestTuple<string, string, size_t>>({ vector<TestTuple<string, string, size_t>>({
make_test<string, string, size_t>( make_test<string, string, size_t>(
"should get a substring", "should get a substring", "Micro", make_tuple(string("Microsoft QBasic"), size_t(5))),
"Micro", make_test<string, string, size_t>("should get the whole string if length is equal to text.size()",
make_tuple(string("Microsoft QBasic"), size_t(5))), "Microsoft QBasic",
make_test<string, string, size_t>( make_tuple(string("Microsoft QBasic"), size_t(16))),
"should get the whole string if length is equal to text.size()", make_test<string, string, size_t>("should get the whole string if length is greater than text.size()",
"Microsoft QBasic", "Microsoft QBasic",
make_tuple(string("Microsoft QBasic"), size_t(16))), make_tuple(string("Microsoft QBasic"), size_t(20))),
make_test<string, string, size_t>( make_test<string, string, size_t>(
"should get the whole string if length is greater than text.size()", "should get an empty string if length is 0", "", make_tuple(string("Microsoft QBasic"), size_t(0))),
"Microsoft QBasic", make_test<string, string, size_t>(
make_tuple(string("Microsoft QBasic"), size_t(20))), "should get an empty string if text is empty", "", make_tuple(string(""), size_t(1))),
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_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",
make_fit_l, make_fit_l,
vector<TestTuple<string, string, int32_t, char>>({ vector<TestTuple<string, string, int32_t, char>>({
make_test<string, string, int32_t, char>( make_test<string, string, int32_t, char>(
"should truncate a string that is too long", "should truncate a string that is too long", "Micro", make_tuple(string("Microsoft QBasic"), 5, 'A')),
"Micro", make_test<string, string, int32_t, char>(
make_tuple(string("Microsoft QBasic"), 5, 'A')), "should pad a string that is too short", "MicroAAAAA", make_tuple(string("Micro"), 10, 'A')),
make_test<string, string, int32_t, char>( make_test<string, string, int32_t, char>(
"should pad a string that is too short", "should return a string that is perfectly sized", "Micro", make_tuple(string("Micro"), 5, 'A')),
"MicroAAAAA", make_test<string, string, int32_t, char>("should pad the string with spaces if padCh is the null character",
make_tuple(string("Micro"), 10, 'A')), "Micro ",
make_test<string, string, int32_t, char>( make_tuple(string("Micro"), 10, '\0')),
"should return a string that is perfectly sized", make_test<string, string, int32_t, char>(
"Micro", "should return a padded string even if text is empty", "ZZZZZZZZZZ", make_tuple(string(""), 10, 'Z')),
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_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",
string_dollar, string_dollar,
vector<TestTuple<string, size_t, char>>({ vector<TestTuple<string, size_t, char>>({
make_test<string, size_t, char>( make_test<string, size_t, char>("should make a string", "YYYYY", make_tuple(size_t(5), 'Y')),
"should make a string", make_test<string, size_t, char>(
"YYYYY", "should make a string of spaces if ch is the null character", " ", make_tuple(size_t(5), '\0')),
make_tuple(size_t(5), 'Y')), make_test<string, size_t, char>("should make an empty string if length is 0", "", make_tuple(size_t(0), 'C')),
make_test<string, size_t, char>( })));
"should make a string of spaces if ch is the null character",
" ",
make_tuple(size_t(5), '\0')),
make_test<string, size_t, char>(
"should make an empty string if length is 0",
"",
make_tuple(size_t(0), 'C')),
})
));
} }
//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 execute_suite<string, string, int32_t>(make_test_suite(
"SBF::word_wrap", "SBF::word_wrap",
word_wrap, word_wrap,
vector<TestTuple<string, string, int32_t>>({ vector<TestTuple<string, string, int32_t>>({
make_test<string, string, int32_t>( make_test<string, string, int32_t>(
"should return the string if it is shorter than max_width", "should return the string if it is shorter than max_width", "0123_", make_tuple(string("0123"), 5)),
"0123_", make_test<string, string, int32_t>(
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\n5____",
"01234", make_tuple(string("012345"), 5)),
make_tuple(string("01234"), 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>( "01234\n56789\n0____",
"should wrap a string to two lines if it has no whitespace", make_tuple(string("01234567890"), 5)),
"01234\n5____", make_test<string, string, int32_t>("should wrap a string with even spacing",
make_tuple(string("012345"), 5)), "01 23\n45 67\n89 01",
make_test<string, string, int32_t>( make_tuple(string("01 23 45 67 89 01"), 5)),
"should wrap a string to three lines if it has no whitespace", make_test<string, string, int32_t>("should collapse whitespace to a single space",
"01234\n56789\n0____", "01 34\n67 90\n23 56\n89___",
make_tuple(string("01234567890"), 5)), make_tuple(string("01 34 67 90 23 56 89 "), 5)),
make_test<string, string, int32_t>( // TODO: Treat newlines and tabs in text as spaces.
"should wrap a string with even spacing", })));
"01 23\n45 67\n89 01",
make_tuple(string("01 23 45 67 89 01"), 5)),
make_test<string, string, int32_t>(
"should collapse whitespace to a single space",
"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

View File

@@ -1,20 +1,22 @@
#include "Virtues.h" #include "Virtues.h"
#include <string> #include <string>
#include <vector> #include <vector>
namespace SBF { namespace SBF {
const std::string GetVirtueLabel(int id) { const std::string GetVirtueLabel(int id) {
if (id > 0 && id <= kVirtuesCount) { if (id > 0 && id <= kVirtuesCount) {
return kVirtueLabels[id]; return kVirtueLabels[id];
} }
return ""; return "";
}
void FillVirtueLabels(std::vector<std::string>& labels) {
labels.clear();
for (int id = 1; id <= kVirtuesCount; id++) {
labels.push_back(GetVirtueLabel(id));
}
} }
} // End namespace SBF void FillVirtueLabels(std::vector<std::string>& labels) {
labels.clear();
for (int id = 1; id <= kVirtuesCount; id++) {
labels.push_back(GetVirtueLabel(id));
}
}
} // End namespace SBF

View File

@@ -1,44 +1,45 @@
#ifndef VIRTUES_H__ #ifndef VIRTUES_H__
#define VIRTUES_H__ #define VIRTUES_H__
/*************************************************************************************** /***************************************************************************************
* @file Virtues.h * @file Virtues.h
* *
* @brief Defines constants and functions for working with virtues. * @brief Defines constants and functions for working with virtues.
* @copyright * @copyright
* Copyright 2023 Tom Hicks * Copyright 2023 Tom Hicks
* 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> #include <vector>
/** \addtogroup Virtues /** \addtogroup Virtues
* @{ * @{
*/ */
namespace SBF { namespace SBF {
const int kVirtuePoints = 7; const int kVirtuePoints = 7;
const std::string kVirtueUnknownLabel = ""; const std::string kVirtueUnknownLabel = "";
const int kVirtueSelfControlId = 1; const int kVirtueSelfControlId = 1;
const std::string kVirtueSelfControlLabel = "Self-Control"; const std::string kVirtueSelfControlLabel = "Self-Control";
const int kVirtueCourageId = 2; const int kVirtueCourageId = 2;
const std::string kVirtueCourageLabel = "Courage"; const std::string kVirtueCourageLabel = "Courage";
const int kVirtueConscienceId = 3; const int kVirtueConscienceId = 3;
const std::string kVirtueConscienceLabel = "Conscience"; const std::string kVirtueConscienceLabel = "Conscience";
const int kVirtuesCount = 3; const int kVirtuesCount = 3;
const std::string kVirtueLabels[] = { const std::string kVirtueLabels[] = {
kVirtueUnknownLabel, kVirtueUnknownLabel,
kVirtueSelfControlLabel, kVirtueSelfControlLabel,
kVirtueCourageLabel, kVirtueCourageLabel,
kVirtueConscienceLabel, kVirtueConscienceLabel,
}; };
/// @brief Gets the label for virtue with the specified id. /// @brief Gets the label for virtue with the specified id.
/// @param virtue_id The id of the virtue to find. /// @param virtue_id The id of the virtue to find.
/// @return The label for the specified virtue or an empty string if virtue_id is invalid. /// @return The label for the specified virtue or an empty string if virtue_id is invalid.
const std::string GetVirtueLabel(int virtue_id); const std::string GetVirtueLabel(int virtue_id);
/// @brief Fills the vector with all of the valid virtue labels.
/// @param virtue_labels The vector to fill. It will be cleared first.
void FillVirtueLabels(std::vector<std::string>& virtue_labels);
} // End namespace SBF
/// @brief Fills the vector with all of the valid virtue labels.
/// @param virtue_labels The vector to fill. It will be cleared first.
void FillVirtueLabels(std::vector<std::string>& virtue_labels);
} // End namespace SBF
/** @}*/ /** @}*/
#endif // End !defined VIRTUES_H__ #endif // End !defined VIRTUES_H__

View File

@@ -1,8 +1,10 @@
#include "Virtues.h" #include "Virtues.h"
#include "test.h"
#include <string> #include <string>
#include <vector>
#include <tuple> #include <tuple>
#include <vector>
#include "test.h"
using namespace SBF; using namespace SBF;
using namespace Test; using namespace Test;
@@ -11,75 +13,55 @@ using namespace std;
namespace Test::Virtues { namespace Test::Virtues {
TestResults test_GetVirtueLabel(); TestResults test_GetVirtueLabel();
TestResults test_FillVirtueLabels(); TestResults test_FillVirtueLabels();
} // End namespace Test::Virtues } // End namespace Test::Virtues
using namespace Test::Virtues; using namespace Test::Virtues;
TestResults main_test_Virtues(int argc, char** argv) { TestResults main_test_Virtues(int argc, char** argv) {
TestResults results; TestResults results;
results += test_GetVirtueLabel(); results += test_GetVirtueLabel();
results += test_FillVirtueLabels(); results += test_FillVirtueLabels();
return results; return results;
} }
namespace Test::Virtues { namespace Test::Virtues {
TestResults test_GetVirtueLabel() { TestResults test_GetVirtueLabel() {
return execute_suite<string, int>(make_test_suite( return execute_suite<string, int>(make_test_suite(
"SBF::GetVirtueLabel", "SBF::GetVirtueLabel",
GetVirtueLabel, GetVirtueLabel,
vector<TestTuple<string, int>>({ vector<TestTuple<string, int>>({
make_test<string, int>( make_test<string, int>("should get \"\" for invalid virtue id 0", "", make_tuple(0)),
"should get \"\" for invalid virtue id 0", make_test<string, int>("should get \"Self-Control\" for virtue id 1", "Self-Control", make_tuple(1)),
"", make_test<string, int>("should get \"Courage\" for virtue id 2", "Courage", make_tuple(2)),
make_tuple(0)), make_test<string, int>("should get \"Conscience\" for virtue id 3", "Conscience", make_tuple(3)),
make_test<string, int>( make_test<string, int>("should get \"\" for invalid virtue id 4", "", make_tuple(4)),
"should get \"Self-Control\" for virtue id 1", })));
"Self-Control",
make_tuple(1)),
make_test<string, int>(
"should get \"Courage\" for virtue id 2",
"Courage",
make_tuple(2)),
make_test<string, int>(
"should get \"Conscience\" for virtue id 3",
"Conscience",
make_tuple(3)),
make_test<string, int>(
"should get \"\" for invalid virtue id 4",
"",
make_tuple(4)),
})
));
} }
TestResults test_FillVirtueLabels() { TestResults test_FillVirtueLabels() {
auto fnToTest = []()->string { auto fnToTest = []() -> string {
ostringstream error_message; ostringstream error_message;
vector<string> expected = { vector<string> expected = {
kVirtueSelfControlLabel, kVirtueSelfControlLabel,
kVirtueCourageLabel, kVirtueCourageLabel,
kVirtueConscienceLabel, kVirtueConscienceLabel,
};
vector<string> actual = {"This should be removed."};
FillVirtueLabels(actual);
compare(error_message, expected, actual);
string error = error_message.str();
if (error.size() > 0) {
return error;
}
return "no errors";
}; };
return execute_suite<string>(make_test_suite( vector<string> actual = {"This should be removed."};
"SBF::FillVirtueLabels", FillVirtueLabels(actual);
fnToTest, compare(error_message, expected, actual);
vector<TestTuple<string>>({ string error = error_message.str();
make_test<string>( if (error.size() > 0) {
"should fill ranks", return error;
"no errors", }
make_tuple()), return "no errors";
}) };
)); return execute_suite<string>(make_test_suite("SBF::FillVirtueLabels",
fnToTest,
vector<TestTuple<string>>({
make_test<string>("should fill ranks", "no errors", make_tuple()),
})));
} }
} // End namespace Test::Virtues } // End namespace Test::Virtues

View File

@@ -1,7 +1,8 @@
#define _XOPEN_SOURCE_EXTENDED #define _XOPEN_SOURCE_EXTENDED
#include <ncursesw/curses.h> #include <ncursesw/curses.h>
#include <iostream>
#include <cstdio> #include <cstdio>
#include <iostream>
#include <string> #include <string>
#define KEY_ESCAPE 0033 #define KEY_ESCAPE 0033
@@ -23,58 +24,58 @@ using namespace std;
*/ */
int set_double_border(WINDOW* screen) { int set_double_border(WINDOW* screen) {
return wborder_set(screen, return wborder_set(screen,
WACS_D_VLINE/*left side*/, WACS_D_VLINE /*left side*/,
WACS_D_VLINE/*right side*/, WACS_D_VLINE /*right side*/,
WACS_D_HLINE/*top side*/, WACS_D_HLINE /*top side*/,
WACS_D_HLINE/*bottom side*/, WACS_D_HLINE /*bottom side*/,
WACS_D_ULCORNER/*top left corner*/, WACS_D_ULCORNER /*top left corner*/,
WACS_D_URCORNER/*top right corner*/, WACS_D_URCORNER /*top right corner*/,
WACS_D_LLCORNER/*bottom left corner*/, WACS_D_LLCORNER /*bottom left corner*/,
WACS_D_LRCORNER/*bottom right corner*/); WACS_D_LRCORNER /*bottom right corner*/);
} }
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
setlocale(LC_ALL, ""); setlocale(LC_ALL, "");
char buffer[255] = {0}; char buffer[255] = {0};
WINDOW* pWindow = nullptr; WINDOW* pWindow = nullptr;
// Load ncurses and initialize stdscr. // Load ncurses and initialize stdscr.
initscr(); initscr();
pWindow = stdscr; pWindow = stdscr;
// Enable raw mode to give us direct access to extra keys. // Enable raw mode to give us direct access to extra keys.
raw(); raw();
// Disable echoing characters as they are typed. // Disable echoing characters as they are typed.
noecho(); noecho();
// Enable keypad characters. (function keys, arrow keys, and numpad keys.) // Enable keypad characters. (function keys, arrow keys, and numpad keys.)
keypad(pWindow, true); keypad(pWindow, true);
// Remove the delay when pressing esc. // Remove the delay when pressing esc.
set_escdelay(0); set_escdelay(0);
int key = KEY_RESIZE; int key = KEY_RESIZE;
while(key != KEY_ESCAPE) { while (key != KEY_ESCAPE) {
if (key == KEY_RESIZE) { if (key == KEY_RESIZE) {
// Clear the screen. // Clear the screen.
werase(pWindow); werase(pWindow);
// Draw a box around the window with default chars. // Draw a box around the window with default chars.
set_double_border(pWindow); set_double_border(pWindow);
// Display the event // Display the event
mvwaddwstr(pWindow, 2, 2, "Resized"); mvwaddstr(pWindow, 2, 2, "Resized");
// Get the window width and height. // Get the window width and height.
int width; int width;
int height; int height;
getmaxyx(pWindow, height, width); getmaxyx(pWindow, height, width);
// Display the width and height. // Display the width and height.
swprintf(buffer, sizeof(buffer), "width: %i, height: %i", width, height); snprintf(buffer, sizeof(buffer), "width: %i, height: %i", width, height);
mvwaddwstr(pWindow, 1, 2, buffer); mvwaddstr(pWindow, 1, 2, buffer);
} else { } else {
// Display the keycode of the key that was pressed in hex and octal. // Display the keycode of the key that was pressed in hex and octal.
swprintf(buffer, sizeof(buffer), "0x%04X %04o pressed", key, key); snprintf(buffer, sizeof(buffer), "0x%04X %04o pressed", key, key);
mvwaddwstr(pWindow,2, 2, buffer); mvwaddstr(pWindow, 2, 2, buffer);
}
wrefresh(pWindow);
key = wgetch(pWindow);
} }
endwin(); wrefresh(pWindow);
key = wgetch(pWindow);
return 0; }
endwin();
return 0;
} }

View File

@@ -1,19 +1,19 @@
#ifndef MAIN_H__ #ifndef MAIN_H__
#define MAIN_H__ #define MAIN_H__
/*************************************************************************************** /***************************************************************************************
* @file main.h * @file main.h
* *
* @brief Defines stuff for the main app. * @brief Defines stuff for the main app.
* @copyright * @copyright
* Copyright 2023 Tom Hicks * Copyright 2023 Tom Hicks
* Licensed under the MIT license see the LICENSE file for details. * Licensed under the MIT license see the LICENSE file for details.
***************************************************************************************/ ***************************************************************************************/
/** \addtogroup Unsorted /** \addtogroup Unsorted
* @{ * @{
*/ */
namespace SBF { namespace SBF {}
}
/** @}*/ /** @}*/
#endif #endif

View File

@@ -1,8 +1,10 @@
#define _XOPEN_SOURCE_EXTENDED #define _XOPEN_SOURCE_EXTENDED
#include "sbf.h" #include "sbf.h"
#include <ncursesw/curses.h> #include <ncursesw/curses.h>
#include <iostream>
#include <cstdio> #include <cstdio>
#include <iostream>
#include <string> #include <string>
#define KEY_ESCAPE 0033 #define KEY_ESCAPE 0033
@@ -24,58 +26,58 @@ using namespace std;
*/ */
int set_double_border(WINDOW* screen) { int set_double_border(WINDOW* screen) {
return wborder_set(screen, return wborder_set(screen,
WACS_D_VLINE/*left side*/, WACS_D_VLINE /*left side*/,
WACS_D_VLINE/*right side*/, WACS_D_VLINE /*right side*/,
WACS_D_HLINE/*top side*/, WACS_D_HLINE /*top side*/,
WACS_D_HLINE/*bottom side*/, WACS_D_HLINE /*bottom side*/,
WACS_D_ULCORNER/*top left corner*/, WACS_D_ULCORNER /*top left corner*/,
WACS_D_URCORNER/*top right corner*/, WACS_D_URCORNER /*top right corner*/,
WACS_D_LLCORNER/*bottom left corner*/, WACS_D_LLCORNER /*bottom left corner*/,
WACS_D_LRCORNER/*bottom right corner*/); WACS_D_LRCORNER /*bottom right corner*/);
} }
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
setlocale(LC_ALL, ""); setlocale(LC_ALL, "");
char buffer[255] = {0}; char buffer[255] = {0};
WINDOW* pWindow = nullptr; WINDOW* pWindow = nullptr;
// Load ncurses and initialize stdscr. // Load ncurses and initialize stdscr.
initscr(); initscr();
pWindow = stdscr; pWindow = stdscr;
// Enable raw mode to give us direct access to extra keys. // Enable raw mode to give us direct access to extra keys.
raw(); raw();
// Disable echoing characters as they are typed. // Disable echoing characters as they are typed.
noecho(); noecho();
// Enable keypad characters. (function keys, arrow keys, and numpad keys.) // Enable keypad characters. (function keys, arrow keys, and numpad keys.)
keypad(pWindow, true); keypad(pWindow, true);
// Remove the delay when pressing esc. // Remove the delay when pressing esc.
set_escdelay(0); set_escdelay(0);
int key = KEY_RESIZE; int key = KEY_RESIZE;
while(key != KEY_ESCAPE) { while (key != KEY_ESCAPE) {
if (key == KEY_RESIZE) { if (key == KEY_RESIZE) {
// Clear the screen. // Clear the screen.
werase(pWindow); werase(pWindow);
// Draw a box around the window with default chars. // Draw a box around the window with default chars.
set_double_border(pWindow); set_double_border(pWindow);
// Display the event // Display the event
mvwaddstr(pWindow, 2, 2, "Resized"); mvwaddstr(pWindow, 2, 2, "Resized");
// Get the window width and height. // Get the window width and height.
int width; int width;
int height; int height;
getmaxyx(pWindow, height, width); getmaxyx(pWindow, height, width);
// Display the width and height. // Display the width and height.
snprintf(buffer, sizeof(buffer), "width: %i, height: %i", width, height); snprintf(buffer, sizeof(buffer), "width: %i, height: %i", width, height);
mvwaddstr(pWindow, 1, 2, buffer); mvwaddstr(pWindow, 1, 2, buffer);
} else { } else {
// Display the keycode of the key that was pressed in hex and octal. // Display the keycode of the key that was pressed in hex and octal.
snprintf(buffer, sizeof(buffer), "0x%04X %04o pressed", key, key); snprintf(buffer, sizeof(buffer), "0x%04X %04o pressed", key, key);
mvwaddstr(pWindow,2, 2, buffer); mvwaddstr(pWindow, 2, 2, buffer);
}
wrefresh(pWindow);
key = wgetch(pWindow);
} }
endwin(); wrefresh(pWindow);
key = wgetch(pWindow);
return 0; }
endwin();
return 0;
} }

View File

@@ -1,29 +1,26 @@
#ifndef SBF_H__ #ifndef SBF_H__
#define SBF_H__ #define SBF_H__
/*************************************************************************************** /***************************************************************************************
* @file sbf.h * @file sbf.h
* *
* @brief Holds code copied from the BASIC version that hasn't been relocated yet. * @brief Holds code copied from the BASIC version that hasn't been relocated yet.
* @copyright * @copyright
* Copyright 2023 Tom Hicks * Copyright 2023 Tom Hicks
* 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 "Character.h"
#include "Colors.h" #include "Colors.h"
#include "Menus.h" #include "Menus.h"
#include "Character.h"
#include <string>
/** \addtogroup Unsorted /** \addtogroup Unsorted
* @{ * @{
*/ */
namespace SBF { namespace SBF {
using std::string; using std::string;
const int kInitialGeneration = 13;
const int kInitialGeneration = 13;
/* /*
@@ -86,29 +83,29 @@ Sub MainMenu
choice = 0 choice = 0
Do Do
Cls Cls
Print "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͻ" Print "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͻ"
Print "<22> What are you going to do? <20>" Print "<22> What are you going to do? <20>"
Print "<22> 1 = Character Generator <20>" Print "<22> 1 = Character Generator <20>"
Print "<22> 2 = Character Generator for Dummies <20>" Print "<22> 2 = Character Generator for Dummies <20>"
Print "<22> 3 = Combat Computer <20>" Print "<22> 3 = Combat Computer <20>"
Print "<22> 4 = Dice Roller <20>" Print "<22> 4 = Dice Roller <20>"
Print "<22> 5 = Random Character Generator <20>" Print "<22> 5 = Random Character Generator <20>"
Print "<22> 6 = <20>" Print "<22> 6 = <20>"
Print "<22> 7 = Vehicle Generator <20>" Print "<22> 7 = Vehicle Generator <20>"
Print "<22> <20>" Print "<22> <20>"
Print "<22> <20>" Print "<22> <20>"
Print "<22> <20>" Print "<22> <20>"
Print "<22> <20>" Print "<22> <20>"
Print "<22> <20>" Print "<22> <20>"
Print "<22> <20>" Print "<22> <20>"
Print "<22> <20>" Print "<22> <20>"
Print "<22> <20>" Print "<22> <20>"
Print "<22> <20>" Print "<22> <20>"
Print "<22> <20>" Print "<22> <20>"
Print "<22> <20>" Print "<22> <20>"
Print "<22> 0 = End <20>" Print "<22> 0 = End <20>"
Print "<22> <20>" Print "<22> <20>"
Print "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ" Print "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ"
choice = GetChoice(0, 7) choice = GetChoice(0, 7)
Select Case choice Select Case choice
Case 1 Case 1
@@ -129,29 +126,29 @@ End Sub
' This sub is not called. It is here so it can be copied whenever I need to make a new bordered screen. ' This sub is not called. It is here so it can be copied whenever I need to make a new bordered screen.
Sub BlankScreen Sub BlankScreen
Print "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͻ" Print "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͻ"
Print "<22> <20>" Print "<22> <20>"
Print "<22> <20>" Print "<22> <20>"
Print "<22> <20>" Print "<22> <20>"
Print "<22> <20>" Print "<22> <20>"
Print "<22> <20>" Print "<22> <20>"
Print "<22> <20>" Print "<22> <20>"
Print "<22> <20>" Print "<22> <20>"
Print "<22> <20>" Print "<22> <20>"
Print "<22> <20>" Print "<22> <20>"
Print "<22> <20>" Print "<22> <20>"
Print "<22> <20>" Print "<22> <20>"
Print "<22> <20>" Print "<22> <20>"
Print "<22> <20>" Print "<22> <20>"
Print "<22> <20>" Print "<22> <20>"
Print "<22> <20>" Print "<22> <20>"
Print "<22> <20>" Print "<22> <20>"
Print "<22> <20>" Print "<22> <20>"
Print "<22> <20>" Print "<22> <20>"
Print "<22> <20>" Print "<22> <20>"
Print "<22> <20>" Print "<22> <20>"
Print "<22> <20>" Print "<22> <20>"
Print "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ" Print "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ"
End Sub End Sub
Function GetChoice (min As Integer, max As Integer) Function GetChoice (min As Integer, max As Integer)
@@ -203,17 +200,11 @@ Function ChooseStringId (labels() As String, style As MenuStyle, count As Intege
ChooseStringId = choice ChooseStringId = choice
End Function End Function
Function ChooseStringIdWithValues (labels() As String, values() As Integer, style As MenuStyle, count As Integer, prompt As String) Function ChooseStringIdWithValues (labels() As String, values() As Integer, style As MenuStyle, count As Integer, prompt
Cls As String) Cls Dim mnuItems(1 To count) As MenuItem Call BuildMenuWithValues(mnuItems(), labels(), values(), count) Call
Dim mnuItems(1 To count) As MenuItem AdjustMenuStyle(style, mnuItems(), count, FALSE) Print prompt Call PrintMenu(mnuItems(), count, style) choice =
Call BuildMenuWithValues(mnuItems(), labels(), values(), count) GetMenuChoice(mnuItems(), style, count) If choice = style.randomItemId Then choice = GetRandomMenuItemId(mnuItems(),
Call AdjustMenuStyle(style, mnuItems(), count, FALSE) count) ChooseStringIdWithValues = choice End Function
Print prompt
Call PrintMenu(mnuItems(), count, style)
choice = GetMenuChoice(mnuItems(), style, count)
If choice = style.randomItemId Then choice = GetRandomMenuItemId(mnuItems(), count)
ChooseStringIdWithValues = choice
End Function
Function ChooseStringIdWithColors (labels() As String, colors() As Integer, style As MenuStyle, prompt As String) Function ChooseStringIdWithColors (labels() As String, colors() As Integer, style As MenuStyle, prompt As String)
Cls Cls
@@ -234,11 +225,8 @@ Function ChooseStringIdWithColors (labels() As String, colors() As Integer, styl
ChooseStringIdWithColors = choice ChooseStringIdWithColors = choice
End Function End Function
Function ChooseMenuItemId (items() As MenuItem, style As MenuStyle, count As Integer, prompt As String, ignoreValue As Integer) Function ChooseMenuItemId (items() As MenuItem, style As MenuStyle, count As Integer, prompt As String, ignoreValue As
Cls Integer) Cls Call AdjustMenuStyle(style, items(), count, ignoreValue) Print prompt Call PrintMenu(items(), count, style)
Call AdjustMenuStyle(style, items(), count, ignoreValue)
Print prompt
Call PrintMenu(items(), count, style)
choice = GetMenuChoice(items(), style, count) choice = GetMenuChoice(items(), style, count)
If choice = style.randomItemId Then choice = GetRandomMenuItemId(items(), count) If choice = style.randomItemId Then choice = GetRandomMenuItemId(items(), count)
ChooseMenuItemId = choice ChooseMenuItemId = choice
@@ -269,11 +257,9 @@ Sub CGGetDisciplines (ch As CharacterType)
While disciplinePoints > 0 While disciplinePoints > 0
Cls Cls
Call FillDisciplines(ch, disciplineValues()) Call FillDisciplines(ch, disciplineValues())
discipline = ChooseStringIdWithValues(Disciplines(), disciplineValues(), ms, DISCIPLINES_COUNT, "Which discipline do you want to spend 1 of your " + itos$(disciplinePoints) + " points on?") discipline = ChooseStringIdWithValues(Disciplines(), disciplineValues(), ms, DISCIPLINES_COUNT, "Which
Call SetDiscipline(ch, discipline, GetDiscipline(ch, discipline) + 1) discipline do you want to spend 1 of your " + itos$(disciplinePoints) + " points on?") Call SetDiscipline(ch,
disciplinePoints = disciplinePoints - 1 discipline, GetDiscipline(ch, discipline) + 1) disciplinePoints = disciplinePoints - 1 Wend End Sub
Wend
End Sub
Sub CGGetAttributes (ch As CharacterType) Sub CGGetAttributes (ch As CharacterType)
Dim msWithoutValues As MenuStyle Dim msWithoutValues As MenuStyle
@@ -294,16 +280,11 @@ Sub CGGetAttributes (ch As CharacterType)
groupSum = 0 groupSum = 0
rankSum = 1 rankSum = 1
For i = 1 To ATTRIBUTE_GROUPS_COUNT - 1 For i = 1 To ATTRIBUTE_GROUPS_COUNT - 1
nextGroup = ChooseMenuItemId(mnuAttributeGroups(), msWithoutValues, ATTRIBUTE_GROUPS_COUNT, "Choose your " + LCase$(Ranks(i).label) + " attribute?", TRUE) nextGroup = ChooseMenuItemId(mnuAttributeGroups(), msWithoutValues, ATTRIBUTE_GROUPS_COUNT, "Choose your " +
mnuAttributeGroups(nextGroup).isVisible = FALSE LCase$(Ranks(i).label) + " attribute?", TRUE) mnuAttributeGroups(nextGroup).isVisible = FALSE attributeRanks(nextGroup)
attributeRanks(nextGroup) = i = i rankSum = rankSum + i + 1 groupSum = groupSum + nextGroup Next ' General formula for last choice given 1 to count
rankSum = rankSum + i + 1 based indexing is this ' (Sum from 1 to count) - (Sum of all previous choice IDs) '
groupSum = groupSum + nextGroup Sum(1..AllAttributesCount)-Sum(Choice[1]..Choice[AllAttributesCount-1]) lastGroup = rankSum - groupSum
Next
' General formula for last choice given 1 to count based indexing is this
' (Sum from 1 to count) - (Sum of all previous choice IDs)
' Sum(1..AllAttributesCount)-Sum(Choice[1]..Choice[AllAttributesCount-1])
lastGroup = rankSum - groupSum
attributeRanks(lastGroup) = ATTRIBUTE_GROUPS_COUNT attributeRanks(lastGroup) = ATTRIBUTE_GROUPS_COUNT
' Spend attribute points ' Spend attribute points
@@ -315,11 +296,9 @@ Sub CGGetAttributes (ch As CharacterType)
ReDim values(1 To count) As Integer ReDim values(1 To count) As Integer
For attrPoints = GetAttributePointsForRank(rank) To 1 Step -1 For attrPoints = GetAttributePointsForRank(rank) To 1 Step -1
Call FillAttributeValues(ch, values(), group) Call FillAttributeValues(ch, values(), group)
attribute = ChooseStringIdWithValues(attributes(), values(), msWithValues, count, "Which " + LCase$(AttributeGroups(group)) + " attribute do you want to spend 1 of your " + itos$(attrPoints) + " points on?") attribute = ChooseStringIdWithValues(attributes(), values(), msWithValues, count, "Which " +
Call SetAttributeValue(ch, group, attribute, GetAttributeValue(ch, group, attribute) + 1) LCase$(AttributeGroups(group)) + " attribute do you want to spend 1 of your " + itos$(attrPoints) + " points on?") Call
Next SetAttributeValue(ch, group, attribute, GetAttributeValue(ch, group, attribute) + 1) Next Next End Sub
Next
End Sub
Sub CGGetAbilities (ch As CharacterType) Sub CGGetAbilities (ch As CharacterType)
Dim msWithoutValues As MenuStyle Dim msWithoutValues As MenuStyle
@@ -340,16 +319,11 @@ Sub CGGetAbilities (ch As CharacterType)
groupSum = 0 groupSum = 0
rankSum = 1 rankSum = 1
For i = 1 To ABILITY_GROUPS_COUNT - 1 For i = 1 To ABILITY_GROUPS_COUNT - 1
nextAbility = ChooseMenuItemId(mnuAbilityGroups(), msWithoutValues, ABILITY_GROUPS_COUNT, "Choose your " + LCase$(Ranks(i).label) + " ability?", TRUE) nextAbility = ChooseMenuItemId(mnuAbilityGroups(), msWithoutValues, ABILITY_GROUPS_COUNT, "Choose your " +
mnuAbilityGroups(nextAbility).isVisible = FALSE LCase$(Ranks(i).label) + " ability?", TRUE) mnuAbilityGroups(nextAbility).isVisible = FALSE abilityRanks(nextAbility) =
abilityRanks(nextAbility) = i i rankSum = rankSum + i + 1 groupSum = groupSum + nextAbility Next ' General formula for last choice given 1 to count
rankSum = rankSum + i + 1 based indexing is this ' (Sum from 1 to count) - (Sum of all previous choice IDs) '
groupSum = groupSum + nextAbility Sum(1..AllAttributesCount)-Sum(Choice[1]..Choice[AllAttributesCount-1]) lastGroup = rankSum - groupSum
Next
' General formula for last choice given 1 to count based indexing is this
' (Sum from 1 to count) - (Sum of all previous choice IDs)
' Sum(1..AllAttributesCount)-Sum(Choice[1]..Choice[AllAttributesCount-1])
lastGroup = rankSum - groupSum
abilityRanks(lastGroup) = ABILITY_GROUPS_COUNT abilityRanks(lastGroup) = ABILITY_GROUPS_COUNT
' Spend ability points ' Spend ability points
@@ -361,11 +335,9 @@ Sub CGGetAbilities (ch As CharacterType)
ReDim values(1 To count) As Integer ReDim values(1 To count) As Integer
For abilityPoints = GetAbilityPointsForRank(rank) To 1 Step -1 For abilityPoints = GetAbilityPointsForRank(rank) To 1 Step -1
Call FillAbilityValues(ch, values(), group) Call FillAbilityValues(ch, values(), group)
ability = ChooseStringIdWithValues(abilityNames(), values(), msWithValues, count, "Which " + LCase$(Abilities(i).singular) + " would you like to spend 1 of your " + itos$(abilityPoints) + " points on?") ability = ChooseStringIdWithValues(abilityNames(), values(), msWithValues, count, "Which " +
Call SetAbilityValue(ch, group, ability, GetAbilityValue(ch, group, ability) + 1) LCase$(Abilities(i).singular) + " would you like to spend 1 of your " + itos$(abilityPoints) + " points on?") Call
Next SetAbilityValue(ch, group, ability, GetAbilityValue(ch, group, ability) + 1) Next Next End Sub
Next
End Sub
Sub CGGetBackgrounds (ch As CharacterType) Sub CGGetBackgrounds (ch As CharacterType)
' Spend background points ' Spend background points
@@ -376,11 +348,9 @@ Sub CGGetBackgrounds (ch As CharacterType)
While backgroundPoints > 0 While backgroundPoints > 0
Cls Cls
Call FillBackgrounds(ch, backgroundValues()) Call FillBackgrounds(ch, backgroundValues())
background = ChooseStringIdWithValues(Backgrounds(), backgroundValues(), ms, BACKGROUNDS_COUNT, "Which background do you want to spend 1 of your " + itos$(backgroundPoints) + " points on?") background = ChooseStringIdWithValues(Backgrounds(), backgroundValues(), ms, BACKGROUNDS_COUNT, "Which
Call SetBackground(ch, background, GetBackground(ch, background) + 1) background do you want to spend 1 of your " + itos$(backgroundPoints) + " points on?") Call SetBackground(ch,
backgroundPoints = backgroundPoints - 1 background, GetBackground(ch, background) + 1) backgroundPoints = backgroundPoints - 1 Wend End Sub
Wend
End Sub
Sub CGGetRoad (ch As CharacterType) Sub CGGetRoad (ch As CharacterType)
ch.roadName = "Humanity" ch.roadName = "Humanity"
@@ -395,12 +365,9 @@ Sub CGSpendVirtuePoints (ch As CharacterType)
Dim values(1 To VIRTUES_COUNT) As Integer Dim values(1 To VIRTUES_COUNT) As Integer
While virtuePoints > 0 While virtuePoints > 0
Call FillVirtues(ch, values()) Call FillVirtues(ch, values())
virtue = ChooseStringIdWithValues(Virtues(), values(), ms, VIRTUES_COUNT, "Which virtue do you want to spend 1 of your " + itos$(virtuePoints) + " points on?") virtue = ChooseStringIdWithValues(Virtues(), values(), ms, VIRTUES_COUNT, "Which virtue do you want to spend 1
If virtue = 0 Then virtue = GetRandomInt(1, VIRTUES_COUNT) of your " + itos$(virtuePoints) + " points on?") If virtue = 0 Then virtue = GetRandomInt(1, VIRTUES_COUNT) Call
Call SetVirtue(ch, virtue, GetVirtue(ch, virtue) + 1) SetVirtue(ch, virtue, GetVirtue(ch, virtue) + 1) virtuePoints = virtuePoints - 1 Wend End Sub
virtuePoints = virtuePoints - 1
Wend
End Sub
Sub CGGetDerangement (ch As CharacterType) Sub CGGetDerangement (ch As CharacterType)
If ch.clan = CLAN_MALKAVIAN Then If ch.clan = CLAN_MALKAVIAN Then
@@ -409,10 +376,8 @@ Sub CGGetDerangement (ch As CharacterType)
Call NewMenuStyle(ms) Call NewMenuStyle(ms)
ms.useColors = TRUE ms.useColors = TRUE
ch.derangementId = ChooseStringIdWithColors(DerangementLabels(), DerangementColors(), ms, "Which derangement do you want?") ch.derangementId = ChooseStringIdWithColors(DerangementLabels(), DerangementColors(), ms, "Which derangement do
If ch.derangementId = 0 Then ch.derangementId = GetRandomInt(1, DERANGEMENTS_COUNT) you want?") If ch.derangementId = 0 Then ch.derangementId = GetRandomInt(1, DERANGEMENTS_COUNT) End If End Sub
End If
End Sub
Sub CGSpendFreebiePoints (ch As CharacterType) Sub CGSpendFreebiePoints (ch As CharacterType)
End Sub End Sub
@@ -586,15 +551,15 @@ Sub ShowCharacterSheet (ch As CharacterType)
Call FillBackgrounds(ch, backgroundValues()) Call FillBackgrounds(ch, backgroundValues())
'... 0123456789 '... 0123456789
'160 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> '160 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
'170 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> '170 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
'180 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> '180 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
'190 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> '190 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
'200 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> '200 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
'210 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> '210 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
'220 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> '220 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
'230 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD><32><EFBFBD><EFBFBD> '230 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD><32><EFBFBD><EFBFBD>
' enquote forms s/^([ɺ<><C9BA><EFBFBD>].*[<5B><><EFBFBD><EFBFBD>])$/print "$1"/g ' enquote forms s/^([ɺ<><C9BA><EFBFBD>].*[<5B><><EFBFBD><EFBFBD>])$/print "$1"/g
Dim disciplineStrings(3) As String Dim disciplineStrings(3) As String
disciplineStringsIndex = 0 disciplineStringsIndex = 0
@@ -627,47 +592,54 @@ Sub ShowCharacterSheet (ch As CharacterType)
Call MakeWrapLines(derangementStrings(), allDerangementsLine$, 37, 5) Call MakeWrapLines(derangementStrings(), allDerangementsLine$, 37, 5)
Cls Cls
Print "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͻ" Print "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͻ"
Print "<22> Name: " + MakeFitL$(ch.name, 30, " ") + " <20> Gender: " + MakeFitL$(Genders(ch.gender), 14, " ") + " Generation: " + MakeFitR$(itos$(ch.generation), 2, " ") + " <20>" Print "<22> Name: " + MakeFitL$(ch.name, 30, " ") + " <20> Gender: " + MakeFitL$(Genders(ch.gender), 14, " ") + "
Print "<22> Clan: " + MakeFitL$(Clans(ch.clan), 30, " ") + " <20> Age: " + MakeFitL$(ch.age$, 32, " ") + " <20>" Generation: " + MakeFitR$(itos$(ch.generation), 2, " ") + " <20>" Print "<22> Clan: " + MakeFitL$(Clans(ch.clan), 30, " ") + "
Print "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͹ Player: " + MakeFitL$(ch.player$, 29, " ") + " <20>" <EFBFBD> Age: " + MakeFitL$(ch.age$, 32, " ") + " <20>"
Print "<22> Attributes <20> Chronicle: " + MakeFitL$(ch.chronicle$, 26, " ") + " <20>" Print "<22><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͹ Player: " + MakeFitL$(ch.player$, 29, " ") +
Print "<22> Physical Social Mental <20> Haven: " + MakeFitL$(ch.haven$, 30, " ") + " <20>" " <20>" Print "<22> Attributes <20> Chronicle: " + MakeFitL$(ch.chronicle$, 26, " ") + " <20>" Print "<22>
Print "<22> Str. " + MakeFitL$(itos$(ch.attr_strength), 7, " ") + " App. " + MakeFitL$(itos$(ch.attr_appearance), 7, " ") + " Int. " + MakeFitL$(itos$(ch.attr_intelligence), 5, " ") + " <20> Concept: " + MakeFitL$(ch.concept$, 28, " ") + " <20>" Physical Social Mental <20> Haven: " + MakeFitL$(ch.haven$, 30, " ") + " <20>" Print "<22> Str. " +
Print "<22> Dex. " + MakeFitL$(itos$(ch.attr_dexterity), 7, " ") + " Cha. " + MakeFitL$(itos$(ch.attr_charisma), 7, " ") + " Per. " + MakeFitL$(itos$(ch.attr_perception), 5, " ") + " <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͹" MakeFitL$(itos$(ch.attr_strength), 7, " ") + " App. " + MakeFitL$(itos$(ch.attr_appearance), 7, " ") + " Int. " +
Print "<22> Sta. " + MakeFitL$(itos$(ch.attr_stamina), 7, " ") + " Man. " + MakeFitL$(itos$(ch.attr_manipulation), 7, " ") + " Wit. " + MakeFitL$(itos$(ch.attr_wits), 5, " ") + " <20> Derangements: <20>" MakeFitL$(itos$(ch.attr_intelligence), 5, " ") + " <EFBFBD> Concept: " + MakeFitL$(ch.concept$, 28, " ") + " <20>" Print "<22> Dex. "
Print "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͹ " + derangementStrings(0) + " <20>" + MakeFitL$(itos$(ch.attr_dexterity), 7, " ") + " Cha. " + MakeFitL$(itos$(ch.attr_charisma), 7, " ") + " Per. " +
Print "<22> Disciplines: <20> " + derangementStrings(1) + " <20>" MakeFitL$(itos$(ch.attr_perception), 5, " ") + "
Print "<22> " + MakeFitL$(disciplineStrings(0), 36, " ") + " <20> " + MakeFitL$(derangementStrings(2), 37, "_") + " <20>" <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͹"
Print "<22> " + MakeFitL$(disciplineStrings(1), 36, " ") + " <EFBFBD> " + MakeFitL$(derangementStrings(3), 37, "_") + " <20>" Print "<22> Sta. " + MakeFitL$(itos$(ch.attr_stamina), 7, " ") + " Man. " + MakeFitL$(itos$(ch.attr_manipulation), 7, "
Print "<22> " + MakeFitL$(disciplineStrings(2), 36, " ") + " <20> " + MakeFitL$(derangementStrings(4), 37, "_") + " <20>" ") + " Wit. " + MakeFitL$(itos$(ch.attr_wits), 5, " ") + " <20> Derangements: <20>" Print
Print "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͹" "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͹ " + derangementStrings(0) +
Print "<22> " + MakeFitL$(ch.roadName + ": " + itos$(ch.roadValue), 36, " ") + " <20> Nature: " + MakeFitL$(Archetypes(ch.nature), 29, " ") + " <20>" " <20>" Print "<22> Disciplines: <20> " + derangementStrings(1) + " <20>" Print "<22> " +
Print "<22> Willpower: " + MakeFitL$(itos$(ch.willpower), 25, " ") + " <20> Demeanor: " + MakeFitL$(Archetypes(ch.demeanor), 27, " ") + " <20>" MakeFitL$(disciplineStrings(0), 36, " ") + " <20> " + MakeFitL$(derangementStrings(2), 37, "_") + " <20>" Print "<22> " +
Print "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͹" MakeFitL$(disciplineStrings(1), 36, " ") + " <20> " + MakeFitL$(derangementStrings(3), 37, "_") + " <20>" Print "<22> " +
Print "<22> <20>" MakeFitL$(disciplineStrings(2), 36, " ") + " <20> " + MakeFitL$(derangementStrings(4), 37, "_") + " <20>" Print
Print "<22> <20>" "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͹"
Print "<22> <20>" Print "<22> " + MakeFitL$(ch.roadName + ": " + itos$(ch.roadValue), 36, " ") + " <20> Nature: " +
Print "<22> <<PRESS ANY KEY TO CONTINUE>> <20>" MakeFitL$(Archetypes(ch.nature), 29, " ") + " <20>" Print "<22> Willpower: " + MakeFitL$(itos$(ch.willpower), 25, " ") + " <20>
Print "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ" Demeanor: " + MakeFitL$(Archetypes(ch.demeanor), 27, " ") + " <20>" Print
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͹"
Print "<22> <20>"
Print "<22> <20>"
Print "<22> <20>"
Print "<22> <<PRESS ANY KEY TO CONTINUE>> <20>"
Print "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ"
Call PressAnyKeyToContinue Call PressAnyKeyToContinue
Print "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͻ" Print "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͻ"
Print "<22> " + MakeFitC$("Abilities", 76, " ") + " <20>" Print "<22> " + MakeFitC$("Abilities", 76, " ") + " <20>"
Print "<22> " + MakeFitC$("Talents", 25, " ") + " " + MakeFitC$("Skills", 25, " ") + " " + MakeFitC$("Knowledges", 24, " ") + " <20>" Print "<22> " + MakeFitC$("Talents", 25, " ") + " " + MakeFitC$("Skills", 25, " ") + " " + MakeFitC$("Knowledges", 24,
For index = 1 To 10 " ") + " <20>" For index = 1 To 10 Print "<22> " + MakeFitC(MakeFitL$(Talents(index) + ":", 14, " ") + itos$(GetTalent(ch,
Print "<22> " + MakeFitC(MakeFitL$(Talents(index) + ":", 14, " ") + itos$(GetTalent(ch, index)), 25, " ") + " " + MakeFitC(MakeFitL$(Skills(index) + ":", 14, " ") + itos$(GetSkill(ch, index)), 25, " ") + " " + MakeFitC(MakeFitL$(Knowledges(index) + ":", 14, " ") + itos$(GetKnowledge(ch, index)), 24, " ") + " <20>" index)), 25, " ") + " " + MakeFitC(MakeFitL$(Skills(index) + ":", 14, " ") + itos$(GetSkill(ch, index)), 25, " ") + " "
Next + MakeFitC(MakeFitL$(Knowledges(index) + ":", 14, " ") + itos$(GetKnowledge(ch, index)), 24, " ") + " <20>" Next Print
Print "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͹" "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͹"
Print "<22> Backgrounds: <20> Virtues: <20>" Print "<22> Backgrounds: <20> Virtues: <20>"
Print "<22> " + MakeFitL$(backgroundStrings(0), 36, " ") + " <20> " + MakeFitB$("Conscience:", itos$(ch.conscience), 37, " ") + " <20>" Print "<22> " + MakeFitL$(backgroundStrings(0), 36, " ") + " <20> " + MakeFitB$("Conscience:", itos$(ch.conscience), 37, "
Print "<22> " + MakeFitL$(backgroundStrings(1), 36, " ") + " <20> " + MakeFitB$("Self-Control:", itos$(ch.selfControl), 37, " ") + " <20>" ") + " <20>" Print "<22> " + MakeFitL$(backgroundStrings(1), 36, " ") + " <20> " + MakeFitB$("Self-Control:",
Print "<22> " + MakeFitL$(backgroundStrings(2), 36, " ") + " <20> " + MakeFitB$("Courage:", itos$(ch.courage), 37, " ") + " <20>" itos$(ch.selfControl), 37, " ") + " <20>" Print "<22> " + MakeFitL$(backgroundStrings(2), 36, " ") + " <20> " +
Print "<22> " + MakeFitL$(backgroundStrings(3), 36, " ") + " <20> " + MakeFitL$("", 37, " ") + " <20>" MakeFitB$("Courage:", itos$(ch.courage), 37, " ") + " <20>" Print "<22> " + MakeFitL$(backgroundStrings(3), 36, " ") + " <20> " +
Print "<22> " + MakeFitL$(backgroundStrings(4), 36, " ") + " <20> " + MakeFitL$("", 37, " ") + " <20>" MakeFitL$("", 37, " ") + " <20>" Print "<22> " + MakeFitL$(backgroundStrings(4), 36, " ") + " <20> " + MakeFitL$("", 37, " ") + "
Print "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͹" <EFBFBD>" Print
Print "<22> <<PRESS ANY KEY TO CONTINUE>> <20>" "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͹"
Print "<22><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ" Print "<22> <<PRESS ANY KEY TO CONTINUE>> <20>"
Print "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ"
Call PressAnyKeyToContinue Call PressAnyKeyToContinue
End Sub End Sub
@@ -698,10 +670,8 @@ Sub Choice6
Print "Unnamed choice 6" Print "Unnamed choice 6"
End Sub End Sub
' Like the character generator but for vehicles. Much simpler with fewer questions. Prints a vehicle sheet when done. Never finished and crashes mid way through currently. ' Like the character generator but for vehicles. Much simpler with fewer questions. Prints a vehicle sheet when done.
Sub VehicleGenerator Never finished and crashes mid way through currently. Sub VehicleGenerator Print "VehicleGenerator" End Sub
Print "VehicleGenerator"
End Sub
Sub PressAnyKeyToContinue () Sub PressAnyKeyToContinue ()
While InKey$ = "": Wend While InKey$ = "": Wend
@@ -821,6 +791,7 @@ Sub Test
End Sub End Sub
*/ */
} // End namespace SBF } // End namespace SBF
/** #}*/ /** #}*/
#endif // End !defined SBF_H__ #endif // End !defined SBF_H__

View File

@@ -1,230 +1,250 @@
#define _XOPEN_SOURCE_EXTENDED #define _XOPEN_SOURCE_EXTENDED
#include <iostream>
#include <cstdio>
#include <string>
#include <cstdint>
#include <vector>
#include "test.h" #include "test.h"
#include <cstdint>
#include <cstdio>
#include <iostream>
#include <string>
#include <vector>
// using namespace std; // using namespace std;
using std::cout;
using std::tuple;
using std::wcerr;
using std::string; using std::string;
using std::endl;
using std::pair;
using std::get;
using std::make_tuple;
using std::vector; using std::vector;
using Test::TestResults;
using std::optional;
using std::function;
using std::for_each;
// using namespace Test; // using namespace Test;
namespace Test { namespace Test {
// Test lifecycle // Test lifecycle
// suiteSetupFn(); - This is called to allocate any suite level resources. This is called once when the suite begins. // suiteSetupFn(); - This is called to allocate any suite level resources. This is called once when the suite begins.
// These functions may be called in parallel but execution will not proceed past this block until they have all finished. // These functions may be called in parallel but execution will not proceed past this block until they have all
// testSetupFn(); - This is called once for every test in tests. You may use it to allocate resources or setup mocks, stubs, and spies. // finished.
// testFn(...); - This is called once for every test to execute the test. // testSetupFn(); - This is called once for every test in tests. You may use it to allocate resources or setup mocks,
// Only one of these test functions will actually be run for each test in tests. They should return true if the test passed, return false if the test failed or there was an error, and be nullptr if they should be skipped. The executed function will be called with expectedOutput and the result of testFn(...). They can be used to test functions with side effects, especially void functions. // stubs, and spies. testFn(...); - This is called once for every test to execute the test. Only one of these test
// maybe_compare_function; - This is the highest priority compare function. If it is not nullptr then it will be called. // functions will actually be run for each test in tests. They should return true if the test passed, return false if
// suite_compare_function; - This is the second highest priority compare function. If maybe_compare_function is nullptr and this is not nullptr then it will be called. // the test failed or there was an error, and be nullptr if they should be skipped. The executed function will be
// [](TResult expected, TResult actual) { return expected, actual; } - This is the lowest priority compare function. If all other compare functions are nullptr then this will be called to evaluate the test. // called with expectedOutput and the result of testFn(...). They can be used to test functions with side effects,
// testTeardownFn(); - This is called once for every test in tests. You must free/release any resources allocated by testSetupFn. // especially void functions. maybe_compare_function; - This is the highest priority compare function. If it is not
// This ends the parallel test functions section all tests will have completed before execution proceeds. // nullptr then it will be called. suite_compare_function; - This is the second highest priority compare function. If
// Collect reports - Ths step is not visible to the user at this point, but data returned by all of the test functions is collected here. This is where you will eventually be able to format/log data for reports. // maybe_compare_function is nullptr and this is not nullptr then it will be called.
// suiteTeardownFn(); - This is called after all test calls have completed, all testTeardownFn calls have completed, and all test reports/logs have been written. You should free any resources allocated in suiteSetupFn. // [](TResult expected, TResult actual) { return expected, actual; } - This is the lowest priority compare function.
// If all other compare functions are nullptr then this will be called to evaluate the test. testTeardownFn(); - This
// TODO: Add TShared(*)(string /*test_name*/, UUID /*testRunId*/) allocateSharedData to the test tuple to make some shared data that can be used in a thread safe way by setup, teardown, and evaluate steps of the test. // is called once for every test in tests. You must free/release any resources allocated by testSetupFn.
// TODO: Add TShared to be returned by the setup functions, and consumed by the evaluate and teardown functions. // This ends the parallel test functions section all tests will have completed before execution proceeds.
// Suite setup/teardown functions should allocate/free. // Collect reports - Ths step is not visible to the user at this point, but data returned by all of the test functions
// Test setup/teardown functions should consume the data allocated by Suite setup. // is collected here. This is where you will eventually be able to format/log data for reports. suiteTeardownFn(); -
// Test setup functions may allocate additional resources. If they do then the allocated resources they should be freed by test teardown function. // This is called after all test calls have completed, all testTeardownFn calls have completed, and all test
// Suite and/or Test compare functions may consume this shared data, but it will not be shared with the execution of testFn. // reports/logs have been written. You should free any resources allocated in suiteSetupFn.
// This function is called to execute a test suite. You provide it with some configuration info, optional utility callback functions, and test data (input parameters for each call to testFn and the expected result). It returns a TestResults that should be treated as an opaque data type. // TODO: Add TShared(*)(string /*test_name*/, UUID /*testRunId*/) allocateSharedData to the test tuple to make some
// Not all parameters are named in code, but they are named and explained in the comments and will be described by those names below. // shared data that can be used in a thread safe way by setup, teardown, and evaluate steps of the test.
// string suite_label - This is the name of this test suite. It is used for reporting messages. // TODO: Add TShared to be returned by the setup functions, and consumed by the evaluate and teardown functions.
// FnToTest testFn - This is the function to test. This may be replaced if necessary by function. It may not currently support class methods, but that is planned. // Suite setup/teardown functions should allocate/free.
// vector<tuple<...>> tests - This is the test run data. Each tuple in the vector is a single test run. It's members are explained below. // Test setup/teardown functions should consume the data allocated by Suite setup.
// string test_name - This is the name of this test. It is used for reporting messages. // Test setup functions may allocate additional resources. If they do then the allocated resources they should be
// TResult expectedOutput - This is the expected result of executing this test. // freed by test teardown function. Suite and/or Test compare functions may consume this shared data, but it will not
// bool(*)(const TResult expected, const TResult actual) maybe_compare_function - This is optional. If unset or set to nullptr it is skipped. If set to a function it is called to evaluate the test results. It takes the expected and actual results as parameters and should return true if the test passed and false otherwise. This may be changed to return a TestResults at some point. // be shared with the execution of testFn.
// void(*)(TInputParams...) testSetupFn - This is optional. If unset or set to nullptr it is skipped. If set to a function it is called before each test to setup the environment for the test. You may use it to allocate resources and setup mocks, stubs, and spies.
// void(*)(TInputParams...) testTeardownFn - This is optiona. If unset or set to nullptr it is skipped. If set to a function it is called after each test to cleanup the environment after the test. You should free resources allocated by testSetupFn.
// bool isEnabled - This is optional. If unset or set to true the test is run. If set to false this test is skipped. If skipped it will be reported as a skipped/disabled test.
// bool(*)(const TResult expected, const TResult actual) suite_compare_function - This is optional. If unset or set to nullptr it is skipped. If set to a function and maybe_compare_function is not called for a test run then this function is called to evaluate the test results. It takes the expected and actual results as parameters and should return true if the test passed and false otherwise. This may be changed to return a TestResults at some point.
// void(*)() suiteSetupFn - This is optional. If unset or set to nullptr it is skipped. If set to a function it is called before starting this test suite to setup the environment. You may use it to allocate resources and setup mocks, stubs, and spies.
// void(*)() suiteTeardownFn - This is optional. If unset or set to nullptr it is skipped. If set to a function it is called after all tests in this suite have finished and all reporting has finished. You should free resources allocated by suiteSetupFn.
// This method should be called like so. This is the minimal call and omits all of the optional params. This is the most common usage. You should put one tuple of inputs and expected output for each test case.
// results = collect_and_report_TestResultstest_fn(
// "Test: functionUnderTest",
// functionUnderTest,
// vector({
// make_tuple(
// "ShouldReturnAppleForGroupId_1_and_ItemId_2",
// string("Apple"),
// make_tuple(1,2),
// ),
// }),
// );
// The suites can be run from one file as such. From a file called ThingDoer_test.cpp to test the class/methods ThingDoer declared in ThingDoer.cpp. This isn't mandatory but is a best practice.
// You can use testFn without calling collect_and_report_TestResults() and also could call it from a normal int main(int argc, char** argv) or other function.
// TestResults test_main_ThingDoer(int argc, char** argv) {
// TestResults results;
// results = collect_and_report_TestResults(results, testFn("doThing1", ...), argc, argv);
// results = collect_and_report_TestResults(results, testFn("doThing2", ...), argc, argv);
// return results;
// }
// Then some test harness either generated or explicit can call test_main_ThingDoer(...) and optionally reported there. Reporting granularity is controlled by how frequently you call collect_and_report_TestResults(...).
// You can combine test results with results = results + testFn(..); and then collect_and_report_TestResults on the aggregate TestResults value.
// _Step_9 - if T2 is a single value then make_tuple<T2>(T2) and call longer version // This function is called to execute a test suite. You provide it with some configuration info, optional utility
// auto testFunction = [](int id){return id==0?"":"";}; // callback functions, and test data (input parameters for each call to testFn and the expected result). It returns a
// auto compareFunction = [](const string a, const string b){return a==b;}; // TestResults that should be treated as an opaque data type. Not all parameters are named in code, but they are named
// template<typename TResult, typename FnToTest, typename... TInputParams> // and explained in the comments and will be described by those names below.
// string suite_label - This is the name of this test suite. It is used for reporting messages.
// FnToTest testFn - This is the function to test. This may be replaced if necessary by function. It may not currently
// support class methods, but that is planned. vector<tuple<...>> tests - This is the test run data. Each tuple in the
// vector is a single test run. It's members are explained below.
// string test_name - This is the name of this test. It is used for reporting messages.
// TResult expectedOutput - This is the expected result of executing this test.
// bool(*)(const TResult expected, const TResult actual) maybe_compare_function - This is optional. If unset or set
// to nullptr it is skipped. If set to a function it is called to evaluate the test results. It takes the expected
// and actual results as parameters and should return true if the test passed and false otherwise. This may be
// changed to return a TestResults at some point. void(*)(TInputParams...) testSetupFn - This is optional. If unset
// or set to nullptr it is skipped. If set to a function it is called before each test to setup the environment for
// the test. You may use it to allocate resources and setup mocks, stubs, and spies. void(*)(TInputParams...)
// testTeardownFn - This is optiona. If unset or set to nullptr it is skipped. If set to a function it is called
// after each test to cleanup the environment after the test. You should free resources allocated by testSetupFn.
// bool isEnabled - This is optional. If unset or set to true the test is run. If set to false this test is skipped.
// If skipped it will be reported as a skipped/disabled test.
// bool(*)(const TResult expected, const TResult actual) suite_compare_function - This is optional. If unset or set to
// nullptr it is skipped. If set to a function and maybe_compare_function is not called for a test run then this
// function is called to evaluate the test results. It takes the expected and actual results as parameters and should
// return true if the test passed and false otherwise. This may be changed to return a TestResults at some point.
// void(*)() suiteSetupFn - This is optional. If unset or set to nullptr it is skipped. If set to a function it is
// called before starting this test suite to setup the environment. You may use it to allocate resources and setup
// mocks, stubs, and spies. void(*)() suiteTeardownFn - This is optional. If unset or set to nullptr it is skipped. If
// set to a function it is called after all tests in this suite have finished and all reporting has finished. You
// should free resources allocated by suiteSetupFn.
// This method should be called like so. This is the minimal call and omits all of the optional params. This is the most
// common usage. You should put one tuple of inputs and expected output for each test case.
// results = collect_and_report_TestResultstest_fn(
// "Test: functionUnderTest",
// functionUnderTest,
// vector({
// make_tuple(
// "ShouldReturnAppleForGroupId_1_and_ItemId_2",
// string("Apple"),
// make_tuple(1,2),
// ),
// }),
// );
// The suites can be run from one file as such. From a file called ThingDoer_test.cpp to test the class/methods
// ThingDoer declared in ThingDoer.cpp. This isn't mandatory but is a best practice. You can use testFn without calling
// collect_and_report_TestResults() and also could call it from a normal int main(int argc, char** argv) or other
// function.
// TestResults test_main_ThingDoer(int argc, char** argv) {
// TestResults results;
// results = collect_and_report_TestResults(results, testFn("doThing1", ...), argc, argv);
// results = collect_and_report_TestResults(results, testFn("doThing2", ...), argc, argv);
// return results;
// }
// Then some test harness either generated or explicit can call test_main_ThingDoer(...) and optionally reported there.
// Reporting granularity is controlled by how frequently you call collect_and_report_TestResults(...). You can combine
// test results with results = results + testFn(..); and then collect_and_report_TestResults on the aggregate
// TestResults value.
// _Step_10 - // _Step_9 - if T2 is a single value then make_tuple<T2>(T2) and call longer version
// test_fn(string, _FnToTest, vector<tuple<string, _T1, _CompareFn, <tuple<_T2...>>>) // auto testFunction = [](int id){return id==0?"":"";};
// Default to (string, _FnToTest, vector<tuple<"", _T1, [](a,b){return a==b;}, make_tuple()) // auto compareFunction = [](const string a, const string b){return a==b;};
// Also allow make_tuple(T2) if the last param is not a tuple. // template<typename TResult, typename FnToTest, typename... TInputParams>
TestResults::TestResults() // _Step_10 -
: errors_(0) // test_fn(string, _FnToTest, vector<tuple<string, _T1, _CompareFn, <tuple<_T2...>>>)
, failed_(0) // Default to (string, _FnToTest, vector<tuple<"", _T1, [](a,b){return a==b;}, make_tuple())
, passed_(0) // Also allow make_tuple(T2) if the last param is not a tuple.
, skipped_(0)
, total_(0) {}
TestResults::TestResults(const TestResults& other) TestResults::TestResults() : errors_(0), failed_(0), passed_(0), skipped_(0), total_(0) {}
: error_messages_(other.error_messages_)
, errors_(other.errors_)
, failed_(other.failed_)
, failure_messages_(other.failure_messages_)
, passed_(other.passed_)
, skip_messages_(other.skip_messages_)
, skipped_(other.skipped_)
, total_(other.total_) {}
TestResults::TestResults(uint32_t errors, uint32_t failed, uint32_t passed, uint32_t skipped, uint32_t total, vector<string> error_messages, vector<string> failure_messages, vector<string> skip_messages) TestResults::TestResults(const TestResults& other)
: error_messages_(error_messages) : error_messages_(other.error_messages_),
, errors_(errors) errors_(other.errors_),
, failed_(failed) failed_(other.failed_),
, failure_messages_(failure_messages) failure_messages_(other.failure_messages_),
, passed_(passed) passed_(other.passed_),
, skip_messages_(skip_messages) skip_messages_(other.skip_messages_),
, skipped_(skipped) skipped_(other.skipped_),
, total_(total) {} total_(other.total_) {}
TestResults& TestResults::error() { TestResults::TestResults(uint32_t errors,
errors_++; uint32_t failed,
return *this; uint32_t passed,
} uint32_t skipped,
uint32_t total,
vector<string> error_messages,
vector<string> failure_messages,
vector<string> skip_messages)
: error_messages_(error_messages),
errors_(errors),
failed_(failed),
failure_messages_(failure_messages),
passed_(passed),
skip_messages_(skip_messages),
skipped_(skipped),
total_(total) {}
TestResults& TestResults::error(string message) { TestResults& TestResults::error() {
errors_++; errors_++;
error_messages_.push_back(message); return *this;
return *this; }
}
TestResults& TestResults::fail() { TestResults& TestResults::error(string message) {
total_++; errors_++;
failed_++; error_messages_.push_back(message);
return *this; return *this;
} }
TestResults& TestResults::fail(const string& message) { TestResults& TestResults::fail() {
total_++; total_++;
failed_++; failed_++;
failure_messages_.push_back(message); return *this;
return *this; }
}
vector<string> TestResults::failure_messages() { TestResults& TestResults::fail(const string& message) {
return failure_messages_; total_++;
} failed_++;
failure_messages_.push_back(message);
return *this;
}
TestResults& TestResults::pass() { vector<string> TestResults::failure_messages() {
total_++; return failure_messages_;
passed_++; }
return *this;
}
TestResults& TestResults::skip() { TestResults& TestResults::pass() {
total_++; total_++;
skipped_++; passed_++;
return *this; return *this;
} }
TestResults& TestResults::skip(const string& message) { TestResults& TestResults::skip() {
total_++; total_++;
skipped_++; skipped_++;
skip_messages_.push_back(message); return *this;
return *this; }
}
vector<string> TestResults::skip_messages() { TestResults& TestResults::skip(const string& message) {
return skip_messages_; total_++;
} skipped_++;
skip_messages_.push_back(message);
return *this;
}
vector<string> TestResults::error_messages() { vector<string> TestResults::skip_messages() {
return error_messages_; return skip_messages_;
} }
uint32_t TestResults::errors() { vector<string> TestResults::error_messages() {
return errors_; return error_messages_;
} }
uint32_t TestResults::failed() { uint32_t TestResults::errors() {
return failed_; return errors_;
} }
uint32_t TestResults::passed() { uint32_t TestResults::failed() {
return passed_; return failed_;
} }
uint32_t TestResults::skipped() { uint32_t TestResults::passed() {
return skipped_; return passed_;
} }
uint32_t TestResults::total() { uint32_t TestResults::skipped() {
return total_; return skipped_;
} }
TestResults TestResults::operator+(const TestResults& other) const { uint32_t TestResults::total() {
vector<string> error_messages; return total_;
error_messages.insert(error_messages.end(), error_messages_.begin(), error_messages_.end()); }
error_messages.insert(error_messages.end(), other.error_messages_.begin(), other.error_messages_.end());
vector<string> failure_messages;
failure_messages.insert(failure_messages.end(), failure_messages_.begin(), failure_messages_.end());
failure_messages.insert(failure_messages.end(), other.failure_messages_.begin(), other.failure_messages_.end());
vector<string> skip_messages;
skip_messages.insert(skip_messages.end(), skip_messages_.begin(), skip_messages_.end());
skip_messages.insert(skip_messages.end(), other.skip_messages_.begin(), other.skip_messages_.end());
return TestResults(
errors_ + other.errors_,
failed_ + other.failed_,
passed_ + other.passed_,
skipped_ + other.skipped_,
total_ + other.total_,
error_messages,
failure_messages,
skip_messages);
}
TestResults& TestResults::operator+=(const TestResults& other) { TestResults TestResults::operator+(const TestResults& other) const {
error_messages_.insert(error_messages_.end(), other.error_messages_.begin(), other.error_messages_.end()); vector<string> error_messages;
errors_ += other.errors_; error_messages.insert(error_messages.end(), error_messages_.begin(), error_messages_.end());
failed_ += other.failed_; error_messages.insert(error_messages.end(), other.error_messages_.begin(), other.error_messages_.end());
failure_messages_.insert(failure_messages_.end(), other.failure_messages_.begin(), other.failure_messages_.end()); vector<string> failure_messages;
passed_ += other.passed_; failure_messages.insert(failure_messages.end(), failure_messages_.begin(), failure_messages_.end());
skip_messages_.insert(skip_messages_.end(), other.skip_messages_.begin(), other.skip_messages_.end()); failure_messages.insert(failure_messages.end(), other.failure_messages_.begin(), other.failure_messages_.end());
skipped_ += other.skipped_; vector<string> skip_messages;
total_ += other.total_; skip_messages.insert(skip_messages.end(), skip_messages_.begin(), skip_messages_.end());
return *this; skip_messages.insert(skip_messages.end(), other.skip_messages_.begin(), other.skip_messages_.end());
}
} // End namespace Test return TestResults(errors_ + other.errors_,
failed_ + other.failed_,
passed_ + other.passed_,
skipped_ + other.skipped_,
total_ + other.total_,
error_messages,
failure_messages,
skip_messages);
}
TestResults& TestResults::operator+=(const TestResults& other) {
error_messages_.insert(error_messages_.end(), other.error_messages_.begin(), other.error_messages_.end());
errors_ += other.errors_;
failed_ += other.failed_;
failure_messages_.insert(failure_messages_.end(), other.failure_messages_.begin(), other.failure_messages_.end());
passed_ += other.passed_;
skip_messages_.insert(skip_messages_.end(), other.skip_messages_.begin(), other.skip_messages_.end());
skipped_ += other.skipped_;
total_ += other.total_;
return *this;
}
} // End namespace Test

View File

@@ -1,466 +1,500 @@
#ifndef TEST_H__ #ifndef TEST_H__
#define TEST_H__ #define TEST_H__
/*************************************************************************************** /***************************************************************************************
* @file test.h * @file test.h
* *
* @brief Defines structs and functions for implementing TinyTest. * @brief Defines structs and functions for implementing TinyTest.
* @copyright * @copyright
* Copyright 2023 Tom Hicks * Copyright 2023 Tom Hicks
* 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 <tuple>
#include <utility>
#include <string>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <string>
#include <tuple>
#include <utility>
// Test lifecycle // Test lifecycle
// suite_setup_function(); - This is called to allocate any suite level resources. This is called once when the suite begins. // suite_setup_function(); - This is called to allocate any suite level resources. This is called once when the suite
// These functions may be called in parallel but execution will not proceed past this block until they have all finished. // begins. These functions may be called in parallel but execution will not proceed past this block until they have all
// test_setup_function(); - This is called once for every test in tests. You may use it to allocate resources or setup mocks, stubs, and spies. // finished.
// function_to_test(...); - This is called once for every test to execute the test. // test_setup_function(); - This is called once for every test in tests. You may use it to allocate resources or setup
// Only one of these test functions will actually be run for each test in tests. They should return true if the test passed, return false if the test failed or there was an error, and be nullptr if they should be skipped. The executed function will be called with expected_output and the result of function_to_test(...). They can be used to test functions with side effects, especially void functions. // mocks, stubs, and spies. function_to_test(...); - This is called once for every test to execute the test. Only one
// test_compare_function; - This is the highest priority compare function. If it is not nullptr then it will be called. // of these test functions will actually be run for each test in tests. They should return true if the test passed,
// suite_compare_function; - This is the second highest priority compare function. If test_compare_function is nullptr and this is not nullptr then it will be called. // return false if the test failed or there was an error, and be nullptr if they should be skipped. The executed
// [](TResult expected, TResult actual) { return expected, actual; } - This is the lowest priority compare function. If all other compare functions are nullptr then this will be called to evaluate the test. // function will be called with expected_output and the result of function_to_test(...). They can be used to test
// test_teardown_function(); - This is called once for every test in tests. You must free/release any resources allocated by test_setup_function. // functions with side effects, especially void functions. test_compare_function; - This is the highest priority
// compare function. If it is not nullptr then it will be called. suite_compare_function; - This is the second highest
// priority compare function. If test_compare_function is nullptr and this is not nullptr then it will be called.
// [](TResult expected, TResult actual) { return expected, actual; } - This is the lowest priority compare function.
// If all other compare functions are nullptr then this will be called to evaluate the test. test_teardown_function();
// - This is called once for every test in tests. You must free/release any resources allocated by
// test_setup_function.
// This ends the parallel test functions section all tests will have completed before execution proceeds. // This ends the parallel test functions section all tests will have completed before execution proceeds.
// Collect reports - Ths step is not visible to the user at this point, but data returned by all of the test functions is collected here. This is where you will eventually be able to format/log data for reports. // Collect reports - Ths step is not visible to the user at this point, but data returned by all of the test functions
// suite_teardown_function(); - This is called after all test calls have completed, all test_teardown_function calls have completed, and all test reports/logs have been written. You should free any resources allocated in suite_setup_function. // is collected here. This is where you will eventually be able to format/log data for reports.
// suite_teardown_function(); - This is called after all test calls have completed, all test_teardown_function calls
// have completed, and all test reports/logs have been written. You should free any resources allocated in
// suite_setup_function.
// Tuple printer from: https://stackoverflow.com/questions/6245735/pretty-print-stdtuple/31116392#58417285 // Tuple printer from: https://stackoverflow.com/questions/6245735/pretty-print-stdtuple/31116392#58417285
template<typename TChar, typename TTraits, typename... TArgs> template <typename TChar, typename TTraits, typename... TArgs>
auto& operator<<(std::basic_ostream<TChar, TTraits>& os, std::tuple<TArgs...> const& t) { auto& operator<<(std::basic_ostream<TChar, TTraits>& os, std::tuple<TArgs...> const& t) {
std::apply([&os](auto&&... args) {((os << args << " "), ...);}, t); std::apply([&os](auto&&... args) { ((os << args << " "), ...); }, t);
return os; return os;
} }
template<typename TChar, typename TTraits, typename TItem> template <typename TChar, typename TTraits, typename TItem>
auto& operator<<(std::basic_ostream<TChar, TTraits>& os, std::vector<TItem> v) { auto& operator<<(std::basic_ostream<TChar, TTraits>& os, std::vector<TItem> v) {
os << "[ "; os << "[ ";
for (auto it = v.begin(); it != v.end(); it++) { for (auto it = v.begin(); it != v.end(); it++) {
if (it != v.begin()) { if (it != v.begin()) {
os << ", "; os << ", ";
}
os << *it;
} }
os << " ]"; os << *it;
return os; }
os << " ]";
return os;
} }
template<typename TChar, typename TTraits, typename TItem> template <typename TChar, typename TTraits, typename TItem>
auto& compare(std::basic_ostream<TChar, TTraits>& error_message, std::vector<TItem> expected, std::vector<TItem> actual) { auto& compare(std::basic_ostream<TChar, TTraits>& error_message,
if (expected.size() != actual.size()) { std::vector<TItem> expected,
error_message << "size mismatch expected: " << expected.size() << ", actual: " << actual.size(); std::vector<TItem> actual) {
return error_message; if (expected.size() != actual.size()) {
} error_message << "size mismatch expected: " << expected.size() << ", actual: " << actual.size();
for (size_t index = 0; index < expected.size(); index++) {
if (expected[index] != actual[index]) {
error_message << "vectors differ at index " << index
<< ", \"" << expected[index] << "\" != \"" << actual[index]
<< "\", expected: \"" << expected
<< "\", actual: \"" << actual << "\"";
return error_message;
}
}
return error_message; return error_message;
}
for (size_t index = 0; index < expected.size(); index++) {
if (expected[index] != actual[index]) {
error_message << "vectors differ at index " << index << ", \"" << expected[index] << "\" != \"" << actual[index]
<< "\", expected: \"" << expected << "\", actual: \"" << actual << "\"";
return error_message;
}
}
return error_message;
} }
namespace Test { namespace Test {
using std::tuple; using std::string;
using std::pair; using std::tuple;
using std::vector; using std::vector;
using std::string;
/// @brief /// @brief
class TestResults { class TestResults {
public: public:
/// @brief Creates an empty TestResults instance representing no tests run. /// @brief Creates an empty TestResults instance representing no tests run.
TestResults(); TestResults();
/// @brief Creates a new TestResults instance that is a copy of other. /// @brief Creates a new TestResults instance that is a copy of other.
/// @param other /// @param other
TestResults(const TestResults& other); TestResults(const TestResults& other);
/// @brief Creates a new TestResults instance with specific counts.
/// @param errors The number of errors while running the tests.
/// @param failed The number of failed tests.
/// @param passed The number of passed tests.
/// @param skipped The number of skipped tests.
/// @param total The total number of tests run. This should equal the sum of failed, passed, and skipped tests.
/// @param error_messages The list of error messages.
/// @param failure_messages The list of failure messages.
/// @param skip_messages The list of skip messages.
TestResults(uint32_t errors, uint32_t failed, uint32_t passed, uint32_t skipped, uint32_t total, std::vector<std::string> error_messages, std::vector<std::string> failure_messages, std::vector<std::string> skip_messages);
/// @brief Adds an error. This increments errors.
/// @return A reference to this instance. Used for chaining.
TestResults& error();
/// @brief Adds an error with a message. This increments errors as well as saving the error message. /// @brief Creates a new TestResults instance with specific counts.
/// @param message The error message. /// @param errors The number of errors while running the tests.
/// @return A reference to this instance. Used for chaining. /// @param failed The number of failed tests.
TestResults& error(std::string message); /// @param passed The number of passed tests.
/// @param skipped The number of skipped tests.
/// @param total The total number of tests run. This should equal the sum of failed, passed, and skipped tests.
/// @param error_messages The list of error messages.
/// @param failure_messages The list of failure messages.
/// @param skip_messages The list of skip messages.
TestResults(uint32_t errors,
uint32_t failed,
uint32_t passed,
uint32_t skipped,
uint32_t total,
std::vector<std::string> error_messages,
std::vector<std::string> failure_messages,
std::vector<std::string> skip_messages);
/// @brief Adds a failed test. This increments total and failed. /// @brief Adds an error. This increments errors.
/// @return A reference to this instance. Used for chaining. /// @return A reference to this instance. Used for chaining.
TestResults& fail(); TestResults& error();
/// @brief Adds a failed test with a message. This increments total and failed as well as saving the failure message. /// @brief Adds an error with a message. This increments errors as well as saving the error message.
/// @param message The reason the test failed. /// @param message The error message.
/// @return A reference to this instance. Used for chaining. /// @return A reference to this instance. Used for chaining.
TestResults& fail(const std::string& message); TestResults& error(std::string message);
/// @brief Adds a passed test. This increments total and passed.
/// @return A reference to this instance. Used for chaining.
TestResults& pass();
/// @brief Adds a skipped test. This increments total and skipped. /// @brief Adds a failed test. This increments total and failed.
/// @return A reference to this instance. Used for chaining. /// @return A reference to this instance. Used for chaining.
TestResults& skip(); TestResults& fail();
/// @brief Adds a skipped test with a message. This increments total and skipped as well as saving the skip message.
/// @param message The reason the test was skipped.
/// @return A reference to this instance. Used for chaining.
TestResults& skip(const std::string& message);
/// @brief Getter for the list of error messages. /// @brief Adds a failed test with a message. This increments total and failed as well as saving the failure message.
/// @return /// @param message The reason the test failed.
vector<string> error_messages(); /// @return A reference to this instance. Used for chaining.
TestResults& fail(const std::string& message);
/// @brief Getter for the count of errors. /// @brief Adds a passed test. This increments total and passed.
/// @return /// @return A reference to this instance. Used for chaining.
uint32_t errors(); TestResults& pass();
/// @brief Getter for the count of failed tests. /// @brief Adds a skipped test. This increments total and skipped.
/// @return The count of failed tests. /// @return A reference to this instance. Used for chaining.
uint32_t failed(); TestResults& skip();
/// @brief Getter for the list of failure messages. /// @brief Adds a skipped test with a message. This increments total and skipped as well as saving the skip message.
/// @return The list of failure messages. /// @param message The reason the test was skipped.
vector<string> failure_messages(); /// @return A reference to this instance. Used for chaining.
TestResults& skip(const std::string& message);
/// @brief Getter for the count of passed tests.
/// @return The count of passed tests.
uint32_t passed();
/// @brief Getter for the count of skipped tests.
/// @return The count of skipped tests.
uint32_t skipped();
/// @brief Getter for the list of skip messages. /// @brief Getter for the list of error messages.
/// @return The list of skip messages. /// @return
vector<string> skip_messages(); vector<string> error_messages();
/// @brief Getter for the count of total tests.
/// @return The count of total tests run.
uint32_t total();
/// @brief Returns the combination of this and another TestResults instance. /// @brief Getter for the count of errors.
/// @param other The other TestResults instance to add to this one. /// @return
/// @return The combination of the two TestResults instances. uint32_t errors();
TestResults operator+(const TestResults& other) const;
/// @brief Adds another TestResults to this one and returns a reference to this instance.
/// @param other The other TestResults instance to add to this one.
/// @return A reference to this instance.
TestResults& operator+=(const TestResults& other);
private:
std::vector<std::string> error_messages_;
uint32_t errors_;
uint32_t failed_;
std::vector<std::string> failure_messages_;
uint32_t passed_;
std::vector<std::string> skip_messages_;
uint32_t skipped_;
uint32_t total_;
};
/// @brief
/// @tparam TResult
template<typename TResult>
using TestCompareFunction = std::function<bool(const TResult& expected, const TResult& actual)>;
/// @brief /// @brief Getter for the count of failed tests.
/// @tparam TResult /// @return The count of failed tests.
template<typename TResult> uint32_t failed();
using MaybeTestCompareFunction = std::optional<TestCompareFunction<TResult>>;
using TestConfigureFunction = std::function<void()>; /// @brief Getter for the list of failure messages.
using MaybeTestConfigureFunction = std::optional<TestConfigureFunction>; /// @return The list of failure messages.
vector<string> failure_messages();
// TODO: For some reason all hell breaks loose if test_name or expected output are const&. Figure out why. /// @brief Getter for the count of passed tests.
/// @brief /// @return The count of passed tests.
/// @tparam TResult uint32_t passed();
/// @tparam ...TInputParams
template<typename TResult, typename... TInputParams>
using TestTuple = std::tuple<
std::string /* test_name */,
TResult /* expected_output */,
std::tuple<TInputParams...> /* input_params - The input parameters for this test. These will be used when calling std::apply with function_to_test to execute the test. */,
MaybeTestCompareFunction<TResult> /* test_compare_function - If this is not nullprt then this function will be called instead of suite_compare_function to determine if the test passes. Use this to check for side effects of the test. Return true if the test passes and false otherwise. */,
MaybeTestConfigureFunction /* test_setup_function - If this is not nullptr this function is called before each test to setup the environment. It is called with std::apply and input_params so you can use them to mock records with specific IDs or calculate an expected result. */,
MaybeTestConfigureFunction /* test_teardown_function If this is not nullptr this function is called after each test to cleanup any allocated/shared resources. */,
bool /* is_enabled If this is false the test, setup, and teardown functions are not run. */>;
/// @brief
/// @tparam TResult
/// @tparam TFunctionToTest
/// @tparam ...TInputParams
template<typename TResult, typename... TInputParams>
using TestSuite = std::tuple<
std::string,
std::function<TResult(TInputParams...)>,
std::vector<TestTuple<TResult, TInputParams...>>,
MaybeTestCompareFunction<TResult>,
MaybeTestConfigureFunction,
MaybeTestConfigureFunction,
bool
>;
// This function is called to execute a test suite. You provide it with some configuration info, optional utility callback functions, and test data (input parameters for each call to function_to_test and the expected result). It returns a TestResults that should be treated as an opaque data type. /// @brief Getter for the count of skipped tests.
// Not all parameters are named in code, but they are named and explained in the comments and will be described by those names below. /// @return The count of skipped tests.
// string suite_name - This is the name of this test suite. It is used for reporting messages. uint32_t skipped();
// TFunctionToTest function_to_test - This is the function to test. This may be replaced if necessary by std::function. It may not currently support class methods, but that is planned.
// vector<tuple<...>> tests - This is the test run data. Each tuple in the vector is a single test run. It's members are explained below.
// string test_name - This is the name of this test. It is used for reporting messages.
// TResult expected_output - This is the expected result of executing this test.
// bool(*)(const TResult expected, const TResult actual) test_compare_function - This is optional. If unset or set to nullptr it is skipped. If set to a function it is called to evaluate the test results. It takes the expected and actual results as parameters and should return true if the test passed and false otherwise. This may be changed to return a TestResults at some point.
// void(*)(TInputParams...) test_setup_function - This is optional. If unset or set to nullptr it is skipped. If set to a function it is called before each test to setup the environment for the test. You may use it to allocate resources and setup mocks, stubs, and spies.
// void(*)(TInputParams...) test_teardown_function - This is optiona. If unset or set to nullptr it is skipped. If set to a function it is called after each test to cleanup the environment after the test. You should free resources allocated by test_setup_function.
// bool is_enabled - This is optional. If unset or set to true the test is run. If set to false this test is skipped. If skipped it will be reported as a skipped/disabled test.
// bool(*)(const TResult expected, const TResult actual) suite_compare_function - This is optional. If unset or set to nullptr it is skipped. If set to a function and test_compare_function is not called for a test run then this function is called to evaluate the test results. It takes the expected and actual results as parameters and should return true if the test passed and false otherwise. This may be changed to return a TestResults at some point.
// void(*)() suite_setup_function - This is optional. If unset or set to nullptr it is skipped. If set to a function it is called before starting this test suite to setup the environment. You may use it to allocate resources and setup mocks, stubs, and spies.
// void(*)() suite_teardown_function - This is optional. If unset or set to nullptr it is skipped. If set to a function it is called after all tests in this suite have finished and all reporting has finished. You should free resources allocated by suite_setup_function.
// This method should be called like so. This is the minimal call and omits all of the optional params. This is the most common usage. You should put one tuple of inputs and expected output for each test case.
// results = collect_and_report_test_resultstest_fn(
// "Test: function_under_test",
// function_under_test,
// vector({
// make_tuple(
// "ShouldReturnAppleForGroupId_1_and_ItemId_2",
// string("Apple"),
// make_tuple(1,2),
// ),
// }),
// );
// The suites can be run from one file as such. From a file called ThingDoer_test.cpp to test the class/methods ThingDoer declared in ThingDoer.cpp. This isn't mandatory but is a best practice.
// You can use function_to_test without calling collect_and_report_test_results() and also could call it from a normal int main(int argc, char** argv) or other function.
// TestResults test_main_ThingDoer(int argc, char** argv) {
// TestResults results;
// results = collect_and_report_test_results(results, function_to_test("do_thing1", ...), argc, argv);
// results = collect_and_report_test_results(results, function_to_test("do_thing2", ...), argc, argv);
// return results;
// }
// Then some test harness either generated or explicit can call test_main_ThingDoer(...) and optionally reported there. Reporting granularity is controlled by how frequently you call collect_and_report_test_results(...).
// You can combine test results with results = results + function_to_test(..); and then collect_and_report_test_results on the aggregate TestResults value.
/// @brief /// @brief Getter for the list of skip messages.
/// @tparam TResult The result type of the test. /// @return The list of skip messages.
/// @tparam TInputParams... The types of parameters sent to the test function. vector<string> skip_messages();
/// @param suite_label The label for this test suite. For example a class name such as "MortgageCalculator".
/// @param function_to_test The function to be tested. It will be called with std::apply and a std::tuple<TInputParams...> made from each item in tests.
/// @param tests A std::vector of test runs.
/// @param suite_compare_function A function used to compare the expected and actual test results. This can be overridden per test by setting test_compare_function.
/// @param after_all This is called before each suite is started to setup the environment. This is where you should build mocks, setup spies, and test fixtures.
/// @param before_all This is called after each suite has completed to cleanup anything allocated in suite_before_each.
/// @param is_enabled If false none of these tests are run and they are all reported as skipped.
template <typename TResult, typename... TInputParams>
TestResults execute_suite(
std::string suite_label,
std::function<TResult(TInputParams...)> function_to_test,
vector<TestTuple<TResult, TInputParams...>> tests,
MaybeTestCompareFunction<TResult> suite_compare = std::nullopt,
MaybeTestConfigureFunction before_all = std::nullopt,
MaybeTestConfigureFunction after_all = std::nullopt,
bool is_enabled = true
) {
TestResults results;
std::cout << "🚀Beginning Suite: " << suite_label << std::endl;
// Step 1: Suite Setup /// @brief Getter for the count of total tests.
/// @return The count of total tests run.
uint32_t total();
if (before_all.has_value()) { /// @brief Returns the combination of this and another TestResults instance.
(*before_all)(); /// @param other The other TestResults instance to add to this one.
} /// @return The combination of the two TestResults instances.
TestResults operator+(const TestResults& other) const;
// Step 2: Execute Tests /// @brief Adds another TestResults to this one and returns a reference to this instance.
for_each(tests.begin(), tests.end(), [&suite_label, &function_to_test, &results, &suite_compare]( /// @param other The other TestResults instance to add to this one.
TestTuple<TResult, TInputParams...> test_data /// @return A reference to this instance.
) { TestResults& operator+=(const TestResults& other);
// Step 2a: Extract our variables from the TestTuple. private:
const std::string& test_name = std::get<0>(test_data); std::vector<std::string> error_messages_;
const std::string qualified_test_name = suite_label + "::" + test_name; uint32_t errors_;
const TResult& expected_output = std::get<1>(test_data); uint32_t failed_;
std::tuple<TInputParams...> input_params = std::get<2>(test_data); std::vector<std::string> failure_messages_;
MaybeTestCompareFunction<TResult> maybe_compare_function = std::get<3>(test_data); uint32_t passed_;
TestCompareFunction<TResult> compare_function = maybe_compare_function.has_value() std::vector<std::string> skip_messages_;
? *maybe_compare_function uint32_t skipped_;
: suite_compare.has_value() uint32_t total_;
? *suite_compare };
: [](const TResult& l, const TResult& r){return l==r;};
MaybeTestConfigureFunction before_each = std::get<4>(test_data);
MaybeTestConfigureFunction after_each = std::get<5>(test_data);
bool is_enabled = std::get<6>(test_data);
if (!is_enabled) { /// @brief
std::cout << " 🚧Skipping Test: " << test_name << std::endl; /// @tparam TResult
results.skip("🚧Skipping Test: " + qualified_test_name); template <typename TResult>
return; using TestCompareFunction = std::function<bool(const TResult& expected, const TResult& actual)>;
}
// Step 2b: Test Setup /// @brief
std::cout << " Beginning Test: " << test_name << std::endl; /// @tparam TResult
if(before_each.has_value()) { template <typename TResult>
(*before_each)(); using MaybeTestCompareFunction = std::optional<TestCompareFunction<TResult>>;
}
TResult actual; using TestConfigureFunction = std::function<void()>;
try { using MaybeTestConfigureFunction = std::optional<TestConfigureFunction>;
// Step 2c: Execute the test method.
actual = std::apply(function_to_test, input_params);
} catch(const std::exception& ex) {
std::ostringstream os;
os << "Caught exception \"" << ex.what() << "\"";
results.error("🔥ERROR: " + qualified_test_name + " " + os.str());
std::cout << " 🔥ERROR: " << os.str() << std::endl;
} catch(const std::string& message) {
std::ostringstream os;
os << "Caught string \"" << message << "\"";
results.error("🔥ERROR: " + qualified_test_name + " " + os.str());
std::cout << " 🔥ERROR: " << os.str() << std::endl;
} catch(...) {
string message = "Caught something that is neither an std::exception nor an std::string.";
results.error("🔥ERROR: " + qualified_test_name + " " + message);
std::cout << " 🔥ERROR: " << message << std::endl;
}
// Step 2d: Pass or fail. // TODO: For some reason all hell breaks loose if test_name or expected output are const&. Figure out why.
if (compare_function(expected_output, actual)) { /// @brief
results.pass(); /// @tparam TResult
std::cout << " ✅PASSED" << std::endl; /// @tparam ...TInputParams
} else { template <typename TResult, typename... TInputParams>
std::ostringstream os; using TestTuple =
os << "expected: \"" << expected_output << "\", actual: \"" << actual << "\""; std::tuple<std::string /* test_name */,
results.fail("❌FAILED: " + qualified_test_name + " " + os.str()); TResult /* expected_output */,
std::cout << " ❌FAILED: " << os.str() << std::endl; std::tuple<TInputParams...> /* input_params - The input parameters for this test. These will be used when
} calling std::apply with function_to_test to execute the test. */
,
MaybeTestCompareFunction<TResult> /* test_compare_function - If this is not nullprt then this function
will be called instead of suite_compare_function to determine if the
test passes. Use this to check for side effects of the test. Return
true if the test passes and false otherwise. */
,
MaybeTestConfigureFunction /* test_setup_function - If this is not nullptr this function is called before
each test to setup the environment. It is called with std::apply and
input_params so you can use them to mock records with specific IDs or
calculate an expected result. */
,
MaybeTestConfigureFunction /* test_teardown_function If this is not nullptr this function is called after
each test to cleanup any allocated/shared resources. */
,
bool /* is_enabled If this is false the test, setup, and teardown functions are not run. */>;
// Step 2e: Test Teardown /// @brief
if (after_each.has_value()) { /// @tparam TResult
(*after_each)(); /// @tparam TFunctionToTest
} /// @tparam ...TInputParams
std::cout << " Ending Test: " << test_name << std::endl; template <typename TResult, typename... TInputParams>
}); using TestSuite = std::tuple<std::string,
std::function<TResult(TInputParams...)>,
std::vector<TestTuple<TResult, TInputParams...>>,
MaybeTestCompareFunction<TResult>,
MaybeTestConfigureFunction,
MaybeTestConfigureFunction,
bool>;
// Step 3: Suite Teardown // This function is called to execute a test suite. You provide it with some configuration info, optional utility
if (after_all.has_value()) { // callback functions, and test data (input parameters for each call to function_to_test and the expected result). It
(*after_all)(); // returns a TestResults that should be treated as an opaque data type. Not all parameters are named in code, but they
} // are named and explained in the comments and will be described by those names below.
std::cout << "Ending Suite: " << suite_label << std::endl; // string suite_name - This is the name of this test suite. It is used for reporting messages.
return results; // TFunctionToTest function_to_test - This is the function to test. This may be replaced if necessary by
// std::function. It may not currently support class methods, but that is planned. vector<tuple<...>> tests - This is
// the test run data. Each tuple in the vector is a single test run. It's members are explained below.
// string test_name - This is the name of this test. It is used for reporting messages.
// TResult expected_output - This is the expected result of executing this test.
// bool(*)(const TResult expected, const TResult actual) test_compare_function - This is optional. If unset or set
// to nullptr it is skipped. If set to a function it is called to evaluate the test results. It takes the expected
// and actual results as parameters and should return true if the test passed and false otherwise. This may be
// changed to return a TestResults at some point. void(*)(TInputParams...) test_setup_function - This is optional.
// If unset or set to nullptr it is skipped. If set to a function it is called before each test to setup the
// environment for the test. You may use it to allocate resources and setup mocks, stubs, and spies.
// void(*)(TInputParams...) test_teardown_function - This is optiona. If unset or set to nullptr it is skipped. If
// set to a function it is called after each test to cleanup the environment after the test. You should free
// resources allocated by test_setup_function. bool is_enabled - This is optional. If unset or set to true the test
// is run. If set to false this test is skipped. If skipped it will be reported as a skipped/disabled test.
// bool(*)(const TResult expected, const TResult actual) suite_compare_function - This is optional. If unset or set to
// nullptr it is skipped. If set to a function and test_compare_function is not called for a test run then this
// function is called to evaluate the test results. It takes the expected and actual results as parameters and should
// return true if the test passed and false otherwise. This may be changed to return a TestResults at some point.
// void(*)() suite_setup_function - This is optional. If unset or set to nullptr it is skipped. If set to a function
// it is called before starting this test suite to setup the environment. You may use it to allocate resources and
// setup mocks, stubs, and spies. void(*)() suite_teardown_function - This is optional. If unset or set to nullptr it
// is skipped. If set to a function it is called after all tests in this suite have finished and all reporting has
// finished. You should free resources allocated by suite_setup_function.
// This method should be called like so. This is the minimal call and omits all of the optional params. This is the most
// common usage. You should put one tuple of inputs and expected output for each test case.
// results = collect_and_report_test_resultstest_fn(
// "Test: function_under_test",
// function_under_test,
// vector({
// make_tuple(
// "ShouldReturnAppleForGroupId_1_and_ItemId_2",
// string("Apple"),
// make_tuple(1,2),
// ),
// }),
// );
// The suites can be run from one file as such. From a file called ThingDoer_test.cpp to test the class/methods
// ThingDoer declared in ThingDoer.cpp. This isn't mandatory but is a best practice. You can use function_to_test
// without calling collect_and_report_test_results() and also could call it from a normal int main(int argc, char**
// argv) or other function.
// TestResults test_main_ThingDoer(int argc, char** argv) {
// TestResults results;
// results = collect_and_report_test_results(results, function_to_test("do_thing1", ...), argc, argv);
// results = collect_and_report_test_results(results, function_to_test("do_thing2", ...), argc, argv);
// return results;
// }
// Then some test harness either generated or explicit can call test_main_ThingDoer(...) and optionally reported there.
// Reporting granularity is controlled by how frequently you call collect_and_report_test_results(...). You can combine
// test results with results = results + function_to_test(..); and then collect_and_report_test_results on the aggregate
// TestResults value.
/// @brief
/// @tparam TResult The result type of the test.
/// @tparam TInputParams... The types of parameters sent to the test function.
/// @param suite_label The label for this test suite. For example a class name such as "MortgageCalculator".
/// @param function_to_test The function to be tested. It will be called with std::apply and a
/// std::tuple<TInputParams...> made from each item in tests.
/// @param tests A std::vector of test runs.
/// @param suite_compare_function A function used to compare the expected and actual test results. This can be
/// overridden per test by setting test_compare_function.
/// @param after_all This is called before each suite is started to setup the environment. This is where you should
/// build mocks, setup spies, and test fixtures.
/// @param before_all This is called after each suite has completed to cleanup anything allocated in suite_before_each.
/// @param is_enabled If false none of these tests are run and they are all reported as skipped.
template <typename TResult, typename... TInputParams>
TestResults execute_suite(std::string suite_label,
std::function<TResult(TInputParams...)> function_to_test,
vector<TestTuple<TResult, TInputParams...>> tests,
MaybeTestCompareFunction<TResult> suite_compare = std::nullopt,
MaybeTestConfigureFunction before_all = std::nullopt,
MaybeTestConfigureFunction after_all = std::nullopt,
bool is_enabled = true) {
TestResults results;
std::cout << "🚀Beginning Suite: " << suite_label << std::endl;
// Step 1: Suite Setup
if (before_all.has_value()) {
(*before_all)();
}
// Step 2: Execute Tests
for_each(tests.begin(),
tests.end(),
[&suite_label, &function_to_test, &results, &suite_compare](TestTuple<TResult, TInputParams...> test_data) {
// Step 2a: Extract our variables from the TestTuple.
const std::string& test_name = std::get<0>(test_data);
const std::string qualified_test_name = suite_label + "::" + test_name;
const TResult& expected_output = std::get<1>(test_data);
std::tuple<TInputParams...> input_params = std::get<2>(test_data);
MaybeTestCompareFunction<TResult> maybe_compare_function = std::get<3>(test_data);
TestCompareFunction<TResult> compare_function =
maybe_compare_function.has_value() ? *maybe_compare_function
: suite_compare.has_value() ? *suite_compare
: [](const TResult& l, const TResult& r) { return l == r; };
MaybeTestConfigureFunction before_each = std::get<4>(test_data);
MaybeTestConfigureFunction after_each = std::get<5>(test_data);
bool is_enabled = std::get<6>(test_data);
if (!is_enabled) {
std::cout << " 🚧Skipping Test: " << test_name << std::endl;
results.skip("🚧Skipping Test: " + qualified_test_name);
return;
}
// Step 2b: Test Setup
std::cout << " Beginning Test: " << test_name << std::endl;
if (before_each.has_value()) {
(*before_each)();
}
TResult actual;
try {
// Step 2c: Execute the test method.
actual = std::apply(function_to_test, input_params);
} catch (const std::exception& ex) {
std::ostringstream os;
os << "Caught exception \"" << ex.what() << "\"";
results.error("🔥ERROR: " + qualified_test_name + " " + os.str());
std::cout << " 🔥ERROR: " << os.str() << std::endl;
} catch (const std::string& message) {
std::ostringstream os;
os << "Caught string \"" << message << "\"";
results.error("🔥ERROR: " + qualified_test_name + " " + os.str());
std::cout << " 🔥ERROR: " << os.str() << std::endl;
} catch (...) {
string message = "Caught something that is neither an std::exception nor an std::string.";
results.error("🔥ERROR: " + qualified_test_name + " " + message);
std::cout << " 🔥ERROR: " << message << std::endl;
}
// Step 2d: Pass or fail.
if (compare_function(expected_output, actual)) {
results.pass();
std::cout << " ✅PASSED" << std::endl;
} else {
std::ostringstream os;
os << "expected: \"" << expected_output << "\", actual: \"" << actual << "\"";
results.fail("❌FAILED: " + qualified_test_name + " " + os.str());
std::cout << " ❌FAILED: " << os.str() << std::endl;
}
// Step 2e: Test Teardown
if (after_each.has_value()) {
(*after_each)();
}
std::cout << " Ending Test: " << test_name << std::endl;
});
// Step 3: Suite Teardown
if (after_all.has_value()) {
(*after_all)();
}
std::cout << "Ending Suite: " << suite_label << std::endl;
return results;
}
/// @brief
/// @tparam TResult The result type of the test.
/// @tparam ...TInputParams The types of parameters sent to the test function.
/// @param test_name The label for this test. For example "should calculate the interest".
/// @param expected The expected output of calling the test function with these input parameters.
/// @param input_params The input parameters to use when calling the test function.
/// @param test_compare_fn An optional function that can be used to compare the expected and actual return values. This
/// is good for when you only care about certain fields being equal.
/// @param before_each This is called to setup the environment before running the test. This is where you should build
/// mocks, setup spies, and set any other values you need before calling the test function.
/// @param after_each This is called after each test run to cleanup anything allocated in before_each.
/// @param is_enabled If false this test run is not executed and considered skipped for reporting purposes.
/// @return A TestTuple suitable for use as a test run when calling test_fn.
template <typename TResult, typename... TInputParams>
TestTuple<TResult, TInputParams...> make_test(const string& test_name,
const TResult& expected,
tuple<TInputParams...> input_params,
MaybeTestCompareFunction<TResult> test_compare_fn = std::nullopt,
MaybeTestConfigureFunction before_each = std::nullopt,
MaybeTestConfigureFunction after_each = std::nullopt,
bool is_enabled = true) {
return make_tuple(test_name, expected, input_params, test_compare_fn, before_each, after_each, is_enabled);
}
/// @brief
/// @tparam TResult
/// @tparam TFunctionToTest
/// @tparam ...TInputParams
/// @param suite_name
/// @param function_to_test
/// @param test_data
/// @param compare
/// @param before_each
/// @param after_each
/// @param is_enabled
/// @return
template <typename TResult, typename TFunctionToTest, typename... TInputParams>
TestSuite<TResult, TInputParams...> make_test_suite(const string& suite_name,
TFunctionToTest function_to_test,
vector<TestTuple<TResult, TInputParams...>> test_data,
MaybeTestCompareFunction<TResult> compare = std::nullopt,
MaybeTestConfigureFunction before_each = std::nullopt,
MaybeTestConfigureFunction after_each = std::nullopt,
bool is_enabled = true) {
return make_tuple(suite_name, function_to_test, test_data, compare, before_each, after_each, is_enabled);
}
template <typename TResult, typename... TInputParams>
TestResults execute_suite(const TestSuite<TResult, TInputParams...>& test_suite) {
return execute_suite<TResult, TInputParams...>(
std::get<0>(test_suite), std::get<1>(test_suite), std::get<2>(test_suite)
// TODO: make this work for the optional parts of the tuple too.
);
}
/// @brief
/// @tparam ...TInputParams
/// @param first
/// @param second
/// @return
template <typename... TInputParams>
MaybeTestConfigureFunction coalesce(MaybeTestConfigureFunction first, MaybeTestConfigureFunction second) {
if (first.has_value()) {
if (second.has_value()) {
// This is the only place we actually need to combine them.
return [&first, &second](TInputParams... input_params) {
*first(input_params...);
*second(input_params...);
};
} else {
return first;
} }
} else {
/// @brief return second;
/// @tparam TResult The result type of the test. }
/// @tparam ...TInputParams The types of parameters sent to the test function. }
/// @param test_name The label for this test. For example "should calculate the interest". } // End namespace Test
/// @param expected The expected output of calling the test function with these input parameters.
/// @param input_params The input parameters to use when calling the test function.
/// @param test_compare_fn An optional function that can be used to compare the expected and actual return values. This is good for when you only care about certain fields being equal.
/// @param before_each This is called to setup the environment before running the test. This is where you should build mocks, setup spies, and set any other values you need before calling the test function.
/// @param after_each This is called after each test run to cleanup anything allocated in before_each.
/// @param is_enabled If false this test run is not executed and considered skipped for reporting purposes.
/// @return A TestTuple suitable for use as a test run when calling test_fn.
template<typename TResult, typename... TInputParams>
TestTuple<TResult, TInputParams...>
make_test(
const string& test_name,
const TResult& expected,
tuple<TInputParams...> input_params,
MaybeTestCompareFunction<TResult> test_compare_fn = std::nullopt,
MaybeTestConfigureFunction before_each = std::nullopt,
MaybeTestConfigureFunction after_each = std::nullopt,
bool is_enabled = true) {
return make_tuple(
test_name,
expected,
input_params,
test_compare_fn,
before_each,
after_each,
is_enabled);
}
/// @brief
/// @tparam TResult
/// @tparam TFunctionToTest
/// @tparam ...TInputParams
/// @param suite_name
/// @param function_to_test
/// @param test_data
/// @param compare
/// @param before_each
/// @param after_each
/// @param is_enabled
/// @return
template<typename TResult, typename TFunctionToTest, typename... TInputParams>
TestSuite<TResult, TInputParams...> make_test_suite(
const string& suite_name,
TFunctionToTest function_to_test,
vector<TestTuple<TResult, TInputParams...>> test_data,
MaybeTestCompareFunction<TResult> compare = std::nullopt,
MaybeTestConfigureFunction before_each = std::nullopt,
MaybeTestConfigureFunction after_each = std::nullopt,
bool is_enabled = true) {
return make_tuple(suite_name, function_to_test, test_data, compare, before_each, after_each, is_enabled);
}
template <typename TResult, typename... TInputParams>
TestResults execute_suite(const TestSuite<TResult, TInputParams...>& test_suite) {
return execute_suite<TResult, TInputParams...>(
std::get<0>(test_suite),
std::get<1>(test_suite),
std::get<2>(test_suite)
// TODO: make this work for the optional parts of the tuple too.
);
}
/// @brief
/// @tparam ...TInputParams
/// @param first
/// @param second
/// @return
template<typename... TInputParams>
MaybeTestConfigureFunction coalesce(
MaybeTestConfigureFunction first,
MaybeTestConfigureFunction second) {
if (first.has_value()) {
if (second.has_value()) {
// This is the only place we actually need to combine them.
return [&first, &second](TInputParams... input_params) {
*first(input_params...);
*second(input_params...);
};
} else {
return first;
}
} else {
return second;
}
}
} // End namespace Test
// TODO: define operator<< for std::tuple. // TODO: define operator<< for std::tuple.
// TODO: Add TShared(*)(string /*test_name*/, UUID /*test_run_id*/) allocate_shared_data to the test tuple to make some shared data that can be used in a thread safe way by setup, teardown, and evaluate steps of the test. // TODO: Add TShared(*)(string /*test_name*/, UUID /*test_run_id*/) allocate_shared_data to the test tuple to make some
// shared data that can be used in a thread safe way by setup, teardown, and evaluate steps of the test.
// TODO: Add TShared to be returned by the setup functions, and consumed by the evaluate and teardown functions. // TODO: Add TShared to be returned by the setup functions, and consumed by the evaluate and teardown functions.
// Suite setup/teardown functions should allocate/free. // Suite setup/teardown functions should allocate/free.
// Test setup/teardown functions should consume the data allocated by suite setup. // Test setup/teardown functions should consume the data allocated by suite setup.
// Test setup functions may allocate additional resources. If they do then the allocated resources they should be freed by test teardown function. // Test setup functions may allocate additional resources. If they do then the allocated resources they should be
// Suite and/or test compare functions may consume this shared data, but it will not be shared with the execution of function_to_test. // freed by test teardown function. Suite and/or test compare functions may consume this shared data, but it will not
#endif // End !defined TEST_H__ // be shared with the execution of function_to_test.
#endif // End !defined TEST_H__